use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// Asset types representing different categories of digital assets #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum AssetType { Artwork, Token, RealEstate, Commodity, Share, Bond, IntellectualProperty, Other, } impl AssetType { pub fn as_str(&self) -> &str { match self { AssetType::Artwork => "Artwork", AssetType::Token => "Token", AssetType::RealEstate => "Real Estate", AssetType::Commodity => "Commodity", AssetType::Share => "Share", AssetType::Bond => "Bond", AssetType::IntellectualProperty => "Intellectual Property", AssetType::Other => "Other", } } } /// Status of an asset #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum AssetStatus { Active, Locked, ForSale, Transferred, Archived, } impl AssetStatus { pub fn as_str(&self) -> &str { match self { AssetStatus::Active => "Active", AssetStatus::Locked => "Locked", AssetStatus::ForSale => "For Sale", AssetStatus::Transferred => "Transferred", AssetStatus::Archived => "Archived", } } } /// Blockchain information for an asset #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BlockchainInfo { pub blockchain: String, pub token_id: String, pub contract_address: String, pub owner_address: String, pub transaction_hash: Option, pub block_number: Option, pub timestamp: Option>, } /// Valuation history point for an asset #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ValuationPoint { pub id: String, pub date: DateTime, pub value: f64, pub currency: String, pub source: String, pub notes: Option, } /// Transaction history for an asset #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AssetTransaction { pub id: String, pub transaction_type: String, pub date: DateTime, pub from_address: Option, pub to_address: Option, pub amount: Option, pub currency: Option, pub transaction_hash: Option, pub notes: Option, } /// Main Asset model #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Asset { pub id: String, pub name: String, pub description: String, pub asset_type: AssetType, pub status: AssetStatus, pub owner_id: String, pub owner_name: String, pub created_at: DateTime, pub updated_at: DateTime, pub blockchain_info: Option, pub current_valuation: Option, pub valuation_currency: Option, pub valuation_date: Option>, pub valuation_history: Vec, pub transaction_history: Vec, pub metadata: serde_json::Value, pub image_url: Option, pub external_url: Option, } impl Asset { /// Creates a new asset pub fn new( name: &str, description: &str, asset_type: AssetType, owner_id: &str, owner_name: &str, ) -> Self { let now = Utc::now(); Self { id: format!("asset-{}", Uuid::new_v4().to_string()[..8].to_string()), name: name.to_string(), description: description.to_string(), asset_type, status: AssetStatus::Active, owner_id: owner_id.to_string(), owner_name: owner_name.to_string(), created_at: now, updated_at: now, blockchain_info: None, current_valuation: None, valuation_currency: None, valuation_date: None, valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({}), image_url: None, external_url: None, } } /// Adds blockchain information to the asset pub fn add_blockchain_info(&mut self, blockchain_info: BlockchainInfo) { self.blockchain_info = Some(blockchain_info); self.updated_at = Utc::now(); } /// Adds a valuation point to the asset's history pub fn add_valuation(&mut self, value: f64, currency: &str, source: &str, notes: Option) { let valuation = ValuationPoint { id: format!("val-{}", Uuid::new_v4().to_string()[..8].to_string()), date: Utc::now(), value, currency: currency.to_string(), source: source.to_string(), notes, }; self.current_valuation = Some(value); self.valuation_currency = Some(currency.to_string()); self.valuation_date = Some(valuation.date); self.valuation_history.push(valuation); self.updated_at = Utc::now(); } /// Adds a transaction to the asset's history pub fn add_transaction( &mut self, transaction_type: &str, from_address: Option, to_address: Option, amount: Option, currency: Option, transaction_hash: Option, notes: Option, ) { let transaction = AssetTransaction { id: format!("tx-{}", Uuid::new_v4().to_string()[..8].to_string()), transaction_type: transaction_type.to_string(), date: Utc::now(), from_address, to_address, amount, currency, transaction_hash, notes, }; self.transaction_history.push(transaction); self.updated_at = Utc::now(); } /// Updates the status of the asset pub fn update_status(&mut self, status: AssetStatus) { self.status = status; self.updated_at = Utc::now(); } /// Gets the latest valuation point pub fn latest_valuation(&self) -> Option<&ValuationPoint> { self.valuation_history.last() } /// Gets the latest transaction pub fn latest_transaction(&self) -> Option<&AssetTransaction> { self.transaction_history.last() } /// Gets the valuation history sorted by date pub fn sorted_valuation_history(&self) -> Vec<&ValuationPoint> { let mut history = self.valuation_history.iter().collect::>(); history.sort_by(|a, b| a.date.cmp(&b.date)); history } /// Gets the transaction history sorted by date pub fn sorted_transaction_history(&self) -> Vec<&AssetTransaction> { let mut history = self.transaction_history.iter().collect::>(); history.sort_by(|a, b| a.date.cmp(&b.date)); history } } /// Filter for assets #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AssetFilter { pub asset_type: Option, pub status: Option, pub owner_id: Option, pub min_valuation: Option, pub max_valuation: Option, pub valuation_currency: Option, pub search_query: Option, } /// Statistics for assets #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AssetStatistics { pub total_assets: usize, pub total_value: f64, pub value_by_type: std::collections::HashMap, pub assets_by_type: std::collections::HashMap, pub assets_by_status: std::collections::HashMap, } impl AssetStatistics { pub fn new(assets: &[Asset]) -> Self { let mut total_value = 0.0; let mut value_by_type = std::collections::HashMap::new(); let mut assets_by_type = std::collections::HashMap::new(); let mut assets_by_status = std::collections::HashMap::new(); for asset in assets { if let Some(valuation) = asset.current_valuation { total_value += valuation; let asset_type = asset.asset_type.as_str().to_string(); *value_by_type.entry(asset_type.clone()).or_insert(0.0) += valuation; *assets_by_type.entry(asset_type).or_insert(0) += 1; } else { let asset_type = asset.asset_type.as_str().to_string(); *assets_by_type.entry(asset_type).or_insert(0) += 1; } let status = asset.status.as_str().to_string(); *assets_by_status.entry(status).or_insert(0) += 1; } Self { total_assets: assets.len(), total_value, value_by_type, assets_by_type, assets_by_status, } } }