use actix_web::{web, HttpResponse, Result}; use tera::{Context, Tera}; use chrono::{Utc, Duration}; use serde::Deserialize; use crate::models::asset::{Asset, AssetType, AssetStatus, BlockchainInfo, ValuationPoint, AssetTransaction, AssetStatistics}; use crate::utils::render_template; #[derive(Debug, Deserialize)] pub struct AssetForm { pub name: String, pub description: String, pub asset_type: String, } #[derive(Debug, Deserialize)] pub struct ValuationForm { pub value: f64, pub currency: String, pub source: String, pub notes: Option, } #[derive(Debug, Deserialize)] pub struct TransactionForm { pub transaction_type: String, pub from_address: Option, pub to_address: Option, pub amount: Option, pub currency: Option, pub transaction_hash: Option, pub notes: Option, } pub struct AssetController; impl AssetController { // Display the assets dashboard pub async fn index(tmpl: web::Data) -> Result { let mut context = Context::new(); println!("DEBUG: Starting assets dashboard rendering"); let assets = Self::get_mock_assets(); println!("DEBUG: Generated {} mock assets", assets.len()); let stats = AssetStatistics::new(&assets); println!("DEBUG: Generated asset statistics: {:?}", stats); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); // Add stats context.insert("stats", &serde_json::to_value(stats).unwrap()); println!("DEBUG: Added stats to context"); // Add recent assets let recent_assets: Vec> = assets .iter() .take(5) .map(|a| Self::asset_to_json(a)) .collect(); context.insert("recent_assets", &recent_assets); // Add assets by type let asset_types = vec![ AssetType::NFT, AssetType::Token, AssetType::RealEstate, AssetType::Commodity, AssetType::Share, AssetType::Bond, AssetType::IntellectualProperty, AssetType::Other, ]; let assets_by_type: Vec> = asset_types .iter() .map(|asset_type| { let mut map = serde_json::Map::new(); let type_str = asset_type.as_str(); let count = assets.iter().filter(|a| a.asset_type == *asset_type).count(); map.insert("type".to_string(), serde_json::Value::String(type_str.to_string())); map.insert("count".to_string(), serde_json::Value::Number(serde_json::Number::from(count))); map }) .collect(); context.insert("assets_by_type", &assets_by_type); println!("DEBUG: Rendering assets dashboard template"); let response = render_template(&tmpl, "assets/index.html", &context); println!("DEBUG: Finished rendering assets dashboard template"); response } // Display the list of all assets pub async fn list(tmpl: web::Data) -> Result { let mut context = Context::new(); println!("DEBUG: Starting assets list rendering"); let assets = Self::get_mock_assets(); println!("DEBUG: Generated {} mock assets", assets.len()); let assets_data: Vec> = assets .iter() .map(|a| Self::asset_to_json(a)) .collect(); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); context.insert("assets", &assets_data); context.insert("filter", &"all"); println!("DEBUG: Rendering assets list template"); let response = render_template(&tmpl, "assets/list.html", &context); println!("DEBUG: Finished rendering assets list template"); response } // Display the list of user's assets pub async fn my_assets(tmpl: web::Data) -> Result { let mut context = Context::new(); println!("DEBUG: Starting my assets rendering"); let assets = Self::get_mock_assets(); println!("DEBUG: Generated {} mock assets", assets.len()); let assets_data: Vec> = assets .iter() .map(|a| Self::asset_to_json(a)) .collect(); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); context.insert("assets", &assets_data); println!("DEBUG: Rendering my assets template"); let response = render_template(&tmpl, "assets/my_assets.html", &context); println!("DEBUG: Finished rendering my assets template"); response } // Display a specific asset pub async fn detail(tmpl: web::Data, path: web::Path) -> Result { let asset_id = path.into_inner(); let mut context = Context::new(); println!("DEBUG: Starting asset detail rendering"); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); // Find the asset by ID let assets = Self::get_mock_assets(); let asset = assets.iter().find(|a| a.id == asset_id); match asset { Some(asset) => { println!("DEBUG: Found asset with ID {}", asset_id); // Convert asset to JSON let asset_json = Self::asset_to_json(asset); context.insert("asset", &asset_json); // Add valuation history for chart let valuation_history: Vec> = asset .sorted_valuation_history() .iter() .map(|v| { let mut map = serde_json::Map::new(); map.insert("date".to_string(), serde_json::Value::String(v.date.format("%Y-%m-%d").to_string())); map.insert("value".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(v.value).unwrap())); map.insert("currency".to_string(), serde_json::Value::String(v.currency.clone())); map }) .collect(); context.insert("valuation_history", &valuation_history); println!("DEBUG: Rendering asset detail template"); let response = render_template(&tmpl, "assets/detail.html", &context); println!("DEBUG: Finished rendering asset detail template"); response }, None => { println!("DEBUG: Asset not found with ID {}", asset_id); Ok(HttpResponse::NotFound().finish()) } } } // Display the create asset form pub async fn create_form(tmpl: web::Data) -> Result { let mut context = Context::new(); println!("DEBUG: Starting create asset form rendering"); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); // Add asset types for dropdown let asset_types = vec![ ("NFT", "NFT"), ("Token", "Token"), ("RealEstate", "Real Estate"), ("Commodity", "Commodity"), ("Share", "Share"), ("Bond", "Bond"), ("IntellectualProperty", "Intellectual Property"), ("Other", "Other") ]; context.insert("asset_types", &asset_types); println!("DEBUG: Rendering create asset form template"); let response = render_template(&tmpl, "assets/create.html", &context); println!("DEBUG: Finished rendering create asset form template"); response } // Process the create asset form pub async fn create( _tmpl: web::Data, _form: web::Form, ) -> Result { println!("DEBUG: Processing create asset form"); // In a real application, we would save the asset to the database // For now, we'll just redirect to the assets list Ok(HttpResponse::Found().append_header(("Location", "/assets")).finish()) } // Add a valuation to an asset pub async fn add_valuation( _tmpl: web::Data, path: web::Path, _form: web::Form, ) -> Result { let asset_id = path.into_inner(); println!("DEBUG: Adding valuation to asset with ID {}", asset_id); // In a real application, we would update the asset in the database // For now, we'll just redirect to the asset detail page Ok(HttpResponse::Found().append_header(("Location", format!("/assets/{}", asset_id))).finish()) } // Add a transaction to an asset pub async fn add_transaction( _tmpl: web::Data, path: web::Path, _form: web::Form, ) -> Result { let asset_id = path.into_inner(); println!("DEBUG: Adding transaction to asset with ID {}", asset_id); // In a real application, we would update the asset in the database // For now, we'll just redirect to the asset detail page Ok(HttpResponse::Found().append_header(("Location", format!("/assets/{}", asset_id))).finish()) } // Update the status of an asset pub async fn update_status( _tmpl: web::Data, path: web::Path<(String, String)>, ) -> Result { let (asset_id, _status) = path.into_inner(); println!("DEBUG: Updating status of asset with ID {}", asset_id); // In a real application, we would update the asset in the database // For now, we'll just redirect to the asset detail page Ok(HttpResponse::Found().append_header(("Location", format!("/assets/{}", asset_id))).finish()) } // Test method to render a simple test page pub async fn test(tmpl: web::Data) -> Result { println!("DEBUG: Starting test page rendering"); let mut context = Context::new(); let assets = Self::get_mock_assets(); println!("DEBUG: Generated {} mock assets for test", assets.len()); let stats = AssetStatistics::new(&assets); println!("DEBUG: Generated asset statistics for test: {:?}", stats); // Add active_page for navigation highlighting context.insert("active_page", &"assets"); // Add stats context.insert("stats", &serde_json::to_value(stats).unwrap()); println!("DEBUG: Added stats to context for test"); // Add recent assets let recent_assets: Vec> = assets .iter() .take(5) .map(|a| Self::asset_to_json(a)) .collect(); context.insert("recent_assets", &recent_assets); println!("DEBUG: Rendering test_base.html with full context"); let response = render_template(&tmpl, "test_base.html", &context); println!("DEBUG: Finished rendering test_base.html"); response } // Helper method to convert Asset to a JSON object for templates fn asset_to_json(asset: &Asset) -> serde_json::Map { let mut map = serde_json::Map::new(); map.insert("id".to_string(), serde_json::Value::String(asset.id.clone())); map.insert("name".to_string(), serde_json::Value::String(asset.name.clone())); map.insert("description".to_string(), serde_json::Value::String(asset.description.clone())); map.insert("asset_type".to_string(), serde_json::Value::String(asset.asset_type.as_str().to_string())); map.insert("status".to_string(), serde_json::Value::String(asset.status.as_str().to_string())); map.insert("owner_id".to_string(), serde_json::Value::String(asset.owner_id.clone())); map.insert("owner_name".to_string(), serde_json::Value::String(asset.owner_name.clone())); map.insert("created_at".to_string(), serde_json::Value::String(asset.created_at.format("%Y-%m-%d").to_string())); map.insert("updated_at".to_string(), serde_json::Value::String(asset.updated_at.format("%Y-%m-%d").to_string())); // Add current valuation if available if let Some(current_valuation) = asset.current_valuation { map.insert("current_valuation".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(current_valuation).unwrap())); if let Some(valuation_currency) = &asset.valuation_currency { map.insert("valuation_currency".to_string(), serde_json::Value::String(valuation_currency.clone())); } if let Some(valuation_date) = asset.valuation_date { map.insert("valuation_date".to_string(), serde_json::Value::String(valuation_date.format("%Y-%m-%d").to_string())); } } // Add blockchain info if available if let Some(blockchain_info) = &asset.blockchain_info { let mut blockchain_map = serde_json::Map::new(); blockchain_map.insert("blockchain".to_string(), serde_json::Value::String(blockchain_info.blockchain.clone())); blockchain_map.insert("token_id".to_string(), serde_json::Value::String(blockchain_info.token_id.clone())); blockchain_map.insert("contract_address".to_string(), serde_json::Value::String(blockchain_info.contract_address.clone())); blockchain_map.insert("owner_address".to_string(), serde_json::Value::String(blockchain_info.owner_address.clone())); if let Some(transaction_hash) = &blockchain_info.transaction_hash { blockchain_map.insert("transaction_hash".to_string(), serde_json::Value::String(transaction_hash.clone())); } if let Some(block_number) = blockchain_info.block_number { blockchain_map.insert("block_number".to_string(), serde_json::Value::Number(serde_json::Number::from(block_number))); } if let Some(timestamp) = blockchain_info.timestamp { blockchain_map.insert("timestamp".to_string(), serde_json::Value::String(timestamp.format("%Y-%m-%d").to_string())); } map.insert("blockchain_info".to_string(), serde_json::Value::Object(blockchain_map)); } // Add valuation history let valuation_history: Vec = asset.valuation_history.iter() .map(|v| { let mut valuation_map = serde_json::Map::new(); valuation_map.insert("id".to_string(), serde_json::Value::String(v.id.clone())); valuation_map.insert("date".to_string(), serde_json::Value::String(v.date.format("%Y-%m-%d").to_string())); valuation_map.insert("value".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(v.value).unwrap())); valuation_map.insert("currency".to_string(), serde_json::Value::String(v.currency.clone())); valuation_map.insert("source".to_string(), serde_json::Value::String(v.source.clone())); if let Some(notes) = &v.notes { valuation_map.insert("notes".to_string(), serde_json::Value::String(notes.clone())); } serde_json::Value::Object(valuation_map) }) .collect(); map.insert("valuation_history".to_string(), serde_json::Value::Array(valuation_history)); // Add transaction history let transaction_history: Vec = asset.transaction_history.iter() .map(|t| { let mut transaction_map = serde_json::Map::new(); transaction_map.insert("id".to_string(), serde_json::Value::String(t.id.clone())); transaction_map.insert("transaction_type".to_string(), serde_json::Value::String(t.transaction_type.clone())); transaction_map.insert("date".to_string(), serde_json::Value::String(t.date.format("%Y-%m-%d").to_string())); if let Some(from_address) = &t.from_address { transaction_map.insert("from_address".to_string(), serde_json::Value::String(from_address.clone())); } if let Some(to_address) = &t.to_address { transaction_map.insert("to_address".to_string(), serde_json::Value::String(to_address.clone())); } if let Some(amount) = t.amount { transaction_map.insert("amount".to_string(), serde_json::Value::Number(serde_json::Number::from_f64(amount).unwrap())); } if let Some(currency) = &t.currency { transaction_map.insert("currency".to_string(), serde_json::Value::String(currency.clone())); } if let Some(transaction_hash) = &t.transaction_hash { transaction_map.insert("transaction_hash".to_string(), serde_json::Value::String(transaction_hash.clone())); } if let Some(notes) = &t.notes { transaction_map.insert("notes".to_string(), serde_json::Value::String(notes.clone())); } serde_json::Value::Object(transaction_map) }) .collect(); map.insert("transaction_history".to_string(), serde_json::Value::Array(transaction_history)); // Add image URL if available if let Some(image_url) = &asset.image_url { map.insert("image_url".to_string(), serde_json::Value::String(image_url.clone())); } // Add external URL if available if let Some(external_url) = &asset.external_url { map.insert("external_url".to_string(), serde_json::Value::String(external_url.clone())); } map } // Generate mock assets for testing fn get_mock_assets() -> Vec { let now = Utc::now(); let mut assets = Vec::new(); // Create Tokenized Real Estate asset let mut zanzibar_resort = Asset { id: "asset-zanzibar-resort".to_string(), name: "Zanzibar Coastal Resort".to_string(), description: "A tokenized luxury eco-resort on the eastern coast of Zanzibar with 20 villas and sustainable energy infrastructure".to_string(), asset_type: AssetType::RealEstate, status: AssetStatus::Active, owner_id: "entity-oceanview-holdings".to_string(), owner_name: "OceanView Holdings Ltd.".to_string(), created_at: now - Duration::days(120), updated_at: now - Duration::days(5), blockchain_info: None, current_valuation: Some(3750000.0), valuation_currency: Some("USD".to_string()), valuation_date: Some(now - Duration::days(15)), valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({ "location": "East Coast, Zanzibar", "property_size": "5.2 hectares", "buildings": 22, "tokenization_date": (now - Duration::days(120)).to_rfc3339(), "total_tokens": 10000, "token_price": 375.0 }), image_url: Some("https://example.com/zanzibar_resort.jpg".to_string()), external_url: Some("https://oceanviewholdings.zaz/resort".to_string()), }; zanzibar_resort.add_blockchain_info(BlockchainInfo { blockchain: "Ethereum".to_string(), token_id: "ZRESORT".to_string(), contract_address: "0x123456789abcdef123456789abcdef12345678ab".to_string(), owner_address: "0xc3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4".to_string(), transaction_hash: Some("0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd".to_string()), block_number: Some(9876543), timestamp: Some(now - Duration::days(120)), }); zanzibar_resort.add_valuation(3500000.0, "USD", "ZAZ Property Registry", Some("Initial tokenization valuation".to_string())); zanzibar_resort.add_valuation(3650000.0, "USD", "International Property Appraisers", Some("Independent third-party valuation".to_string())); zanzibar_resort.add_valuation(3750000.0, "USD", "ZAZ Property Registry", Some("Updated valuation after infrastructure improvements".to_string())); zanzibar_resort.add_transaction( "Tokenization", None, Some("0xc3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4".to_string()), Some(3500000.0), Some("USD".to_string()), Some("0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcd".to_string()), Some("Initial property tokenization under ZAZ Property Registry".to_string()), ); zanzibar_resort.add_transaction( "Token Sale", Some("0xc3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4".to_string()), Some("0x7a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b".to_string()), Some(375000.0), Some("USD".to_string()), Some("0xdef123456789abcdef123456789abcdef123456789abcdef123456789abcdef".to_string()), Some("Sale of 10% ownership tokens to Zanzibar Investment Collective".to_string()), ); assets.push(zanzibar_resort); // Create ZAZ Governance Token let mut zaz_token = Asset { id: "asset-zaz-governance".to_string(), name: "ZAZ Governance Token".to_string(), description: "Official governance token of the Zanzibar Autonomous Zone, used for voting on proposals and zone-wide decisions".to_string(), asset_type: AssetType::Token, status: AssetStatus::Active, owner_id: "entity-zaz-foundation".to_string(), owner_name: "Zanzibar Autonomous Zone Foundation".to_string(), created_at: now - Duration::days(365), updated_at: now - Duration::days(2), blockchain_info: None, current_valuation: Some(12500000.0), valuation_currency: Some("USD".to_string()), valuation_date: Some(now - Duration::days(3)), valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({ "total_supply": 10000000, "circulating_supply": 7500000, "governance_weight": 1.0, "minimum_holding_for_proposals": 10000, "launch_date": (now - Duration::days(365)).to_rfc3339() }), image_url: Some("https://example.com/zaz_token.png".to_string()), external_url: Some("https://governance.zaz/token".to_string()), }; zaz_token.add_blockchain_info(BlockchainInfo { blockchain: "ThreeFold".to_string(), token_id: "ZAZT".to_string(), contract_address: "0xf6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1".to_string(), owner_address: "0xe5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6".to_string(), transaction_hash: None, block_number: None, timestamp: Some(now - Duration::days(365)), }); zaz_token.add_valuation(8000000.0, "USD", "ZAZ Token Exchange", Some("Initial valuation at launch".to_string())); zaz_token.add_valuation(10500000.0, "USD", "ZAZ Token Exchange", Some("Valuation after successful governance implementation".to_string())); zaz_token.add_valuation(12500000.0, "USD", "ZAZ Token Exchange", Some("Current market valuation".to_string())); zaz_token.add_transaction( "Distribution", Some("0xe5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6".to_string()), Some("0x9a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b".to_string()), Some(1000000.0), Some("ZAZT".to_string()), Some("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()), Some("Initial token distribution to founding members".to_string()), ); zaz_token.add_transaction( "Distribution", Some("0xe5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6".to_string()), Some("0x8b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c".to_string()), Some(2500000.0), Some("ZAZT".to_string()), Some("0x234567890abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()), Some("Public token sale for zone participants".to_string()), ); assets.push(zaz_token); // Create Spice Trade Venture Shares let mut spice_trade_shares = Asset { id: "asset-spice-trade-shares".to_string(), name: "Zanzibar Spice Trade Ventures".to_string(), description: "Equity shares in Zanzibar Spice Trade Ventures, a leading exporter of organic spices from the Zanzibar region".to_string(), asset_type: AssetType::Share, status: AssetStatus::Active, owner_id: "entity-spice-trade".to_string(), owner_name: "Zanzibar Spice Trade Ventures Ltd.".to_string(), created_at: now - Duration::days(180), updated_at: now - Duration::days(7), blockchain_info: None, current_valuation: Some(4250000.0), valuation_currency: Some("USD".to_string()), valuation_date: Some(now - Duration::days(7)), valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({ "total_shares": 1000000, "share_type": "Common", "business_sector": "Agriculture & Export", "dividend_yield": 5.2, "last_dividend_date": (now - Duration::days(30)).to_rfc3339(), "incorporation_date": (now - Duration::days(180)).to_rfc3339() }), image_url: Some("https://example.com/spice_trade_logo.png".to_string()), external_url: Some("https://spicetrade.zaz".to_string()), }; spice_trade_shares.add_blockchain_info(BlockchainInfo { blockchain: "Ethereum".to_string(), token_id: "SPICE".to_string(), contract_address: "0x3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4".to_string(), owner_address: "0x6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b".to_string(), transaction_hash: Some("0x789abcdef123456789abcdef123456789abcdef123456789abcdef123456789a".to_string()), block_number: Some(7654321), timestamp: Some(now - Duration::days(180)), }); spice_trade_shares.add_valuation(3800000.0, "USD", "ZAZ Business Registry", Some("Initial company valuation at incorporation".to_string())); spice_trade_shares.add_valuation(4000000.0, "USD", "ZAZ Business Registry", Some("Valuation after first export contracts".to_string())); spice_trade_shares.add_valuation(4250000.0, "USD", "ZAZ Business Registry", Some("Current valuation after expansion to European markets".to_string())); spice_trade_shares.add_transaction( "Share Issuance", None, Some("0x6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b".to_string()), Some(3800000.0), Some("USD".to_string()), Some("0x789abcdef123456789abcdef123456789abcdef123456789abcdef123456789a".to_string()), Some("Initial share issuance at company formation".to_string()), ); spice_trade_shares.add_transaction( "Share Transfer", Some("0x6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b".to_string()), Some("0x7b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c".to_string()), Some(950000.0), Some("USD".to_string()), Some("0x89abcdef123456789abcdef123456789abcdef123456789abcdef123456789ab".to_string()), Some("Sale of 25% equity to East African Growth Partners".to_string()), ); assets.push(spice_trade_shares); // Create Sustainable Energy Patent let mut tidal_energy_patent = Asset { id: "asset-tidal-energy-patent".to_string(), name: "Zanzibar Tidal Energy System Patent".to_string(), description: "Patent for an innovative tidal energy harvesting system designed specifically for the coastal conditions of Zanzibar".to_string(), asset_type: AssetType::IntellectualProperty, status: AssetStatus::Active, owner_id: "entity-zaz-energy-innovations".to_string(), owner_name: "ZAZ Energy Innovations".to_string(), created_at: now - Duration::days(210), updated_at: now - Duration::days(30), blockchain_info: None, current_valuation: Some(2800000.0), valuation_currency: Some("USD".to_string()), valuation_date: Some(now - Duration::days(30)), valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({ "patent_number": "ZAZ-PAT-2024-0142", "filing_date": (now - Duration::days(210)).to_rfc3339(), "grant_date": (now - Duration::days(120)).to_rfc3339(), "patent_type": "Utility", "jurisdiction": "Zanzibar Autonomous Zone", "inventors": ["Dr. Amina Juma", "Eng. Ibrahim Hassan", "Dr. Sarah Mbeki"] }), image_url: Some("https://example.com/tidal_energy_diagram.png".to_string()), external_url: Some("https://patents.zaz/ZAZ-PAT-2024-0142".to_string()), }; tidal_energy_patent.add_blockchain_info(BlockchainInfo { blockchain: "Polygon".to_string(), token_id: "TIDALIP".to_string(), contract_address: "0x2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3".to_string(), owner_address: "0x4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f".to_string(), transaction_hash: Some("0x56789abcdef123456789abcdef123456789abcdef123456789abcdef12345678".to_string()), block_number: Some(5432109), timestamp: Some(now - Duration::days(120)), }); tidal_energy_patent.add_valuation(1500000.0, "USD", "ZAZ IP Registry", Some("Initial patent valuation upon filing".to_string())); tidal_energy_patent.add_valuation(2200000.0, "USD", "ZAZ IP Registry", Some("Valuation after successful prototype testing".to_string())); tidal_energy_patent.add_valuation(2800000.0, "USD", "ZAZ IP Registry", Some("Current valuation after pilot implementation".to_string())); tidal_energy_patent.add_transaction( "Registration", None, Some("0x4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f".to_string()), Some(1500000.0), Some("USD".to_string()), Some("0x56789abcdef123456789abcdef123456789abcdef123456789abcdef12345678".to_string()), Some("Initial patent registration and tokenization".to_string()), ); tidal_energy_patent.add_transaction( "Licensing", Some("0x4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f".to_string()), Some("0x5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a".to_string()), Some(450000.0), Some("USD".to_string()), Some("0x6789abcdef123456789abcdef123456789abcdef123456789abcdef123456789".to_string()), Some("Licensing agreement with Coastal Energy Solutions".to_string()), ); assets.push(tidal_energy_patent); // Create Digital Art NFT let mut zanzibar_heritage_nft = Asset { id: "asset-heritage-nft".to_string(), name: "Zanzibar Heritage Collection #1".to_string(), description: "Limited edition digital art NFT showcasing Zanzibar's cultural heritage, created by renowned local artist Fatma Busaidy".to_string(), asset_type: AssetType::NFT, status: AssetStatus::Active, owner_id: "entity-zaz-digital-arts".to_string(), owner_name: "ZAZ Digital Arts Collective".to_string(), created_at: now - Duration::days(90), updated_at: now - Duration::days(10), blockchain_info: None, current_valuation: Some(15000.0), valuation_currency: Some("USD".to_string()), valuation_date: Some(now - Duration::days(10)), valuation_history: Vec::new(), transaction_history: Vec::new(), metadata: serde_json::json!({ "artist": "Fatma Busaidy", "edition": "1 of 10", "medium": "Digital Mixed Media", "dimensions": "4000x3000 px", "creation_date": (now - Duration::days(95)).to_rfc3339(), "authenticity_certificate": "ZAZ-ART-CERT-2024-089" }), image_url: Some("https://example.com/zanzibar_heritage_nft.jpg".to_string()), external_url: Some("https://digitalarts.zaz/collections/heritage/1".to_string()), }; zanzibar_heritage_nft.add_blockchain_info(BlockchainInfo { blockchain: "Ethereum".to_string(), token_id: "HERITAGE1".to_string(), contract_address: "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d".to_string(), owner_address: "0xb794f5ea0ba39494ce839613fffba74279579268".to_string(), transaction_hash: Some("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()), block_number: Some(12345678), timestamp: Some(now - Duration::days(90)), }); zanzibar_heritage_nft.add_valuation(12000.0, "USD", "ZAZ NFT Marketplace", Some("Initial offering price".to_string())); zanzibar_heritage_nft.add_valuation(13500.0, "USD", "ZAZ NFT Marketplace", Some("Valuation after artist exhibition".to_string())); zanzibar_heritage_nft.add_valuation(15000.0, "USD", "ZAZ NFT Marketplace", Some("Current market valuation".to_string())); zanzibar_heritage_nft.add_transaction( "Minting", None, Some("0xb794f5ea0ba39494ce839613fffba74279579268".to_string()), Some(0.0), Some("ETH".to_string()), Some("0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()), Some("Initial NFT minting by artist".to_string()), ); zanzibar_heritage_nft.add_transaction( "Sale", Some("0xb794f5ea0ba39494ce839613fffba74279579268".to_string()), Some("0xa1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2".to_string()), Some(12000.0), Some("USD".to_string()), Some("0x234567890abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string()), Some("Primary sale to ZAZ Digital Arts Collective".to_string()), ); assets.push(zanzibar_heritage_nft); assets } }