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:
@@ -131,6 +131,9 @@ pub mod pezpallet {
|
|||||||
|
|
||||||
type WeightInfo: WeightInfo;
|
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
|
/// Hook called when citizenship is approved - used by referral pezpallet
|
||||||
type OnKycApproved: crate::types::OnKycApproved<Self::AccountId>;
|
type OnKycApproved: crate::types::OnKycApproved<Self::AccountId>;
|
||||||
|
|
||||||
@@ -284,49 +287,59 @@ pub mod pezpallet {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// - `identity_hash`: H256 hash of identity documents (calculated off-chain)
|
/// - `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
|
/// # Workflow
|
||||||
/// 1. Applicant submits hash + referrer
|
/// 1. Applicant submits hash + optional referrer
|
||||||
/// 2. Deposit is reserved (spam prevention)
|
/// 2. If referrer is None/invalid, DefaultReferrer is used
|
||||||
/// 3. Status becomes PendingReferral
|
/// 3. Deposit is reserved (spam prevention)
|
||||||
/// 4. Referrer must call approve_referral
|
/// 4. Status becomes PendingReferral
|
||||||
|
/// 5. Referrer must call approve_referral
|
||||||
#[pezpallet::call_index(0)]
|
#[pezpallet::call_index(0)]
|
||||||
#[pezpallet::weight(T::WeightInfo::apply_for_citizenship())]
|
#[pezpallet::weight(T::WeightInfo::apply_for_citizenship())]
|
||||||
pub fn apply_for_citizenship(
|
pub fn apply_for_citizenship(
|
||||||
origin: OriginFor<T>,
|
origin: OriginFor<T>,
|
||||||
identity_hash: H256,
|
identity_hash: H256,
|
||||||
referrer: T::AccountId,
|
referrer: Option<T::AccountId>,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
let applicant = ensure_signed(origin)?;
|
let applicant = ensure_signed(origin)?;
|
||||||
|
|
||||||
// Cannot refer yourself
|
|
||||||
ensure!(applicant != referrer, Error::<T>::SelfReferral);
|
|
||||||
|
|
||||||
// Must not have existing application
|
// Must not have existing application
|
||||||
ensure!(
|
ensure!(
|
||||||
KycStatuses::<T>::get(&applicant) == KycLevel::NotStarted,
|
KycStatuses::<T>::get(&applicant) == KycLevel::NotStarted,
|
||||||
Error::<T>::ApplicationAlreadyExists
|
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!(
|
ensure!(
|
||||||
KycStatuses::<T>::get(&referrer) == KycLevel::Approved,
|
KycStatuses::<T>::get(&actual_referrer) == KycLevel::Approved,
|
||||||
Error::<T>::ReferrerNotCitizen
|
Error::<T>::ReferrerNotCitizen
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Cannot refer yourself (even with DefaultReferrer)
|
||||||
|
ensure!(applicant != actual_referrer, Error::<T>::SelfReferral);
|
||||||
|
|
||||||
// Reserve deposit (spam prevention, returned on approval)
|
// Reserve deposit (spam prevention, returned on approval)
|
||||||
let deposit = T::KycApplicationDeposit::get();
|
let deposit = T::KycApplicationDeposit::get();
|
||||||
T::Currency::reserve(&applicant, deposit)?;
|
T::Currency::reserve(&applicant, deposit)?;
|
||||||
|
|
||||||
// Store application (only hash, no personal data)
|
// 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);
|
Applications::<T>::insert(&applicant, application);
|
||||||
|
|
||||||
// Update status
|
// Update status
|
||||||
KycStatuses::<T>::insert(&applicant, KycLevel::PendingReferral);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,7 @@ impl pezpallet_identity_kyc::Config for Runtime {
|
|||||||
type KycApplicationDeposit = KycApplicationDeposit;
|
type KycApplicationDeposit = KycApplicationDeposit;
|
||||||
type MaxStringLength = MaxStringLength;
|
type MaxStringLength = MaxStringLength;
|
||||||
type MaxCidLength = MaxCidLength;
|
type MaxCidLength = MaxCidLength;
|
||||||
|
type DefaultReferrer = DefaultReferrer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -371,8 +372,14 @@ impl pezpallet_perwerde::Config for Runtime {
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
/// Default referrer account (genesis/system account)
|
/// Default referrer account - Founder address
|
||||||
pub DefaultReferrer: AccountId = pezsp_keyring::Sr25519Keyring::Alice.to_account_id();
|
/// 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)
|
/// Penalty per revocation (trust score reduction)
|
||||||
pub const PenaltyPerRevocation: u32 = 10;
|
pub const PenaltyPerRevocation: u32 = 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ pezkuwi-teyrchain-primitives = { workspace = true }
|
|||||||
|
|
||||||
# Custom Pezkuwi Pallets
|
# Custom Pezkuwi Pallets
|
||||||
pezpallet-validator-pool = { workspace = true }
|
pezpallet-validator-pool = { workspace = true }
|
||||||
|
pezpallet-staking-score = { workspace = true }
|
||||||
|
|
||||||
xcm = { workspace = true }
|
xcm = { workspace = true }
|
||||||
xcm-builder = { workspace = true }
|
xcm-builder = { workspace = true }
|
||||||
@@ -192,6 +193,7 @@ std = [
|
|||||||
"pezpallet-treasury/std",
|
"pezpallet-treasury/std",
|
||||||
"pezpallet-utility/std",
|
"pezpallet-utility/std",
|
||||||
"pezpallet-validator-pool/std",
|
"pezpallet-validator-pool/std",
|
||||||
|
"pezpallet-staking-score/std",
|
||||||
"pezpallet-vesting/std",
|
"pezpallet-vesting/std",
|
||||||
"pezpallet-whitelist/std",
|
"pezpallet-whitelist/std",
|
||||||
"pezpallet-xcm-benchmarks?/std",
|
"pezpallet-xcm-benchmarks?/std",
|
||||||
@@ -284,6 +286,7 @@ runtime-benchmarks = [
|
|||||||
"pezpallet-treasury/runtime-benchmarks",
|
"pezpallet-treasury/runtime-benchmarks",
|
||||||
"pezpallet-utility/runtime-benchmarks",
|
"pezpallet-utility/runtime-benchmarks",
|
||||||
"pezpallet-validator-pool/runtime-benchmarks",
|
"pezpallet-validator-pool/runtime-benchmarks",
|
||||||
|
"pezpallet-staking-score/runtime-benchmarks",
|
||||||
"pezpallet-vesting/runtime-benchmarks",
|
"pezpallet-vesting/runtime-benchmarks",
|
||||||
"pezpallet-whitelist/runtime-benchmarks",
|
"pezpallet-whitelist/runtime-benchmarks",
|
||||||
"pezpallet-xcm-benchmarks/runtime-benchmarks",
|
"pezpallet-xcm-benchmarks/runtime-benchmarks",
|
||||||
@@ -366,6 +369,7 @@ try-runtime = [
|
|||||||
"pezpallet-treasury/try-runtime",
|
"pezpallet-treasury/try-runtime",
|
||||||
"pezpallet-utility/try-runtime",
|
"pezpallet-utility/try-runtime",
|
||||||
"pezpallet-validator-pool/try-runtime",
|
"pezpallet-validator-pool/try-runtime",
|
||||||
|
"pezpallet-staking-score/try-runtime",
|
||||||
"pezpallet-vesting/try-runtime",
|
"pezpallet-vesting/try-runtime",
|
||||||
"pezpallet-whitelist/try-runtime",
|
"pezpallet-whitelist/try-runtime",
|
||||||
"pezpallet-xcm-benchmarks?/try-runtime",
|
"pezpallet-xcm-benchmarks?/try-runtime",
|
||||||
|
|||||||
@@ -565,6 +565,42 @@ impl pezpallet_staking::Config for Runtime {
|
|||||||
type BenchmarkingConfig = PezkuwiStakingBenchmarkingConfig;
|
type BenchmarkingConfig = PezkuwiStakingBenchmarkingConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// STAKING SCORE CONFIGURATION
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
/// Relay Chain StakingInfoProvider - reads directly from pezpallet_staking
|
||||||
|
/// This is the REAL implementation that accesses actual staking data
|
||||||
|
pub struct RelayStakingInfoProvider;
|
||||||
|
|
||||||
|
impl pezpallet_staking_score::StakingInfoProvider<AccountId, Balance>
|
||||||
|
for RelayStakingInfoProvider
|
||||||
|
{
|
||||||
|
fn get_staking_details(
|
||||||
|
who: &AccountId,
|
||||||
|
) -> Option<pezpallet_staking_score::StakingDetails<Balance>> {
|
||||||
|
// Get staking ledger from pezpallet_staking
|
||||||
|
let ledger = pezpallet_staking::Ledger::<Runtime>::get(who)?;
|
||||||
|
|
||||||
|
// Get nominations if any
|
||||||
|
let nominations_count = pezpallet_staking::Nominators::<Runtime>::get(who)
|
||||||
|
.map(|n| n.targets.len() as u32)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
Some(pezpallet_staking_score::StakingDetails {
|
||||||
|
staked_amount: ledger.active,
|
||||||
|
nominations_count,
|
||||||
|
unlocking_chunks_count: ledger.unlocking.len() as u32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pezpallet_staking_score::Config for Runtime {
|
||||||
|
type Balance = Balance;
|
||||||
|
type StakingInfo = RelayStakingInfoProvider;
|
||||||
|
type WeightInfo = pezpallet_staking_score::weights::BizinikiwiWeight<Runtime>;
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// FAST UNSTAKE CONFIGURATION
|
// FAST UNSTAKE CONFIGURATION
|
||||||
// =====================================================
|
// =====================================================
|
||||||
@@ -1570,6 +1606,9 @@ construct_runtime! {
|
|||||||
// TNPoS Validator Pool - Shadow Mode (runs parallel to NPoS)
|
// TNPoS Validator Pool - Shadow Mode (runs parallel to NPoS)
|
||||||
ValidatorPool: pezpallet_validator_pool = 91,
|
ValidatorPool: pezpallet_validator_pool = 91,
|
||||||
|
|
||||||
|
// Staking Score - Time-weighted staking reputation score
|
||||||
|
StakingScore: pezpallet_staking_score = 92,
|
||||||
|
|
||||||
// Root testing pezpallet.
|
// Root testing pezpallet.
|
||||||
RootTesting: pezpallet_root_testing = 249,
|
RootTesting: pezpallet_root_testing = 249,
|
||||||
|
|
||||||
@@ -1821,6 +1860,7 @@ mod benches {
|
|||||||
[pezpallet_whitelist, Whitelist]
|
[pezpallet_whitelist, Whitelist]
|
||||||
// Pezkuwichain Custom Pallets
|
// Pezkuwichain Custom Pallets
|
||||||
[pezpallet_validator_pool, ValidatorPool]
|
[pezpallet_validator_pool, ValidatorPool]
|
||||||
|
[pezpallet_staking_score, StakingScore]
|
||||||
// XCM
|
// XCM
|
||||||
[pezpallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
|
[pezpallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
|
||||||
[pezpallet_xcm_benchmarks::fungible, pezpallet_xcm_benchmarks::fungible::Pezpallet::<Runtime>]
|
[pezpallet_xcm_benchmarks::fungible, pezpallet_xcm_benchmarks::fungible::Pezpallet::<Runtime>]
|
||||||
|
|||||||
Reference in New Issue
Block a user