use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttackVector {
pub name: String,
pub attack_type: AttackType,
pub cost: Decimal,
pub potential_profit: Decimal,
pub success_probability: Decimal,
pub detection_probability: Decimal,
pub penalty: Decimal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AttackType {
Consensus51,
FrontRunning,
OracleManipulation,
FlashLoan,
Sybil,
EconomicExploit,
}
impl AttackVector {
pub fn expected_value(&self) -> Decimal {
let expected_profit = self.potential_profit * self.success_probability;
let expected_penalty = self.penalty * self.detection_probability;
expected_profit - expected_penalty - self.cost
}
pub fn is_rational(&self) -> bool {
self.expected_value() > dec!(0)
}
pub fn profit_cost_ratio(&self) -> Decimal {
if self.cost > dec!(0) {
(self.potential_profit * self.success_probability) / self.cost
} else {
dec!(0)
}
}
}
pub struct EconomicSecurityAnalyzer {
tvl: Decimal,
attack_vectors: Vec<AttackVector>,
#[allow(dead_code)]
security_budget: Decimal,
}
impl EconomicSecurityAnalyzer {
pub fn new(tvl: Decimal, security_budget: Decimal) -> Self {
Self {
tvl,
attack_vectors: Vec::new(),
security_budget,
}
}
pub fn add_attack_vector(&mut self, vector: AttackVector) {
self.attack_vectors.push(vector);
}
pub fn minimum_attack_cost(&self) -> Decimal {
self.attack_vectors
.iter()
.map(|v| v.cost)
.min()
.unwrap_or(dec!(0))
}
pub fn byzantine_threshold(&self, validator_stake: Decimal, total_stake: Decimal) -> Decimal {
if total_stake > dec!(0) {
(validator_stake / total_stake) * dec!(100)
} else {
dec!(0)
}
}
pub fn nakamoto_coefficient(&self, stakes: &[Decimal]) -> usize {
if stakes.is_empty() {
return 0;
}
let total: Decimal = stakes.iter().sum();
let target = total / dec!(2); let mut sorted = stakes.to_vec();
sorted.sort_by(|a, b| b.cmp(a));
let mut cumulative = dec!(0);
for (i, stake) in sorted.iter().enumerate() {
cumulative += stake;
if cumulative > target {
return i + 1;
}
}
stakes.len()
}
pub fn identify_rational_attacks(&self) -> Vec<&AttackVector> {
self.attack_vectors
.iter()
.filter(|v| v.is_rational())
.collect()
}
pub fn security_factor(&self) -> Decimal {
let min_cost = self.minimum_attack_cost();
if self.tvl > dec!(0) {
min_cost / self.tvl
} else {
dec!(0)
}
}
pub fn security_level(&self) -> SecurityLevel {
let factor = self.security_factor();
let rational_attacks = self.identify_rational_attacks().len();
if rational_attacks > 0 {
return SecurityLevel::Critical;
}
if factor >= dec!(2.0) {
SecurityLevel::High
} else if factor >= dec!(1.0) {
SecurityLevel::Medium
} else if factor >= dec!(0.5) {
SecurityLevel::Low
} else {
SecurityLevel::Critical
}
}
pub fn recommend_improvements(&self) -> Vec<SecurityRecommendation> {
let mut recommendations = Vec::new();
let rational_attacks = self.identify_rational_attacks();
for attack in rational_attacks {
let rec = SecurityRecommendation {
priority: Priority::Critical,
description: format!("Mitigate {} attack", attack.name),
estimated_cost: attack.cost * dec!(0.1), expected_benefit: attack.potential_profit,
action: match attack.attack_type {
AttackType::Consensus51 => {
"Increase validator requirements or implement slashing".to_string()
}
AttackType::FrontRunning => "Implement MEV protection mechanisms".to_string(),
AttackType::OracleManipulation => {
"Use decentralized oracles with multiple sources".to_string()
}
AttackType::FlashLoan => "Implement flash loan attack prevention".to_string(),
AttackType::Sybil => "Require economic stake for participation".to_string(),
AttackType::EconomicExploit => "Audit economic model".to_string(),
},
};
recommendations.push(rec);
}
recommendations
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SecurityLevel {
Critical,
Low,
Medium,
High,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Priority {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityRecommendation {
pub priority: Priority,
pub description: String,
pub estimated_cost: Decimal,
pub expected_benefit: Decimal,
pub action: String,
}
pub struct GameTheoreticModel {
players: HashMap<String, Player>,
strategies: Vec<Strategy>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Player {
pub id: String,
pub player_type: PlayerType,
pub stake: Decimal,
pub current_strategy: Option<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PlayerType {
Validator,
Trader,
LiquidityProvider,
Attacker,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Strategy {
pub name: String,
pub base_payoff: Decimal,
pub risk: Decimal,
pub cost: Decimal,
}
impl GameTheoreticModel {
pub fn new() -> Self {
Self {
players: HashMap::new(),
strategies: Vec::new(),
}
}
pub fn add_player(&mut self, player: Player) {
self.players.insert(player.id.clone(), player);
}
pub fn add_strategy(&mut self, strategy: Strategy) {
self.strategies.push(strategy);
}
pub fn calculate_payoff(&self, player_id: &str, strategy_idx: usize) -> Decimal {
let player = match self.players.get(player_id) {
Some(p) => p,
None => return dec!(0),
};
let strategy = match self.strategies.get(strategy_idx) {
Some(s) => s,
None => return dec!(0),
};
let stake_factor = (player.stake / dec!(1000)).min(dec!(10)); strategy.base_payoff * stake_factor - strategy.cost
}
pub fn find_nash_equilibrium(&self) -> HashMap<String, usize> {
let mut equilibrium = HashMap::new();
for player_id in self.players.keys() {
let mut best_strategy = 0;
let mut best_payoff = dec!(0);
for (idx, _) in self.strategies.iter().enumerate() {
let payoff = self.calculate_payoff(player_id, idx);
if payoff > best_payoff {
best_payoff = payoff;
best_strategy = idx;
}
}
equilibrium.insert(player_id.clone(), best_strategy);
}
equilibrium
}
pub fn is_honest_incentivized(&self, honest_strategy_idx: usize) -> bool {
for player_id in self.players.keys() {
let honest_payoff = self.calculate_payoff(player_id, honest_strategy_idx);
for (idx, _) in self.strategies.iter().enumerate() {
if idx != honest_strategy_idx {
let other_payoff = self.calculate_payoff(player_id, idx);
if other_payoff > honest_payoff {
return false; }
}
}
}
true
}
}
impl Default for GameTheoreticModel {
fn default() -> Self {
Self::new()
}
}
pub struct IncentiveAlignmentVerifier {
rewards: HashMap<String, Decimal>,
penalties: HashMap<String, Decimal>,
}
impl IncentiveAlignmentVerifier {
pub fn new() -> Self {
Self {
rewards: HashMap::new(),
penalties: HashMap::new(),
}
}
pub fn set_reward(&mut self, action: String, reward: Decimal) {
self.rewards.insert(action, reward);
}
pub fn set_penalty(&mut self, action: String, penalty: Decimal) {
self.penalties.insert(action, penalty);
}
pub fn net_incentive(&self, action: &str) -> Decimal {
let reward = self.rewards.get(action).copied().unwrap_or(dec!(0));
let penalty = self.penalties.get(action).copied().unwrap_or(dec!(0));
reward - penalty
}
pub fn check_alignment(&self, desired_action: &str, undesired_actions: &[String]) -> bool {
let desired_incentive = self.net_incentive(desired_action);
for action in undesired_actions {
let undesired_incentive = self.net_incentive(action);
if undesired_incentive >= desired_incentive {
return false; }
}
true
}
pub fn suggest_adjustments(
&self,
desired_action: &str,
undesired_actions: &[String],
) -> Vec<IncentiveAdjustment> {
let mut suggestions = Vec::new();
let desired_incentive = self.net_incentive(desired_action);
for action in undesired_actions {
let undesired_incentive = self.net_incentive(action);
if undesired_incentive >= desired_incentive {
let gap = undesired_incentive - desired_incentive;
suggestions.push(IncentiveAdjustment {
action: action.clone(),
current_incentive: undesired_incentive,
adjustment_type: AdjustmentType::IncreasePenalty,
recommended_change: gap + dec!(100), reason: format!(
"Undesired action {} has higher incentive than desired",
action
),
});
}
}
suggestions
}
}
impl Default for IncentiveAlignmentVerifier {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncentiveAdjustment {
pub action: String,
pub current_incentive: Decimal,
pub adjustment_type: AdjustmentType,
pub recommended_change: Decimal,
pub reason: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AdjustmentType {
IncreaseReward,
DecreaseReward,
IncreasePenalty,
DecreasePenalty,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_attack_vector() {
let attack = AttackVector {
name: "51% Attack".to_string(),
attack_type: AttackType::Consensus51,
cost: dec!(1000000),
potential_profit: dec!(500000),
success_probability: dec!(0.5),
detection_probability: dec!(0.8),
penalty: dec!(2000000),
};
let ev = attack.expected_value();
assert!(ev < dec!(0));
assert!(!attack.is_rational());
}
#[test]
fn test_rational_attack() {
let attack = AttackVector {
name: "Profitable Attack".to_string(),
attack_type: AttackType::EconomicExploit,
cost: dec!(10000),
potential_profit: dec!(100000),
success_probability: dec!(0.9),
detection_probability: dec!(0.1),
penalty: dec!(50000),
};
let ev = attack.expected_value();
assert!(ev > dec!(70000));
assert!(attack.is_rational());
}
#[test]
fn test_economic_security_analyzer() {
let mut analyzer = EconomicSecurityAnalyzer::new(dec!(10000000), dec!(500000));
analyzer.add_attack_vector(AttackVector {
name: "Attack A".to_string(),
attack_type: AttackType::FlashLoan,
cost: dec!(50000),
potential_profit: dec!(30000),
success_probability: dec!(0.5),
detection_probability: dec!(0.9),
penalty: dec!(100000),
});
assert_eq!(analyzer.minimum_attack_cost(), dec!(50000));
let factor = analyzer.security_factor();
assert!(factor > dec!(0.004) && factor < dec!(0.006));
}
#[test]
fn test_nakamoto_coefficient() {
let analyzer = EconomicSecurityAnalyzer::new(dec!(1000000), dec!(50000));
let stakes = vec![dec!(400000), dec!(350000), dec!(250000)];
let coef = analyzer.nakamoto_coefficient(&stakes);
assert_eq!(coef, 2);
}
#[test]
fn test_security_level() {
let mut analyzer = EconomicSecurityAnalyzer::new(dec!(1000000), dec!(100000));
analyzer.add_attack_vector(AttackVector {
name: "Expensive Attack".to_string(),
attack_type: AttackType::Consensus51,
cost: dec!(5000000), potential_profit: dec!(1000000),
success_probability: dec!(0.3),
detection_probability: dec!(0.9),
penalty: dec!(10000000),
});
assert_eq!(analyzer.security_level(), SecurityLevel::High);
}
#[test]
fn test_game_theoretic_model() {
let mut model = GameTheoreticModel::new();
model.add_player(Player {
id: "validator1".to_string(),
player_type: PlayerType::Validator,
stake: dec!(100000),
current_strategy: None,
});
model.add_strategy(Strategy {
name: "Honest Validation".to_string(),
base_payoff: dec!(100),
risk: dec!(0.1),
cost: dec!(10),
});
model.add_strategy(Strategy {
name: "Dishonest Validation".to_string(),
base_payoff: dec!(50),
risk: dec!(0.5),
cost: dec!(20),
});
let payoff = model.calculate_payoff("validator1", 0);
assert!(payoff > dec!(0));
}
#[test]
fn test_nash_equilibrium() {
let mut model = GameTheoreticModel::new();
model.add_player(Player {
id: "player1".to_string(),
player_type: PlayerType::Trader,
stake: dec!(10000),
current_strategy: None,
});
model.add_strategy(Strategy {
name: "Strategy A".to_string(),
base_payoff: dec!(100),
risk: dec!(0.1),
cost: dec!(10),
});
model.add_strategy(Strategy {
name: "Strategy B".to_string(),
base_payoff: dec!(80),
risk: dec!(0.05),
cost: dec!(5),
});
let equilibrium = model.find_nash_equilibrium();
assert!(equilibrium.contains_key("player1"));
}
#[test]
fn test_honest_incentivization() {
let mut model = GameTheoreticModel::new();
model.add_player(Player {
id: "validator".to_string(),
player_type: PlayerType::Validator,
stake: dec!(100000),
current_strategy: None,
});
model.add_strategy(Strategy {
name: "Honest".to_string(),
base_payoff: dec!(200),
risk: dec!(0.1),
cost: dec!(10),
});
model.add_strategy(Strategy {
name: "Dishonest".to_string(),
base_payoff: dec!(100), risk: dec!(0.5),
cost: dec!(20),
});
assert!(model.is_honest_incentivized(0));
}
#[test]
fn test_incentive_alignment() {
let mut verifier = IncentiveAlignmentVerifier::new();
verifier.set_reward("stake".to_string(), dec!(1000));
verifier.set_penalty("attack".to_string(), dec!(5000));
let stake_incentive = verifier.net_incentive("stake");
let attack_incentive = verifier.net_incentive("attack");
assert_eq!(stake_incentive, dec!(1000));
assert_eq!(attack_incentive, dec!(-5000));
}
#[test]
fn test_alignment_check() {
let mut verifier = IncentiveAlignmentVerifier::new();
verifier.set_reward("honest_behavior".to_string(), dec!(1000));
verifier.set_reward("malicious_behavior".to_string(), dec!(500));
verifier.set_penalty("malicious_behavior".to_string(), dec!(2000));
let undesired = vec!["malicious_behavior".to_string()];
assert!(verifier.check_alignment("honest_behavior", &undesired));
}
#[test]
fn test_misaligned_incentives() {
let mut verifier = IncentiveAlignmentVerifier::new();
verifier.set_reward("desired".to_string(), dec!(100));
verifier.set_reward("undesired".to_string(), dec!(200));
let undesired = vec!["undesired".to_string()];
assert!(!verifier.check_alignment("desired", &undesired));
}
#[test]
fn test_incentive_adjustment_suggestions() {
let mut verifier = IncentiveAlignmentVerifier::new();
verifier.set_reward("desired".to_string(), dec!(100));
verifier.set_reward("undesired".to_string(), dec!(200));
let undesired = vec!["undesired".to_string()];
let suggestions = verifier.suggest_adjustments("desired", &undesired);
assert!(!suggestions.is_empty());
assert_eq!(
suggestions[0].adjustment_type,
AdjustmentType::IncreasePenalty
);
}
}