use sha2::{Sha256, Digest};
use serde::{Deserialize, Serialize};
use hex::encode;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct PerformanceScore {
pub win_rate: f32,
pub profit_factor: f32,
pub sharpe_equivalent: f32,
pub max_drawdown: f32,
pub consistency: f32,
pub damage_penalty: f32,
}
impl PerformanceScore {
pub fn from_agent_metrics(
win_rate: f32,
max_drawdown: f32,
total_trades: u64,
scar_count: u32,
) -> Self {
let profit_factor = if win_rate > 50.0 {
1.0 + ((win_rate - 50.0) / 50.0) * 0.5
} else {
0.5 + (win_rate / 50.0) * 0.5
};
let sharpe = (win_rate / 100.0) / (max_drawdown.max(1.0) / 100.0);
let consistency = if total_trades > 100 {
1.0
} else {
total_trades as f32 / 100.0
};
let damage_penalty = (scar_count as f32) * 10.0;
PerformanceScore {
win_rate,
profit_factor,
sharpe_equivalent: sharpe,
max_drawdown,
consistency,
damage_penalty: damage_penalty.min(100.0),
}
}
pub fn composite_score(&self) -> f32 {
let win_component = self.win_rate;
let drawdown_component = (100.0 - self.max_drawdown) * 0.5;
let consistency_component = self.consistency * 100.0;
let sharpe_component = (self.sharpe_equivalent.min(5.0) / 5.0) * 100.0;
let mut score = win_component * 0.35 +
drawdown_component * 0.25 +
consistency_component * 0.20 +
sharpe_component * 0.20;
score = (score * (1.0 - (self.damage_penalty / 200.0))).max(0.0);
score.min(100.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrustGrant {
Gold { score: f32 },
Silver { score: f32 },
Bronze { score: f32 },
Restricted { score: f32, reason: String },
}
pub struct TrustFormula {
pub performance_weight: f32,
pub consistency_weight: f32,
pub damage_weight: f32,
pub longevity_weight: f32,
}
impl Default for TrustFormula {
fn default() -> Self {
TrustFormula {
performance_weight: 0.40,
consistency_weight: 0.25,
damage_weight: 0.20,
longevity_weight: 0.15,
}
}
}
impl TrustFormula {
pub fn compute_trust_score(
&self,
perf_score: &PerformanceScore,
days_trading: u64,
) -> f32 {
let longevity = (days_trading as f32 / 365.0).min(1.0);
let score = perf_score.composite_score() * self.performance_weight +
perf_score.consistency * 100.0 * self.consistency_weight +
(100.0 - perf_score.damage_penalty) * self.damage_weight +
longevity * 100.0 * self.longevity_weight;
score.min(100.0)
}
pub fn compute_trust_hash(
agent_id: &str,
score: f32,
timestamp: u64,
) -> String {
let data = format!("{}:{}:{}", agent_id, score, timestamp);
let mut hasher = Sha256::new();
hasher.update(data.as_bytes());
encode(hasher.finalize())
}
pub fn determine_grant(score: f32) -> TrustGrant {
match score {
80.0..=100.0 => TrustGrant::Gold { score },
60.0..=79.99 => TrustGrant::Silver { score },
40.0..=59.99 => TrustGrant::Bronze { score },
_ => TrustGrant::Restricted {
score,
reason: format!("Score {:.2} below minimum", score),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrustRecord {
pub agent_id: String,
pub current_score: f32,
pub grant: TrustGrant,
pub trust_hash: String,
pub timestamp: u64,
pub score_history: Vec<f32>,
pub permissions: Vec<TrustPermission>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TrustPermission {
PremiumDataFeed,
MarginTrading,
PrivatePoolAccess,
GovernanceVoting,
Spawning,
Competition,
DerivativeTrading,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrustResult {
Authorized {
score: f32,
permissions: Vec<TrustPermission>,
},
Denied {
score: f32,
reason: String,
required_score: f32,
},
TemporaryBan {
reason: String,
duration_hours: u32,
},
Revoked {
reason: String,
},
}
impl TrustRecord {
pub fn new(agent_id: String, initial_score: f32, _formula: &TrustFormula) -> Self {
let grant = TrustFormula::determine_grant(initial_score);
let trust_hash = TrustFormula::compute_trust_hash(&agent_id, initial_score, 0);
let permissions = match &grant {
TrustGrant::Gold { .. } => vec![
TrustPermission::PremiumDataFeed,
TrustPermission::MarginTrading,
TrustPermission::PrivatePoolAccess,
TrustPermission::GovernanceVoting,
TrustPermission::Spawning,
TrustPermission::Competition,
TrustPermission::DerivativeTrading,
],
TrustGrant::Silver { .. } => vec![
TrustPermission::MarginTrading,
TrustPermission::Spawning,
TrustPermission::Competition,
],
TrustGrant::Bronze { .. } => vec![
TrustPermission::Competition,
],
TrustGrant::Restricted { .. } => vec![],
};
TrustRecord {
agent_id,
current_score: initial_score,
grant,
trust_hash,
timestamp: 0,
score_history: vec![initial_score],
permissions,
}
}
pub fn update_score(&mut self, new_score: f32, _formula: &TrustFormula) {
self.current_score = new_score;
self.score_history.push(new_score);
self.grant = TrustFormula::determine_grant(new_score);
self.trust_hash = TrustFormula::compute_trust_hash(
&self.agent_id,
new_score,
self.score_history.len() as u64,
);
self.permissions = match &self.grant {
TrustGrant::Gold { .. } => vec![
TrustPermission::PremiumDataFeed,
TrustPermission::MarginTrading,
TrustPermission::PrivatePoolAccess,
TrustPermission::GovernanceVoting,
TrustPermission::Spawning,
TrustPermission::Competition,
TrustPermission::DerivativeTrading,
],
TrustGrant::Silver { .. } => vec![
TrustPermission::MarginTrading,
TrustPermission::Spawning,
TrustPermission::Competition,
],
TrustGrant::Bronze { .. } => vec![
TrustPermission::Competition,
],
TrustGrant::Restricted { .. } => vec![],
};
}
pub fn has_permission(&self, permission: TrustPermission) -> bool {
self.permissions.contains(&permission)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_performance_score() {
let score = PerformanceScore::from_agent_metrics(65.0, 10.0, 50, 1);
assert!(score.composite_score() > 0.0);
}
#[test]
fn test_trust_formula() {
let formula = TrustFormula::default();
let perf = PerformanceScore::from_agent_metrics(70.0, 5.0, 100, 0);
let trust = formula.compute_trust_score(&perf, 365);
assert!(trust > 0.0);
}
#[test]
fn test_trust_grant_levels() {
assert!(matches!(TrustFormula::determine_grant(85.0), TrustGrant::Gold { .. }));
assert!(matches!(TrustFormula::determine_grant(65.0), TrustGrant::Silver { .. }));
assert!(matches!(TrustFormula::determine_grant(30.0), TrustGrant::Restricted { .. }));
}
}