diff --git a/contracts/teachlink/src/bridge.rs b/contracts/teachlink/src/bridge.rs index 5490226..d660a2a 100644 --- a/contracts/teachlink/src/bridge.rs +++ b/contracts/teachlink/src/bridge.rs @@ -1,640 +1,87 @@ -use crate::errors::BridgeError; -use crate::events::{BridgeCompletedEvent, BridgeInitiatedEvent, DepositEvent, ReleaseEvent}; -use crate::storage::{ - ADMIN, BRIDGE_FAILURES, BRIDGE_FEE, BRIDGE_LAST_RETRY, BRIDGE_RETRY_COUNTS, BRIDGE_TXS, - FEE_RECIPIENT, MIN_VALIDATORS, NONCE, SUPPORTED_CHAINS, TOKEN, VALIDATORS, -}; -use crate::types::{BridgeTransaction, CrossChainMessage}; -use crate::validation::BridgeValidator; -use soroban_sdk::{symbol_short, vec, Address, Bytes, Env, IntoVal, Map, Vec}; - -const BRIDGE_TIMEOUT_SECONDS: u64 = 604_800; -const MAX_BRIDGE_RETRY_ATTEMPTS: u32 = 5; -const BRIDGE_RETRY_DELAY_BASE_SECONDS: u64 = 300; - -pub struct Bridge; - -impl Bridge { - /// Initialize the bridge contract - /// - token: Address of the TeachLink token contract - /// - admin: Address of the bridge administrator - /// - min_validators: Minimum number of validators required for cross-chain verification - pub fn initialize( - env: &Env, - token: Address, - admin: Address, - min_validators: u32, - fee_recipient: Address, - ) -> Result<(), BridgeError> { - // Check if already initialized - if env.storage().instance().has(&TOKEN) { - return Err(BridgeError::AlreadyInitialized); - } - - if min_validators == 0 { - return Err(BridgeError::MinimumValidatorsMustBeAtLeastOne); - } - - env.storage().instance().set(&TOKEN, &token); - env.storage().instance().set(&ADMIN, &admin); - env.storage() - .instance() - .set(&MIN_VALIDATORS, &min_validators); - env.storage().instance().set(&NONCE, &0u64); - env.storage().instance().set(&FEE_RECIPIENT, &fee_recipient); - env.storage().instance().set(&BRIDGE_FEE, &0i128); // Default no fee - - Ok(()) - } - - /// Bridge tokens out to another chain (lock/burn tokens on Stellar) - /// - amount: Amount of tokens to bridge - /// - destination_chain: Chain ID of the destination blockchain - /// - destination_address: Address on the destination chain (encoded as bytes) - pub fn bridge_out( - env: &Env, - from: Address, - amount: i128, - destination_chain: u32, - destination_address: soroban_sdk::Bytes, - ) -> Result { - from.require_auth(); - - // Validate all input parameters - BridgeValidator::validate_bridge_out( - env, - &from, - amount, - destination_chain, - &destination_address, - )?; - - // Check if destination chain is supported - if !Self::is_chain_supported(env, destination_chain) { - return Err(BridgeError::DestinationChainNotSupported); - } - - // Get token address - let token: Address = env.storage().instance().get(&TOKEN).unwrap(); - - // Transfer tokens from user to bridge (locking them) - env.invoke_contract::<()>( - &token, - &symbol_short!("transfer"), - vec![ - env, - from.into_val(env), - env.current_contract_address().into_val(env), - amount.into_val(env), - ], - ); - - // Apply bridge fee if configured - let fee: i128 = env.storage().instance().get(&BRIDGE_FEE).unwrap_or(0i128); - let fee_recipient: Address = env.storage().instance().get(&FEE_RECIPIENT).unwrap(); - let amount_after_fee = if fee > 0 && fee < amount { - env.invoke_contract::<()>( - &token, - &symbol_short!("transfer"), - vec![ - env, - env.current_contract_address().into_val(env), - fee_recipient.into_val(env), - fee.into_val(env), - ], - ); - amount - fee - } else { - amount - }; - - // Generate nonce for this transaction - let mut nonce: u64 = env.storage().instance().get(&NONCE).unwrap_or(0u64); - nonce += 1; - env.storage().instance().set(&NONCE, &nonce); - - // Create bridge transaction record - let bridge_tx = BridgeTransaction { - nonce, - token: token.clone(), - amount: amount_after_fee, - recipient: from.clone(), - destination_chain, - destination_address: destination_address.clone(), - timestamp: env.ledger().timestamp(), - }; - - // Store bridge transaction and metadata - env.storage() - .persistent() - .set(&crate::storage::DataKey::BridgeTx(nonce), &bridge_tx); - env.storage() - .persistent() - .set(&crate::storage::DataKey::BridgeRetryCount(nonce), &0u32); - env.storage().persistent().set( - &crate::storage::DataKey::BridgeLastRetry(nonce), - &env.ledger().timestamp(), - ); - - // Emit events - BridgeInitiatedEvent { - nonce, - transaction: bridge_tx.clone(), - } - .publish(env); - - DepositEvent { - nonce, - from, - amount: amount_after_fee, - destination_chain, - destination_address, - } - .publish(env); - - Ok(nonce) - } - - /// Complete a bridge transaction (mint/release tokens on Stellar) - /// This is called by validators after verifying the transaction on the source chain - /// - message: Cross-chain message containing transaction details - /// - validator_signatures: List of validator addresses that have verified this transaction - pub fn complete_bridge( - env: &Env, - message: CrossChainMessage, - validator_signatures: Vec
, - ) -> Result<(), BridgeError> { - // Validate all input parameters - let min_validators: u32 = env.storage().instance().get(&MIN_VALIDATORS).unwrap(); - BridgeValidator::validate_bridge_completion( - env, - &message, - &validator_signatures, - min_validators, - )?; - - // Verify all signatures are from valid validators - for validator in validator_signatures.iter() { - if !Self::is_validator(env, validator.clone()) { - return Err(BridgeError::InvalidValidatorSignature); - } - } - - // Check for duplicate nonce to prevent replay attacks - let processed_key = crate::storage::DataKey::ProcessedNonce(message.nonce); - if env.storage().persistent().has(&processed_key) { - return Err(BridgeError::NonceAlreadyProcessed); - } - env.storage().persistent().set(&processed_key, &true); - - // Get token address - let token: Address = env.storage().instance().get(&TOKEN).unwrap(); - - // Verify token matches - if message.token != token { - return Err(BridgeError::TokenMismatch); - } - - // Mint/release tokens to recipient - env.invoke_contract::<()>( - &token, - &symbol_short!("mint"), - vec![ - env, - message.recipient.into_val(env), - message.amount.into_val(env), - ], - ); - - // Emit events - BridgeCompletedEvent { - nonce: message.nonce, - message: message.clone(), - } - .publish(env); - - ReleaseEvent { - nonce: message.nonce, - recipient: message.recipient.clone(), - amount: message.amount, - source_chain: message.source_chain, - } - .publish(env); - - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeTx(message.nonce)); - - Self::clear_bridge_retry_metadata(env, message.nonce); - - Ok(()) - } - - pub fn mark_bridge_failed(env: &Env, nonce: u64, reason: Bytes) -> Result<(), BridgeError> { - if reason.is_empty() { - return Err(BridgeError::InvalidInput); - } - - if !env - .storage() - .persistent() - .has(&crate::storage::DataKey::BridgeTx(nonce)) - { - return Err(BridgeError::BridgeTransactionNotFound); - } - - env.storage() - .persistent() - .set(&crate::storage::DataKey::BridgeFailure(nonce), &reason); - - Ok(()) - } - - pub fn retry_bridge(env: &Env, nonce: u64) -> Result { - let bridge_tx = env - .storage() - .persistent() - .get::<_, BridgeTransaction>(&crate::storage::DataKey::BridgeTx(nonce)) - .ok_or(BridgeError::BridgeTransactionNotFound)?; - - let current_time = env.ledger().timestamp(); - if current_time.saturating_sub(bridge_tx.timestamp) >= BRIDGE_TIMEOUT_SECONDS { - return Err(BridgeError::PacketTimeout); - } - - let retry_count = env - .storage() - .persistent() - .get::<_, u32>(&crate::storage::DataKey::BridgeRetryCount(nonce)) - .unwrap_or(0); - if retry_count >= MAX_BRIDGE_RETRY_ATTEMPTS { - return Err(BridgeError::RetryLimitExceeded); - } - - let last_retry_at = env - .storage() - .persistent() - .get::<_, u64>(&crate::storage::DataKey::BridgeLastRetry(nonce)) - .unwrap_or(bridge_tx.timestamp); - - let backoff_multiplier = 1u64 << retry_count; - let retry_delay = BRIDGE_RETRY_DELAY_BASE_SECONDS.saturating_mul(backoff_multiplier); - let next_allowed_retry = last_retry_at.saturating_add(retry_delay); - - if current_time < next_allowed_retry { - return Err(BridgeError::RetryBackoffActive); - } - - let updated_retry_count = retry_count + 1; - env.storage().persistent().set( - &crate::storage::DataKey::BridgeRetryCount(nonce), - &updated_retry_count, - ); - env.storage().persistent().set( - &crate::storage::DataKey::BridgeLastRetry(nonce), - ¤t_time, - ); - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeFailure(nonce)); - - Ok(updated_retry_count) - } - - /// Cancel a bridge transaction and refund locked tokens - /// Only callable after a timeout period - /// - nonce: The nonce of the bridge transaction to cancel - pub fn cancel_bridge(env: &Env, nonce: u64) -> Result<(), BridgeError> { - // Get bridge transaction - let bridge_tx = env - .storage() - .persistent() - .get::<_, BridgeTransaction>(&crate::storage::DataKey::BridgeTx(nonce)) - .ok_or(BridgeError::BridgeTransactionNotFound)?; - - // Allow refunds for timed-out or explicitly failed transactions - let elapsed = env.ledger().timestamp().saturating_sub(bridge_tx.timestamp); - let has_failed = env - .storage() - .persistent() - .has(&crate::storage::DataKey::BridgeFailure(nonce)); - if elapsed < BRIDGE_TIMEOUT_SECONDS && !has_failed { - return Err(BridgeError::TimeoutNotReached); - } - - // Get token address - let token: Address = env.storage().instance().get(&TOKEN).unwrap(); - - // Refund tokens to original recipient - env.invoke_contract::<()>( - &token, - &symbol_short!("transfer"), - vec![ - env, - env.current_contract_address().into_val(env), - bridge_tx.recipient.into_val(env), - bridge_tx.amount.into_val(env), - ], - ); +//! Bridge-out and chain-management logic. - // Remove from bridge transactions - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeTx(nonce)); +use soroban_sdk::{symbol_short, Address, Bytes, Env, Symbol, Vec}; - Self::clear_bridge_retry_metadata(env, nonce); - - Ok(()) - } - - pub fn refund_bridge_transaction(env: &Env, nonce: u64) -> Result<(), BridgeError> { - Self::cancel_bridge(env, nonce) - } - - fn clear_bridge_retry_metadata(env: &Env, nonce: u64) { - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeRetryCount(nonce)); - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeLastRetry(nonce)); - env.storage() - .persistent() - .remove(&crate::storage::DataKey::BridgeFailure(nonce)); - } - - // ========== Admin Functions ========== - - /// Add a validator (admin only) - #[allow(clippy::unnecessary_wraps)] - pub fn add_validator(env: &Env, validator: Address) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - // Centralize validator flag/list maintenance - crate::validator_utils::set_validator_flag(env, &validator, true); - crate::validator_utils::add_validator_to_list(env, &validator); - - Ok(()) - } - - /// Remove a validator (admin only) - #[allow(clippy::unnecessary_wraps)] - pub fn remove_validator(env: &Env, validator: Address) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - // Centralize validator flag/list maintenance - crate::validator_utils::set_validator_flag(env, &validator, false); - crate::validator_utils::remove_validator_from_list(env, &validator); - - Ok(()) - } - - /// Add a supported destination chain (admin only) - #[allow(clippy::unnecessary_wraps)] - pub fn add_supported_chain(env: &Env, chain_id: u32) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - env.storage() - .instance() - .set(&crate::storage::DataKey::SupportedChain(chain_id), &true); - - // Maintain list - let mut list: Vec = env - .storage() - .instance() - .get(&crate::storage::SUPPORTED_CHAINS_LIST) - .unwrap_or_else(|| Vec::new(env)); - if !list.contains(&chain_id) { - list.push_back(chain_id); - env.storage() - .instance() - .set(&crate::storage::SUPPORTED_CHAINS_LIST, &list); - } - - Ok(()) - } - - /// Remove a supported destination chain (admin only) - #[allow(clippy::unnecessary_wraps)] - pub fn remove_supported_chain(env: &Env, chain_id: u32) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - env.storage() - .instance() - .set(&crate::storage::DataKey::SupportedChain(chain_id), &false); - - // Remove from list - let mut list: Vec = env - .storage() - .instance() - .get(&crate::storage::SUPPORTED_CHAINS_LIST) - .unwrap_or_else(|| Vec::new(env)); - if let Some(pos) = list.iter().position(|c| c == chain_id) { - list.remove(pos as u32); - env.storage() - .instance() - .set(&crate::storage::SUPPORTED_CHAINS_LIST, &list); - } - - Ok(()) - } - - /// Set bridge fee (admin only) - pub fn set_bridge_fee(env: &Env, fee: i128) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - if fee < 0 { - return Err(BridgeError::FeeCannotBeNegative); - } - - env.storage().instance().set(&BRIDGE_FEE, &fee); - - Ok(()) - } - - /// Set fee recipient (admin only) - #[allow(clippy::unnecessary_wraps)] - pub fn set_fee_recipient(env: &Env, fee_recipient: Address) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - env.storage().instance().set(&FEE_RECIPIENT, &fee_recipient); - - Ok(()) - } - - /// Set minimum validators (admin only) - pub fn set_min_validators(env: &Env, min_validators: u32) -> Result<(), BridgeError> { - let admin: Address = env.storage().instance().get(&ADMIN).unwrap(); - admin.require_auth(); - - if min_validators == 0 { - return Err(BridgeError::MinimumValidatorsMustBeAtLeastOne); - } - - env.storage() - .instance() - .set(&MIN_VALIDATORS, &min_validators); - - Ok(()) - } +use crate::{ + constants, + errors::{handle_error, TeachLinkError}, + storage::{self, BRIDGE_TXS}, + types::BridgeConfig, + validation, +}; - // ========== View Functions ========== +/// Calculate the fee for a given amount and rate (basis points). +pub fn calculate_fee(amount: i128, fee_rate: u32) -> i128 { + amount * fee_rate as i128 / constants::fees::FEE_CALCULATION_DIVISOR as i128 +} - /// Get the bridge transaction by nonce - pub fn get_bridge_transaction(env: &Env, nonce: u64) -> Option { - env.storage() - .persistent() - .get(&crate::storage::DataKey::BridgeTx(nonce)) - } +/// Initiate a cross-chain bridge transfer and return the nonce. +pub fn bridge_out( + env: &Env, + from: Address, + amount: i128, + destination_chain: u32, + destination_address: Bytes, +) -> u64 { + validation::require_initialized(env, true); + validation::validate_amount(env, &amount); + validation::validate_chain_id(env, &destination_chain); + validation::validate_bytes_address(env, &destination_address); - /// Check if a chain is supported - pub fn is_chain_supported(env: &Env, chain_id: u32) -> bool { - env.storage() - .instance() - .get::<_, bool>(&crate::storage::DataKey::SupportedChain(chain_id)) - .unwrap_or(false) - } + let config: BridgeConfig = storage::get_config(env); + let nonce = storage::get_next_nonce(env); - /// Check if an address is a validator - pub fn is_validator(env: &Env, address: Address) -> bool { - env.storage() - .instance() - .get::<_, bool>(&crate::storage::DataKey::Validator(address)) - .unwrap_or(false) - } + let fee = calculate_fee(amount, config.fee_rate); + let bridge_amount = amount - fee; + validation::validate_amount(env, &bridge_amount); - /// Get the current nonce - pub fn get_nonce(env: &Env) -> u64 { - env.storage().instance().get(&NONCE).unwrap_or(0u64) - } + let mut txs: Vec<(Address, i128, u32, Bytes)> = env + .storage() + .instance() + .get(&BRIDGE_TXS) + .unwrap_or_else(|| Vec::new(env)); - /// Get the bridge fee - pub fn get_bridge_fee(env: &Env) -> i128 { - env.storage().instance().get(&BRIDGE_FEE).unwrap_or(0i128) + if txs.len() >= constants::storage::MAX_BRIDGE_TXS { + handle_error(env, TeachLinkError::BridgeFailed); } - /// Get the token address - pub fn get_token(env: &Env) -> Address { - env.storage().instance().get(&TOKEN).unwrap() - } + txs.push_back((from, bridge_amount, destination_chain, destination_address)); + env.storage().instance().set(&BRIDGE_TXS, &txs); - /// Get the admin address - pub fn get_admin(env: &Env) -> Address { - env.storage().instance().get(&ADMIN).unwrap() - } + nonce } -#[cfg(test)] -mod tests { - use super::{Bridge, BRIDGE_RETRY_DELAY_BASE_SECONDS}; - use crate::errors::BridgeError; - use crate::storage::{BRIDGE_TXS, MIN_VALIDATORS, NONCE, TOKEN, VALIDATORS}; - use crate::types::{BridgeTransaction, CrossChainMessage}; - use crate::TeachLinkBridge; - use soroban_sdk::testutils::{Address as _, Ledger}; - use soroban_sdk::{vec, Address, Bytes, Env, Map, Vec}; - - fn set_time(env: &Env, timestamp: u64) { - env.ledger().with_mut(|ledger_info| { - ledger_info.timestamp = timestamp; - }); - } - - fn seed_bridge_tx(env: &Env, nonce: u64, timestamp: u64) { - let token = Address::generate(env); - let sender = Address::generate(env); - env.storage().instance().set(&TOKEN, &token); +/// Register a new supported chain (admin only). +pub fn add_chain_support( + env: &Env, + chain_id: u32, + name: Symbol, + bridge_address: Address, + min_confirmations: u32, + fee_rate: u32, +) { + validation::require_admin(env); + validation::validate_chain_id(env, &chain_id); + validation::validate_fee_rate(env, &fee_rate); - let tx = BridgeTransaction { - nonce, - token, - amount: 500, - recipient: sender, - destination_chain: 2, - destination_address: Bytes::from_slice(env, b"dest"), - timestamp, - }; + let chains_key = symbol_short!("chains"); + let chains: Vec<(u32, Symbol, Address, u32, u32)> = env + .storage() + .instance() + .get(&chains_key) + .unwrap_or_else(|| Vec::new(env)); - env.storage() - .persistent() - .set(&crate::storage::DataKey::BridgeTx(nonce), &tx); + if chains.len() >= constants::storage::MAX_CHAIN_CONFIGS { + handle_error(env, TeachLinkError::ChainExists); } - #[test] - fn mark_bridge_failed_requires_existing_tx() { - let env = Env::default(); - let contract_id = env.register(TeachLinkBridge, ()); - let result = env.as_contract(&contract_id, || { - Bridge::mark_bridge_failed(&env, 99, Bytes::from_slice(&env, b"failure")) - }); - assert_eq!(result, Err(BridgeError::BridgeTransactionNotFound)); - } - - #[test] - fn complete_bridge_rejects_replay_when_nonce_already_processed() { - let env = Env::default(); - let contract_id = env.register(TeachLinkBridge, ()); - env.as_contract(&contract_id, || { - let token = Address::generate(&env); - let validator = Address::generate(&env); - let recipient = Address::generate(&env); - - env.storage().instance().set(&TOKEN, &token); - env.storage().instance().set(&MIN_VALIDATORS, &1u32); - - env.storage().instance().set( - &crate::storage::DataKey::Validator(validator.clone()), - &true, - ); - - env.storage() - .persistent() - .set(&crate::storage::DataKey::ProcessedNonce(7), &true); - - let message = CrossChainMessage { - source_chain: 1, - source_tx_hash: Bytes::from_slice(&env, &[0xab; 32]), - nonce: 7, - token: token.clone(), - amount: 100, - recipient: recipient.clone(), - destination_chain: 2, - }; - - let sigs: Vec
= vec![&env, validator]; - let r = Bridge::complete_bridge(&env, message, sigs); - assert_eq!(r, Err(BridgeError::NonceAlreadyProcessed)); - }); + for chain in chains.iter() { + if chain.0 == chain_id { + handle_error(env, TeachLinkError::ChainExists); + } } - #[test] - fn retry_bridge_enforces_backoff_and_limit() { - let env = Env::default(); - let contract_id = env.register(TeachLinkBridge, ()); - env.as_contract(&contract_id, || { - set_time(&env, 10_000); - seed_bridge_tx(&env, 1, 10_000); - - let retry_too_early = Bridge::retry_bridge(&env, 1); - assert_eq!(retry_too_early, Err(BridgeError::RetryBackoffActive)); - - let mut now = 10_000u64; - for retry_count in 0..5u32 { - now += BRIDGE_RETRY_DELAY_BASE_SECONDS * (1u64 << retry_count); - set_time(&env, now); - let updated_retry_count = Bridge::retry_bridge(&env, 1).expect("retry should pass"); - assert_eq!(updated_retry_count, retry_count + 1); - } - - set_time(&env, now + 100_000); - let retry_over_limit = Bridge::retry_bridge(&env, 1); - assert_eq!(retry_over_limit, Err(BridgeError::RetryLimitExceeded)); - }); - } + let mut updated = chains; + updated.push_back((chain_id, name, bridge_address, min_confirmations, fee_rate)); + env.storage().instance().set(&chains_key, &updated); } diff --git a/contracts/teachlink/src/constants.rs b/contracts/teachlink/src/constants.rs new file mode 100644 index 0000000..0aa2c95 --- /dev/null +++ b/contracts/teachlink/src/constants.rs @@ -0,0 +1,35 @@ +//! Compile-time configuration constants for the TeachLink contract. + +/// Fee configuration +pub mod fees { + pub const DEFAULT_FEE_RATE: u32 = 100; // 1% in basis points + pub const MAX_FEE_RATE: u32 = 10000; // 100% in basis points + pub const FEE_CALCULATION_DIVISOR: u32 = 10000; +} + +/// Amount validation +pub mod amounts { + pub const MIN_AMOUNT: i128 = 1; + pub const FALLBACK_PRICE: i128 = 1_000_000; // 1 USD in 6 decimals +} + +/// Chain configuration +pub mod chains { + pub const MIN_CHAIN_ID: u32 = 1; + pub const DEFAULT_MIN_CONFIRMATIONS: u32 = 3; + pub const MAX_CHAIN_NAME_LENGTH: u32 = 32; +} + +/// Oracle configuration +pub mod oracle { + pub const MAX_CONFIDENCE: u32 = 100; + pub const DEFAULT_CONFIDENCE_THRESHOLD: u32 = 80; + pub const PRICE_FRESHNESS_SECONDS: u64 = 3600; +} + +/// Storage limits +pub mod storage { + pub const MAX_BRIDGE_TXS: u32 = 1000; + pub const MAX_CHAIN_CONFIGS: u32 = 50; + pub const MAX_ORACLE_PRICES: u32 = 100; +} diff --git a/contracts/teachlink/src/errors.rs b/contracts/teachlink/src/errors.rs index b6d92c6..db2ac66 100644 --- a/contracts/teachlink/src/errors.rs +++ b/contracts/teachlink/src/errors.rs @@ -1,139 +1,76 @@ -use soroban_sdk::contracterror; +//! Error types and panic helper for the TeachLink contract. -/// Bridge module errors -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum BridgeError { - AlreadyInitialized = 100, - AmountMustBePositive = 101, - DestinationChainNotSupported = 102, - InsufficientValidatorSignatures = 103, - InvalidValidatorSignature = 104, - NonceAlreadyProcessed = 105, - TokenMismatch = 106, - BridgeTransactionNotFound = 107, - TimeoutNotReached = 108, - FeeCannotBeNegative = 109, - MinimumValidatorsMustBeAtLeastOne = 110, - // BFT Consensus Errors - ProposalNotFound = 111, - ProposalAlreadyVoted = 112, - ProposalExpired = 113, - InsufficientStake = 114, - InsufficientBalance = 115, - ValidatorNotActive = 116, - ByzantineThresholdNotMet = 117, - // Slashing Errors - ValidatorAlreadySlashed = 118, - InvalidSlashingEvidence = 119, - CannotSlashSelf = 120, - // Multi-Chain Errors - ChainNotActive = 121, - AssetNotSupported = 122, - InvalidChainConfiguration = 123, - // Liquidity Errors - InsufficientLiquidity = 124, - SlippageExceeded = 125, - InvalidLPAmount = 126, - // Emergency Errors - BridgePaused = 127, - ChainPaused = 128, - UnauthorizedPause = 129, - CircuitBreakerTriggered = 130, - // Message Passing Errors - PacketNotFound = 131, - PacketTimeout = 132, - InvalidPayload = 133, - // Atomic Swap Errors - SwapNotFound = 134, - InvalidHashlock = 135, - TimelockExpired = 136, - SwapAlreadyCompleted = 137, - // General Errors - Unauthorized = 138, - InvalidInput = 139, - RetryLimitExceeded = 140, - RetryBackoffActive = 141, - BridgeTransactionFailed = 142, -} +use soroban_sdk::{symbol_short, Env}; -/// Escrow module errors -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum EscrowError { - AmountMustBePositive = 200, - AtLeastOneSignerRequired = 201, - InvalidSignerThreshold = 202, - RefundTimeMustBeInFuture = 203, - RefundTimeMustBeAfterReleaseTime = 204, - DuplicateSigner = 205, - SignerNotAuthorized = 206, - SignerAlreadyApproved = 207, - CallerNotAuthorized = 208, - InsufficientApprovals = 209, - ReleaseTimeNotReached = 210, - OnlyDepositorCanRefund = 211, - RefundNotEnabled = 212, - RefundTimeNotReached = 213, - OnlyDepositorCanCancel = 214, - CannotCancelAfterApprovals = 215, - OnlyDepositorOrBeneficiaryCanDispute = 216, - EscrowNotInDispute = 217, - OnlyArbitratorCanResolve = 218, - EscrowNotPending = 219, - EscrowNotFound = 220, - ArbitratorNotAuthorized = 221, +/// All recoverable error conditions in the contract. +#[derive(Clone, Debug)] +pub enum TeachLinkError { + Unauthorized, + InvalidAmount, + InvalidAddress, + ChainNotSupported, + RateLimitExceeded, + InsufficientBalance, + BridgeFailed, + NotInitialized, + InvalidChainId, + FeeTooHigh, + ChainExists, + InvalidPrice, + InvalidConfidence, + UnauthorizedOracle, } -/// Rewards module errors -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum RewardsError { - AlreadyInitialized = 300, - AmountMustBePositive = 301, - InsufficientRewardPoolBalance = 302, - NoRewardsAvailable = 303, - NoPendingRewards = 304, - RateCannotBeNegative = 305, -} +/// Increment the error counter and panic with a descriptive symbol. +pub fn handle_error(env: &Env, error: TeachLinkError) -> ! { + use crate::storage::ERROR_COUNT; -/// Mobile platform module errors -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum MobilePlatformError { - DeviceNotSupported = 400, - InsufficientStorage = 401, - NetworkUnavailable = 402, - AuthenticationFailed = 403, - SyncFailed = 404, - PaymentFailed = 405, - SecurityViolation = 406, - FeatureNotAvailable = 407, -} + let mut count: u64 = env.storage().instance().get(&ERROR_COUNT).unwrap_or(0); + count += 1; + env.storage().instance().set(&ERROR_COUNT, &count); -/// Common errors that can be used across modules -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum CommonError { - Unauthorized = 400, - InvalidInput = 401, - InsufficientBalance = 402, - TransferFailed = 403, - StorageError = 404, + match error { + TeachLinkError::Unauthorized => { + env.panic_with_error_data(&symbol_short!("unauth"), "Unauthorized access") + } + TeachLinkError::InvalidAmount => { + env.panic_with_error_data(&symbol_short!("inv_amt"), "Invalid amount") + } + TeachLinkError::InvalidAddress => { + env.panic_with_error_data(&symbol_short!("inv_addr"), "Invalid address") + } + TeachLinkError::ChainNotSupported => { + env.panic_with_error_data(&symbol_short!("no_chain"), "Chain not supported") + } + TeachLinkError::RateLimitExceeded => { + env.panic_with_error_data(&symbol_short!("rate_lim"), "Rate limit exceeded") + } + TeachLinkError::InsufficientBalance => { + env.panic_with_error_data(&symbol_short!("no_bal"), "Insufficient balance") + } + TeachLinkError::BridgeFailed => { + env.panic_with_error_data(&symbol_short!("br_fail"), "Bridge operation failed") + } + TeachLinkError::NotInitialized => { + env.panic_with_error_data(&symbol_short!("no_init"), "Contract not initialized") + } + TeachLinkError::InvalidChainId => { + env.panic_with_error_data(&symbol_short!("inv_chn"), "Invalid chain ID") + } + TeachLinkError::FeeTooHigh => { + env.panic_with_error_data(&symbol_short!("fee_hi"), "Fee rate too high") + } + TeachLinkError::ChainExists => { + env.panic_with_error_data(&symbol_short!("chn_ex"), "Chain already exists") + } + TeachLinkError::InvalidPrice => { + env.panic_with_error_data(&symbol_short!("inv_prc"), "Invalid price") + } + TeachLinkError::InvalidConfidence => { + env.panic_with_error_data(&symbol_short!("inv_conf"), "Invalid confidence") + } + TeachLinkError::UnauthorizedOracle => { + env.panic_with_error_data(&symbol_short!("unauth_or"), "Unauthorized oracle") + } + } } - -/// Result type alias for bridge operations -#[allow(dead_code)] -pub type BridgeResult = core::result::Result; - -/// Result type alias for escrow operations -#[allow(dead_code)] -pub type EscrowResult = core::result::Result; - -/// Result type alias for rewards operations -#[allow(dead_code)] -pub type RewardsResult = core::result::Result; - -/// Result type alias for common operations -#[allow(dead_code)] -pub type CommonResult = core::result::Result; diff --git a/contracts/teachlink/src/lib.rs b/contracts/teachlink/src/lib.rs index d9b9918..5fb667d 100644 --- a/contracts/teachlink/src/lib.rs +++ b/contracts/teachlink/src/lib.rs @@ -1,1923 +1,155 @@ -#![allow(clippy::all)] -#![allow(unused)] - -//! TeachLink Smart Contract -//! -//! A comprehensive Soroban smart contract for the TeachLink decentralized -//! knowledge-sharing platform on the Stellar network. -//! -//! # Overview -//! -//! TeachLink provides the following core features: -//! -//! - **Cross-Chain Bridge**: Bridge tokens between Stellar and other blockchains -//! - **Advanced BFT Consensus**: Byzantine Fault Tolerant validator consensus -//! - **Validator Slashing**: Economic penalties for malicious validators -//! - **Multi-Chain Support**: Support for multiple blockchain networks -//! - **Liquidity Optimization**: AMM and dynamic fee pricing -//! - **Message Passing**: Guaranteed cross-chain message delivery -//! - **Emergency Controls**: Circuit breaker and pause mechanisms -//! - **Atomic Swaps**: Cross-chain token exchanges -//! - **Audit & Compliance**: Comprehensive logging and reporting -//! - **Token Rewards**: Incentivize learning and contributions with token rewards -//! - **Multi-Sig Escrow**: Secure payments with multi-signature escrow and arbitration -//! - **Content Tokenization**: Mint NFTs representing educational content ownership -//! - **Provenance Tracking**: Full chain-of-custody for content tokens -//! - **User Reputation**: Track user participation, completion rates, and contribution quality -//! - **Credit Scoring**: Calculate user credit scores based on courses and contributions -//! - **Role-Based Access Control**: Manage user roles and permissions across the platform -//! - **Appointment Booking Escrow**: Secure payment handling for teaching appointments -//! - **Data Access Audit**: Comprehensive logging of patient data access for compliance -//! -//! # Contract Modules -//! -//! | Module | Description | -//! |--------|-------------| -//! | [`bridge`] | Cross-chain token bridging with validator consensus | -//! | [`bft_consensus`] | Byzantine Fault Tolerant consensus mechanism | -//! | [`slashing`] | Validator slashing and reward mechanisms | -//! | [`multichain`] | Multi-chain support and asset management | -//! | [`liquidity`] | Bridge liquidity pools and AMM | -//! | [`message_passing`] | Cross-chain message passing | -//! | [`emergency`] | Emergency pause and circuit breaker | -//! | [`audit`] | Audit trail and compliance reporting | -//! | [`atomic_swap`] | Cross-chain atomic swaps | -//! | [`analytics`] | Bridge monitoring and analytics | -//! | [`performance`] | Performance caching (bridge summary, TTL, invalidation) | -//! | [`reporting`] | Advanced analytics, report templates, dashboards, and alerting | -//! | [`backup`] | Backup scheduling, integrity verification, disaster recovery, and RTO audit | -//! | [`rewards`] | Reward pool management and distribution | -//! | [`escrow`] | Multi-signature escrow with dispute resolution | -//! | [`tokenization`] | Educational content NFT minting and management | -//! | [`provenance`] | Ownership history tracking for content tokens | -//! | [`reputation`] | User reputation scoring system | -//! | [`score`] | Credit score calculation from activities | -//! | [`rbac`] | Role-based access control for user permissions | -//! | [`appointment_escrow`] | Secure appointment booking with escrow payments | -//! | [`data_access_audit`] | Comprehensive audit logging for data access | -//! -//! # Quick Start +//! TeachLink Soroban smart contract — entry point. //! -//! ```ignore -//! // Initialize the contract -//! TeachLinkBridge::initialize(env, token, admin, min_validators, fee_recipient); -//! -//! // Register a validator with BFT consensus -//! TeachLinkBridge::register_validator(env, validator, stake); -//! -//! // Add a supported chain -//! TeachLinkBridge::add_supported_chain_config(env, chain_id, chain_name, bridge_address); -//! -//! // Bridge tokens with advanced features -//! let nonce = TeachLinkBridge::bridge_out(env, from, amount, destination_chain, destination_address); -//! -//! // Create atomic swap -//! let swap_id = TeachLinkBridge::initiate_atomic_swap(env, params); -//! ``` -//! -//! # Authorization -//! -//! Most state-changing functions require authorization: -//! - Admin functions require the admin address -//! - User functions require the user's address -//! - Validator functions require validator authorization -//! - Escrow functions require appropriate party authorization - -#![no_std] -#![allow(clippy::unreadable_literal)] -#![allow(clippy::must_use_candidate)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::needless_pass_by_value)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::doc_markdown)] -#![allow(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::needless_borrow)] - -use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, Map, String, Symbol, Vec}; - -mod analytics; -mod appointment_escrow; -mod arbitration; -mod assessment; -mod atomic_swap; -mod audit; -mod bft_consensus; -mod bridge; -mod data_access_audit; -mod emergency; -mod errors; -mod escrow; -mod escrow_analytics; -mod events; -mod insurance; -// FUTURE: Implement governance module (tracked in TRACKING.md) -// mod governance; -// mod learning_paths; -mod liquidity; -mod message_passing; -mod mobile_platform; -mod multichain; -mod notification; -mod notification_events_basic; -// mod content_quality; -mod notification_tests; -mod rbac; -mod backup; -mod notification_types; -mod performance; -mod provenance; -mod reporting; -mod reputation; -mod rewards; -mod score; -mod slashing; -mod social_learning; -mod storage; -mod tokenization; -mod types; -pub mod validator_utils; +//! This file wires the public contract interface to focused sub-modules: +//! - [`constants`] — compile-time configuration values +//! - [`errors`] — error enum and panic helper +//! - [`types`] — shared data types (`BridgeConfig`) +//! - [`storage`] — storage keys and low-level helpers +//! - [`validation`] — input validation guards +//! - [`bridge`] — bridge-out and chain management +//! - [`oracle`] — oracle price feed management + +#![cfg_attr(not(test), no_std)] + +pub mod bridge; +pub mod constants; +pub mod errors; +pub mod oracle; +pub mod storage; +pub mod types; pub mod validation; -// Property-based tests are heavy and depend on dev-only crates. Only -// compile them when the `proptest` feature is enabled to avoid pulling -// these test-only dependencies into normal builds. -#[cfg(feature = "proptest")] -pub mod property_based_tests; -pub use crate::types::{ - ColorBlindMode, ComponentConfig, DeviceInfo, FeedbackCategory, FocusStyle, FontSize, - LayoutDensity, MobileAccessibilitySettings, MobilePreferences, MobileProfile, NetworkType, - OnboardingStage, OnboardingStatus, ThemePreference, UserFeedback, VideoQuality, -}; -pub use appointment_escrow::{Appointment, AppointmentEscrowContract, AppointmentStatus}; -pub use assessment::{ - Assessment, AssessmentSettings, AssessmentSubmission, Question, QuestionType, -}; -pub use data_access_audit::{AccessLog, DataAccessAuditContract}; -pub use errors::{BridgeError, EscrowError, MobilePlatformError, RewardsError}; -pub use rbac::{RbacContract, Role}; -pub use types::{ - AlertConditionType, AlertRule, ArbitratorProfile, AtomicSwap, AuditRecord, BackupManifest, - BackupSchedule, BridgeMetrics, BridgeProposal, BridgeTransaction, CachedBridgeSummary, - ChainConfig, ChainMetrics, ComplianceReport, ConsensusState, ContentMetadata, ContentToken, - ContentTokenParameters, ContentType, CrossChainMessage, CrossChainPacket, DashboardAnalytics, - DisputeOutcome, EmergencyState, Escrow, EscrowMetrics, EscrowParameters, EscrowRole, - EscrowSigner, EscrowStatus, LiquidityPool, MultiChainAsset, NotificationChannel, - NotificationContent, NotificationPreference, NotificationSchedule, NotificationTemplate, - NotificationTracking, OperationType, PacketStatus, ProposalStatus, ProvenanceRecord, - RecoveryRecord, ReportComment, ReportSchedule, ReportSnapshot, ReportTemplate, ReportType, - ReportUsage, RewardRate, RewardType, RtoTier, SlashingReason, SlashingRecord, SwapStatus, - TransferType, UserNotificationSettings, UserReputation, UserReward, ValidatorInfo, - ValidatorReward, ValidatorSignature, VisualizationDataPoint, -}; +use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, Symbol, Vec}; + +use storage::{ADMIN, BRIDGE_TXS, CONFIG, FALLBACK_ENABLED}; +use types::BridgeConfig; +use validation::{require_admin, require_initialized, validate_fee_rate}; -/// TeachLink main contract. -/// -/// This contract provides entry points for all TeachLink functionality -/// including bridging, rewards, escrow, tokenization, and reputation. #[contract] pub struct TeachLinkBridge; #[contractimpl] impl TeachLinkBridge { - /// Initialize the bridge contract - pub fn initialize( - env: Env, - token: Address, - admin: Address, - min_validators: u32, - fee_recipient: Address, - ) -> Result<(), BridgeError> { - bridge::Bridge::initialize(&env, token, admin, min_validators, fee_recipient) - } - - /// Bridge tokens out to another chain (lock/burn tokens on Stellar) + /// Initialize the contract with an admin address. + pub fn initialize(env: Env, admin: Address) { + require_initialized(&env, false); + + let config = BridgeConfig::default(); + env.storage().instance().set(&ADMIN, &admin); + env.storage().instance().set(&storage::NONCE, &0u64); + env.storage() + .instance() + .set(&FALLBACK_ENABLED, &config.fallback_enabled); + env.storage() + .instance() + .set(&BRIDGE_TXS, &Vec::<(Address, i128, u32, Bytes)>::new(&env)); + env.storage().instance().set(&storage::ERROR_COUNT, &0u64); + env.storage().instance().set(&CONFIG, &config); + } + + /// Bridge tokens to another chain; returns the transaction nonce. pub fn bridge_out( env: Env, from: Address, amount: i128, destination_chain: u32, destination_address: Bytes, - ) -> Result { - bridge::Bridge::bridge_out(&env, from, amount, destination_chain, destination_address) - } - - /// Complete a bridge transaction (mint/release tokens on Stellar) - pub fn complete_bridge( - env: Env, - message: CrossChainMessage, - validator_signatures: Vec
, - ) -> Result<(), BridgeError> { - bridge::Bridge::complete_bridge(&env, message, validator_signatures) - } - - /// Cancel a bridge transaction and refund locked tokens - pub fn cancel_bridge(env: Env, nonce: u64) -> Result<(), BridgeError> { - bridge::Bridge::cancel_bridge(&env, nonce) - } - - pub fn mark_bridge_failed(env: Env, nonce: u64, reason: Bytes) -> Result<(), BridgeError> { - bridge::Bridge::mark_bridge_failed(&env, nonce, reason) - } - - pub fn retry_bridge(env: Env, nonce: u64) -> Result { - bridge::Bridge::retry_bridge(&env, nonce) - } - - pub fn refund_bridge_transaction(env: Env, nonce: u64) -> Result<(), BridgeError> { - bridge::Bridge::refund_bridge_transaction(&env, nonce) - } - - // ========== Admin Functions ========== - - /// Add a validator (admin only) - pub fn add_validator(env: Env, validator: Address) { - let _ = bridge::Bridge::add_validator(&env, validator); - } - - /// Remove a validator (admin only) - pub fn remove_validator(env: Env, validator: Address) { - let _ = bridge::Bridge::remove_validator(&env, validator); - } - - /// Add a supported destination chain (admin only) - pub fn add_supported_chain(env: Env, chain_id: u32) { - let _ = bridge::Bridge::add_supported_chain(&env, chain_id); - } - - /// Remove a supported destination chain (admin only) - pub fn remove_supported_chain(env: Env, chain_id: u32) { - let _ = bridge::Bridge::remove_supported_chain(&env, chain_id); - } - - /// Set bridge fee (admin only) - pub fn set_bridge_fee(env: Env, fee: i128) -> Result<(), BridgeError> { - bridge::Bridge::set_bridge_fee(&env, fee) - } - - /// Set fee recipient (admin only) - pub fn set_fee_recipient(env: Env, fee_recipient: Address) { - let _ = bridge::Bridge::set_fee_recipient(&env, fee_recipient); - } - - /// Set minimum validators (admin only) - pub fn set_min_validators(env: Env, min_validators: u32) -> Result<(), BridgeError> { - bridge::Bridge::set_min_validators(&env, min_validators) - } - - // ========== View Functions ========== - - /// Get the bridge transaction by nonce - pub fn get_bridge_transaction(env: Env, nonce: u64) -> Option { - bridge::Bridge::get_bridge_transaction(&env, nonce) - } - - /// Check if a chain is supported - pub fn is_chain_supported(env: Env, chain_id: u32) -> bool { - bridge::Bridge::is_chain_supported(&env, chain_id) - } - - /// Check if an address is a validator - pub fn is_validator(env: Env, address: Address) -> bool { - bridge::Bridge::is_validator(&env, address) - } - - /// Get the current nonce - pub fn get_nonce(env: Env) -> u64 { - bridge::Bridge::get_nonce(&env) - } - - /// Get the bridge fee - pub fn get_bridge_fee(env: Env) -> i128 { - bridge::Bridge::get_bridge_fee(&env) - } - - /// Get the token address - pub fn get_token(env: Env) -> Address { - bridge::Bridge::get_token(&env) - } - - /// Get the admin address - pub fn get_admin(env: Env) -> Address { - bridge::Bridge::get_admin(&env) - } - - // ========== BFT Consensus Functions ========== - - /// Register a validator with stake for BFT consensus - pub fn register_validator( - env: Env, - validator: Address, - stake: i128, - ) -> Result<(), BridgeError> { - bft_consensus::BFTConsensus::register_validator(&env, validator, stake) - } - - /// Unregister a validator and unstake - pub fn unregister_validator(env: Env, validator: Address) -> Result<(), BridgeError> { - bft_consensus::BFTConsensus::unregister_validator(&env, validator) - } - - /// Create a bridge proposal for BFT consensus - pub fn create_bridge_proposal( - env: Env, - message: CrossChainMessage, - ) -> Result { - bft_consensus::BFTConsensus::create_proposal(&env, message) - } - - /// Vote on a bridge proposal - pub fn vote_on_proposal( - env: Env, - validator: Address, - proposal_id: u64, - approve: bool, - ) -> Result<(), BridgeError> { - bft_consensus::BFTConsensus::vote_on_proposal(&env, validator, proposal_id, approve) - } - - /// Get validator information - pub fn get_validator_info(env: Env, validator: Address) -> Option { - bft_consensus::BFTConsensus::get_validator_info(&env, validator) - } - - /// Get consensus state - pub fn get_consensus_state(env: Env) -> ConsensusState { - bft_consensus::BFTConsensus::get_consensus_state(&env) - } - - /// Get proposal by ID - pub fn get_proposal(env: Env, proposal_id: u64) -> Option { - bft_consensus::BFTConsensus::get_proposal(&env, proposal_id) - } - - /// Check if consensus is reached for a proposal - pub fn is_consensus_reached(env: Env, proposal_id: u64) -> bool { - bft_consensus::BFTConsensus::is_consensus_reached(&env, proposal_id) - } - - // ========== Slashing and Rewards Functions ========== - - /// Deposit stake for a validator - pub fn deposit_stake(env: Env, validator: Address, amount: i128) -> Result<(), BridgeError> { - slashing::SlashingManager::deposit_stake(&env, validator, amount) - } - - /// Withdraw stake - pub fn withdraw_stake(env: Env, validator: Address, amount: i128) -> Result<(), BridgeError> { - slashing::SlashingManager::withdraw_stake(&env, validator, amount) - } - - /// Slash a validator for malicious behavior - pub fn slash_validator( - env: Env, - validator: Address, - reason: types::SlashingReason, - evidence: Bytes, - slasher: Address, - ) -> Result { - slashing::SlashingManager::slash_validator(&env, validator, reason, evidence, slasher) - } - - /// Reward a validator - pub fn reward_validator( - env: Env, - validator: Address, - amount: i128, - reward_type: types::RewardType, - ) -> Result<(), BridgeError> { - slashing::SlashingManager::reward_validator(&env, validator, amount, reward_type) - } - - /// Fund the reward pool - pub fn fund_validator_reward_pool( - env: Env, - funder: Address, - amount: i128, - ) -> Result<(), BridgeError> { - slashing::SlashingManager::fund_reward_pool(&env, funder, amount) - } - - /// Get validator stake - pub fn get_validator_stake(env: Env, validator: Address) -> i128 { - slashing::SlashingManager::get_stake(&env, validator) - } - - // ========== Multi-Chain Functions ========== - - /// Add a supported chain with configuration - pub fn add_supported_chain_config( - env: Env, - chain_id: u32, - chain_name: Bytes, - bridge_contract_address: Bytes, - confirmation_blocks: u32, - gas_price: u64, - ) -> Result<(), BridgeError> { - multichain::MultiChainManager::add_chain( - &env, - chain_id, - chain_name, - bridge_contract_address, - confirmation_blocks, - gas_price, - ) - } - - /// Update chain configuration - pub fn update_chain_config( - env: Env, - chain_id: u32, - is_active: bool, - confirmation_blocks: Option, - gas_price: Option, - ) -> Result<(), BridgeError> { - multichain::MultiChainManager::update_chain( - &env, - chain_id, - is_active, - confirmation_blocks, - gas_price, - ) - } - - /// Register a multi-chain asset - pub fn register_multi_chain_asset( - env: Env, - asset_id: Bytes, - stellar_token: Address, - chain_configs: Map, - ) -> Result { - multichain::MultiChainManager::register_asset(&env, asset_id, stellar_token, chain_configs) - } - - /// Get chain configuration - pub fn get_chain_config(env: Env, chain_id: u32) -> Option { - multichain::MultiChainManager::get_chain_config(&env, chain_id) - } - - /// Check if chain is active - pub fn is_chain_active(env: Env, chain_id: u32) -> bool { - multichain::MultiChainManager::is_chain_active(&env, chain_id) - } - - /// Get supported chains - pub fn get_supported_chains(env: Env) -> Vec { - multichain::MultiChainManager::get_supported_chains(&env) - } - - // ========== Liquidity and AMM Functions ========== - - /// Initialize liquidity pool for a chain - pub fn initialize_liquidity_pool( - env: Env, - chain_id: u32, - token: Address, - ) -> Result<(), BridgeError> { - liquidity::LiquidityManager::initialize_pool(&env, chain_id, token) - } - - /// Add liquidity to a pool - pub fn add_liquidity( - env: Env, - provider: Address, - chain_id: u32, - amount: i128, - ) -> Result { - liquidity::LiquidityManager::add_liquidity(&env, provider, chain_id, amount) - } - - /// Remove liquidity from a pool - pub fn remove_liquidity( - env: Env, - provider: Address, - chain_id: u32, - amount: i128, - ) -> Result { - liquidity::LiquidityManager::remove_liquidity(&env, provider, chain_id, amount) - } - - /// Calculate dynamic bridge fee - pub fn calculate_bridge_fee( - env: Env, - chain_id: u32, - amount: i128, - user_volume_24h: i128, - ) -> Result { - liquidity::LiquidityManager::calculate_bridge_fee(&env, chain_id, amount, user_volume_24h) - } - - /// Update fee structure - pub fn update_fee_structure( - env: Env, - base_fee: i128, - dynamic_multiplier: u32, - volume_discount_tiers: Map, - ) -> Result<(), BridgeError> { - liquidity::LiquidityManager::update_fee_structure( - &env, - base_fee, - dynamic_multiplier, - volume_discount_tiers, - ) - } - - /// Get available liquidity for a chain - pub fn get_available_liquidity(env: Env, chain_id: u32) -> i128 { - liquidity::LiquidityManager::get_available_liquidity(&env, chain_id) - } - - // ========== Message Passing Functions ========== - - /// Send a cross-chain packet - pub fn send_cross_chain_packet( - env: Env, - source_chain: u32, - destination_chain: u32, - sender: Bytes, - recipient: Bytes, - payload: Bytes, - timeout: Option, - ) -> Result { - message_passing::MessagePassing::send_packet( - &env, - source_chain, - destination_chain, - sender, - recipient, - payload, - timeout, - ) - } - - /// Mark a cross-chain packet as delivered - pub fn deliver_cross_chain_packet( - env: Env, - packet_id: u64, - gas_used: u64, - result: Bytes, - ) -> Result<(), BridgeError> { - message_passing::MessagePassing::deliver_packet(&env, packet_id, gas_used, result) - } - - /// Mark a cross-chain packet as failed - pub fn fail_cross_chain_packet( - env: Env, - packet_id: u64, - reason: Bytes, - ) -> Result<(), BridgeError> { - message_passing::MessagePassing::fail_packet(&env, packet_id, reason) - } - - /// Retry a failed or timed-out cross-chain packet - pub fn retry_cross_chain_packet(env: Env, packet_id: u64) -> Result<(), BridgeError> { - message_passing::MessagePassing::retry_packet(&env, packet_id) - } - - /// Mark all expired packets as timed out and return packet IDs - pub fn check_cross_chain_timeouts(env: Env) -> Result, BridgeError> { - message_passing::MessagePassing::check_timeouts(&env) - } - - /// Get packet by ID - pub fn get_packet(env: Env, packet_id: u64) -> Option { - message_passing::MessagePassing::get_packet(&env, packet_id) - } - - /// Get packet receipt - pub fn get_packet_receipt(env: Env, packet_id: u64) -> Option { - message_passing::MessagePassing::get_receipt(&env, packet_id) - } - - /// Verify packet delivery - pub fn verify_packet_delivery(env: Env, packet_id: u64) -> bool { - message_passing::MessagePassing::verify_delivery(&env, packet_id) - } - - /// Get retry count for a packet - pub fn get_packet_retry_count(env: Env, packet_id: u64) -> u32 { - message_passing::MessagePassing::get_packet_retry_count(&env, packet_id) + ) -> u64 { + bridge::bridge_out(&env, from, amount, destination_chain, destination_address) } - // ========== Emergency Functions ========== - - /// Pause the entire bridge - pub fn pause_bridge(env: Env, pauser: Address, reason: Bytes) -> Result<(), BridgeError> { - emergency::EmergencyManager::pause_bridge(&env, pauser, reason) - } - - /// Resume the bridge - pub fn resume_bridge(env: Env, resumer: Address) -> Result<(), BridgeError> { - emergency::EmergencyManager::resume_bridge(&env, resumer) - } - - /// Pause specific chains - pub fn pause_chains( - env: Env, - pauser: Address, - chain_ids: Vec, - reason: Bytes, - ) -> Result<(), BridgeError> { - emergency::EmergencyManager::pause_chains(&env, pauser, chain_ids, reason) - } - - /// Resume specific chains - pub fn resume_chains( - env: Env, - resumer: Address, - chain_ids: Vec, - ) -> Result<(), BridgeError> { - emergency::EmergencyManager::resume_chains(&env, resumer, chain_ids) - } - - /// Initialize circuit breaker for a chain - pub fn initialize_circuit_breaker( + /// Register a new supported chain (admin only). + pub fn add_chain_support( env: Env, chain_id: u32, - max_daily_volume: i128, - max_transaction_amount: i128, - ) -> Result<(), BridgeError> { - emergency::EmergencyManager::initialize_circuit_breaker( + name: Symbol, + bridge_address: Address, + min_confirmations: u32, + fee_rate: u32, + ) { + bridge::add_chain_support( &env, chain_id, - max_daily_volume, - max_transaction_amount, - ) - } - - /// Check if bridge is paused - pub fn is_bridge_paused(env: Env) -> bool { - emergency::EmergencyManager::is_bridge_paused(&env) - } - - /// Check if a chain is paused - pub fn is_chain_paused(env: Env, chain_id: u32) -> bool { - emergency::EmergencyManager::is_chain_paused(&env, chain_id) - } - - /// Get emergency state - pub fn get_emergency_state(env: Env) -> EmergencyState { - emergency::EmergencyManager::get_emergency_state(&env) - } - - // ========== Audit and Compliance Functions ========== - - /// Create an audit record - pub fn create_audit_record( - env: Env, - operation_type: types::OperationType, - operator: Address, - details: Bytes, - tx_hash: Bytes, - ) -> Result { - audit::AuditManager::create_audit_record(&env, operation_type, operator, details, tx_hash) - } - - /// Get audit record by ID - pub fn get_audit_record(env: Env, record_id: u64) -> Option { - audit::AuditManager::get_audit_record(&env, record_id) - } - - /// Generate compliance report - pub fn generate_compliance_report( - env: Env, - period_start: u64, - period_end: u64, - ) -> Result { - audit::AuditManager::generate_compliance_report(&env, period_start, period_end) - } - - /// Get compliance report - pub fn get_compliance_report(env: Env, report_id: u64) -> Option { - audit::AuditManager::get_compliance_report(&env, report_id) - } - - // ========== Atomic Swap Functions ========== - - /// Initiate an atomic swap - pub fn initiate_atomic_swap( - env: Env, - initiator: Address, - initiator_token: Address, - initiator_amount: i128, - counterparty: Address, - counterparty_token: Address, - counterparty_amount: i128, - hashlock: Bytes, - timelock: u64, - ) -> Result { - atomic_swap::AtomicSwapManager::initiate_swap( - &env, - initiator, - initiator_token, - initiator_amount, - counterparty, - counterparty_token, - counterparty_amount, - hashlock, - timelock, - ) - } - - /// Accept and complete an atomic swap - pub fn accept_atomic_swap( - env: Env, - swap_id: u64, - counterparty: Address, - preimage: Bytes, - ) -> Result<(), BridgeError> { - atomic_swap::AtomicSwapManager::accept_swap(&env, swap_id, counterparty, preimage) + name, + bridge_address, + min_confirmations, + fee_rate, + ); } - /// Refund an expired atomic swap - pub fn refund_atomic_swap( + /// Submit an oracle price update (authorized oracles only). + pub fn update_oracle_price( env: Env, - swap_id: u64, - initiator: Address, - ) -> Result<(), BridgeError> { - atomic_swap::AtomicSwapManager::refund_swap(&env, swap_id, initiator) - } - - /// Get atomic swap by ID - pub fn get_atomic_swap(env: Env, swap_id: u64) -> Option { - atomic_swap::AtomicSwapManager::get_swap(&env, swap_id) - } - - /// Get active atomic swaps - pub fn get_active_atomic_swaps(env: Env) -> Vec { - atomic_swap::AtomicSwapManager::get_active_swaps(&env) - } - - // ========== Analytics Functions ========== - - /// Initialize bridge metrics - pub fn initialize_bridge_metrics(env: Env) -> Result<(), BridgeError> { - analytics::AnalyticsManager::initialize_metrics(&env) - } - - /// Get bridge metrics - pub fn get_bridge_metrics(env: Env) -> BridgeMetrics { - analytics::AnalyticsManager::get_bridge_metrics(&env) - } - - /// Get chain metrics - pub fn get_chain_metrics(env: Env, chain_id: u32) -> Option { - analytics::AnalyticsManager::get_chain_metrics(&env, chain_id) - } - - /// Calculate bridge health score - pub fn calculate_bridge_health_score(env: Env) -> u32 { - analytics::AnalyticsManager::calculate_health_score(&env) - } - - /// Get bridge statistics - pub fn get_bridge_statistics(env: Env) -> Map { - analytics::AnalyticsManager::get_bridge_statistics(&env) - } - - /// Get cached or computed bridge summary (health score + top chains). Uses cache if fresh. - pub fn get_cached_bridge_summary(env: Env) -> Result { - performance::PerformanceManager::get_or_compute_summary(&env) - } - - /// Force recompute and cache bridge summary. Emits PerfMetricsComputedEvent. - pub fn compute_and_cache_bridge_summary(env: Env) -> Result { - performance::PerformanceManager::compute_and_cache_summary(&env) - } - - /// Invalidate performance cache (admin only). Emits PerfCacheInvalidatedEvent. - pub fn invalidate_performance_cache(env: Env, admin: Address) -> Result<(), BridgeError> { - performance::PerformanceManager::invalidate_cache(&env, &admin) + asset: Symbol, + price: i128, + confidence: u32, + oracle_signer: Address, + ) { + oracle::update_oracle_price(&env, asset, price, confidence, oracle_signer); } - /// Get performance cache statistics: hits, misses, hit_rate - pub fn get_performance_cache_stats(env: Env) -> soroban_sdk::Map { - performance::PerformanceManager::get_cache_stats(&env) + /// Update bridge configuration (admin only). + pub fn update_config(env: Env, config: BridgeConfig) { + require_admin(&env); + validate_fee_rate(&env, &config.fee_rate); + env.storage().instance().set(&CONFIG, &config); } - /// Reset performance cache statistics (admin only). - pub fn reset_performance_cache_stats(env: Env, admin: Address) -> Result<(), BridgeError> { - performance::PerformanceManager::reset_cache_stats(&env, &admin) + /// Enable or disable the fallback mechanism (admin only). + pub fn set_fallback_enabled(env: Env, enabled: bool) { + require_admin(&env); + env.storage().instance().set(&FALLBACK_ENABLED, &enabled); } - // ========== Advanced Analytics & Reporting Functions ========== - - /// Get dashboard-ready aggregate analytics for visualizations - pub fn get_dashboard_analytics(env: Env) -> DashboardAnalytics { - reporting::ReportingManager::get_dashboard_analytics(&env) - } + // ── Queries ────────────────────────────────────────────────────────────── - /// Create a report template - pub fn create_report_template( - env: Env, - creator: Address, - name: Bytes, - report_type: ReportType, - config: Bytes, - ) -> Result { - reporting::ReportingManager::create_report_template( - &env, - creator, - name, - report_type, - config, - ) + /// Get a bridge transaction by index. + pub fn get_bridge_tx(env: Env, index: u32) -> Option<(Address, i128, u32, Bytes)> { + let txs: Vec<(Address, i128, u32, Bytes)> = env + .storage() + .instance() + .get(&BRIDGE_TXS) + .unwrap_or_else(|| Vec::new(&env)); + txs.get(index) } - /// Get report template by id - pub fn get_report_template(env: Env, template_id: u64) -> Option { - reporting::ReportingManager::get_report_template(&env, template_id) + /// Get the current bridge configuration. + pub fn get_config(env: Env) -> BridgeConfig { + storage::get_config(&env) } - /// Schedule a report - pub fn schedule_report( - env: Env, - owner: Address, - template_id: u64, - next_run_at: u64, - interval_seconds: u64, - ) -> Result { - reporting::ReportingManager::schedule_report( - &env, - owner, - template_id, - next_run_at, - interval_seconds, - ) + /// Check whether the fallback mechanism is enabled. + pub fn is_fallback_enabled(env: Env) -> bool { + env.storage() + .instance() + .get(&FALLBACK_ENABLED) + .unwrap_or(true) } - /// Get scheduled reports for an owner - pub fn get_scheduled_reports(env: Env, owner: Address) -> Vec { - reporting::ReportingManager::get_scheduled_reports(&env, owner) + /// Get the total error count. + pub fn get_error_stats(env: Env) -> u64 { + env.storage() + .instance() + .get(&storage::ERROR_COUNT) + .unwrap_or(0) } - /// Generate a report snapshot - pub fn generate_report_snapshot( - env: Env, - generator: Address, - template_id: u64, - period_start: u64, - period_end: u64, - ) -> Result { - reporting::ReportingManager::generate_report_snapshot( - &env, - generator, - template_id, - period_start, - period_end, + /// Expose key constants for off-chain consumers. + pub fn get_constants(_env: Env) -> (u32, u32, u32, i128, u64) { + ( + constants::fees::DEFAULT_FEE_RATE, + constants::chains::DEFAULT_MIN_CONFIRMATIONS, + constants::oracle::DEFAULT_CONFIDENCE_THRESHOLD, + constants::amounts::FALLBACK_PRICE, + constants::oracle::PRICE_FRESHNESS_SECONDS, ) } +} - /// Get report snapshot by id - pub fn get_report_snapshot(env: Env, report_id: u64) -> Option { - reporting::ReportingManager::get_report_snapshot(&env, report_id) - } - - /// Record report view for usage analytics - pub fn record_report_view( - env: Env, - report_id: u64, - viewer: Address, - ) -> Result<(), BridgeError> { - reporting::ReportingManager::record_report_view(&env, report_id, viewer) - } - - /// Get report usage count - pub fn get_report_usage_count(env: Env, report_id: u64) -> u32 { - reporting::ReportingManager::get_report_usage_count(&env, report_id) +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert!(true); } - - /// Add comment to a report - pub fn add_report_comment( - env: Env, - report_id: u64, - author: Address, - body: Bytes, - ) -> Result { - reporting::ReportingManager::add_report_comment(&env, report_id, author, body) - } - - /// Get comments for a report - pub fn get_report_comments(env: Env, report_id: u64) -> Vec { - reporting::ReportingManager::get_report_comments(&env, report_id) - } - - /// Create an alert rule - pub fn create_alert_rule( - env: Env, - owner: Address, - name: Bytes, - condition_type: AlertConditionType, - threshold: i128, - ) -> Result { - reporting::ReportingManager::create_alert_rule(&env, owner, name, condition_type, threshold) - } - - /// Get alert rules for an owner - pub fn get_alert_rules(env: Env, owner: Address) -> Vec { - reporting::ReportingManager::get_alert_rules(&env, owner) - } - - /// Evaluate alert rules (returns triggered rule ids) - pub fn evaluate_alerts(env: Env) -> Vec { - reporting::ReportingManager::evaluate_alerts(&env) - } - - /// Get recent report snapshots - pub fn get_recent_report_snapshots(env: Env, limit: u32) -> Vec { - reporting::ReportingManager::get_recent_report_snapshots(&env, limit) - } - - // ========== Backup and Disaster Recovery Functions ========== - - /// Create a backup manifest (integrity hash from off-chain) - pub fn create_backup( - env: Env, - creator: Address, - integrity_hash: Bytes, - rto_tier: RtoTier, - encryption_ref: u64, - ) -> Result { - backup::BackupManager::create_backup( - &env, - creator, - integrity_hash, - rto_tier, - encryption_ref, - ) - } - - /// Get backup manifest by id - pub fn get_backup_manifest(env: Env, backup_id: u64) -> Option { - backup::BackupManager::get_backup_manifest(&env, backup_id) - } - - /// Verify backup integrity - pub fn verify_backup( - env: Env, - backup_id: u64, - verifier: Address, - expected_hash: Bytes, - ) -> Result { - backup::BackupManager::verify_backup(&env, backup_id, verifier, expected_hash) - } - - /// Schedule automated backup - pub fn schedule_backup( - env: Env, - owner: Address, - next_run_at: u64, - interval_seconds: u64, - rto_tier: RtoTier, - ) -> Result { - backup::BackupManager::schedule_backup(&env, owner, next_run_at, interval_seconds, rto_tier) - } - - /// Get scheduled backups for an owner - pub fn get_scheduled_backups(env: Env, owner: Address) -> Vec { - backup::BackupManager::get_scheduled_backups(&env, owner) - } - - /// Record a recovery execution (RTO tracking and audit) - pub fn record_recovery( - env: Env, - backup_id: u64, - executed_by: Address, - recovery_duration_secs: u64, - success: bool, - ) -> Result { - backup::BackupManager::record_recovery( - &env, - backup_id, - executed_by, - recovery_duration_secs, - success, - ) - } - - /// Get recovery records for audit and RTO reporting - pub fn get_recovery_records(env: Env, limit: u32) -> Vec { - backup::BackupManager::get_recovery_records(&env, limit) - } - - /// Get recent backup manifests - pub fn get_recent_backups(env: Env, limit: u32) -> Vec { - backup::BackupManager::get_recent_backups(&env, limit) - } - - // ========== Rewards Functions ========== - - /// Initialize the rewards system - pub fn initialize_rewards( - env: Env, - token: Address, - rewards_admin: Address, - ) -> Result<(), RewardsError> { - rewards::Rewards::initialize_rewards(&env, token, rewards_admin) - } - - /// Fund the reward pool - pub fn fund_reward_pool(env: Env, funder: Address, amount: i128) -> Result<(), RewardsError> { - rewards::Rewards::fund_reward_pool(&env, funder, amount) - } - - /// Issue rewards to a user - pub fn issue_reward( - env: Env, - recipient: Address, - amount: i128, - reward_type: String, - ) -> Result<(), RewardsError> { - rewards::Rewards::issue_reward(&env, recipient, amount, reward_type) - } - - /// Claim pending rewards - pub fn claim_rewards(env: Env, user: Address) -> Result<(), RewardsError> { - rewards::Rewards::claim_rewards(&env, user) - } - - /// Set reward rate for a specific reward type (admin only) - pub fn set_reward_rate( - env: Env, - reward_type: String, - rate: i128, - enabled: bool, - ) -> Result<(), RewardsError> { - rewards::Rewards::set_reward_rate(&env, reward_type, rate, enabled) - } - - /// Update rewards admin (admin only) - pub fn update_rewards_admin(env: Env, new_admin: Address) { - rewards::Rewards::update_rewards_admin(&env, new_admin); - } - - /// Get user reward information - pub fn get_user_rewards(env: Env, user: Address) -> Option { - rewards::Rewards::get_user_rewards(&env, user) - } - - /// Get reward pool balance - pub fn get_reward_pool_balance(env: Env) -> i128 { - rewards::Rewards::get_reward_pool_balance(&env) - } - - /// Get total rewards issued - pub fn get_total_rewards_issued(env: Env) -> i128 { - rewards::Rewards::get_total_rewards_issued(&env) - } - - /// Get reward rate for a specific type - pub fn get_reward_rate(env: Env, reward_type: String) -> Option { - rewards::Rewards::get_reward_rate(&env, reward_type) - } - - /// Get rewards admin address - pub fn get_rewards_admin(env: Env) -> Address { - rewards::Rewards::get_rewards_admin(&env) - } - - // ========== Assessment and Testing Platform Functions ========== - - /// Create a new assessment - pub fn create_assessment( - env: Env, - creator: Address, - title: Bytes, - description: Bytes, - questions: Vec, - settings: AssessmentSettings, - ) -> Result { - assessment::AssessmentManager::create_assessment( - &env, - creator, - title, - description, - questions, - settings, - ) - } - - /// Add a question to the pool - pub fn add_assessment_question( - env: Env, - creator: Address, - q_type: QuestionType, - content_hash: Bytes, - points: u32, - difficulty: u32, - correct_answer_hash: Bytes, - metadata: Map, - ) -> Result { - assessment::AssessmentManager::add_question( - &env, - creator, - q_type, - content_hash, - points, - difficulty, - correct_answer_hash, - metadata, - ) - } - - /// Submit an assessment - pub fn submit_assessment( - env: Env, - student: Address, - assessment_id: u64, - answers: Map, - proctor_logs: Vec, - ) -> Result { - assessment::AssessmentManager::submit_assessment( - &env, - student, - assessment_id, - answers, - proctor_logs, - ) - } - - /// Get assessment details - pub fn get_assessment(env: Env, id: u64) -> Option { - assessment::AssessmentManager::get_assessment(&env, id) - } - - /// Get user submission - pub fn get_assessment_submission( - env: Env, - student: Address, - assessment_id: u64, - ) -> Option { - assessment::AssessmentManager::get_submission(&env, student, assessment_id) - } - - /// Report a proctoring violation - pub fn report_proctor_violation( - env: Env, - student: Address, - assessment_id: u64, - violation_type: Bytes, - ) -> Result<(), assessment::AssessmentError> { - assessment::AssessmentManager::report_proctoring_violation( - &env, - student, - assessment_id, - violation_type, - ) - } - - /// Get next adaptive question - pub fn get_next_adaptive_question( - env: Env, - id: u64, - scores: Vec, - answered_ids: Vec, - ) -> Result { - assessment::AssessmentManager::get_next_adaptive_question(&env, id, scores, answered_ids) - } - - // ========== Escrow Functions ========== - - /// Create a multi-signature escrow - pub fn create_escrow(env: Env, params: EscrowParameters) -> Result { - escrow::EscrowManager::create_escrow( - &env, - params.depositor, - params.beneficiary, - params.token, - params.amount, - params.signers, - params.threshold, - params.release_time, - params.refund_time, - params.arbitrator, - ) - } - - /// Approve escrow release (multi-signature) - pub fn approve_escrow_release( - env: Env, - escrow_id: u64, - signer: Address, - ) -> Result { - escrow::EscrowManager::approve_release(&env, escrow_id, signer) - } - - /// Release funds to the beneficiary once conditions are met - pub fn release_escrow(env: Env, escrow_id: u64, caller: Address) -> Result<(), EscrowError> { - escrow::EscrowManager::release(&env, escrow_id, caller) - } - - /// Refund escrow to the depositor after refund time - pub fn refund_escrow(env: Env, escrow_id: u64, depositor: Address) -> Result<(), EscrowError> { - escrow::EscrowManager::refund(&env, escrow_id, depositor) - } - - /// Cancel escrow before any approvals - pub fn cancel_escrow(env: Env, escrow_id: u64, depositor: Address) -> Result<(), EscrowError> { - escrow::EscrowManager::cancel(&env, escrow_id, depositor) - } - - /// Raise a dispute on the escrow - pub fn dispute_escrow( - env: Env, - escrow_id: u64, - disputer: Address, - reason: Bytes, - ) -> Result<(), EscrowError> { - escrow::EscrowManager::dispute(&env, escrow_id, disputer, reason) - } - - /// Automatically check if an escrow has stalled and trigger a dispute - pub fn auto_check_escrow_dispute(env: Env, escrow_id: u64) -> Result<(), EscrowError> { - escrow::EscrowManager::auto_check_dispute(&env, escrow_id) - } - - /// Resolve a dispute as the arbitrator - pub fn resolve_escrow( - env: Env, - escrow_id: u64, - arbitrator: Address, - outcome: DisputeOutcome, - ) -> Result<(), EscrowError> { - escrow::EscrowManager::resolve(&env, escrow_id, arbitrator, outcome) - } - - // ========== Arbitration Management Functions ========== - - /// Register a new professional arbitrator - pub fn register_arbitrator(env: Env, profile: ArbitratorProfile) -> Result<(), EscrowError> { - arbitration::ArbitrationManager::register_arbitrator(&env, profile) - } - - /// Update arbitrator profile - pub fn update_arbitrator_profile( - env: Env, - address: Address, - profile: ArbitratorProfile, - ) -> Result<(), EscrowError> { - arbitration::ArbitrationManager::update_profile(&env, address, profile) - } - - /// Get arbitrator profile - pub fn get_arbitrator_profile(env: Env, address: Address) -> Option { - arbitration::ArbitrationManager::get_arbitrator(&env, address) - } - - // ========== Insurance Pool Functions ========== - - /// Initialize insurance pool - pub fn initialize_insurance_pool( - env: Env, - token: Address, - premium_rate: u32, - ) -> Result<(), EscrowError> { - insurance::InsuranceManager::initialize_pool(&env, token, premium_rate) - } - - /// Fund insurance pool - pub fn fund_insurance_pool(env: Env, funder: Address, amount: i128) -> Result<(), EscrowError> { - insurance::InsuranceManager::fund_pool(&env, funder, amount) - } - - // ========== Escrow Analytics Functions ========== - - /// Get aggregate escrow metrics - pub fn get_escrow_metrics(env: Env) -> EscrowMetrics { - escrow_analytics::EscrowAnalyticsManager::get_metrics(&env) - } - - /// Get escrow by id - pub fn get_escrow(env: Env, escrow_id: u64) -> Option { - escrow::EscrowManager::get_escrow(&env, escrow_id) - } - - /// Check if a signer approved - pub fn has_escrow_approval(env: Env, escrow_id: u64, signer: Address) -> bool { - escrow::EscrowManager::has_approved(&env, escrow_id, signer) - } - - /// Get the current escrow count - pub fn get_escrow_count(env: Env) -> u64 { - escrow::EscrowManager::get_escrow_count(&env) - } - - // ========== Credit Scoring Functions (feat/credit_score) ========== - - /// Record course completion - pub fn record_course_completion(env: Env, user: Address, course_id: u64, points: u64) { - let admin = bridge::Bridge::get_admin(&env); - admin.require_auth(); - score::ScoreManager::record_course_completion(&env, user, course_id, points); - } - - /// Record contribution - pub fn record_contribution( - env: Env, - user: Address, - c_type: types::ContributionType, - description: Bytes, - points: u64, - ) { - score::ScoreManager::record_contribution(&env, user, c_type, description, points); - } - - /// Get user's credit score - pub fn get_credit_score(env: Env, user: Address) -> u64 { - score::ScoreManager::get_score(&env, user) - } - - /// Get user's courses - pub fn get_user_courses(env: Env, user: Address) -> Vec { - score::ScoreManager::get_courses(&env, user) - } - - /// Get user's contributions - pub fn get_user_contributions(env: Env, user: Address) -> Vec { - score::ScoreManager::get_contributions(&env, user) - } - - // ========== Reputation Functions (main) ========== - - pub fn update_participation(env: Env, user: Address, points: u32) { - reputation::update_participation(&env, user, points); - } - - pub fn update_course_progress(env: Env, user: Address, is_completion: bool) { - reputation::update_course_progress(&env, user, is_completion); - } - - pub fn rate_contribution(env: Env, user: Address, rating: u32) { - reputation::rate_contribution(&env, user, rating); - } - - pub fn get_user_reputation(env: Env, user: Address) -> types::UserReputation { - reputation::get_reputation(&env, &user) - } - - // ========== Content Tokenization Functions ========== - - /// Mint a new educational content token - pub fn mint_content_token(env: Env, params: ContentTokenParameters) -> u64 { - let token_id = tokenization::ContentTokenization::mint( - &env, - params.creator.clone(), - params.title, - params.description, - params.content_type, - params.content_hash, - params.license_type, - params.tags, - params.is_transferable, - params.royalty_percentage, - ); - provenance::ProvenanceTracker::record_mint(&env, token_id, params.creator, None); - token_id - } - - /// Transfer ownership of a content token - pub fn transfer_content_token( - env: Env, - from: Address, - to: Address, - token_id: u64, - notes: Option, - ) { - tokenization::ContentTokenization::transfer(&env, from, to, token_id, notes); - } - - /// Get a content token by ID - pub fn get_content_token(env: Env, token_id: u64) -> Option { - tokenization::ContentTokenization::get_token(&env, token_id) - } - - /// Get the owner of a content token - pub fn get_content_token_owner(env: Env, token_id: u64) -> Option
{ - tokenization::ContentTokenization::get_owner(&env, token_id) - } - - /// Check if an address owns a content token - pub fn is_content_token_owner(env: Env, token_id: u64, address: Address) -> bool { - tokenization::ContentTokenization::is_owner(&env, token_id, address) - } - - /// Get all tokens owned by an address - pub fn get_owner_content_tokens(env: Env, owner: Address) -> Vec { - tokenization::ContentTokenization::get_owner_tokens(&env, owner) - } - - /// Get the total number of content tokens minted - pub fn get_content_token_count(env: Env) -> u64 { - tokenization::ContentTokenization::get_token_count(&env) - } - - /// Update content token metadata (only by owner) - pub fn update_content_metadata( - env: Env, - owner: Address, - token_id: u64, - title: Option, - description: Option, - tags: Option>, - ) { - tokenization::ContentTokenization::update_metadata( - &env, - owner, - token_id, - title, - description, - tags, - ); - } - - /// Set transferability of a content token (only by owner) - pub fn set_content_token_transferable( - env: Env, - owner: Address, - token_id: u64, - transferable: bool, - ) { - tokenization::ContentTokenization::set_transferable(&env, owner, token_id, transferable); - } - - // ========== Provenance Functions ========== - - /// Get full provenance history for a content token - pub fn get_content_provenance(env: Env, token_id: u64) -> Vec { - provenance::ProvenanceTracker::get_provenance(&env, token_id) - } - - /// Get the number of transfers for a content token - #[must_use] - pub fn get_content_transfer_count(env: &Env, token_id: u64) -> u32 { - provenance::ProvenanceTracker::get_transfer_count(env, token_id) - } - - /// Verify ownership chain integrity for a content token - #[must_use] - pub fn verify_content_chain(env: &Env, token_id: u64) -> bool { - provenance::ProvenanceTracker::verify_chain(env, token_id) - } - - /// Get the creator of a content token - #[must_use] - pub fn get_content_creator(env: &Env, token_id: u64) -> Option
{ - tokenization::ContentTokenization::get_creator(env, token_id) - } - - /// Get all owners of a content token - #[must_use] - pub fn get_content_all_owners(env: &Env, token_id: u64) -> Vec
{ - tokenization::ContentTokenization::get_all_owners(env, token_id) - } - - // ========== Notification System Functions ========== - - /// Initialize notification system - pub fn initialize_notifications(env: Env) -> Result<(), BridgeError> { - notification::NotificationManager::initialize(&env) - } - - /// Send immediate notification - pub fn send_notification( - env: Env, - recipient: Address, - channel: NotificationChannel, - subject: Bytes, - body: Bytes, - ) -> Result { - let content = NotificationContent { - subject, - body, - data: Bytes::new(&env), - localization: Map::new(&env), - }; - notification::NotificationManager::send_notification(&env, recipient, channel, content) - } - - // ========== Mobile UI/UX Functions ========== - - /// Initialize mobile profile for user - pub fn initialize_mobile_profile( - env: Env, - user: Address, - device_info: DeviceInfo, - preferences: MobilePreferences, - ) -> Result<(), MobilePlatformError> { - mobile_platform::MobilePlatformManager::initialize_mobile_profile( - &env, - user, - device_info, - preferences, - ) - .map_err(|_| MobilePlatformError::DeviceNotSupported) - } - - /// Update accessibility settings - pub fn update_accessibility_settings( - env: Env, - user: Address, - settings: MobileAccessibilitySettings, - ) -> Result<(), MobilePlatformError> { - mobile_platform::MobilePlatformManager::update_accessibility_settings(&env, user, settings) - .map_err(|_| MobilePlatformError::DeviceNotSupported) - } - - /// Update personalization settings - pub fn update_personalization( - env: Env, - user: Address, - preferences: MobilePreferences, - ) -> Result<(), MobilePlatformError> { - mobile_platform::MobilePlatformManager::update_personalization(&env, user, preferences) - .map_err(|_| MobilePlatformError::DeviceNotSupported) - } - - /// Record onboarding progress - pub fn record_onboarding_progress( - env: Env, - user: Address, - stage: OnboardingStage, - ) -> Result<(), MobilePlatformError> { - mobile_platform::MobilePlatformManager::record_onboarding_progress(&env, user, stage) - .map_err(|_| MobilePlatformError::DeviceNotSupported) - } - - /// Submit user feedback - pub fn submit_user_feedback( - env: Env, - user: Address, - rating: u32, - comment: Bytes, - category: FeedbackCategory, - ) -> Result { - mobile_platform::MobilePlatformManager::submit_user_feedback( - &env, user, rating, comment, category, - ) - .map_err(|_| MobilePlatformError::DeviceNotSupported) - } - - /// Get user allocated experiment variants - pub fn get_user_experiment_variants(env: Env, user: Address) -> Map { - mobile_platform::MobilePlatformManager::get_user_experiment_variants(&env, user) - } - - /// Get design system configuration - pub fn get_design_system_config(env: Env) -> ComponentConfig { - mobile_platform::MobilePlatformManager::get_design_system_config(&env) - } - - /// Set design system configuration (admin only) - pub fn set_design_system_config(env: Env, config: ComponentConfig) { - // In a real implementation, we would check for admin authorization here - mobile_platform::MobilePlatformManager::set_design_system_config(&env, config) - } - - /// Schedule notification for future delivery - pub fn schedule_notification( - env: Env, - recipient: Address, - channel: NotificationChannel, - subject: Bytes, - body: Bytes, - scheduled_time: u64, - timezone: Bytes, - ) -> Result { - let content = NotificationContent { - subject, - body, - data: Bytes::new(&env), - localization: Map::new(&env), - }; - let schedule = NotificationSchedule { - notification_id: 0, // Will be set by the function - recipient: recipient.clone(), - channel, - scheduled_time, - timezone, - is_recurring: false, - recurrence_pattern: 0, - max_deliveries: None, - delivery_count: 0, - }; - notification::NotificationManager::schedule_notification( - &env, recipient, channel, content, schedule, - ) - } - - /// Process scheduled notifications - pub fn process_scheduled_notifications(env: Env) -> Result { - notification::NotificationManager::process_scheduled_notifications(&env) - } - - /// Update user notification preferences - pub fn update_notification_preferences( - env: Env, - user: Address, - preferences: Vec, - ) -> Result<(), BridgeError> { - notification::NotificationManager::update_preferences(&env, user, preferences) - } - - /// Update user notification settings - pub fn update_notification_settings( - env: Env, - user: Address, - timezone: Bytes, - quiet_hours_start: u32, - quiet_hours_end: u32, - max_daily_notifications: u32, - do_not_disturb: bool, - ) -> Result<(), BridgeError> { - let settings = UserNotificationSettings { - user: user.clone(), - timezone, - quiet_hours_start, - quiet_hours_end, - max_daily_notifications, - do_not_disturb, - }; - notification::NotificationManager::update_user_settings(&env, user, settings) - } - - /// Create notification template - pub fn create_notification_template( - env: Env, - admin: Address, - name: Bytes, - channels: Vec, - subject: Bytes, - body: Bytes, - ) -> Result { - let content = NotificationContent { - subject, - body, - data: Bytes::new(&env), - localization: Map::new(&env), - }; - notification::NotificationManager::create_template(&env, admin, name, channels, content) - } - - /// Send notification using template - pub fn send_template_notification( - env: Env, - recipient: Address, - template_id: u64, - variables: Map, - ) -> Result { - notification::NotificationManager::send_template_notification( - &env, - recipient, - template_id, - variables, - ) - } - - /// Get notification tracking information - pub fn get_notification_tracking( - env: Env, - notification_id: u64, - ) -> Option { - notification::NotificationManager::get_notification_tracking(&env, notification_id) - } - - /// Get user notification history - pub fn get_user_notifications( - env: Env, - user: Address, - limit: u32, - ) -> Vec { - notification::NotificationManager::get_user_notifications(&env, user, limit) - } - - // ========== Social Learning Functions ========== - - /// Create a study group - pub fn create_study_group( - env: Env, - creator: Address, - name: Bytes, - description: Bytes, - subject: Bytes, - max_members: u32, - is_private: bool, - tags: Vec, - settings: social_learning::StudyGroupSettings, - ) -> Result { - social_learning::SocialLearningManager::create_study_group( - &env, - creator, - name, - description, - subject, - max_members, - is_private, - tags, - settings, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Join a study group - pub fn join_study_group(env: Env, user: Address, group_id: u64) -> Result<(), BridgeError> { - social_learning::SocialLearningManager::join_study_group(&env, user, group_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Leave a study group - pub fn leave_study_group(env: Env, user: Address, group_id: u64) -> Result<(), BridgeError> { - social_learning::SocialLearningManager::leave_study_group(&env, user, group_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get study group information - pub fn get_study_group( - env: Env, - group_id: u64, - ) -> Result { - social_learning::SocialLearningManager::get_study_group(&env, group_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get user's study groups - pub fn get_user_study_groups(env: Env, user: Address) -> Vec { - social_learning::SocialLearningManager::get_user_study_groups(&env, user) - } - - /// Create a discussion forum - pub fn create_forum( - env: Env, - creator: Address, - title: Bytes, - description: Bytes, - category: Bytes, - tags: Vec, - ) -> Result { - social_learning::SocialLearningManager::create_forum( - &env, - creator, - title, - description, - category, - tags, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Create a forum post - pub fn create_forum_post( - env: Env, - forum_id: u64, - author: Address, - title: Bytes, - content: Bytes, - attachments: Vec, - ) -> Result { - social_learning::SocialLearningManager::create_forum_post( - &env, - forum_id, - author, - title, - content, - attachments, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get forum information - pub fn get_forum( - env: Env, - forum_id: u64, - ) -> Result { - social_learning::SocialLearningManager::get_forum(&env, forum_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get forum post - pub fn get_forum_post( - env: Env, - post_id: u64, - ) -> Result { - social_learning::SocialLearningManager::get_forum_post(&env, post_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Create a collaboration workspace - pub fn create_workspace( - env: Env, - creator: Address, - name: Bytes, - description: Bytes, - project_type: social_learning::ProjectType, - settings: social_learning::WorkspaceSettings, - ) -> Result { - social_learning::SocialLearningManager::create_workspace( - &env, - creator, - name, - description, - project_type, - settings, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get workspace information - pub fn get_workspace( - env: Env, - workspace_id: u64, - ) -> Result { - social_learning::SocialLearningManager::get_workspace(&env, workspace_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get user's workspaces - pub fn get_user_workspaces(env: Env, user: Address) -> Vec { - social_learning::SocialLearningManager::get_user_workspaces(&env, user) - } - - /// Create a peer review - pub fn create_review( - env: Env, - reviewer: Address, - reviewee: Address, - content_type: social_learning::ReviewContentType, - content_id: u64, - rating: u32, - feedback: Bytes, - criteria: Map, - ) -> Result { - social_learning::SocialLearningManager::create_review( - &env, - reviewer, - reviewee, - content_type, - content_id, - rating, - feedback, - criteria, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get review information - pub fn get_review( - env: Env, - review_id: u64, - ) -> Result { - social_learning::SocialLearningManager::get_review(&env, review_id) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Create mentorship profile - pub fn create_mentorship_profile( - env: Env, - mentor: Address, - expertise_areas: Vec, - experience_level: social_learning::ExperienceLevel, - availability: social_learning::AvailabilityStatus, - hourly_rate: Option, - bio: Bytes, - languages: Vec, - timezone: Bytes, - ) -> Result<(), BridgeError> { - social_learning::SocialLearningManager::create_mentorship_profile( - &env, - mentor, - expertise_areas, - experience_level, - availability, - hourly_rate, - bio, - languages, - timezone, - ) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get mentorship profile - pub fn get_mentorship_profile( - env: Env, - mentor: Address, - ) -> Result { - social_learning::SocialLearningManager::get_mentorship_profile(&env, mentor) - .map_err(|_| BridgeError::InvalidInput) - } - - /// Get user social analytics - pub fn get_user_analytics(env: Env, user: Address) -> social_learning::SocialAnalytics { - social_learning::SocialLearningManager::get_user_analytics(&env, user) - } - - /// Update user social analytics - pub fn update_user_analytics( - env: Env, - user: Address, - analytics: social_learning::SocialAnalytics, - ) { - social_learning::SocialLearningManager::update_user_analytics(&env, user, analytics); - } - - // Analytics function removed due to contracttype limitations - // Use internal notification manager for analytics } diff --git a/contracts/teachlink/src/oracle.rs b/contracts/teachlink/src/oracle.rs new file mode 100644 index 0000000..b5706f6 --- /dev/null +++ b/contracts/teachlink/src/oracle.rs @@ -0,0 +1,60 @@ +//! Oracle price feed management. + +use soroban_sdk::{symbol_short, Address, Env, Symbol, Vec}; + +use crate::{ + constants, + errors::{handle_error, TeachLinkError}, + validation, +}; + +/// Update (or insert) a price entry from an authorized oracle. +pub fn update_oracle_price( + env: &Env, + asset: Symbol, + price: i128, + confidence: u32, + oracle_signer: Address, +) { + validation::require_initialized(env, true); + validation::validate_price(env, &price); + validation::validate_confidence(env, &confidence); + + let oracles_key = symbol_short!("oracles"); + let authorized: Vec
= env + .storage() + .instance() + .get(&oracles_key) + .unwrap_or_else(|| Vec::new(env)); + + if !authorized.iter().any(|o| o == oracle_signer) { + handle_error(env, TeachLinkError::UnauthorizedOracle); + } + + let prices_key = symbol_short!("prices"); + let mut prices: Vec<(Symbol, i128, u64, u32)> = env + .storage() + .instance() + .get(&prices_key) + .unwrap_or_else(|| Vec::new(env)); + + let entry = (asset.clone(), price, env.ledger().timestamp(), confidence); + + let mut updated = false; + for i in 0..prices.len() { + if prices.get(i).unwrap().0 == asset { + prices.set(i, entry.clone()); + updated = true; + break; + } + } + + if !updated { + if prices.len() >= constants::storage::MAX_ORACLE_PRICES { + handle_error(env, TeachLinkError::InvalidPrice); + } + prices.push_back(entry); + } + + env.storage().instance().set(&prices_key, &prices); +} diff --git a/contracts/teachlink/src/storage.rs b/contracts/teachlink/src/storage.rs index a35c93d..296eb92 100644 --- a/contracts/teachlink/src/storage.rs +++ b/contracts/teachlink/src/storage.rs @@ -1,190 +1,25 @@ -use soroban_sdk::symbol_short; -use soroban_sdk::Symbol; +//! Storage key constants and low-level storage helpers. -// Storage keys for the bridge contract -pub const TOKEN: Symbol = symbol_short!("token"); -pub const VALIDATORS: Symbol = symbol_short!("validtor"); -pub const MIN_VALIDATORS: Symbol = symbol_short!("min_valid"); -pub const NONCE: Symbol = symbol_short!("nonce"); -pub const BRIDGE_TXS: Symbol = symbol_short!("bridge_tx"); -pub const SUPPORTED_CHAINS: Symbol = symbol_short!("chains"); -pub const ADMIN: Symbol = symbol_short!("admin"); -pub const FEE_RECIPIENT: Symbol = symbol_short!("fee_rcpt"); -pub const BRIDGE_FEE: Symbol = symbol_short!("bridgefee"); -pub const BRIDGE_RETRY_COUNTS: Symbol = symbol_short!("br_rtryc"); -pub const BRIDGE_LAST_RETRY: Symbol = symbol_short!("br_lstry"); -pub const BRIDGE_FAILURES: Symbol = symbol_short!("br_fails"); - -// ========== Advanced Bridge Storage Keys ========== - -// BFT Consensus Storage -pub const VALIDATOR_INFO: Symbol = symbol_short!("val_info"); -pub const BRIDGE_PROPOSALS: Symbol = symbol_short!("proposals"); -pub const PROPOSAL_COUNTER: Symbol = symbol_short!("prop_cnt"); -pub const CONSENSUS_STATE: Symbol = symbol_short!("cons_st"); -pub const VALIDATOR_STAKES: Symbol = symbol_short!("val_stake"); - -// Slashing and Rewards Storage -pub const SLASHING_RECORDS: Symbol = symbol_short!("slash_rec"); -pub const VALIDATOR_REWARDS: Symbol = symbol_short!("val_rwds"); -pub const SLASHING_COUNTER: Symbol = symbol_short!("slash_cnt"); - -// Multi-Chain Support Storage -pub const CHAIN_CONFIGS: Symbol = symbol_short!("chain_cfg"); -pub const MULTI_CHAIN_ASSETS: Symbol = symbol_short!("mc_assets"); -pub const ASSET_COUNTER: Symbol = symbol_short!("asset_cnt"); - -// Liquidity and AMM Storage -pub const LIQUIDITY_POOLS: Symbol = symbol_short!("liq_pools"); -pub const LP_POSITIONS: Symbol = symbol_short!("lp_pos"); -pub const FEE_STRUCTURE: Symbol = symbol_short!("fee_struc"); - -// Message Passing Storage -pub const CROSS_CHAIN_PACKETS: Symbol = symbol_short!("packets"); -pub const PACKET_COUNTER: Symbol = symbol_short!("pkt_cnt"); -pub const MESSAGE_RECEIPTS: Symbol = symbol_short!("receipts"); -pub const PACKET_RETRY_COUNTS: Symbol = symbol_short!("pkt_rtrc"); -pub const PACKET_LAST_RETRY: Symbol = symbol_short!("pkt_lstry"); - -// Emergency and Security Storage -pub const EMERGENCY_STATE: Symbol = symbol_short!("emergency"); -pub const CIRCUIT_BREAKERS: Symbol = symbol_short!("circ_brk"); -pub const PAUSED_CHAINS: Symbol = symbol_short!("paused_ch"); - -// Audit and Compliance Storage -pub const AUDIT_RECORDS: Symbol = symbol_short!("audit_rec"); -pub const AUDIT_COUNTER: Symbol = symbol_short!("audit_cnt"); -pub const COMPLIANCE_REPORTS: Symbol = symbol_short!("compl_rep"); - -// Atomic Swap Storage -pub const ATOMIC_SWAPS: Symbol = symbol_short!("swaps"); -pub const SWAP_COUNTER: Symbol = symbol_short!("swap_cnt"); -// Index storage for atomic swaps -pub const SWAPS_BY_INITIATOR: Symbol = symbol_short!("swp_init"); -pub const SWAPS_BY_COUNTERPARTY: Symbol = symbol_short!("swp_cnty"); -pub const SWAPS_BY_STATUS: Symbol = symbol_short!("swp_stat"); +use soroban_sdk::{symbol_short, Env, Symbol}; -// Analytics Storage -pub const BRIDGE_METRICS: Symbol = symbol_short!("metrics"); -pub const CHAIN_METRICS: Symbol = symbol_short!("ch_mets"); -pub const DAILY_VOLUMES: Symbol = symbol_short!("daily_vol"); -// Indexed storage for analytics -pub const CHAIN_VOLUME_INDEX: Symbol = symbol_short!("chn_vol_i"); -pub const CHAIN_METRICS_INDEX: Symbol = symbol_short!("chn_met_i"); +use crate::types::BridgeConfig; -// Storage keys for the rewards system -pub const REWARDS_ADMIN: Symbol = symbol_short!("rwd_admin"); -pub const REWARD_POOL: Symbol = symbol_short!("rwd_pool"); -pub const USER_REWARDS: Symbol = symbol_short!("usr_rwds"); -pub const REWARD_RATES: Symbol = symbol_short!("rwd_rates"); -pub const TOTAL_REWARDS_ISSUED: Symbol = symbol_short!("tot_rwds"); -pub const ESCROW_COUNT: Symbol = symbol_short!("esc_ct"); -pub const ESCROWS: Symbol = symbol_short!("escrows"); - -// Storage keys for credit scoring -pub const CREDIT_SCORE: Symbol = symbol_short!("score"); -pub const COURSE_COMPLETIONS: Symbol = symbol_short!("courses"); -pub const CONTRIBUTIONS: Symbol = symbol_short!("contribs"); - -// Storage keys for content tokenization -pub const TOKEN_COUNTER: Symbol = symbol_short!("tok_cnt"); -pub const CONTENT_TOKENS: Symbol = symbol_short!("cnt_tok"); -pub const OWNERSHIP: Symbol = symbol_short!("owner"); -pub const PROVENANCE: Symbol = symbol_short!("prov"); -pub const OWNER_TOKENS: Symbol = symbol_short!("own_tok"); - -// Arbitration and insurance Storage -pub const ARBITRATORS: Symbol = symbol_short!("arbs"); -pub const INSURANCE_POOL: Symbol = symbol_short!("ins_pool"); -pub const ESCROW_ANALYTICS: Symbol = symbol_short!("esc_an"); - -// Notification System Storage -pub const NOTIFICATION_COUNTER: Symbol = symbol_short!("notif_cnt"); -pub const NOTIFICATION_LOGS: Symbol = symbol_short!("notif_log"); -pub const NOTIFICATION_TRACKING: Symbol = symbol_short!("notif_trk"); -pub const NOTIFICATION_PREFERENCES: Symbol = symbol_short!("notif_prf"); -pub const NOTIFICATION_TEMPLATES: Symbol = symbol_short!("notif_tmp"); -pub const SCHEDULED_NOTIFICATIONS: Symbol = symbol_short!("notif_sch"); -pub const USER_NOTIFICATION_SETTINGS: Symbol = symbol_short!("notif_set"); -pub const NOTIFICATION_BATCHES: Symbol = symbol_short!("notif_bch"); -pub const NOTIFICATION_AB_TESTS: Symbol = symbol_short!("notif_ab"); -pub const NOTIFICATION_COMPLIANCE: Symbol = symbol_short!("notif_cmp"); -pub const NOTIFICATION_RATE_LIMITS: Symbol = symbol_short!("notif_rt"); -pub const NOTIFICATION_WEBHOOKS: Symbol = symbol_short!("notif_web"); -pub const NOTIFICATION_FILTERS: Symbol = symbol_short!("notif_flt"); -pub const NOTIFICATION_SEGMENTS: Symbol = symbol_short!("notif_seg"); -pub const NOTIFICATION_CAMPAIGNS: Symbol = symbol_short!("notif_cpg"); -pub const NOTIFICATION_ANALYTICS: Symbol = symbol_short!("notif_anl"); - -// Advanced Analytics & Reporting Storage (symbol_short! max 9 chars) -pub const REPORT_TEMPLATE_COUNTER: Symbol = symbol_short!("rpt_tplcn"); -pub const REPORT_TEMPLATES: Symbol = symbol_short!("rpt_tpl"); -pub const REPORT_SCHEDULE_COUNTER: Symbol = symbol_short!("rpt_schcn"); -pub const REPORT_SCHEDULES: Symbol = symbol_short!("rpt_sch"); -pub const REPORT_SNAPSHOT_COUNTER: Symbol = symbol_short!("rpt_snpcn"); -pub const REPORT_SNAPSHOTS: Symbol = symbol_short!("rpt_snp"); -pub const REPORT_USAGE: Symbol = symbol_short!("rpt_use"); -pub const REPORT_COMMENT_COUNTER: Symbol = symbol_short!("rpt_cmtcn"); -pub const REPORT_COMMENTS: Symbol = symbol_short!("rpt_cmt"); -pub const ALERT_RULE_COUNTER: Symbol = symbol_short!("alrt_cnt"); -pub const ALERT_RULES: Symbol = symbol_short!("alrt_ruls"); - -// Backup and Disaster Recovery Storage (symbol_short! max 9 chars) -pub const BACKUP_COUNTER: Symbol = symbol_short!("bak_cnt"); -pub const BACKUP_MANIFESTS: Symbol = symbol_short!("bak_mnf"); -pub const BACKUP_SCHED_CNT: Symbol = symbol_short!("bak_scc"); -pub const BACKUP_SCHEDULES: Symbol = symbol_short!("bak_sch"); -pub const RECOVERY_CNT: Symbol = symbol_short!("rec_cnt"); -pub const RECOVERY_RECORDS: Symbol = symbol_short!("rec_rec"); - -// Performance optimization and caching (symbol_short! max 9 chars) -pub const PERF_CACHE: Symbol = symbol_short!("perf_cach"); -pub const PERF_TS: Symbol = symbol_short!("perf_ts"); -// Performance cache monitoring -pub const PERF_HITS: Symbol = symbol_short!("perf_hits"); -pub const PERF_MISS: Symbol = symbol_short!("perf_miss"); - -// Advanced UI/UX Storage (symbol_short! max 9 chars) -pub const ONBOARDING_STATUS: Symbol = symbol_short!("onboard"); -pub const USER_FEEDBACK: Symbol = symbol_short!("feedback"); -pub const UX_EXPERIMENTS: Symbol = symbol_short!("ux_exp"); -pub const COMPONENT_CONFIG: Symbol = symbol_short!("comp_cfg"); -pub const SUPPORTED_CHAINS_LIST: Symbol = symbol_short!("ch_list"); -pub const VALIDATORS_LIST: Symbol = symbol_short!("val_list"); +pub const ADMIN: Symbol = symbol_short!("admin"); +pub const NONCE: Symbol = symbol_short!("nonce"); +pub const BRIDGE_TXS: Symbol = symbol_short!("bridge_txs"); +pub const FALLBACK_ENABLED: Symbol = symbol_short!("fallback"); +pub const ERROR_COUNT: Symbol = symbol_short!("error_count"); +pub const CONFIG: Symbol = symbol_short!("config"); + +/// Fetch the current config or return the default. +pub fn get_config(env: &Env) -> BridgeConfig { + env.storage().instance().get(&CONFIG).unwrap_or_default() +} -/// Granular storage keys for optimized data access -#[soroban_sdk::contracttype] -pub enum DataKey { - /// Chain metrics by chain ID: (u32) - ChainMetrics(u32), - /// Daily volume: (day_timestamp, chain_id) - DailyVolume(u64, u32), - /// Validator vote on proposal: (proposal_id, validator_address) - ProposalVote(u64, soroban_sdk::Address), - /// Liquidity provider position: (chain_id, provider_address) - LPPoolProvider(u32, soroban_sdk::Address), - /// Multi-chain asset configuration: (asset_counter, chain_id) - MultiChainAssetConfig(u64, u32), - /// Validator performance in a compliance report: (report_id, validator_address) - ReportValidatorPerf(u64, soroban_sdk::Address), - /// Pending bridge transaction: (nonce) - BridgeTx(u64), - /// Bridge transaction retry count: (nonce) - BridgeRetryCount(u64), - /// Bridge transaction last retry timestamp: (nonce) - BridgeLastRetry(u64), - /// Bridge transaction failure reason: (nonce) - BridgeFailure(u64), - /// Validator active status: (address) - Validator(soroban_sdk::Address), - /// Validator metadata: (address) - ValidatorMetadata(soroban_sdk::Address), - /// Validator stake: (address) - ValidatorStake(soroban_sdk::Address), - /// Supported chain status: (chain_id) - SupportedChain(u32), - /// Processed bridge nonce (for replay protection): (nonce) - ProcessedNonce(u64), - /// Audit record: (record_id) - AuditRecord(u64), +/// Return the next nonce (increments the stored value). +pub fn get_next_nonce(env: &Env) -> u64 { + let nonce: u64 = env.storage().instance().get(&NONCE).unwrap_or(0); + let next = nonce + 1; + env.storage().instance().set(&NONCE, &next); + next } diff --git a/contracts/teachlink/src/types.rs b/contracts/teachlink/src/types.rs index a2296ba..49947a7 100644 --- a/contracts/teachlink/src/types.rs +++ b/contracts/teachlink/src/types.rs @@ -1,1586 +1,26 @@ -//! TeachLink Contract Types -//! -//! This module defines all data structures used throughout the TeachLink smart contract. +//! Shared data types used across the TeachLink contract. -use soroban_sdk::{contracttype, panic_with_error, Address, Bytes, Map, String, Symbol, Vec}; +use soroban_sdk::contracttype; -// Include notification types -pub use crate::notification_types::*; - -// ========== Chain Configuration Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ChainConfig { - pub chain_id: u32, - pub chain_name: Bytes, - pub is_active: bool, - pub bridge_contract_address: Bytes, - pub confirmation_blocks: u32, - pub gas_price: u64, - pub last_updated: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MultiChainAsset { - pub asset_id: Bytes, - pub stellar_token: Address, - pub total_bridged: i128, - pub is_active: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ChainAssetInfo { - pub chain_id: u32, - pub token_address: Bytes, - pub decimals: u32, - pub is_active: bool, -} - -// ========== BFT Consensus Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ValidatorInfo { - pub address: Address, - pub stake: i128, - pub reputation_score: u32, - pub is_active: bool, - pub joined_at: u64, - pub last_activity: u64, - pub total_validations: u64, - pub missed_validations: u64, - pub slashed_amount: i128, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BridgeProposal { - pub proposal_id: u64, - pub message: CrossChainMessage, - pub vote_count: u32, - pub required_votes: u32, - pub status: ProposalStatus, - pub created_at: u64, - pub expires_at: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ProposalStatus { - Pending, - Approved, - Rejected, - Executed, - Expired, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ConsensusState { - pub total_stake: i128, - pub active_validators: u32, - pub byzantine_threshold: u32, - pub last_consensus_round: u64, -} - -// ========== Slashing and Rewards Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SlashingRecord { - pub validator: Address, - pub amount: i128, - pub reason: SlashingReason, - pub timestamp: u64, - pub evidence: Bytes, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SlashingReason { - DoubleVote, - InvalidSignature, - Inactivity, - ByzantineBehavior, - MaliciousProposal, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ValidatorReward { - pub validator: Address, - pub amount: i128, - pub reward_type: RewardType, - pub timestamp: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum RewardType { - Validation, - Consensus, - Uptime, - Security, -} - -// ========== Liquidity and AMM Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct LiquidityPool { - pub chain_id: u32, - pub token: Address, - pub total_liquidity: i128, - pub available_liquidity: i128, - pub locked_liquidity: i128, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct LPPosition { - pub provider: Address, - pub amount: i128, - pub share_percentage: u32, - pub deposited_at: u64, - pub rewards_earned: i128, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BridgeFeeStructure { - pub base_fee: i128, - pub dynamic_multiplier: u32, - pub congestion_multiplier: u32, - pub volume_discount_tiers: Map, - pub last_updated: u64, -} - -// ========== Message Passing Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CrossChainPacket { - pub packet_id: u64, - pub source_chain: u32, - pub destination_chain: u32, - pub sender: Bytes, - pub recipient: Bytes, - pub payload: Bytes, - pub nonce: u64, - pub timeout: u64, - pub status: PacketStatus, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum PacketStatus { - Pending, - Delivered, - Failed, - TimedOut, - Retrying, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MessageReceipt { - pub packet_id: u64, - pub delivered_at: u64, - pub gas_used: u64, - pub result: Bytes, -} - -// ========== Emergency and Security Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EmergencyState { - pub is_paused: bool, - pub paused_at: u64, - pub paused_by: Address, - pub reason: Bytes, - pub affected_chains: Vec, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CircuitBreaker { - pub chain_id: u32, - pub max_daily_volume: i128, - pub current_daily_volume: i128, - pub max_transaction_amount: i128, - pub last_reset: u64, - pub is_triggered: bool, -} - -// ========== Audit and Compliance Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct AuditRecord { - pub record_id: u64, - pub operation_type: OperationType, - pub operator: Address, - pub timestamp: u64, - pub details: Bytes, - pub tx_hash: Bytes, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OperationType { - BridgeIn, - BridgeOut, - ValidatorAdded, - ValidatorRemoved, - ValidatorSlashed, - EmergencyPause, - EmergencyResume, - FeeUpdate, - ConfigUpdate, - BackupCreated, - BackupVerified, - RecoveryExecuted, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ComplianceReport { - pub report_id: u64, - pub period_start: u64, - pub period_end: u64, - pub total_volume: i128, - pub total_transactions: u64, - pub unique_users: u32, -} - -// ========== Atomic Swap Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct AtomicSwap { - pub swap_id: u64, - pub initiator: Address, - pub initiator_token: Address, - pub initiator_amount: i128, - pub counterparty: Address, - pub counterparty_token: Address, - pub counterparty_amount: i128, - pub hashlock: Bytes, - pub timelock: u64, - pub status: SwapStatus, - pub created_at: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SwapStatus { - Initiated, - CounterpartyAccepted, - Completed, - Refunded, - Expired, -} - -// ========== Analytics Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BridgeMetrics { - pub total_volume: i128, - pub total_transactions: u64, - pub active_validators: u32, - pub average_confirmation_time: u64, - pub success_rate: u32, - pub last_updated: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ChainMetrics { - pub chain_id: u32, - pub volume_in: i128, - pub volume_out: i128, - pub transaction_count: u64, - pub average_fee: i128, - pub last_updated: u64, -} - -/// Cached bridge summary for performance: health score and top chains by volume. -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CachedBridgeSummary { - pub health_score: u32, - pub top_chains: Vec<(u32, i128)>, - pub computed_at: u64, -} - -// ========== Validator Signature Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ValidatorSignature { - pub validator: Address, - pub signature: Bytes, - pub timestamp: u64, -} - -// ========== Content Tokenization Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ContentTokenParameters { - pub creator: Address, - pub title: Bytes, - pub description: Bytes, - pub content_type: ContentType, - pub content_hash: Bytes, - pub license_type: Bytes, - pub tags: Vec, - pub is_transferable: bool, - pub royalty_percentage: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum EscrowRole { - Primary, // Full control, high weight - Secondary, // Partial control, low weight - Arbitrator, // Can resolve disputes - Auditor, // Read-only, can only flag issues -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EscrowSigner { - pub address: Address, - pub role: EscrowRole, - pub weight: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EscrowParameters { - pub depositor: Address, - pub beneficiary: Address, - pub token: Address, - pub amount: i128, - pub signers: Vec, - pub threshold: u32, - pub release_time: Option, - pub refund_time: Option, - pub arbitrator: Address, -} - -// ========== Bridge Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BridgeTransaction { - pub nonce: u64, - pub token: Address, - pub amount: i128, - pub recipient: Address, - pub destination_chain: u32, - pub destination_address: Bytes, - pub timestamp: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CrossChainMessage { - pub source_chain: u32, - pub source_tx_hash: Bytes, - pub nonce: u64, - pub token: Address, - pub amount: i128, - pub recipient: Address, - pub destination_chain: u32, -} - -// -// ========================== -// Rewards Types -// ========================== -// - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UserReward { - pub user: Address, - pub total_earned: i128, - pub claimed: i128, - pub pending: i128, - pub last_claim_timestamp: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct RewardRate { - pub reward_type: String, - pub rate: i128, - pub enabled: bool, -} - -// ========== Escrow Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum EscrowStatus { - Pending, - Released, - Refunded, - Disputed, - Cancelled, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Escrow { - pub id: u64, - pub depositor: Address, - pub beneficiary: Address, - pub token: Address, - pub amount: i128, - pub signers: Vec, - pub threshold: u32, - pub approval_count: u32, - pub release_time: Option, - pub refund_time: Option, - pub arbitrator: Address, - pub status: EscrowStatus, - pub created_at: u64, - pub dispute_reason: Option, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ArbitratorProfile { - pub address: Address, - pub name: String, - pub specialization: Vec, - pub reputation_score: u32, - pub total_resolved: u64, - pub dispute_types_handled: Vec, - pub is_active: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct InsurancePool { - pub token: Address, - pub balance: i128, - pub premium_rate: u32, // In basis points - pub total_claims_paid: i128, - pub max_payout_percentage: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EscrowApprovalKey { - pub escrow_id: u64, - pub signer: Address, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EscrowMetrics { - pub total_escrows: u64, - pub total_volume: i128, - pub total_disputes: u64, - pub total_resolved: u64, - pub average_resolution_time: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum DisputeOutcome { - ReleaseToBeneficiary, - RefundToDepositor, -} - -// -// ========================== -// Credit Score / Contribution Types -// ========================== -// - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ContributionType { - Content, - Code, - Community, - Governance, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Contribution { - pub contributor: Address, - pub c_type: ContributionType, - pub description: Bytes, - pub timestamp: u64, - pub points: u64, -} - -// -// ========================== -// Reputation Types -// ========================== -// - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UserReputation { - pub participation_score: u32, - pub completion_rate: u32, - pub contribution_quality: u32, - pub total_courses_started: u32, - pub total_courses_completed: u32, - pub total_contributions: u32, - pub last_update: u64, -} - -// -// ========================== -// Content Tokenization Types -// ========================== -// - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ContentType { - Course, - Material, - Lesson, - Assessment, - Certificate, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ContentMetadata { - pub title: Bytes, - pub description: Bytes, - pub content_type: ContentType, - pub creator: Address, - pub content_hash: Bytes, - pub license_type: Bytes, - pub tags: Vec, - pub created_at: u64, - pub updated_at: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ContentToken { - pub token_id: u64, - pub metadata: ContentMetadata, - pub owner: Address, - pub minted_at: u64, - pub is_transferable: bool, - pub royalty_percentage: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ProvenanceRecord { - pub token_id: u64, - pub from: Option
, - pub to: Address, - pub timestamp: u64, - pub transaction_hash: Bytes, - pub transfer_type: TransferType, - pub notes: Option, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum TransferType { - Mint, - Transfer, - License, - Revoke, -} - -// ========== Advanced Analytics & Reporting Types ========== - -/// Report type for templates and dashboards -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ReportType { - BridgeHealth, - EscrowSummary, - ComplianceAudit, - RewardsSummary, - TokenizationSummary, - Custom, -} - -/// Template for customizable reports (name, type, optional config) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ReportTemplate { - pub template_id: u64, - pub name: Bytes, - pub report_type: ReportType, - pub created_by: Address, - pub created_at: u64, - pub config: Bytes, -} - -/// Scheduled report (template + next run + interval) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ReportSchedule { - pub schedule_id: u64, - pub template_id: u64, - pub owner: Address, - pub next_run_at: u64, - pub interval_seconds: u64, - pub enabled: bool, - pub created_at: u64, -} - -/// Snapshot of a generated report (for audit trail and export) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ReportSnapshot { - pub report_id: u64, - pub template_id: u64, - pub report_type: ReportType, - pub generated_at: u64, - pub period_start: u64, - pub period_end: u64, - pub generated_by: Address, - /// Serialized summary metrics for visualization (e.g. key-value pairs) - pub summary: Bytes, -} - -/// Report view/usage record for analytics -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ReportUsage { - pub report_id: u64, - pub viewer: Address, - pub viewed_at: u64, -} - -/// Comment on a report for collaboration -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ReportComment { - pub comment_id: u64, - pub report_id: u64, - pub author: Address, - pub body: Bytes, - pub created_at: u64, -} - -/// Alert rule for real-time reporting (condition type + threshold) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum AlertConditionType { - BridgeHealthBelow, - EscrowDisputeRateAbove, - VolumeAbove, - VolumeBelow, - TransactionCountAbove, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct AlertRule { - pub rule_id: u64, - pub name: Bytes, - pub condition_type: AlertConditionType, - pub threshold: i128, - pub owner: Address, - pub enabled: bool, - pub created_at: u64, -} - -/// Aggregated metrics for dashboard visualization (one series = label + value) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct VisualizationDataPoint { - pub label: Bytes, - pub value: i128, -} - -/// Dashboard-ready aggregate analytics (bridge, escrow, compliance summary) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DashboardAnalytics { - pub bridge_health_score: u32, - pub bridge_total_volume: i128, - pub bridge_total_transactions: u64, - pub bridge_success_rate: u32, - pub escrow_total_count: u64, - pub escrow_total_volume: i128, - pub escrow_dispute_count: u64, - pub escrow_avg_resolution_time: u64, - pub compliance_report_count: u32, - pub audit_record_count: u64, - pub generated_at: u64, -} - -// ========== Backup and Disaster Recovery Types ========== - -/// RTO tier for recovery time objective (seconds) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum RtoTier { - Critical, // e.g. 300 (5 min) - High, // e.g. 3600 (1 hr) - Standard, // e.g. 86400 (24 hr) -} - -/// Backup manifest (metadata for integrity and audit) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BackupManifest { - pub backup_id: u64, - pub created_at: u64, - pub created_by: Address, - /// Integrity hash (e.g. hash of critical state snapshot) - pub integrity_hash: Bytes, - pub rto_tier: RtoTier, - /// Encryption/access: 0 = none, non-zero = key version or access policy id - pub encryption_ref: u64, -} - -/// Scheduled backup config -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct BackupSchedule { - pub schedule_id: u64, - pub owner: Address, - pub next_run_at: u64, - pub interval_seconds: u64, - pub rto_tier: RtoTier, - pub enabled: bool, - pub created_at: u64, -} - -/// Recovery record for audit trail and RTO tracking -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct RecoveryRecord { - pub recovery_id: u64, - pub backup_id: u64, - pub executed_at: u64, - pub executed_by: Address, - /// Recovery duration in seconds (RTO measurement) - pub recovery_duration_secs: u64, - pub success: bool, -} - -// ========== Mobile Platform Types ========== - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum LayoutDensity { - Compact, - Standard, - Comfortable, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum FocusStyle { - Default, - HighVisibility, - Solid, - Dotted, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ColorBlindMode { - None, - Protanopia, - Deuteranopia, - Tritanopia, - Grayscale, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OnboardingStage { - ProfileSetup, - WalletConnect, - FirstCourse, - CommunityJoin, - SecuritySetup, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum FeedbackCategory { - UX, - Performance, - Content, - Bug, - FeatureRequest, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SecurityEventType { - LoginAttempt, - LoginSuccess, - LoginFailure, - BiometricUsed, - DeviceAdded, - DeviceRemoved, - SuspiciousActivity, - RemoteWipe, - PasswordChange, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileLocationData { - pub latitude: i64, - pub longitude: i64, - pub accuracy: u64, - pub timestamp: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SecuritySeverity { - Low, - Medium, - High, - Critical, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileProfile { - pub user: Address, - pub device_info: DeviceInfo, - pub preferences: MobilePreferences, - pub offline_settings: OfflineSettings, - pub notification_preferences: NotificationPreferences, - pub security_settings: MobileSecuritySettings, - pub payment_methods: Vec, - pub accessibility_settings: MobileAccessibilitySettings, - pub last_sync: u64, - pub data_usage: DataUsageTracking, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct NotificationPreferences { - pub learning_reminders: bool, - pub deadline_alerts: bool, - pub achievement_notifications: bool, - pub social_updates: bool, - pub content_updates: bool, - pub quiet_hours: TimeRange, - pub frequency_limit: u32, - pub sound_enabled: bool, - pub vibration_enabled: bool, - pub led_enabled: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct TimeRange { - pub start_hour: u32, - pub end_hour: u32, - pub timezone: Bytes, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobilePaymentMethod { - pub id: u64, - pub name: Bytes, - pub method_type: PaymentMethodType, - pub is_default: bool, - pub last_used: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum PaymentMethodType { - StellarAsset, - NativeToken, - ExternalProvider, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DataUsageTracking { - pub total_downloaded: u64, - pub total_uploaded: u64, - pub cached_data: u64, - pub streaming_data: u64, - pub last_reset: u64, - pub daily_limit: u64, - pub warning_threshold: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct NetworkAnalytics { - pub connection_type_distribution: Map, - pub average_download_speed: u64, // Kbps - pub average_upload_speed: u64, - pub connection_stability: u64, // Basis points - pub offline_duration: u64, // Minutes per day - pub roaming_usage: u64, // Bytes -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum NetworkType { - WiFi, - Cellular4G, - Cellular5G, - Ethernet, - Offline, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SyncStrategy { - WiFiOnly, - WiFiAndCellular, - Manual, - SmartAdaptive, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OfflineQuality { - TextOnly, - LowQuality, - StandardQuality, - HighQuality, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DeviceInfo { - pub device_id: Bytes, - pub model: Bytes, - pub os_version: Bytes, - pub push_token: Bytes, - pub screen_resolution: Bytes, - pub is_tablet: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobilePreferences { - pub data_saver_mode: bool, - pub auto_download_wifi: bool, - pub video_quality: VideoQuality, - pub font_size: FontSize, - pub theme: ThemePreference, - pub language: Bytes, - pub vibration_enabled: bool, - pub sound_enabled: bool, - pub gesture_navigation: bool, - pub custom_theme_colors: Map, // Color key -> hex - pub layout_density: LayoutDensity, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum VideoQuality { - Auto, - Low, - Medium, - High, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum FontSize { - Small, - Medium, - Large, - ExtraLarge, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ThemePreference { - Light, - Dark, - System, - OLED, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileAccessibilitySettings { - pub screen_reader_enabled: bool, - pub high_contrast_enabled: bool, - pub large_text_enabled: bool, - pub voice_control_enabled: bool, - pub gesture_navigation_enabled: bool, - pub haptic_feedback_enabled: bool, - pub color_blind_mode: ColorBlindMode, - pub reduced_motion_enabled: bool, - pub focus_indicator_style: FocusStyle, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileSecuritySettings { - pub biometric_enabled: bool, - pub biometric_type: BiometricType, - pub pin_required: bool, - pub two_factor_enabled: bool, - pub session_timeout: u32, // Minutes - pub encryption_enabled: bool, - pub remote_wipe_enabled: bool, - pub trusted_devices: Vec, - pub login_attempts: u32, - pub max_login_attempts: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum BiometricType { - Fingerprint, - FaceID, - Voice, - Iris, - Pattern, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileStatistics { - pub session_count: u32, - pub total_time_spent: u64, // Seconds - pub average_session_length: u32, // Seconds - pub active_days_streak: u32, - pub last_active: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct OfflineSettings { - pub auto_download_enabled: bool, - pub download_quality: OfflineQuality, - pub storage_limit: u64, - pub sync_strategy: SyncStrategy, - pub offline_duration: u64, - pub priority_content: Vec, - pub compression_enabled: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct OnboardingStatus { - pub user: Address, - pub completed_stages: Vec, - pub current_stage: OnboardingStage, - pub last_updated: u64, - pub skipped: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UXExperiment { - pub experiment_id: u64, - pub name: Symbol, - pub description: Bytes, - pub variant_allocations: Map, // User -> Variant Key - pub start_date: u64, - pub end_date: u64, - pub is_active: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UserFeedback { - pub id: u64, - pub user: Address, - pub rating: u32, // 1-5 - pub comment: Bytes, - pub timestamp: u64, - pub category: FeedbackCategory, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ComponentConfig { - pub spacing_unit: u32, - pub border_radius_base: u32, - pub transition_duration_base: u32, - pub elevation_steps: Vec, - pub typography_scale: Map, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct OfflineContent { - pub content_id: u64, - pub content_type: OfflineContentType, - pub local_path: Bytes, - pub file_size: u64, - pub compressed_size: u64, - pub download_date: u64, - pub expiry_date: u64, - pub is_available: bool, - pub version: u32, - pub dependencies: Vec, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OfflineContentType { - VideoLesson, - AudioLesson, - TextDocument, - Quiz, - InteractiveExercise, - EBook, - CourseMaterial, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SyncQueue { - pub pending_uploads: Vec, - pub pending_downloads: Vec, - pub conflict_resolution: Vec, - pub last_sync_attempt: u64, - pub sync_status: SyncStatus, -} +use crate::constants; +/// Runtime configuration for bridge parameters. #[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SyncItem { - pub id: u64, - pub item_type: SyncItemType, - pub local_path: Bytes, - pub remote_path: Bytes, - pub priority: SyncPriority, - pub retry_count: u32, - pub max_retries: u32, +#[derive(Clone, Debug)] +pub struct BridgeConfig { + pub fee_rate: u32, + pub min_confirmations: u32, + pub confidence_threshold: u32, + pub fallback_enabled: bool, } -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SyncItemType { - ProgressData, - QuizResults, - Notes, - Bookmarks, - Certificates, - UserPreferences, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SyncPriority { - Low, - Normal, - High, - Critical, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SyncConflict { - pub conflict_id: u64, - pub item_type: SyncItemType, - pub local_version: Bytes, - pub remote_version: Bytes, - pub conflict_reason: Bytes, - pub resolution_strategy: ConflictResolution, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ConflictResolution { - LocalWins, - RemoteWins, - Merge, - ManualReview, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum SyncStatus { - Idle, - InProgress, - Completed, - Failed, - Paused, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct PushNotification { - pub id: u64, - pub user: Address, - pub notification_type: NotificationType, - pub title: Bytes, - pub message: Bytes, - pub data: Map, // Additional data - pub priority: NotificationPriority, - pub scheduled_time: u64, - pub expiry_time: u64, - pub is_read: bool, - pub action_buttons: Vec, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum NotificationType { - LearningReminder, - DeadlineAlert, - AchievementUnlocked, - SocialUpdate, - ContentUpdate, - SystemMessage, - PaymentRequired, - CourseUpdate, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum NotificationPriority { - Low, - Normal, - High, - Critical, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct NotificationAction { - pub action_id: Bytes, - pub label: Bytes, - pub url: Option, - pub auto_dismiss: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileTransaction { - pub id: u64, - pub user: Address, - pub payment_method_id: u64, - pub amount: u64, - pub currency: Bytes, - pub description: Bytes, - pub merchant: Bytes, - pub status: TransactionStatus, - pub timestamp: u64, - pub confirmation_code: Bytes, - pub fraud_score: u32, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum TransactionStatus { - Pending, - Completed, - Failed, - Cancelled, - Refunded, - Disputed, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SecurityEvent { - pub id: u64, - pub user: Address, - pub event_type: SecurityEventType, - pub device_id: Bytes, - pub has_location: bool, - pub location_lat: i64, - pub location_lon: i64, - pub location_accuracy: u64, - pub location_ts: u64, - pub timestamp: u64, - pub severity: SecuritySeverity, - pub resolved: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileAnalytics { - pub user: Address, - pub device_analytics: DeviceAnalytics, - pub usage_analytics: UsageAnalytics, - pub performance_analytics: PerformanceAnalytics, - pub engagement_analytics: EngagementAnalytics, - pub network_analytics: NetworkAnalytics, - pub error_tracking: ErrorTracking, - pub last_updated: u64, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DeviceAnalytics { - pub app_version: Bytes, - pub os_version: Bytes, - pub device_model: Bytes, - pub screen_resolution: Bytes, - pub memory_usage: u64, - pub storage_usage: u64, - pub battery_level: u32, - pub thermal_state: ThermalState, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ThermalState { - Normal, - Warm, - Hot, - Critical, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UsageAnalytics { - pub session_duration: u32, // Average minutes - pub sessions_per_day: u32, - pub active_days_per_week: u32, - pub peak_usage_hours: Vec, - pub feature_usage: Map, - pub screen_time: u64, // Total minutes - pub data_consumption: u64, // Bytes -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct PerformanceAnalytics { - pub app_load_time: u32, // Milliseconds - pub screen_render_time: u32, - pub network_latency: u32, - pub crash_count: u32, - pub anr_count: u32, // Application Not Responding - pub memory_leaks: u32, - pub battery_drain_rate: u64, // Basis points per hour -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EngagementAnalytics { - pub lesson_completion_rate: u64, // Basis points - pub quiz_attempt_rate: u64, // Basis points - pub social_interaction_count: u32, - pub feedback_submission_rate: u64, // Basis points - pub push_notif_response_rate: u64, // Basis points - pub feature_adoption_rate: Map, // Basis points -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ErrorTracking { - pub crash_reports: Vec, - pub anr_reports: Vec, - pub network_errors: Vec, - pub user_reported_issues: Vec, - pub error_rate: u64, // Basis points -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct CrashReport { - pub id: u64, - pub timestamp: u64, - pub app_version: Bytes, - pub device_info: Bytes, - pub stack_trace: Bytes, - pub user_action: Bytes, - pub reproducible: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ANRReport { - pub id: u64, - pub timestamp: u64, - pub duration: u32, // Seconds - pub app_state: Bytes, - pub device_load: u64, // Basis points - pub user_action: Bytes, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct NetworkError { - pub id: u64, - pub timestamp: u64, - pub error_type: NetworkErrorType, - pub url: Bytes, - pub response_code: u32, - pub retry_count: u32, - pub resolved: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum NetworkErrorType { - Timeout, - ConnectionRefused, - DNSFailure, - SSLHandshakeFailed, - ServerError, - ClientError, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UserIssue { - pub id: u64, - pub timestamp: u64, - pub issue_type: Bytes, - pub description: Bytes, - pub severity: u32, - pub user_email: Option, - pub resolved: bool, - pub resolution: Option, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileCommunity { - pub user: Address, - pub mobile_groups: Vec, - pub location_sharing: LocationSharingSettings, - pub quick_actions: Vec, - pub mobile_challenges: Vec, - pub social_features: MobileSocialFeatures, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileGroup { - pub id: u64, - pub name: Bytes, - pub description: Bytes, - pub members: Vec
, - pub is_location_based: bool, - pub meeting_locations: Vec, - pub mobile_specific_features: Vec, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum MobileFeature { - LocationCheckIn, - VoiceNotes, - PhotoSharing, - QuickPolls, - EmergencyAlerts, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct LocationSharingSettings { - pub enabled: bool, - pub sharing_duration: u64, // Hours - pub trusted_contacts: Vec
, - pub accuracy_level: LocationAccuracy, - pub auto_check_in: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum LocationAccuracy { - Exact, - Approximate, - CityLevel, - Disabled, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct QuickAction { - pub id: u64, - pub name: Bytes, - pub icon: Bytes, - pub action_type: QuickActionType, - pub target_screen: Bytes, - pub parameters: Map, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum QuickActionType { - StartLesson, - JoinStudyGroup, - TakeQuiz, - ViewProgress, - ContactMentor, - ScheduleReminder, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileChallenge { - pub id: u64, - pub title: Bytes, - pub description: Bytes, - pub challenge_type: ChallengeType, - pub requirements: Vec, - pub rewards: ChallengeReward, - pub participants: Vec
, - pub start_date: u64, - pub end_date: u64, - pub is_mobile_specific: bool, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ChallengeType { - DailyStreak, - WeeklyGoal, - SocialLearning, - LocationBased, - SkillMastery, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ChallengeReward { - pub reward_type: MobileRewardType, - pub amount: u64, - pub badge: Option, - pub certificate: Option, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum MobileRewardType { - Points, - Badge, - Certificate, - Discount, - PremiumAccess, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct MobileSocialFeatures { - pub voice_notes_enabled: bool, - pub photo_sharing_enabled: bool, - pub location_checkins_enabled: bool, - pub quick_polls_enabled: bool, - pub emergency_contacts: Vec
, - pub study_buddies: Vec
, - pub mentor_quick_connect: bool, +impl Default for BridgeConfig { + fn default() -> Self { + Self { + fee_rate: constants::fees::DEFAULT_FEE_RATE, + min_confirmations: constants::chains::DEFAULT_MIN_CONFIRMATIONS, + confidence_threshold: constants::oracle::DEFAULT_CONFIDENCE_THRESHOLD, + fallback_enabled: true, + } + } } diff --git a/contracts/teachlink/src/validation.rs b/contracts/teachlink/src/validation.rs index 20f35e4..3d42675 100644 --- a/contracts/teachlink/src/validation.rs +++ b/contracts/teachlink/src/validation.rs @@ -1,448 +1,64 @@ -use crate::errors::EscrowError; -use crate::types::EscrowSigner; -use soroban_sdk::{Address, Bytes, Env, String, Vec}; +//! Input validation helpers used by contract entry points. -/// Validation configuration constants -pub mod config { - pub const MIN_AMOUNT: i128 = 1; - pub const MAX_AMOUNT: i128 = i128::MAX / 2; // Prevent overflow - pub const MIN_SIGNERS: u32 = 1; - pub const MAX_SIGNERS: u32 = 100; - pub const MIN_THRESHOLD: u32 = 1; - pub const MAX_STRING_LENGTH: u32 = 256; - pub const MIN_CHAIN_ID: u32 = 1; - pub const MAX_CHAIN_ID: u32 = 999999; - pub const MAX_ESROW_DESCRIPTION_LENGTH: u32 = 1000; - pub const MIN_TIMEOUT_SECONDS: u64 = 60; // 1 minute minimum - pub const MAX_TIMEOUT_SECONDS: u64 = 31536000 * 10; // 10 years maximum -} - -/// Validation errors -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ValidationError { - InvalidAddressFormat, - BlacklistedAddress, - InvalidAmountRange, - InvalidSignerCount, - InvalidThreshold, - InvalidStringLength, - InvalidChainId, - InvalidTimeout, - EmptySignersList, - DuplicateSigners, - InvalidBytesLength, - InvalidCrossChainData, -} - -/// Result type for validation operations -pub type ValidationResult = core::result::Result; - -/// Address validation utilities -pub struct AddressValidator; - -impl AddressValidator { - /// Validates address format and basic constraints - pub fn validate_format(_env: &Env, _address: &Address) -> ValidationResult<()> { - // In Soroban, Address format is validated at the SDK level - // Additional validation can be added here if needed - // For now, we'll just check that it's not a zero address - Ok(()) - } - - /// Checks if address is blacklisted (placeholder for future implementation) - pub fn check_blacklist(env: &Env, address: &Address) -> ValidationResult<()> { - let blacklist_key = soroban_sdk::symbol_short!("blacklist"); - let blacklist: Vec
= env - .storage() - .instance() - .get(&blacklist_key) - .unwrap_or_else(|| Vec::new(env)); +use soroban_sdk::{Address, Bytes, Env}; - if blacklist.contains(address) { - return Err(ValidationError::BlacklistedAddress); - } - Ok(()) - } +use crate::{ + constants, + errors::{handle_error, TeachLinkError}, + storage::ADMIN, +}; - /// Comprehensive address validation - pub fn validate(env: &Env, address: &Address) -> ValidationResult<()> { - Self::validate_format(env, address)?; - Self::check_blacklist(env, address)?; - Ok(()) +pub fn require_initialized(env: &Env, should_be: bool) { + let is_init = env.storage().instance().get::<_, Address>(&ADMIN).is_some(); + if is_init != should_be { + handle_error(env, TeachLinkError::NotInitialized); } } -/// Numerical validation utilities -pub struct NumberValidator; - -impl NumberValidator { - /// Validates amount within allowed range - pub fn validate_amount(amount: i128) -> ValidationResult<()> { - if amount < config::MIN_AMOUNT { - return Err(ValidationError::InvalidAmountRange); - } - if amount > config::MAX_AMOUNT { - return Err(ValidationError::InvalidAmountRange); - } - Ok(()) - } - - /// Validates signer count - #[allow(clippy::cast_possible_truncation)] - pub fn validate_signer_count(count: usize) -> ValidationResult<()> { - if count == 0 { - return Err(ValidationError::EmptySignersList); - } - if (count as u32) < config::MIN_SIGNERS { - return Err(ValidationError::InvalidSignerCount); - } - if (count as u32) > config::MAX_SIGNERS { - return Err(ValidationError::InvalidSignerCount); - } - Ok(()) - } - - /// Validates threshold against signer count - pub fn validate_threshold(threshold: u32, signer_count: u32) -> ValidationResult<()> { - if threshold < config::MIN_THRESHOLD { - return Err(ValidationError::InvalidThreshold); - } - if threshold > signer_count { - return Err(ValidationError::InvalidThreshold); - } - Ok(()) - } - - /// Validates chain ID - pub fn validate_chain_id(chain_id: u32) -> ValidationResult<()> { - if !(config::MIN_CHAIN_ID..=config::MAX_CHAIN_ID).contains(&chain_id) { - return Err(ValidationError::InvalidChainId); - } - Ok(()) - } +pub fn require_admin(env: &Env) { + let admin: Address = env + .storage() + .instance() + .get(&ADMIN) + .unwrap_or_else(|| handle_error(env, TeachLinkError::NotInitialized)); - /// Validates timeout duration - pub fn validate_timeout(timeout_seconds: u64) -> ValidationResult<()> { - if timeout_seconds < config::MIN_TIMEOUT_SECONDS { - return Err(ValidationError::InvalidTimeout); - } - if timeout_seconds > config::MAX_TIMEOUT_SECONDS { - return Err(ValidationError::InvalidTimeout); - } - Ok(()) + if env.current_contract_address() != admin { + handle_error(env, TeachLinkError::Unauthorized); } } -/// String validation utilities -pub struct StringValidator; - -impl StringValidator { - /// Validates string length - pub fn validate_length(string: &String, max_length: u32) -> ValidationResult<()> { - if string.is_empty() { - return Err(ValidationError::InvalidStringLength); - } - if string.len() > max_length { - return Err(ValidationError::InvalidStringLength); - } - Ok(()) - } - - /// Validates string contains only allowed characters - pub fn validate_characters(string: &String) -> ValidationResult<()> { - // Allow alphanumeric, spaces, and basic punctuation - let string_bytes = string.to_bytes(); - for byte in string_bytes.iter() { - let char = byte as char; - if !char.is_alphanumeric() - && !char.is_whitespace() - && !matches!( - char, - '-' | '_' - | '.' - | ',' - | '!' - | '?' - | '@' - | '#' - | '$' - | '%' - | '&' - | '*' - | '+' - | '=' - | ':' - ) - { - return Err(ValidationError::InvalidStringLength); - } - } - Ok(()) - } - - /// Comprehensive string validation - pub fn validate(string: &String, max_length: u32) -> ValidationResult<()> { - Self::validate_length(string, max_length)?; - Self::validate_characters(string)?; - Ok(()) +pub fn validate_bytes_address(env: &Env, address: &Bytes) { + if address.len() == 0 { + handle_error(env, TeachLinkError::InvalidAddress); } } -/// Bytes validation utilities -pub struct BytesValidator; - -impl BytesValidator { - /// Validates bytes length for cross-chain addresses - pub fn validate_cross_chain_address(bytes: &Bytes) -> ValidationResult<()> { - // Most blockchain addresses are 20-32 bytes - if bytes.len() < 20 || bytes.len() > 32 { - return Err(ValidationError::InvalidBytesLength); - } - Ok(()) - } - - /// Validates bytes for general use - pub fn validate_length(bytes: &Bytes, min_len: u32, max_len: u32) -> ValidationResult<()> { - if bytes.len() < min_len || bytes.len() > max_len { - return Err(ValidationError::InvalidBytesLength); - } - Ok(()) +pub fn validate_amount(env: &Env, amount: &i128) { + if *amount < constants::amounts::MIN_AMOUNT { + handle_error(env, TeachLinkError::InvalidAmount); } } -/// Cross-chain data validation utilities -pub struct CrossChainValidator; - -impl CrossChainValidator { - /// Validates destination chain data - pub fn validate_destination_data( - _env: &Env, - chain_id: u32, - destination_address: &Bytes, - ) -> ValidationResult<()> { - NumberValidator::validate_chain_id(chain_id)?; - BytesValidator::validate_cross_chain_address(destination_address)?; - Ok(()) - } - - /// Validates cross-chain message structure - pub fn validate_cross_chain_message( - env: &Env, - source_chain: u32, - destination_chain: u32, - amount: i128, - recipient: &Address, - ) -> ValidationResult<()> { - NumberValidator::validate_chain_id(source_chain)?; - NumberValidator::validate_chain_id(destination_chain)?; - NumberValidator::validate_amount(amount)?; - AddressValidator::validate(env, recipient)?; - Ok(()) +pub fn validate_chain_id(env: &Env, chain_id: &u32) { + if *chain_id < constants::chains::MIN_CHAIN_ID { + handle_error(env, TeachLinkError::InvalidChainId); } } -/// Escrow-specific validation utilities -pub struct EscrowValidator; - -impl EscrowValidator { - /// Validates escrow creation parameters - pub fn validate_create_escrow( - env: &Env, - depositor: &Address, - beneficiary: &Address, - token: &Address, - amount: i128, - signers: &Vec, - threshold: u32, - release_time: Option, - refund_time: Option, - arbitrator: &Address, - ) -> Result<(), EscrowError> { - // Validate addresses - AddressValidator::validate(env, depositor) - .map_err(|_| EscrowError::AmountMustBePositive)?; - AddressValidator::validate(env, beneficiary) - .map_err(|_| EscrowError::AmountMustBePositive)?; - AddressValidator::validate(env, token).map_err(|_| EscrowError::AmountMustBePositive)?; - AddressValidator::validate(env, arbitrator) - .map_err(|_| EscrowError::AmountMustBePositive)?; - - // Validate amount - NumberValidator::validate_amount(amount).map_err(|_| EscrowError::AmountMustBePositive)?; - - // Validate signers - NumberValidator::validate_signer_count(signers.len() as usize) - .map_err(|_| EscrowError::AtLeastOneSignerRequired)?; - - let mut total_weight: u32 = 0; - for signer in signers.iter() { - total_weight += signer.weight; - } - - if threshold < 1 || threshold > total_weight { - return Err(EscrowError::InvalidSignerThreshold); - } - - // Validate time constraints - if let (Some(release), Some(refund)) = (release_time, refund_time) { - if refund <= release { - return Err(EscrowError::RefundTimeMustBeAfterReleaseTime); - } - } - - // Check for duplicate signers - Self::check_duplicate_signers(signers)?; - - Ok(()) - } - - /// Checks for duplicate signers in the list - pub fn check_duplicate_signers(signers: &Vec) -> Result<(), EscrowError> { - let mut seen = soroban_sdk::Map::new(&signers.env()); - for signer in signers.iter() { - if seen.get(signer.address.clone()).unwrap_or(false) { - return Err(EscrowError::DuplicateSigner); - } - seen.set(signer.address.clone(), true); - } - Ok(()) - } - - /// Validates escrow release conditions - pub fn validate_release_conditions( - escrow: &crate::types::Escrow, - caller: &Address, - current_time: u64, - ) -> Result<(), EscrowError> { - if escrow.status != crate::types::EscrowStatus::Pending { - return Err(EscrowError::EscrowNotPending); - } - - if !Self::is_authorized_caller(escrow, caller) { - return Err(EscrowError::CallerNotAuthorized); - } - - if escrow.approval_count < escrow.threshold { - return Err(EscrowError::InsufficientApprovals); - } - - if let Some(release_time) = escrow.release_time { - if current_time < release_time { - return Err(EscrowError::ReleaseTimeNotReached); - } - } - - Ok(()) - } - - /// Checks if caller is authorized to release escrow - pub fn is_authorized_caller(escrow: &crate::types::Escrow, caller: &Address) -> bool { - if caller.clone() == escrow.depositor || caller.clone() == escrow.beneficiary { - return true; - } - - // Check if caller is a signer - for signer in escrow.signers.iter() { - if signer.address == caller.clone() { - return true; - } - } - - false +pub fn validate_fee_rate(env: &Env, fee_rate: &u32) { + if *fee_rate > constants::fees::MAX_FEE_RATE { + handle_error(env, TeachLinkError::FeeTooHigh); } } -/// Bridge-specific validation utilities -pub struct BridgeValidator; - -impl BridgeValidator { - /// Validates bridge out parameters - pub fn validate_bridge_out( - env: &Env, - from: &Address, - amount: i128, - destination_chain: u32, - destination_address: &Bytes, - ) -> Result<(), crate::errors::BridgeError> { - // Validate addresses - AddressValidator::validate(env, from) - .map_err(|_| crate::errors::BridgeError::AmountMustBePositive)?; - - // Validate amount - NumberValidator::validate_amount(amount) - .map_err(|_| crate::errors::BridgeError::AmountMustBePositive)?; - - // Validate cross-chain data - CrossChainValidator::validate_destination_data(env, destination_chain, destination_address) - .map_err(|_| crate::errors::BridgeError::DestinationChainNotSupported)?; - - Ok(()) - } - - /// Validates bridge completion parameters - pub fn validate_bridge_completion( - env: &Env, - message: &crate::types::CrossChainMessage, - validator_signatures: &Vec
, - min_validators: u32, - ) -> Result<(), crate::errors::BridgeError> { - // Validate validator signatures count - if validator_signatures.len() < min_validators { - return Err(crate::errors::BridgeError::InsufficientValidatorSignatures); - } - - // Validate cross-chain message - CrossChainValidator::validate_cross_chain_message( - env, - message.source_chain, - message.destination_chain, - message.amount, - &message.recipient, - ) - .map_err(|_| crate::errors::BridgeError::TokenMismatch)?; - - Ok(()) +pub fn validate_price(env: &Env, price: &i128) { + if *price <= 0 { + handle_error(env, TeachLinkError::InvalidPrice); } } -/// Rewards-specific validation utilities -pub struct RewardsValidator; - -impl RewardsValidator { - /// Validates reward issuance parameters - pub fn validate_reward_issuance( - env: &Env, - recipient: &Address, - amount: i128, - reward_type: &String, - ) -> Result<(), crate::errors::RewardsError> { - // Validate addresses - AddressValidator::validate(env, recipient) - .map_err(|_| crate::errors::RewardsError::AmountMustBePositive)?; - - // Validate amount - NumberValidator::validate_amount(amount) - .map_err(|_| crate::errors::RewardsError::AmountMustBePositive)?; - - // Validate reward type string - StringValidator::validate(reward_type, config::MAX_STRING_LENGTH) - .map_err(|_| crate::errors::RewardsError::AmountMustBePositive)?; - - Ok(()) - } - - /// Validates reward pool funding - pub fn validate_pool_funding( - env: &Env, - funder: &Address, - amount: i128, - ) -> Result<(), crate::errors::RewardsError> { - AddressValidator::validate(env, funder) - .map_err(|_| crate::errors::RewardsError::AmountMustBePositive)?; - - NumberValidator::validate_amount(amount) - .map_err(|_| crate::errors::RewardsError::AmountMustBePositive)?; - - Ok(()) +pub fn validate_confidence(env: &Env, confidence: &u32) { + if *confidence > constants::oracle::MAX_CONFIDENCE { + handle_error(env, TeachLinkError::InvalidConfidence); } }