feat: add staking score pallet to relay chain and fix referral default

Relay Chain:
- Add pezpallet-staking-score to runtime
- Implement RelayStakingInfoProvider to read from pallet_staking
- StakingScore pallet index = 92

People Chain:
- Add DefaultReferrer type to identity-kyc pallet Config
- Change DefaultReferrer from Alice to founder address
- Make referrer parameter optional in apply_for_citizenship
- Fallback to DefaultReferrer when no valid referrer provided
This commit is contained in:
2026-02-07 00:43:28 +03:00
parent 6a02481f00
commit 1d64a1317a
4 changed files with 79 additions and 15 deletions
@@ -131,6 +131,9 @@ pub mod pezpallet {
type WeightInfo: WeightInfo;
/// Default referrer account (founder) - used when no valid referrer is provided
type DefaultReferrer: Get<Self::AccountId>;
/// Hook called when citizenship is approved - used by referral pezpallet
type OnKycApproved: crate::types::OnKycApproved<Self::AccountId>;
@@ -284,49 +287,59 @@ pub mod pezpallet {
///
/// # Arguments
/// - `identity_hash`: H256 hash of identity documents (calculated off-chain)
/// - `referrer`: Account of existing citizen who will vouch for you
/// - `referrer`: Optional account of existing citizen who will vouch for you.
/// If None or invalid, DefaultReferrer (founder) is used.
///
/// # Workflow
/// 1. Applicant submits hash + referrer
/// 2. Deposit is reserved (spam prevention)
/// 3. Status becomes PendingReferral
/// 4. Referrer must call approve_referral
/// 1. Applicant submits hash + optional referrer
/// 2. If referrer is None/invalid, DefaultReferrer is used
/// 3. Deposit is reserved (spam prevention)
/// 4. Status becomes PendingReferral
/// 5. Referrer must call approve_referral
#[pezpallet::call_index(0)]
#[pezpallet::weight(T::WeightInfo::apply_for_citizenship())]
pub fn apply_for_citizenship(
origin: OriginFor<T>,
identity_hash: H256,
referrer: T::AccountId,
referrer: Option<T::AccountId>,
) -> DispatchResult {
let applicant = ensure_signed(origin)?;
// Cannot refer yourself
ensure!(applicant != referrer, Error::<T>::SelfReferral);
// Must not have existing application
ensure!(
KycStatuses::<T>::get(&applicant) == KycLevel::NotStarted,
Error::<T>::ApplicationAlreadyExists
);
// Referrer must be an approved citizen
// Determine the actual referrer:
// 1. Use provided referrer if valid (approved citizen and not self)
// 2. Fall back to DefaultReferrer otherwise
let actual_referrer = referrer
.filter(|r| *r != applicant) // Not self-referral
.filter(|r| KycStatuses::<T>::get(r) == KycLevel::Approved) // Must be citizen
.unwrap_or_else(|| T::DefaultReferrer::get());
// Verify the actual referrer is valid (including DefaultReferrer)
ensure!(
KycStatuses::<T>::get(&referrer) == KycLevel::Approved,
KycStatuses::<T>::get(&actual_referrer) == KycLevel::Approved,
Error::<T>::ReferrerNotCitizen
);
// Cannot refer yourself (even with DefaultReferrer)
ensure!(applicant != actual_referrer, Error::<T>::SelfReferral);
// Reserve deposit (spam prevention, returned on approval)
let deposit = T::KycApplicationDeposit::get();
T::Currency::reserve(&applicant, deposit)?;
// Store application (only hash, no personal data)
let application = CitizenshipApplication { identity_hash, referrer: referrer.clone() };
let application = CitizenshipApplication { identity_hash, referrer: actual_referrer.clone() };
Applications::<T>::insert(&applicant, application);
// Update status
KycStatuses::<T>::insert(&applicant, KycLevel::PendingReferral);
Self::deposit_event(Event::CitizenshipApplied { applicant, referrer, identity_hash });
Self::deposit_event(Event::CitizenshipApplied { applicant, referrer: actual_referrer, identity_hash });
Ok(())
}
@@ -298,6 +298,7 @@ impl pezpallet_identity_kyc::Config for Runtime {
type KycApplicationDeposit = KycApplicationDeposit;
type MaxStringLength = MaxStringLength;
type MaxCidLength = MaxCidLength;
type DefaultReferrer = DefaultReferrer;
}
// =============================================================================
@@ -371,8 +372,14 @@ impl pezpallet_perwerde::Config for Runtime {
// =============================================================================
parameter_types! {
/// Default referrer account (genesis/system account)
pub DefaultReferrer: AccountId = pezsp_keyring::Sr25519Keyring::Alice.to_account_id();
/// Default referrer account - Founder address
/// SS58: 5CyuFfbF95rzBxru7c9yEsX4XmQXUxpLUcbj9RLg9K1cGiiF
pub DefaultReferrer: AccountId = AccountId::from([
0x28, 0x92, 0x5e, 0xd8, 0xb4, 0xc0, 0xc9, 0x54,
0x02, 0xb3, 0x15, 0x63, 0x25, 0x1f, 0xd3, 0x18,
0x41, 0x43, 0x51, 0x11, 0x4b, 0x1c, 0x77, 0x97,
0xee, 0x78, 0x86, 0x66, 0xd2, 0x7d, 0x63, 0x05,
]);
/// Penalty per revocation (trust score reduction)
pub const PenaltyPerRevocation: u32 = 10;
}