Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 27 additions & 63 deletions quicklendx-contracts/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,30 @@ pub fn calculate_investor_risk_score(
Ok(risk_score)
}

/// Compute investor tier from the investor record and a risk score.
///
/// This wrapper is used by public contract entrypoints and internal business
/// logic, while the core deterministic tier rules are implemented in the
/// `compute_investor_tier_from_stats` helper.
pub fn compute_investor_tier(
env: &Env,
investor: &Address,
risk_score: u32,
) -> Result<InvestorTier, QuickLendXError> {
validate_risk_score(risk_score)?;

if let Some(verification) = InvestorVerificationStorage::get(env, investor) {
return compute_investor_tier_from_stats(
verification.total_invested,
verification.successful_investments,
verification.defaulted_investments,
risk_score,
);
}

Ok(InvestorTier::Basic)
}

/// Determine investor tier based on risk score and investment history.
/// Calculate the investor tier using deterministic performance thresholds.
///
Expand All @@ -1299,21 +1323,10 @@ pub fn determine_investor_tier(
investor: &Address,
risk_score: u32,
) -> Result<InvestorTier, QuickLendXError> {
validate_risk_score(risk_score)?;

if let Some(verification) = InvestorVerificationStorage::get(env, investor) {
return compute_investor_tier_from_stats(
verification.total_invested,
verification.successful_investments,
verification.defaulted_investments,
risk_score,
);
}

Ok(InvestorTier::Basic)
compute_investor_tier(env, investor, risk_score)
}

pub fn compute_investor_tier(
pub fn compute_investor_tier_from_stats(
total_invested: i128,
successful_investments: u32,
defaulted_investments: u32,
Expand Down Expand Up @@ -1377,55 +1390,6 @@ pub fn determine_risk_level(risk_score: u32) -> InvestorRiskLevel {
}
}

/// Core tier computation using raw counters (total invested, successes, defaults).
pub fn compute_investor_tier(
total_invested: i128,
successful_investments: u32,
defaulted_investments: u32,
risk_score: u32,
) -> Result<InvestorTier, QuickLendXError> {
let total = successful_investments.saturating_add(defaulted_investments);
let default_rate = if total > 0 {
(defaulted_investments.saturating_mul(100)) / total
} else {
0u32
};

if risk_score <= 10
&& total_invested >= 5_000_000
&& successful_investments >= 50
&& default_rate <= 5
{
return Ok(InvestorTier::VIP);
}

if risk_score <= 20
&& total_invested >= 1_000_000
&& successful_investments >= 20
&& default_rate <= 10
{
return Ok(InvestorTier::Platinum);
}

if risk_score <= 40
&& total_invested >= 100_000
&& successful_investments >= 10
&& default_rate <= 15
{
return Ok(InvestorTier::Gold);
}

if risk_score <= 60
&& total_invested >= 10_000
&& successful_investments >= 3
&& default_rate <= 25
{
return Ok(InvestorTier::Silver);
}

Ok(InvestorTier::Basic)
}

/// Calculate investment limit based on tier and risk level
pub fn calculate_investment_limit(
tier: &InvestorTier,
Expand Down Expand Up @@ -1670,7 +1634,7 @@ pub fn recompute_investor_tier(
let risk_score = calculate_investor_risk_score(env, investor, &verification.kyc_data)?;
validate_risk_score(risk_score)?;

let tier = compute_investor_tier(
let tier = compute_investor_tier_from_stats(
verification.total_invested,
verification.successful_investments,
verification.defaulted_investments,
Expand Down
Loading