diff --git a/contracts/governance/src/curation.rs b/contracts/governance/src/curation.rs new file mode 100644 index 0000000..22f120c --- /dev/null +++ b/contracts/governance/src/curation.rs @@ -0,0 +1,5 @@ +pub struct QualityVote { + pub token_id: u64, + pub voter: Address, + pub score: u8, +} \ No newline at end of file diff --git a/contracts/insurance/src/content_protection.rs b/contracts/insurance/src/content_protection.rs new file mode 100644 index 0000000..e7c52d9 --- /dev/null +++ b/contracts/insurance/src/content_protection.rs @@ -0,0 +1,13 @@ +pub struct ContentInsurancePolicy { + pub token_id: u64, + pub coverage_amount: u128, + pub premium_paid: u128, + pub active: bool, +} + +pub struct Order { + pub token_id: u64, + pub trader: Address, + pub price: u128, + pub is_buy: bool, +} \ No newline at end of file diff --git a/contracts/teachlink/src/analytics.rs b/contracts/teachlink/src/analytics.rs index 71656e7..a9ecf49 100644 --- a/contracts/teachlink/src/analytics.rs +++ b/contracts/teachlink/src/analytics.rs @@ -1,378 +1,108 @@ -//! Bridge Monitoring and Analytics Module -//! -//! This module implements comprehensive analytics and monitoring -//! for bridge operations, validator performance, and chain metrics. - -use crate::errors::BridgeError; -use crate::storage::{BRIDGE_METRICS, CHAIN_METRICS, DAILY_VOLUMES}; -use crate::types::{BridgeMetrics, ChainMetrics}; -use soroban_sdk::{Address, Bytes, Env, Map, Vec}; - -/// Metrics update interval (1 hour) -pub const METRICS_UPDATE_INTERVAL: u64 = 3_600; - -/// Analytics Manager -pub struct AnalyticsManager; - -impl AnalyticsManager { - /// Initialize bridge metrics - pub fn initialize_metrics(env: &Env) -> Result<(), BridgeError> { - let metrics = BridgeMetrics { - total_volume: 0, - total_transactions: 0, - active_validators: 0, - average_confirmation_time: 0, - success_rate: 10000, // 100% in basis points - last_updated: env.ledger().timestamp(), - }; - - env.storage().instance().set(&BRIDGE_METRICS, &metrics); - - Ok(()) - } - - /// Update bridge metrics - pub fn update_bridge_metrics( - env: &Env, - volume: i128, - transactions: u64, - confirmation_time: u64, - success: bool, - ) -> Result<(), BridgeError> { - let mut metrics: BridgeMetrics = - env.storage() - .instance() - .get(&BRIDGE_METRICS) - .unwrap_or(BridgeMetrics { - total_volume: 0, - total_transactions: 0, - active_validators: 0, - average_confirmation_time: 0, - success_rate: 10000, - last_updated: env.ledger().timestamp(), - }); - - // Update metrics - metrics.total_volume += volume; - metrics.total_transactions += transactions; - - // Update average confirmation time (exponential moving average) - if metrics.total_transactions > 0 { - let alpha = 10; // Smoothing factor (10% weight to new value) - metrics.average_confirmation_time = ((metrics.average_confirmation_time - * (100 - alpha) as u64) - + (confirmation_time * alpha as u64)) - / 100; - } else { - metrics.average_confirmation_time = confirmation_time; - } - - // Update success rate - if success { - metrics.success_rate = ((metrics.success_rate * 99) + 10000) / 100; - } else { - metrics.success_rate = (metrics.success_rate * 99) / 100; - } - - metrics.last_updated = env.ledger().timestamp(); - - env.storage().instance().set(&BRIDGE_METRICS, &metrics); - - Ok(()) - } - - /// Update validator count - pub fn update_validator_count(env: &Env, active_validators: u32) -> Result<(), BridgeError> { - let mut metrics: BridgeMetrics = - env.storage() - .instance() - .get(&BRIDGE_METRICS) - .unwrap_or(BridgeMetrics { - total_volume: 0, - total_transactions: 0, - active_validators: 0, - average_confirmation_time: 0, - success_rate: 10000, - last_updated: env.ledger().timestamp(), - }); - - metrics.active_validators = active_validators; - metrics.last_updated = env.ledger().timestamp(); - - env.storage().instance().set(&BRIDGE_METRICS, &metrics); - - Ok(()) - } - - /// Initialize chain metrics - pub fn initialize_chain_metrics(env: &Env, chain_id: u32) -> Result<(), BridgeError> { - let metrics = ChainMetrics { - chain_id, - volume_in: 0, - volume_out: 0, - transaction_count: 0, - average_fee: 0, - last_updated: env.ledger().timestamp(), - }; - - let mut chain_metrics: Map = env - .storage() - .instance() - .get(&CHAIN_METRICS) - .unwrap_or_else(|| Map::new(env)); - chain_metrics.set(chain_id, metrics); - env.storage().instance().set(&CHAIN_METRICS, &chain_metrics); - - Ok(()) - } - - /// Update chain metrics - pub fn update_chain_metrics( - env: &Env, - chain_id: u32, - volume: i128, - is_incoming: bool, - fee: i128, - ) -> Result<(), BridgeError> { - let mut chain_metrics: Map = env - .storage() - .instance() - .get(&CHAIN_METRICS) - .unwrap_or_else(|| Map::new(env)); - - let mut metrics = chain_metrics.get(chain_id).unwrap_or(ChainMetrics { - chain_id, - volume_in: 0, - volume_out: 0, - transaction_count: 0, - average_fee: 0, - last_updated: env.ledger().timestamp(), - }); - - // Update volume - if is_incoming { - metrics.volume_in += volume; - } else { - metrics.volume_out += volume; - } - - // Update transaction count - metrics.transaction_count += 1; - - // Update average fee - if metrics.transaction_count > 0 { - metrics.average_fee = ((metrics.average_fee * (metrics.transaction_count - 1) as i128) - + fee) - / metrics.transaction_count as i128; - } else { - metrics.average_fee = fee; - } - - metrics.last_updated = env.ledger().timestamp(); - - chain_metrics.set(chain_id, metrics); - env.storage().instance().set(&CHAIN_METRICS, &chain_metrics); - - Ok(()) - } - - /// Record daily volume - pub fn record_daily_volume( - env: &Env, - day_timestamp: u64, - volume: i128, - chain_id: u32, - ) -> Result<(), BridgeError> { - let mut daily_volumes: Map<(u64, u32), i128> = env - .storage() - .instance() - .get(&DAILY_VOLUMES) - .unwrap_or_else(|| Map::new(env)); - - let key = (day_timestamp, chain_id); - let current_volume = daily_volumes.get(key.clone()).unwrap_or(0); - daily_volumes.set(key, current_volume + volume); - env.storage().instance().set(&DAILY_VOLUMES, &daily_volumes); - - Ok(()) - } - - /// Get daily volume - pub fn get_daily_volume(env: &Env, day_timestamp: u64, chain_id: u32) -> i128 { - let daily_volumes: Map<(u64, u32), i128> = env - .storage() - .instance() - .get(&DAILY_VOLUMES) - .unwrap_or_else(|| Map::new(env)); - daily_volumes.get((day_timestamp, chain_id)).unwrap_or(0) - } - - /// Get bridge metrics - pub fn get_bridge_metrics(env: &Env) -> BridgeMetrics { - env.storage() - .instance() - .get(&BRIDGE_METRICS) - .unwrap_or(BridgeMetrics { - total_volume: 0, - total_transactions: 0, - active_validators: 0, - average_confirmation_time: 0, - success_rate: 10000, - last_updated: env.ledger().timestamp(), - }) - } - - /// Get chain metrics - pub fn get_chain_metrics(env: &Env, chain_id: u32) -> Option { - let chain_metrics: Map = env - .storage() - .instance() - .get(&CHAIN_METRICS) - .unwrap_or_else(|| Map::new(env)); - chain_metrics.get(chain_id) - } - - /// Get all chain metrics - pub fn get_all_chain_metrics(env: &Env) -> Vec { - let chain_metrics: Map = env - .storage() - .instance() - .get(&CHAIN_METRICS) - .unwrap_or_else(|| Map::new(env)); - - let mut result = Vec::new(env); - for (_chain_id, metrics) in chain_metrics.iter() { - result.push_back(metrics); - } - result - } - - /// Calculate bridge health score (0-100) - pub fn calculate_health_score(env: &Env) -> u32 { - let metrics = Self::get_bridge_metrics(env); - - // Success rate weight: 40% - let success_score = metrics.success_rate / 100; - - // Validator participation weight: 30% - let validator_score = if metrics.active_validators > 0 { - 100u32 - } else { - 0u32 - }; +#![no_std] + +use soroban_sdk::{ + contractevent, Address, Bytes, Env, Map, Symbol, Vec, +}; + +/// Storage keys used for analytics tracking +#[derive(Clone)] +#[repr(u32)] +pub enum DataKey { + Views = 0, + Purchases = 1, + Revenue = 2, + BridgeStats = 3, +} - // Confirmation time weight: 30% - // Ideal: < 5 minutes (300 seconds) - let confirmation_score = if metrics.average_confirmation_time < 300 { - 100u32 - } else if metrics.average_confirmation_time < 600 { - 80u32 - } else if metrics.average_confirmation_time < 1800 { - 60u32 - } else if metrics.average_confirmation_time < 3600 { - 40u32 - } else { - 20u32 - }; +/// Event emitted when content is viewed +#[contractevent] +pub struct ContentViewed { + pub token_id: Bytes, +} - // Weighted average - ((success_score * 40) + (validator_score * 30) + (confirmation_score * 30)) / 100 - } +/// Event emitted when content is purchased +#[contractevent] +pub struct ContentPurchased { + pub token_id: Bytes, + pub buyer: Address, +} - /// Get top chains by volume - pub fn get_top_chains_by_volume(env: &Env, limit: u32) -> Vec<(u32, i128)> { - let chain_metrics: Map = env - .storage() - .instance() - .get(&CHAIN_METRICS) - .unwrap_or_else(|| Map::new(env)); +/// Record a content view +pub fn record_view(env: &Env, token_id: Bytes) { + let mut views: Map = + env.storage().instance().get(&DataKey::Views).unwrap_or(Map::new(env)); - let mut chains: Vec<(u32, i128)> = Vec::new(env); - for (chain_id, metrics) in chain_metrics.iter() { - let total_volume = metrics.volume_in + metrics.volume_out; - chains.push_back((chain_id, total_volume)); - } + let count = views.get(token_id.clone()).unwrap_or(0); + views.set(token_id.clone(), count + 1); - // Simple bubble sort (for small datasets) - let len = chains.len(); - for i in 0..len { - for j in 0..(len - i - 1) { - let (_, vol_a) = chains.get(j).unwrap(); - let (_, vol_b) = chains.get(j + 1).unwrap(); - if vol_a < vol_b { - let temp = chains.get(j).unwrap(); - chains.set(j, chains.get(j + 1).unwrap()); - chains.set(j + 1, temp); - } - } - } + env.storage().instance().set(&DataKey::Views, &views); - // Return top N - let mut result = Vec::new(env); - for i in 0..limit.min(chains.len()) { - if let Some(chain) = chains.get(i) { - result.push_back(chain); - } - } - result - } + ContentViewed { token_id }.publish(env); +} - /// Get bridge statistics - pub fn get_bridge_statistics(env: &Env) -> Map { - let metrics = Self::get_bridge_metrics(env); - let mut stats: Map = Map::new(env); +/// Record a purchase with amount (used for revenue tracking) +pub fn record_purchase( + env: &Env, + token_id: Bytes, + buyer: Address, + amount: i128, +) { + // Update purchase count + let mut purchases: Map = + env.storage().instance().get(&DataKey::Purchases).unwrap_or(Map::new(env)); + + let count = purchases.get(token_id.clone()).unwrap_or(0); + purchases.set(token_id.clone(), count + 1); + env.storage().instance().set(&DataKey::Purchases, &purchases); + + // Update revenue + let mut revenue: Map = + env.storage().instance().get(&DataKey::Revenue).unwrap_or(Map::new(env)); + + let total = revenue.get(token_id.clone()).unwrap_or(0); + revenue.set(token_id.clone(), total + amount); + env.storage().instance().set(&DataKey::Revenue, &revenue); + + ContentPurchased { token_id, buyer }.publish(env); +} - stats.set( - Bytes::from_slice(env, b"total_volume"), - metrics.total_volume, - ); - stats.set( - Bytes::from_slice(env, b"total_transactions"), - metrics.total_transactions as i128, - ); - stats.set( - Bytes::from_slice(env, b"active_validators"), - metrics.active_validators as i128, - ); - stats.set( - Bytes::from_slice(env, b"avg_confirmation_time"), - metrics.average_confirmation_time as i128, - ); - stats.set( - Bytes::from_slice(env, b"success_rate"), - metrics.success_rate as i128, - ); - stats.set( - Bytes::from_slice(env, b"health_score"), - Self::calculate_health_score(env) as i128, - ); +/// Get total views for a specific content +pub fn get_views(env: &Env, token_id: Bytes) -> u64 { + let views: Map = + env.storage().instance().get(&DataKey::Views).unwrap_or(Map::new(env)); - stats - } + views.get(token_id).unwrap_or(0) +} - /// Reset metrics (admin only) - pub fn reset_metrics(env: &Env, admin: Address) -> Result<(), BridgeError> { - admin.require_auth(); +/// Get total purchases for a specific content +pub fn get_purchases(env: &Env, token_id: Bytes) -> u64 { + let purchases: Map = + env.storage().instance().get(&DataKey::Purchases).unwrap_or(Map::new(env)); - let metrics = BridgeMetrics { - total_volume: 0, - total_transactions: 0, - active_validators: 0, - average_confirmation_time: 0, - success_rate: 10000, - last_updated: env.ledger().timestamp(), - }; + purchases.get(token_id).unwrap_or(0) +} - env.storage().instance().set(&BRIDGE_METRICS, &metrics); +/// Get total revenue for a specific content +pub fn get_revenue(env: &Env, token_id: Bytes) -> i128 { + let revenue: Map = + env.storage().instance().get(&DataKey::Revenue).unwrap_or(Map::new(env)); - Ok(()) - } + revenue.get(token_id).unwrap_or(0) +} - /// Check if metrics need update - pub fn needs_update(env: &Env) -> bool { - let metrics = Self::get_bridge_metrics(env); - let current_time = env.ledger().timestamp(); +/// Store bridge statistics (cross-chain or external integrations) +pub fn set_bridge_stat(env: &Env, key: Bytes, value: i128) { + let mut stats: Map = + env.storage().instance().get(&DataKey::BridgeStats).unwrap_or(Map::new(env)); - current_time - metrics.last_updated > METRICS_UPDATE_INTERVAL - } + stats.set(key, value); + env.storage().instance().set(&DataKey::BridgeStats, &stats); } + +/// Retrieve all bridge statistics +pub fn get_bridge_statistics(env: &Env) -> Map { + env.storage() + .instance() + .get(&DataKey::BridgeStats) + .unwrap_or(Map::new(env)) +} \ No newline at end of file diff --git a/contracts/teachlink/src/collaboration.rs b/contracts/teachlink/src/collaboration.rs new file mode 100644 index 0000000..e69de29 diff --git a/contracts/teachlink/src/content_nft.rs b/contracts/teachlink/src/content_nft.rs new file mode 100644 index 0000000..8abe2c9 --- /dev/null +++ b/contracts/teachlink/src/content_nft.rs @@ -0,0 +1,45 @@ +#[derive(Serialize, Deserialize, Clone)] +pub struct ContentMetadata { + pub title: String, + pub description: String, + pub content_uri: String, + pub preview_uri: Option, + pub category: String, + pub tags: Vec, + pub license_type: LicenseType, + pub version: u32, + pub quality_score: u32, +} + +pub struct ContentNFT { + pub token_id: u64, + pub creator: Address, + pub co_owners: Vec
, + pub metadata: ContentMetadata, + pub royalty_percentage: u16, + pub fractionalized: bool, + pub created_at: u64, +} + +pub fn mint_content( + creator: Address, + metadata: ContentMetadata, + royalty_percentage: u16, +) -> Result { + assert!(royalty_percentage <= 2000); // max 20% + + let token_id = Self::next_token_id(); + + let nft = ContentNFT { + token_id, + creator, + co_owners: vec![], + metadata, + royalty_percentage, + fractionalized: false, + created_at: block_timestamp(), + }; + + Self::store_nft(token_id, nft); + Ok(token_id) +} \ No newline at end of file diff --git a/contracts/teachlink/src/fractional.rs b/contracts/teachlink/src/fractional.rs new file mode 100644 index 0000000..c76f0b1 --- /dev/null +++ b/contracts/teachlink/src/fractional.rs @@ -0,0 +1,7 @@ +pub struct FractionalVault { + pub token_id: u64, + pub total_shares: u128, + pub price_per_share: u128, + pub shareholders: Map, +} + diff --git a/contracts/teachlink/src/licensing.rs b/contracts/teachlink/src/licensing.rs new file mode 100644 index 0000000..da93e25 --- /dev/null +++ b/contracts/teachlink/src/licensing.rs @@ -0,0 +1,14 @@ +pub enum LicenseType { + Personal, + Commercial, + Exclusive, + Subscription, +} + +pub struct LicenseAgreement { + pub token_id: u64, + pub licensee: Address, + pub license_type: LicenseType, + pub expires_at: Option, +} + diff --git a/contracts/teachlink/src/marketplace.rs b/contracts/teachlink/src/marketplace.rs new file mode 100644 index 0000000..3b5d5a1 --- /dev/null +++ b/contracts/teachlink/src/marketplace.rs @@ -0,0 +1,26 @@ +pub struct Listing { + pub listing_id: u64, + pub token_id: u64, + pub seller: Address, + pub price: u128, + pub payment_token: Address, + pub active: bool, +} + +pub fn buy(listing_id: u64, buyer: Address) -> Result<()> { + let listing = Self::get_listing(listing_id)?; + let nft = ContentModule::get_nft(listing.token_id)?; + + let royalty = listing.price * nft.royalty_percentage as u128 / 10000; + let seller_amount = listing.price - royalty; + + // Transfer funds + Self::transfer(buyer, nft.creator, royalty); + Self::transfer(buyer, listing.seller, seller_amount); + + // Transfer ownership + ContentModule::transfer_nft(listing.token_id, buyer)?; + + Ok(()) +} + diff --git a/contracts/teachlink/src/recommendation.rs b/contracts/teachlink/src/recommendation.rs new file mode 100644 index 0000000..e69de29 diff --git a/contracts/teachlink/src/royalty.rs b/contracts/teachlink/src/royalty.rs new file mode 100644 index 0000000..a774f8e --- /dev/null +++ b/contracts/teachlink/src/royalty.rs @@ -0,0 +1,12 @@ +pub struct RoyaltySplit { + pub recipients: Vec<(Address, u16)>, // percentage basis points +} + +pub fn distribute(token_id: u64, amount: u128) { + let splits = Self::get_royalty_split(token_id); + + for (recipient, percentage) in splits { + let share = amount * percentage as u128 / 10000; + Self::transfer_platform(recipient, share); + } +} \ No newline at end of file