From fbcb2085bc845eb114c0a14bd0fda1e50ea101d9 Mon Sep 17 00:00:00 2001 From: Timi Date: Sun, 26 Apr 2026 06:44:45 +0100 Subject: [PATCH 1/4] refactor: remove dead code and commented-out tests from escrow and event modules --- contracts/teachlink/src/errors.rs | 15 ---- contracts/teachlink/src/events.rs | 16 +--- .../src/repository/escrow_repository.rs | 78 ------------------- contracts/teachlink/src/repository/mod.rs | 5 -- 4 files changed, 2 insertions(+), 112 deletions(-) diff --git a/contracts/teachlink/src/errors.rs b/contracts/teachlink/src/errors.rs index c351b6ee..2e04a96f 100644 --- a/contracts/teachlink/src/errors.rs +++ b/contracts/teachlink/src/errors.rs @@ -138,18 +138,3 @@ pub enum CommonError { StorageError = 404, } -/// 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/events.rs b/contracts/teachlink/src/events.rs index 3ad0148b..4d76059b 100644 --- a/contracts/teachlink/src/events.rs +++ b/contracts/teachlink/src/events.rs @@ -2,13 +2,10 @@ use soroban_sdk::contractevent; use crate::types::{ BridgeTransaction, ContentMetadata, ContributionType, CrossChainMessage, DisputeOutcome, - Escrow, EscrowStatus, OperationType, PacketStatus, ProposalStatus, ProvenanceRecord, - RewardType, SlashingReason, SwapStatus, + Escrow, EscrowStatus, OperationType, ProposalStatus, ProvenanceRecord, RewardType, + SlashingReason, }; -// Include notification events -// pub use crate::notification_events::*; - use soroban_sdk::{Address, Bytes, String}; // ================= Bridge Events ================= @@ -345,15 +342,6 @@ pub struct AuditRecordCreatedEvent { pub timestamp: u64, } -// #[contractevent] -// #[derive(Clone, Debug)] -// pub struct ComplianceReportGeneratedEvent { -// pub report_id: u64, -// pub period_start: u64, -// pub period_end: u64, -// pub total_volume: i128, -// } - // ================= Atomic Swap Events ================= #[contractevent] diff --git a/contracts/teachlink/src/repository/escrow_repository.rs b/contracts/teachlink/src/repository/escrow_repository.rs index 741a14c0..ef9a8bda 100644 --- a/contracts/teachlink/src/repository/escrow_repository.rs +++ b/contracts/teachlink/src/repository/escrow_repository.rs @@ -147,81 +147,3 @@ impl<'a> EscrowAggregateRepository<'a> { } } -// #[cfg(test)] -// mod tests { // Removed - tests require env.as_contract() wrapper -// use super::*; -// use crate::types::EscrowSigner; -// use soroban_sdk::testutils::Address as _; -// -// #[test] -// fn test_escrow_repository_create_and_get() { -// let env = Env::default(); -// let repo = EscrowRepository::new(&env); -// -// let depositor = Address::generate(&env); -// let beneficiary = Address::generate(&env); -// let token = Address::generate(&env); -// -// let escrow = Escrow { -// id: 1, -// depositor: depositor.clone(), -// beneficiary: beneficiary.clone(), -// token: token.clone(), -// amount: 1000, -// signers: soroban_sdk::Vec::new(&env), -// threshold: 1, -// approval_count: 0, -// release_time: None, -// refund_time: None, -// arbitrator: depositor.clone(), -// status: crate::types::EscrowStatus::Pending, -// created_at: env.ledger().timestamp(), -// dispute_reason: None, -// }; -// -// repo.save_escrow(&escrow).expect("Should save escrow"); -// -// let retrieved = repo.get_escrow(1); -// assert!(retrieved.is_some()); -// assert_eq!(retrieved.unwrap().amount, 1000); -// } -// -// #[test] -// fn test_escrow_repository_counter() { -// let env = Env::default(); -// let repo = EscrowRepository::new(&env); -// -// let initial_count = repo.get_count().expect("Should get count"); -// let next_id = repo.get_next_id().expect("Should get next ID"); -// -// assert_eq!(initial_count, 0); -// assert_eq!(next_id, 1); -// -// let second_id = repo.get_next_id().expect("Should get second ID"); -// assert_eq!(second_id, 2); -// } -// -// #[test] -// fn test_approval_repository() { -// let env = Env::default(); -// let escrow_repo = EscrowRepository::new(&env); -// let approval_repo = EscrowApprovalRepository::new(&env); -// -// let signer = Address::generate(&env); -// let escrow_id = 1u64; -// -// let key = EscrowApprovalKey { -// escrow_id, -// signer: signer.clone(), -// }; -// -// // Initially should not be approved -// assert!(!approval_repo.has_approved(&key)); -// -// // Approve -// approval_repo.approve(&key).expect("Should approve"); -// -// // Now should be approved -// assert!(approval_repo.has_approved(&key)); -// } -// } diff --git a/contracts/teachlink/src/repository/mod.rs b/contracts/teachlink/src/repository/mod.rs index 010546ac..090edfbe 100644 --- a/contracts/teachlink/src/repository/mod.rs +++ b/contracts/teachlink/src/repository/mod.rs @@ -11,10 +11,6 @@ pub mod bridge_repository; pub mod escrow_repository; pub mod generic; pub mod traits; -// pub mod facade; // Removed - broken tests - -// #[cfg(test)] -// mod tests; // Removed - broken tests // Re-export for convenience pub use bridge_repository::{ @@ -31,4 +27,3 @@ pub use traits::{ CounterRepository, InstanceStorage, MapRepository, PersistentStorage, StorageError, TemporaryStorage, }; -// pub use facade::{StorageFacade, StorageBuilder}; // Removed - broken tests From cd134e34e989828b15588c22fbfb8dd33258eeca Mon Sep 17 00:00:00 2001 From: Timi Date: Sun, 26 Apr 2026 07:14:41 +0100 Subject: [PATCH 2/4] refactor: remove dead code and commented-out event structures from notification_events and provenance modules --- PR_DESCRIPTION.md | 108 -------------- .../teachlink/src/notification_events.rs | 132 ------------------ contracts/teachlink/src/provenance.rs | 31 ---- 3 files changed, 271 deletions(-) delete mode 100644 PR_DESCRIPTION.md diff --git a/PR_DESCRIPTION.md b/PR_DESCRIPTION.md deleted file mode 100644 index 3c651462..00000000 --- a/PR_DESCRIPTION.md +++ /dev/null @@ -1,108 +0,0 @@ -# Summary - -This PR implements 4 critical tasks to enhance the security and reliability of the TeachLink contract system. - -## Tasks Completed - -### Task 1: Rewards Overflow Protection (Critical) -**Files Modified:** `contracts/teachlink/src/rewards.rs`, `contracts/teachlink/src/errors.rs` - -**Changes:** -- Added checked arithmetic operations to prevent overflow -- Implemented input validation with MAX_REWARD_AMOUNT constant (i128::MAX / 2) -- Added ArithmeticOverflow and AmountExceedsMaxLimit error types -- All reward calculations now handle overflow gracefully -- Added comprehensive test cases for overflow detection - -**Impact:** Prevents incorrect reward distribution due to integer overflow with large values. - ---- - -### Task 2: Event Queue Memory Leak Fix -**Files Modified:** `contracts/teachlink/src/notification.rs`, `contracts/teachlink/src/storage.rs` - -**Changes:** -- Added TTL (Time-To-Live) mechanism with 7-day default for notification events -- Implemented queue size limits (10,000 events maximum) -- Added automatic cleanup of expired events with configurable intervals (1 hour) -- Events now stored with timestamps -- Added cleanup_expired_events(), get_queue_stats(), and update_ttl_config() functions -- Automatic cleanup triggered when queue reaches capacity - -**Impact:** Prevents unbounded memory growth from processed events accumulating indefinitely. - ---- - -### Task 3: Contract Upgrade Mechanism -**Files Created:** `contracts/teachlink/src/upgrade.rs` -**Files Modified:** `contracts/teachlink/src/lib.rs` - -**Changes:** -- Created comprehensive upgrade system with state preservation -- Version tracking with complete upgrade history -- Automated state backup before upgrades -- Rollback support within 30-day window -- Admin-controlled upgrade process with validation -- Added 7 new public functions for upgrade management - -**Impact:** Enables safe contract upgrades without losing state, with rollback capability. - ---- - -### Task 4: Network Failure Recovery -**Files Created:** `contracts/teachlink/src/network_recovery.rs` -**Files Modified:** `contracts/teachlink/src/lib.rs` - -**Changes:** -- Implemented retry logic with exponential backoff (1min to 1hr max) -- State preservation for failed operations -- User notification system for retry attempts -- Fallback mechanisms when max retries (5) exceeded -- Configurable retry parameters -- Circuit breaker pattern support -- Added 6 new public functions for recovery management - -**Impact:** Transforms hard errors into graceful recovery with automatic retries and user notifications. - ---- - -## Testing - -All modules include comprehensive unit tests: -- Overflow protection tests -- Retry logic and backoff tests -- Upgrade lifecycle tests -- Rollback window tests - -## Acceptance Criteria Met - -### Task 1: -- [x] Add checked arithmetic operations -- [x] Validate input ranges -- [x] Handle overflow gracefully -- [x] Add overflow test cases - -### Task 2: -- [x] Remove processed events from queue -- [x] Implement queue size limits -- [x] Add TTL for events - -### Task 3: -- [x] Preserve state during upgrades -- [x] Track versions -- [x] Automate migration -- [x] Support rollback - -### Task 4: -- [x] Add retry logic -- [x] Preserve state -- [x] Notify users -- [x] Implement fallback mechanisms - -## Breaking Changes -None - All changes are additive and backward compatible. - -## Migration Notes -- Existing notification logs will be migrated to new format with timestamps on next write -- Upgrade system initializes at version 1 -- Recovery system uses default configuration (can be customized by admin) diff --git a/contracts/teachlink/src/notification_events.rs b/contracts/teachlink/src/notification_events.rs index 0ab617fa..d797bfeb 100644 --- a/contracts/teachlink/src/notification_events.rs +++ b/contracts/teachlink/src/notification_events.rs @@ -227,135 +227,3 @@ pub struct NotificationThrottlingActivatedEvent { pub activated_at: u64, } -// Events exceeding 32 character limit commented out -/* -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationValidationFailedEvent { - pub notification_id: u64, - pub validation_errors: Vec, - pub failed_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationDeliveryOptimizedEvent { - pub notification_id: u64, - pub original_channel: NotificationChannel, - pub optimized_channel: NotificationChannel, - pub optimization_reason: Bytes, - pub optimized_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationUserPreferencesMigratedEvent { - pub user: Address, - pub old_preferences: Vec, - pub new_preferences: Vec, - pub migrated_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationSystemInitializedEvent { - pub initialized_by: Address, - pub default_templates: Vec, - pub initialized_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationConfigurationUpdatedEvent { - pub config_type: Bytes, // "rate_limits", "compliance", "templates", etc. - pub updated_by: Address, - pub old_config: Bytes, - pub new_config: Bytes, - pub updated_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationEmergencyModeActivatedEvent { - pub activated_by: Address, - pub reason: Bytes, - pub affected_channels: Vec, - pub activated_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationEmergencyModeDeactivatedEvent { - pub deactivated_by: Address, - pub deactivated_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationBatchCreatedEvent { - pub batch_id: u64, - pub notification_count: u32, - pub channels: Vec, - pub created_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationDeliveryRetryEvent { - pub notification_id: u64, - pub retry_attempt: u32, - pub max_retries: u32, - pub retry_reason: Bytes, - pub scheduled_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationUserActivityTrackedEvent { - pub user: Address, - pub activity_type: Bytes, // "login", "transaction", "profile_update", etc. - pub timestamp: u64, - pub metadata: Bytes, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationContentRenderedEvent { - pub notification_id: u64, - pub template_id: u64, - pub user: Address, - pub render_time_ms: u32, - pub rendered_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationLocalizationAppliedEvent { - pub notification_id: u64, - pub language_code: Bytes, - pub original_subject: Bytes, - pub localized_subject: Bytes, - pub applied_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationFeedbackReceivedEvent { - pub notification_id: u64, - pub user: Address, - pub feedback_type: u32, // 0=positive, 1=negative, 2=neutral - pub feedback_message: Bytes, - pub received_at: u64, -} - -#[contractevent] -#[derive(Clone, Debug)] -pub struct NotificationPerformanceReportedEvent { - pub period_start: u64, - pub period_end: u64, - pub total_notifications: u64, - pub delivery_rate: u32, - pub engagement_rate: u32, - pub reported_at: u64, -} -*/ diff --git a/contracts/teachlink/src/provenance.rs b/contracts/teachlink/src/provenance.rs index cfa71e84..d9982669 100644 --- a/contracts/teachlink/src/provenance.rs +++ b/contracts/teachlink/src/provenance.rs @@ -110,35 +110,4 @@ impl ProvenanceTracker { true } - /// Get the original creator of a token - #[allow(dead_code)] - pub fn get_creator(env: &Env, token_id: u64) -> Option
{ - let history = Self::get_provenance(env, token_id); - if history.is_empty() { - return None; - } - - let first = history.first().unwrap(); - if first.transfer_type == TransferType::Mint { - Some(first.to) - } else { - None - } - } - - /// Get all addresses that have owned this token - #[allow(dead_code)] - pub fn get_all_owners(env: &Env, token_id: u64) -> Vec
{ - let history = Self::get_provenance(env, token_id); - let mut owners = Vec::new(env); - - for record in history.iter() { - // Add the 'to' address (new owner) - if !owners.contains(record.to.clone()) { - owners.push_back(record.to); - } - } - - owners - } } From 4bbbe22f4bd94617bea928fcac20bf35bb0e44de Mon Sep 17 00:00:00 2001 From: Timi Date: Sun, 26 Apr 2026 07:36:06 +0100 Subject: [PATCH 3/4] refactor: enforce caller authentication in role management functions --- contracts/teachlink/src/access_control.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/teachlink/src/access_control.rs b/contracts/teachlink/src/access_control.rs index d9d91ad9..f1a086ff 100644 --- a/contracts/teachlink/src/access_control.rs +++ b/contracts/teachlink/src/access_control.rs @@ -36,7 +36,6 @@ impl AccessControlManager { /// Enforce a role check, panicking if unauthorized pub fn check_role(env: &Env, address: &Address, role: AccessRole) { - address.require_auth(); if !Self::has_role(env, address, role) { panic!("Unauthorized: Missing required role"); } @@ -49,6 +48,7 @@ impl AccessControlManager { target: Address, role: AccessRole, ) -> Result<(), BridgeError> { + caller.require_auth(); // Only Admin can grant roles Self::check_role(env, &caller, AccessRole::Admin); @@ -88,6 +88,7 @@ impl AccessControlManager { target: Address, role: AccessRole, ) -> Result<(), BridgeError> { + caller.require_auth(); Self::check_role(env, &caller, AccessRole::Admin); let mut roles: Map> = env From 9921154540f7a4aeb11eef18f524e281319c7bf1 Mon Sep 17 00:00:00 2001 From: Timi Date: Sun, 26 Apr 2026 07:41:22 +0100 Subject: [PATCH 4/4] fix: apply rust formatting --- contracts/teachlink/src/errors.rs | 1 - contracts/teachlink/src/provenance.rs | 1 - contracts/teachlink/src/repository/escrow_repository.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/contracts/teachlink/src/errors.rs b/contracts/teachlink/src/errors.rs index 2e04a96f..74752ceb 100644 --- a/contracts/teachlink/src/errors.rs +++ b/contracts/teachlink/src/errors.rs @@ -137,4 +137,3 @@ pub enum CommonError { TransferFailed = 403, StorageError = 404, } - diff --git a/contracts/teachlink/src/provenance.rs b/contracts/teachlink/src/provenance.rs index d9982669..5682b2eb 100644 --- a/contracts/teachlink/src/provenance.rs +++ b/contracts/teachlink/src/provenance.rs @@ -109,5 +109,4 @@ impl ProvenanceTracker { true } - } diff --git a/contracts/teachlink/src/repository/escrow_repository.rs b/contracts/teachlink/src/repository/escrow_repository.rs index ef9a8bda..3bd416d5 100644 --- a/contracts/teachlink/src/repository/escrow_repository.rs +++ b/contracts/teachlink/src/repository/escrow_repository.rs @@ -146,4 +146,3 @@ impl<'a> EscrowAggregateRepository<'a> { } } } -