3139ffa25e
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs) - pallet/ directories → pezpallet/ (4 locations) - Fixed pezpallet.rs self-include recursion bug - Fixed sc-chain-spec hardcoded crate name in derive macro - Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API) - Added BizinikiwiConfig type alias for zombienet tests - Deleted obsolete session state files Verified: pezsnowbridge-pezpallet-*, pezpallet-staking, pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
552 lines
16 KiB
Rust
552 lines
16 KiB
Rust
use crate::{mock::*, types::KycLevel, Error, Event};
|
|
use pezframe_support::{assert_noop, assert_ok, traits::Currency};
|
|
use pezsp_core::H256;
|
|
use pezsp_runtime::DispatchError;
|
|
|
|
// Kolay erişim için paletimize bir takma ad veriyoruz.
|
|
type IdentityKycPallet = crate::Pezpallet<Test>;
|
|
|
|
// ============================================================================
|
|
// Genesis Config Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn genesis_config_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// FOUNDER and CITIZEN_1 should be pre-approved via genesis
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(FOUNDER), KycLevel::Approved);
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(CITIZEN_1), KycLevel::Approved);
|
|
|
|
// Their identity hashes should be stored
|
|
assert!(IdentityKycPallet::identity_hash_of(FOUNDER).is_some());
|
|
assert!(IdentityKycPallet::identity_hash_of(CITIZEN_1).is_some());
|
|
|
|
// Non-founding users should be NotStarted
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::NotStarted);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// apply_for_citizenship Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn apply_for_citizenship_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let identity_hash = H256::from_low_u64_be(12345);
|
|
|
|
// APPLICANT applies with CITIZEN_1 as referrer (who is pre-approved)
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
identity_hash,
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Check status changed to PendingReferral
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::PendingReferral);
|
|
|
|
// Check application was stored
|
|
let app = IdentityKycPallet::applications(APPLICANT).expect("Application should exist");
|
|
assert_eq!(app.identity_hash, identity_hash);
|
|
assert_eq!(app.referrer, CITIZEN_1);
|
|
|
|
// Check deposit was reserved
|
|
assert_eq!(Balances::reserved_balance(APPLICANT), KycApplicationDepositAmount::get());
|
|
|
|
// Check event was emitted
|
|
System::assert_last_event(
|
|
Event::CitizenshipApplied { applicant: APPLICANT, referrer: CITIZEN_1, identity_hash }
|
|
.into(),
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn apply_for_citizenship_fails_if_self_referral() {
|
|
new_test_ext().execute_with(|| {
|
|
// Cannot refer yourself
|
|
assert_noop!(
|
|
IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
H256::from_low_u64_be(999),
|
|
CITIZEN_1 // Same as caller
|
|
),
|
|
Error::<Test>::SelfReferral
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn apply_for_citizenship_fails_if_referrer_not_citizen() {
|
|
new_test_ext().execute_with(|| {
|
|
// APPLICANT is not a citizen, so cannot be a referrer
|
|
assert_noop!(
|
|
IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(CITIZEN_2),
|
|
H256::from_low_u64_be(999),
|
|
APPLICANT // Not a citizen
|
|
),
|
|
Error::<Test>::ReferrerNotCitizen
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn apply_for_citizenship_fails_if_already_applied() {
|
|
new_test_ext().execute_with(|| {
|
|
let identity_hash = H256::from_low_u64_be(12345);
|
|
|
|
// First application succeeds
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
identity_hash,
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Second application fails
|
|
assert_noop!(
|
|
IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(99999),
|
|
CITIZEN_1
|
|
),
|
|
Error::<Test>::ApplicationAlreadyExists
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn apply_for_citizenship_fails_insufficient_balance() {
|
|
new_test_ext().execute_with(|| {
|
|
let poor_user = 999; // No balance in genesis
|
|
|
|
assert_noop!(
|
|
IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(poor_user),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
),
|
|
pezpallet_balances::Error::<Test>::InsufficientBalance
|
|
);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// approve_referral Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn approve_referral_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let identity_hash = H256::from_low_u64_be(12345);
|
|
|
|
// APPLICANT applies with CITIZEN_1 as referrer
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
identity_hash,
|
|
CITIZEN_1
|
|
));
|
|
|
|
// CITIZEN_1 approves the referral
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
|
|
// Check status changed to ReferrerApproved
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::ReferrerApproved);
|
|
|
|
// Check event
|
|
System::assert_last_event(
|
|
Event::ReferralApproved { referrer: CITIZEN_1, applicant: APPLICANT }.into(),
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn approve_referral_fails_if_not_referrer() {
|
|
new_test_ext().execute_with(|| {
|
|
// APPLICANT applies with CITIZEN_1 as referrer
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
|
|
// FOUNDER (different citizen) cannot approve
|
|
assert_noop!(
|
|
IdentityKycPallet::approve_referral(RuntimeOrigin::signed(FOUNDER), APPLICANT),
|
|
Error::<Test>::NotTheReferrer
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn approve_referral_fails_if_not_pending() {
|
|
new_test_ext().execute_with(|| {
|
|
// Try to approve referral for someone who hasn't applied
|
|
assert_noop!(
|
|
IdentityKycPallet::approve_referral(RuntimeOrigin::signed(CITIZEN_1), APPLICANT),
|
|
Error::<Test>::CannotApproveInCurrentState
|
|
);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// confirm_citizenship Tests (Self-confirmation for Welati NFT)
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn confirm_citizenship_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let identity_hash = H256::from_low_u64_be(12345);
|
|
let initial_balance = Balances::free_balance(APPLICANT);
|
|
|
|
// Apply
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
identity_hash,
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Referrer approves
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
|
|
// Self-confirm
|
|
assert_ok!(IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
|
|
// Check status is Approved
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::Approved);
|
|
|
|
// Check identity hash is stored permanently
|
|
assert_eq!(IdentityKycPallet::identity_hash_of(APPLICANT), Some(identity_hash));
|
|
|
|
// Check referrer is stored permanently
|
|
assert_eq!(IdentityKycPallet::citizen_referrer(APPLICANT), Some(CITIZEN_1));
|
|
|
|
// Check application was removed
|
|
assert!(IdentityKycPallet::applications(APPLICANT).is_none());
|
|
|
|
// Check deposit was returned
|
|
assert_eq!(Balances::reserved_balance(APPLICANT), 0);
|
|
assert_eq!(Balances::free_balance(APPLICANT), initial_balance);
|
|
|
|
// Check event
|
|
System::assert_last_event(Event::CitizenshipConfirmed { who: APPLICANT }.into());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn confirm_citizenship_fails_if_not_referrer_approved() {
|
|
new_test_ext().execute_with(|| {
|
|
// Apply but don't get referrer approval
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Try to self-confirm without referrer approval
|
|
assert_noop!(
|
|
IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)),
|
|
Error::<Test>::CannotConfirmInCurrentState
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn confirm_citizenship_fails_if_not_applied() {
|
|
new_test_ext().execute_with(|| {
|
|
// Try to confirm without applying
|
|
assert_noop!(
|
|
IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)),
|
|
Error::<Test>::CannotConfirmInCurrentState
|
|
);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// cancel_application Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn cancel_application_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let initial_balance = Balances::free_balance(APPLICANT);
|
|
|
|
// Apply
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Deposit should be reserved
|
|
assert_eq!(Balances::reserved_balance(APPLICANT), KycApplicationDepositAmount::get());
|
|
|
|
// Cancel
|
|
assert_ok!(IdentityKycPallet::cancel_application(RuntimeOrigin::signed(APPLICANT)));
|
|
|
|
// Status should be reset to NotStarted
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::NotStarted);
|
|
|
|
// Application should be removed
|
|
assert!(IdentityKycPallet::applications(APPLICANT).is_none());
|
|
|
|
// Deposit should be returned
|
|
assert_eq!(Balances::reserved_balance(APPLICANT), 0);
|
|
assert_eq!(Balances::free_balance(APPLICANT), initial_balance);
|
|
|
|
// Event
|
|
System::assert_last_event(Event::ApplicationCancelled { who: APPLICANT }.into());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn cancel_application_fails_if_not_pending_referral() {
|
|
new_test_ext().execute_with(|| {
|
|
// Apply and get referrer approval
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
|
|
// Cannot cancel after referrer approved (status is ReferrerApproved)
|
|
assert_noop!(
|
|
IdentityKycPallet::cancel_application(RuntimeOrigin::signed(APPLICANT)),
|
|
Error::<Test>::CannotCancelInCurrentState
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn cancel_application_allows_reapplication() {
|
|
new_test_ext().execute_with(|| {
|
|
// First application
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
|
|
// Cancel
|
|
assert_ok!(IdentityKycPallet::cancel_application(RuntimeOrigin::signed(APPLICANT)));
|
|
|
|
// Can apply again with different referrer
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(99999),
|
|
FOUNDER // Different referrer this time
|
|
));
|
|
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::PendingReferral);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// revoke_citizenship Tests (Governance action)
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn revoke_citizenship_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// Complete citizenship flow for APPLICANT
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
assert_ok!(IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::Approved);
|
|
|
|
// Governance revokes
|
|
assert_ok!(IdentityKycPallet::revoke_citizenship(RuntimeOrigin::root(), APPLICANT));
|
|
|
|
// Status should be Revoked
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::Revoked);
|
|
|
|
// Event
|
|
System::assert_last_event(Event::CitizenshipRevoked { who: APPLICANT }.into());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn revoke_citizenship_fails_for_bad_origin() {
|
|
new_test_ext().execute_with(|| {
|
|
// Non-root cannot revoke
|
|
assert_noop!(
|
|
IdentityKycPallet::revoke_citizenship(RuntimeOrigin::signed(CITIZEN_1), FOUNDER),
|
|
DispatchError::BadOrigin
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn revoke_citizenship_fails_if_not_citizen() {
|
|
new_test_ext().execute_with(|| {
|
|
// APPLICANT is not a citizen
|
|
assert_noop!(
|
|
IdentityKycPallet::revoke_citizenship(RuntimeOrigin::root(), APPLICANT),
|
|
Error::<Test>::CannotRevokeInCurrentState
|
|
);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// renounce_citizenship Tests (Voluntary exit)
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn renounce_citizenship_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// CITIZEN_1 is pre-approved, can renounce
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(CITIZEN_1), KycLevel::Approved);
|
|
|
|
assert_ok!(IdentityKycPallet::renounce_citizenship(RuntimeOrigin::signed(CITIZEN_1)));
|
|
|
|
// Status should be reset to NotStarted
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(CITIZEN_1), KycLevel::NotStarted);
|
|
|
|
// Identity hash should be removed
|
|
assert!(IdentityKycPallet::identity_hash_of(CITIZEN_1).is_none());
|
|
|
|
// Event
|
|
System::assert_last_event(Event::CitizenshipRenounced { who: CITIZEN_1 }.into());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn renounce_citizenship_fails_if_not_citizen() {
|
|
new_test_ext().execute_with(|| {
|
|
// APPLICANT is not a citizen
|
|
assert_noop!(
|
|
IdentityKycPallet::renounce_citizenship(RuntimeOrigin::signed(APPLICANT)),
|
|
Error::<Test>::NotACitizen
|
|
);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// Full Workflow Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn full_citizenship_workflow() {
|
|
new_test_ext().execute_with(|| {
|
|
let identity_hash = H256::from_low_u64_be(12345);
|
|
|
|
// 1. Apply
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
identity_hash,
|
|
CITIZEN_1
|
|
));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::PendingReferral);
|
|
|
|
// 2. Referrer approves
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::ReferrerApproved);
|
|
|
|
// 3. Self-confirm
|
|
assert_ok!(IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::Approved);
|
|
|
|
// 4. Now APPLICANT is a citizen and can be a referrer for others
|
|
let new_user = 50;
|
|
// First give new_user some balance
|
|
Balances::make_free_balance_be(&new_user, 10_000);
|
|
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(new_user),
|
|
H256::from_low_u64_be(99999),
|
|
APPLICANT // APPLICANT is now the referrer
|
|
));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(new_user), KycLevel::PendingReferral);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn renounce_and_reapply_workflow() {
|
|
new_test_ext().execute_with(|| {
|
|
// Complete first citizenship
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
assert_ok!(IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::Approved);
|
|
|
|
// Renounce
|
|
assert_ok!(IdentityKycPallet::renounce_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::NotStarted);
|
|
|
|
// Can reapply (free world principle)
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(99999), // Different hash
|
|
FOUNDER // Different referrer
|
|
));
|
|
assert_eq!(IdentityKycPallet::kyc_status_of(APPLICANT), KycLevel::PendingReferral);
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Function Tests
|
|
// ============================================================================
|
|
|
|
#[test]
|
|
fn is_citizen_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// Founding citizens should return true
|
|
assert!(IdentityKycPallet::is_citizen(&FOUNDER));
|
|
assert!(IdentityKycPallet::is_citizen(&CITIZEN_1));
|
|
|
|
// Non-citizens should return false
|
|
assert!(!IdentityKycPallet::is_citizen(&APPLICANT));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn get_referrer_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// Complete citizenship for APPLICANT
|
|
assert_ok!(IdentityKycPallet::apply_for_citizenship(
|
|
RuntimeOrigin::signed(APPLICANT),
|
|
H256::from_low_u64_be(12345),
|
|
CITIZEN_1
|
|
));
|
|
assert_ok!(IdentityKycPallet::approve_referral(
|
|
RuntimeOrigin::signed(CITIZEN_1),
|
|
APPLICANT
|
|
));
|
|
assert_ok!(IdentityKycPallet::confirm_citizenship(RuntimeOrigin::signed(APPLICANT)));
|
|
|
|
// Should return the referrer
|
|
assert_eq!(IdentityKycPallet::get_referrer(&APPLICANT), Some(CITIZEN_1));
|
|
|
|
// Founding citizens have no referrer (they were genesis)
|
|
assert_eq!(IdentityKycPallet::get_referrer(&FOUNDER), None);
|
|
});
|
|
}
|