fix: referral pallet - force_confirm stats tracking and penalty_score usage
- force_confirm_referral now updates ReferrerStatsStorage (was missing) - get_referral_score uses stored penalty_score from PenaltyPerRevocation instead of hardcoded (revoked*10)/4 formula - Updated tests to match new penalty calculation behavior
This commit is contained in:
@@ -239,6 +239,11 @@ pub mod pezpallet {
|
||||
let new_count = ReferralCount::<T>::get(&referrer).saturating_add(1);
|
||||
ReferralCount::<T>::insert(&referrer, new_count);
|
||||
|
||||
// Update referrer stats for direct responsibility tracking
|
||||
ReferrerStatsStorage::<T>::mutate(&referrer, |stats| {
|
||||
stats.total_referrals = stats.total_referrals.saturating_add(1);
|
||||
});
|
||||
|
||||
// Create and store referral info
|
||||
let referral_info = ReferralInfo {
|
||||
referrer: referrer.clone(),
|
||||
@@ -343,21 +348,12 @@ pub mod pezpallet {
|
||||
fn get_referral_score(who: &T::AccountId) -> RawScore {
|
||||
let stats = ReferrerStatsStorage::<T>::get(who);
|
||||
|
||||
// Calculate good referrals (total minus revoked)
|
||||
// Step 1: "Haksız olanı geri alma" - Remove revoked referrals from count
|
||||
// This is NOT a penalty, it's correcting the record to reflect reality
|
||||
let good_referrals = stats.total_referrals.saturating_sub(stats.revoked_referrals);
|
||||
|
||||
// BALANCED PENALTY SYSTEM (Gemini's suggestion):
|
||||
// "Every 4 bad referrals = -10 points"
|
||||
// This is equivalent to "1 bad = -2.5 points"
|
||||
// Much fairer than "1 bad = 3 good deleted"
|
||||
//
|
||||
// Formula: penalty_points = (revoked_referrals / 4) * 10
|
||||
// Simplified: penalty_points = revoked_referrals * 10 / 4 = revoked_referrals * 2.5
|
||||
// Using integer math: penalty_points = (revoked_referrals * 10) / 4
|
||||
let penalty_points = (stats.revoked_referrals.saturating_mul(10)) / 4;
|
||||
|
||||
// Calculate base score from good referrals
|
||||
// Scoring system with max 500 points:
|
||||
// Step 2: Calculate base score from good referrals
|
||||
// Tiered scoring system with max 500 points:
|
||||
// 0 referrals = 0 points
|
||||
// 1-10 referrals = count * 10 points (10, 20, 30, ..., 100)
|
||||
// 11-50 referrals = 100 + ((count - 10) * 5) = 105, 110, ..., 300
|
||||
@@ -371,8 +367,10 @@ pub mod pezpallet {
|
||||
_ => 500,
|
||||
};
|
||||
|
||||
// Apply penalty (cannot go below 0)
|
||||
base_score.saturating_sub(penalty_points)
|
||||
// Step 3: "Cezalandırma" - Apply stored penalty from PenaltyPerRevocation
|
||||
// Uses the pre-calculated penalty_score accumulated in on_citizenship_revoked()
|
||||
// This is the actual punishment: "you should have been more careful"
|
||||
base_score.saturating_sub(stats.penalty_score)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ impl pezpallet_identity_kyc::Config for Test {
|
||||
type OnKycApproved = Referral; // Referral pezpallet handles KYC approval hook
|
||||
type OnCitizenshipRevoked = Referral; // Referral pezpallet handles revocation penalty
|
||||
type CitizenNftProvider = MockCitizenNftProvider;
|
||||
type DefaultReferrer = DefaultReferrerAccount;
|
||||
type KycApplicationDeposit = KycApplicationDepositAmount;
|
||||
type MaxStringLength = MaxStringLen;
|
||||
type MaxCidLength = MaxCidLen;
|
||||
|
||||
@@ -317,28 +317,31 @@ fn referral_score_with_balanced_penalty() {
|
||||
ReferrerStatsStorage::<Test>::mutate(REFERRER, |stats| {
|
||||
stats.total_referrals = 10;
|
||||
stats.revoked_referrals = 0;
|
||||
stats.penalty_score = 0;
|
||||
});
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 100);
|
||||
|
||||
// 10 total, 4 revoked = 6 good
|
||||
// Penalty: (4 * 10) / 4 = 10 points deducted
|
||||
// penalty_score: 4 * PenaltyPerRevocation(3) = 12
|
||||
// Base score: 6 * 10 = 60
|
||||
// Final: 60 - 10 = 50
|
||||
// Final: 60 - 12 = 48
|
||||
ReferrerStatsStorage::<Test>::mutate(REFERRER, |stats| {
|
||||
stats.total_referrals = 10;
|
||||
stats.revoked_referrals = 4;
|
||||
stats.penalty_score = 4 * PenaltyPerRevocationAmount::get();
|
||||
});
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 50);
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 48);
|
||||
|
||||
// 20 total, 8 revoked = 12 good (tier 2)
|
||||
// Penalty: (8 * 10) / 4 = 20 points deducted
|
||||
// penalty_score: 8 * PenaltyPerRevocation(3) = 24
|
||||
// Base score: 100 + (2 * 5) = 110
|
||||
// Final: 110 - 20 = 90
|
||||
// Final: 110 - 24 = 86
|
||||
ReferrerStatsStorage::<Test>::mutate(REFERRER, |stats| {
|
||||
stats.total_referrals = 20;
|
||||
stats.revoked_referrals = 8;
|
||||
stats.penalty_score = 8 * PenaltyPerRevocationAmount::get();
|
||||
});
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 90);
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 86);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -349,12 +352,13 @@ fn referral_score_cannot_go_negative() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Extreme case: All referrals revoked
|
||||
// 5 total, 5 revoked = 0 good
|
||||
// Penalty: (5 * 10) / 4 = 12 points
|
||||
// penalty_score: 5 * PenaltyPerRevocation(3) = 15
|
||||
// Base score: 0
|
||||
// Final: 0 - 12 = 0 (saturating_sub)
|
||||
// Final: 0 - 15 = 0 (saturating_sub)
|
||||
ReferrerStatsStorage::<Test>::mutate(REFERRER, |stats| {
|
||||
stats.total_referrals = 5;
|
||||
stats.revoked_referrals = 5;
|
||||
stats.penalty_score = 5 * PenaltyPerRevocationAmount::get();
|
||||
});
|
||||
assert_eq!(ReferralPallet::get_referral_score(&REFERRER), 0);
|
||||
});
|
||||
@@ -412,6 +416,12 @@ fn force_confirm_referral_works() {
|
||||
assert!(Referrals::<Test>::contains_key(REFERRED));
|
||||
assert_eq!(Referrals::<Test>::get(REFERRED).unwrap().referrer, REFERRER);
|
||||
|
||||
// Verify ReferrerStats is updated (was missing before fix)
|
||||
let stats = ReferrerStatsStorage::<Test>::get(REFERRER);
|
||||
assert_eq!(stats.total_referrals, 1);
|
||||
assert_eq!(stats.revoked_referrals, 0);
|
||||
assert_eq!(stats.penalty_score, 0);
|
||||
|
||||
// Verify trait implementations
|
||||
assert_eq!(ReferralPallet::get_inviter(&REFERRED), Some(REFERRER));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user