From b79a6ef07cf62edf2d55fca22ff5bf5520ba3733 Mon Sep 17 00:00:00 2001 From: tali-creator Date: Tue, 24 Mar 2026 16:12:58 +0100 Subject: [PATCH 1/5] feature: Audit Log Service --- .../20260324160000_extend_action_logs.sql | 13 +++++ backend/src/auth.rs | 10 ++-- backend/src/compliance.rs | 4 ++ backend/src/interest_reconciliation.rs | 6 ++- backend/src/liquidation_bot.rs | 4 ++ backend/src/loan_lifecycle.rs | 12 +++++ backend/src/notifications.rs | 53 ++++++++++++++++--- backend/src/price_feed_handlers.rs | 29 ++++++++++ backend/src/risk_engine.rs | 4 ++ backend/src/service.rs | 34 +++++++++++- 10 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 backend/migrations/20260324160000_extend_action_logs.sql diff --git a/backend/migrations/20260324160000_extend_action_logs.sql b/backend/migrations/20260324160000_extend_action_logs.sql new file mode 100644 index 0000000..89ce48d --- /dev/null +++ b/backend/migrations/20260324160000_extend_action_logs.sql @@ -0,0 +1,13 @@ +-- Extend action_logs table for detailed audit logging +-- Add admin_id for admin-specific actions +ALTER TABLE action_logs ADD COLUMN IF NOT EXISTS admin_id UUID REFERENCES admins(id) ON DELETE SET NULL; + +-- Add value tracking for parameter updates +ALTER TABLE action_logs ADD COLUMN IF NOT EXISTS old_value TEXT; +ALTER TABLE action_logs ADD COLUMN IF NOT EXISTS new_value TEXT; + +-- Add metadata for additional context +ALTER TABLE action_logs ADD COLUMN IF NOT EXISTS metadata JSONB; + +-- Create index for admin_id +CREATE INDEX IF NOT EXISTS idx_action_logs_admin_id ON action_logs(admin_id); diff --git a/backend/src/auth.rs b/backend/src/auth.rs index 5255802..3a03238 100644 --- a/backend/src/auth.rs +++ b/backend/src/auth.rs @@ -1,7 +1,7 @@ use crate::api_error::ApiError; use crate::app::AppState; use crate::config::Config; -use crate::notifications::AuditLogService; +use crate::notifications::{audit_action, entity_type, AuditLogService}; use axum::{extract::State, Json}; use bcrypt::verify; use chrono::{DateTime, Duration, Utc}; @@ -385,9 +385,13 @@ pub async fn send_2fa( AuditLogService::log( &state.db, Some(payload.user_id), - "2fa_sent", + None, + audit_action::TWO_FA_SENT, Some(payload.user_id), - Some("user"), + Some(entity_type::USER), + None, + None, + None, ) .await?; diff --git a/backend/src/compliance.rs b/backend/src/compliance.rs index 0cf0c34..12e7aa4 100644 --- a/backend/src/compliance.rs +++ b/backend/src/compliance.rs @@ -216,9 +216,13 @@ impl ComplianceEngine { AuditLogService::log( &mut *tx, Some(user_id), + None, audit_action::SUSPICIOUS_BORROWING_DETECTED, Some(plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; diff --git a/backend/src/interest_reconciliation.rs b/backend/src/interest_reconciliation.rs index d890a5d..10eb357 100644 --- a/backend/src/interest_reconciliation.rs +++ b/backend/src/interest_reconciliation.rs @@ -91,10 +91,14 @@ impl InterestReconciliationService { // Log discrepancy to audit logs AuditLogService::log( &mut *tx, - None, // System action + None, + None, "yield_discrepancy_detected", None, Some("system"), + None, + None, + None, ) .await?; diff --git a/backend/src/liquidation_bot.rs b/backend/src/liquidation_bot.rs index 89fc8e5..33c1d4c 100644 --- a/backend/src/liquidation_bot.rs +++ b/backend/src/liquidation_bot.rs @@ -151,9 +151,13 @@ impl LiquidationBotService { AuditLogService::log( &mut *tx, Some(loan.user_id), + None, // Not an admin action in the traditional sense, but we can track it audit_action::LIQUIDATION_WARNING, // fallback Some(loan.plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; diff --git a/backend/src/loan_lifecycle.rs b/backend/src/loan_lifecycle.rs index 977c2da..539ea0c 100644 --- a/backend/src/loan_lifecycle.rs +++ b/backend/src/loan_lifecycle.rs @@ -393,9 +393,13 @@ impl LoanLifecycleService { AuditLogService::log( &mut *tx, Some(req.user_id), + None, audit_action::LOAN_CREATED, Some(record.id), Some(entity_type::LOAN), + None, + None, + None, ) .await?; @@ -475,6 +479,7 @@ impl LoanLifecycleService { AuditLogService::log( &mut *tx, Some(user_id), + None, if fully_repaid { audit_action::LOAN_REPAID } else { @@ -482,6 +487,9 @@ impl LoanLifecycleService { }, Some(loan_id), Some(entity_type::LOAN), + None, + None, + None, ) .await?; @@ -540,10 +548,14 @@ impl LoanLifecycleService { AuditLogService::log( &mut *tx, + None, Some(admin_id), audit_action::LOAN_LIQUIDATED, Some(loan_id), Some(entity_type::LOAN), + None, + None, + None, ) .await?; diff --git a/backend/src/notifications.rs b/backend/src/notifications.rs index 9ea9b9f..82e2cef 100644 --- a/backend/src/notifications.rs +++ b/backend/src/notifications.rs @@ -170,6 +170,9 @@ pub mod audit_action { pub const LOAN_PARTIAL_REPAYMENT: &str = "loan_partial_repayment"; pub const LOAN_LIQUIDATED: &str = "loan_liquidated"; pub const LOAN_MARKED_OVERDUE: &str = "loan_marked_overdue"; + // Admin & System + pub const EMERGENCY_STOP: &str = "emergency_stop"; + pub const PARAMETER_UPDATE: &str = "parameter_update"; } /// Entity type constants — stored in `entity_type` column of `action_logs`. @@ -183,9 +186,13 @@ pub mod entity_type { pub struct ActionLog { pub id: Uuid, pub user_id: Option, + pub admin_id: Option, pub action: String, pub entity_id: Option, pub entity_type: Option, + pub old_value: Option, + pub new_value: Option, + pub metadata: Option, pub timestamp: DateTime, } @@ -193,25 +200,34 @@ pub struct AuditLogService; impl AuditLogService { pub async fn log( - // Use an executor that can be a Pool or a Transaction executor: impl sqlx::PgExecutor<'_>, user_id: Option, + admin_id: Option, action: &str, entity_id: Option, entity_type: Option<&str>, + old_value: Option<&str>, + new_value: Option<&str>, + metadata: Option, ) -> Result<(), ApiError> { - // Return Result instead of () sqlx::query( r#" - INSERT INTO action_logs (user_id, action, entity_id, entity_type) - VALUES ($1, $2, $3, $4) + INSERT INTO action_logs ( + user_id, admin_id, action, entity_id, entity_type, + old_value, new_value, metadata + ) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) "#, ) .bind(user_id) + .bind(admin_id) .bind(action) .bind(entity_id) .bind(entity_type) - .execute(executor) // Execute on the provided transaction/pool + .bind(old_value) + .bind(new_value) + .bind(metadata) + .execute(executor) .await?; Ok(()) @@ -220,7 +236,8 @@ impl AuditLogService { pub async fn list_all(db: &PgPool) -> Result, ApiError> { let rows = sqlx::query_as::<_, ActionLog>( r#" - SELECT id, user_id, action, entity_id, entity_type, timestamp + SELECT id, user_id, admin_id, action, entity_id, entity_type, + old_value, new_value, metadata, timestamp FROM action_logs ORDER BY timestamp DESC "#, @@ -239,7 +256,8 @@ impl AuditLogService { let offset = ((page.saturating_sub(1)) as i64) * (limit as i64); let rows = sqlx::query_as::<_, ActionLog>( r#" - SELECT id, user_id, action, entity_id, entity_type, timestamp + SELECT id, user_id, admin_id, action, entity_id, entity_type, + old_value, new_value, metadata, timestamp FROM action_logs ORDER BY timestamp DESC LIMIT $1 OFFSET $2 @@ -270,7 +288,8 @@ impl AuditLogService { pub async fn list_for_user(db: &PgPool, user_id: Uuid) -> Result, ApiError> { let rows = sqlx::query_as::<_, ActionLog>( r#" - SELECT id, user_id, action, entity_id, entity_type, timestamp + SELECT id, user_id, admin_id, action, entity_id, entity_type, + old_value, new_value, metadata, timestamp FROM action_logs WHERE user_id = $1 ORDER BY timestamp DESC @@ -282,6 +301,24 @@ impl AuditLogService { Ok(rows) } + + /// Return audit log entries for a specific admin, newest first. + pub async fn list_for_admin(db: &PgPool, admin_id: Uuid) -> Result, ApiError> { + let rows = sqlx::query_as::<_, ActionLog>( + r#" + SELECT id, user_id, admin_id, action, entity_id, entity_type, + old_value, new_value, metadata, timestamp + FROM action_logs + WHERE admin_id = $1 + ORDER BY timestamp DESC + "#, + ) + .bind(admin_id) + .fetch_all(db) + .await?; + + Ok(rows) + } } // ─── Tests ─────────────────────────────────────────────────────────────────── diff --git a/backend/src/price_feed_handlers.rs b/backend/src/price_feed_handlers.rs index 206537a..8c77a51 100644 --- a/backend/src/price_feed_handlers.rs +++ b/backend/src/price_feed_handlers.rs @@ -10,6 +10,7 @@ use sqlx::PgPool; use std::str::FromStr; use std::sync::Arc; use tracing; +use crate::notifications::AuditLogService; use uuid::Uuid; #[derive(Debug, Serialize, Deserialize)] @@ -130,6 +131,20 @@ pub async fn register_price_feed( .register_feed(&req.asset_code, source, &req.feed_id) .await?; + // Audit Log + AuditLogService::log( + &(_db), + None, + Some(_admin.admin_id), + crate::notifications::audit_action::PARAMETER_UPDATE, + None, + Some("price_feed"), + None, + Some(&format!("{}: {}/{}", req.asset_code, req.source, req.feed_id)), + None, + ) + .await?; + Ok(Json(json!({ "status": "success", "message": format!("Price feed registered for {}", req.asset_code), @@ -158,6 +173,20 @@ pub async fn update_price( let asset_price = price_service.update_price(&asset_code, req.price).await?; + // Audit Log + AuditLogService::log( + &(_db), + None, + Some(_admin.admin_id), + crate::notifications::audit_action::PARAMETER_UPDATE, + None, + Some("price"), + None, + Some(&req.price.to_string()), + None, + ) + .await?; + Ok(Json(json!({ "status": "success", "message": format!("Price updated for {}", asset_code), diff --git a/backend/src/risk_engine.rs b/backend/src/risk_engine.rs index 7199574..a66840d 100644 --- a/backend/src/risk_engine.rs +++ b/backend/src/risk_engine.rs @@ -156,9 +156,13 @@ impl RiskEngine { AuditLogService::log( &mut *tx, Some(loan.user_id), + None, audit_action::LIQUIDATION_WARNING, Some(loan.plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; diff --git a/backend/src/service.rs b/backend/src/service.rs index 844ecc5..00bedcb 100644 --- a/backend/src/service.rs +++ b/backend/src/service.rs @@ -264,11 +264,15 @@ impl PlanService { // 3. Audit: This must now return Result and use the transaction AuditLogService::log( - &mut *tx, // Pass the transaction + &mut *tx, Some(user_id), + None, audit_action::PLAN_CREATED, Some(plan.id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; // If this fails, '?' triggers an early return @@ -451,9 +455,13 @@ impl PlanService { AuditLogService::log( &mut *tx, Some(user_id), + None, audit_action::PLAN_CLAIMED, Some(plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; @@ -827,9 +835,13 @@ impl PlanService { AuditLogService::log( &mut *tx, Some(user_id), + None, audit_action::PLAN_DEACTIVATED, Some(plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; @@ -916,9 +928,13 @@ impl KycService { AuditLogService::log( &mut *tx, // Re-borrow here as well Some(user_id), + None, audit_action::KYC_SUBMITTED, Some(user_id), Some(entity_type::USER), + None, + None, + None, ) .await?; @@ -986,6 +1002,7 @@ impl KycService { // Audit log is now ATOMIC AuditLogService::log( &mut *tx, + None, Some(admin_id), if record.status == "approved" { audit_action::KYC_APPROVED @@ -994,6 +1011,9 @@ impl KycService { }, Some(user_id), Some(entity_type::USER), + None, + None, + None, ) .await?; @@ -2488,10 +2508,14 @@ impl EmergencyAdminService { // Audit log AuditLogService::log( &mut *tx, + None, Some(admin_id), audit_action::PLAN_PAUSED, Some(req.plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; @@ -2559,10 +2583,14 @@ impl EmergencyAdminService { // Audit log AuditLogService::log( &mut *tx, + None, Some(admin_id), audit_action::PLAN_UNPAUSED, Some(req.plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; @@ -2650,10 +2678,14 @@ impl EmergencyAdminService { // Audit log AuditLogService::log( &mut *tx, + None, Some(admin_id), action_type, Some(req.plan_id), Some(entity_type::PLAN), + None, + None, + None, ) .await?; From 4ad5fc447693bec8aa7386f77f7711d40fc760f7 Mon Sep 17 00:00:00 2001 From: tali-creator Date: Tue, 24 Mar 2026 16:22:26 +0100 Subject: [PATCH 2/5] feature: Audit Log Service --- backend/src/price_feed_handlers.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/src/price_feed_handlers.rs b/backend/src/price_feed_handlers.rs index 8c77a51..3aaf22c 100644 --- a/backend/src/price_feed_handlers.rs +++ b/backend/src/price_feed_handlers.rs @@ -1,5 +1,6 @@ use crate::api_error::ApiError; use crate::auth::AuthenticatedAdmin; +use crate::notifications::AuditLogService; use crate::price_feed::{PriceFeedService, PriceFeedSource}; use axum::extract::{Path, State}; use axum::Json; @@ -10,7 +11,6 @@ use sqlx::PgPool; use std::str::FromStr; use std::sync::Arc; use tracing; -use crate::notifications::AuditLogService; use uuid::Uuid; #[derive(Debug, Serialize, Deserialize)] @@ -140,7 +140,10 @@ pub async fn register_price_feed( None, Some("price_feed"), None, - Some(&format!("{}: {}/{}", req.asset_code, req.source, req.feed_id)), + Some(&format!( + "{}: {}/{}", + req.asset_code, req.source, req.feed_id + )), None, ) .await?; From e10d8dd75b2076f913248bd250359414d2d19583 Mon Sep 17 00:00:00 2001 From: tali-creator Date: Sun, 29 Mar 2026 00:05:38 +0100 Subject: [PATCH 3/5] fix/conflict --- backend/src/app.rs | 12 ++--- backend/src/auth.rs | 4 +- backend/src/compliance.rs | 2 +- backend/src/event_handlers.rs | 5 +- backend/src/events.rs | 12 ++--- backend/src/interest_reconciliation.rs | 6 +-- backend/src/notifications.rs | 14 +++-- backend/src/price_feed.rs | 4 +- backend/src/price_feed_handlers.rs | 2 +- backend/src/reputation.rs | 4 +- backend/src/risk_engine.rs | 8 +-- backend/src/safe_math.rs | 21 +++----- backend/src/service.rs | 29 +++++----- backend/tests/admin-reject-kyc.rs | 10 ++-- backend/tests/admin_audit_log.rs | 26 ++++----- backend/tests/admin_due_plans_tests.rs | 4 +- backend/tests/admin_metrics_tests.rs | 8 +-- backend/tests/auth_tests.rs | 14 ++--- backend/tests/cancel_plan_tests.rs | 34 ++++++------ backend/tests/claim_metrics_tests.rs | 8 +-- backend/tests/claim_tests.rs | 28 +++++----- backend/tests/concurrent_claim_tests.rs | 28 +++++----- backend/tests/create_plan_atomic_safety.rs | 4 +- backend/tests/double_claim.rs | 10 ++-- backend/tests/fee_calculation_tests.rs | 14 ++--- backend/tests/health_tests.rs | 6 +-- backend/tests/integration_flow.rs | 16 +++--- backend/tests/invalid_signature_tests.rs | 2 +- backend/tests/kyc_submit_tests.rs | 16 +++--- backend/tests/kyc_tests.rs | 6 +-- backend/tests/lifecycle.rs | 16 +++--- backend/tests/loan_lifecycle_tests.rs | 48 ++++++++--------- backend/tests/login_failure_tests.rs | 6 +-- backend/tests/notification_atomic_safety.rs | 8 +-- backend/tests/notification_tests.rs | 59 ++++++++++----------- backend/tests/ownership_protection_tests.rs | 14 ++--- backend/tests/pagination_tests.rs | 14 ++--- backend/tests/plan_statistics_tests.rs | 8 +-- backend/tests/plan_tests.rs | 30 +++++------ backend/tests/rate_limit_tests.rs | 2 +- backend/tests/replay_attack_tests.rs | 2 +- backend/tests/revenue_metrics_tests.rs | 14 ++--- backend/tests/security_tests.rs | 14 ++--- backend/tests/token_transfer_failure.rs | 8 +-- backend/tests/two_fa_tests.rs | 8 +-- backend/tests/user_due_plans_tests.rs | 12 ++--- backend/tests/user_growth_metrics_tests.rs | 6 +-- backend/tests/wallet_balance_tests.rs | 6 +-- backend/tests/yield_reporting_tests.rs | 10 ++-- 49 files changed, 315 insertions(+), 327 deletions(-) diff --git a/backend/src/app.rs b/backend/src/app.rs index c039797..a31d392 100644 --- a/backend/src/app.rs +++ b/backend/src/app.rs @@ -134,7 +134,7 @@ async fn get_plan( "status": "success", "data": p }))), - None => Err(ApiError::NotFound(format!("Plan {} not found", plan_id))), + None => Err(ApiError::NotFound(format!("Plan {plan_id} not found"))), } } @@ -164,10 +164,7 @@ async fn get_due_for_claim_plan( "status": "success", "data": plan }))), - None => Err(ApiError::NotFound(format!( - "Plan {} not found or not due for claim", - plan_id - ))), + None => Err(ApiError::NotFound(format!("Plan {plan_id} not found or not due for claim"))), } } @@ -286,10 +283,7 @@ async fn get_simulation( "status": "success", "data": sim }))), - None => Err(ApiError::NotFound(format!( - "Simulation {} not found", - simulation_id - ))), + None => Err(ApiError::NotFound(format!("Simulation {simulation_id} not found"))), } } diff --git a/backend/src/auth.rs b/backend/src/auth.rs index 3a03238..db45571 100644 --- a/backend/src/auth.rs +++ b/backend/src/auth.rs @@ -353,7 +353,7 @@ pub async fn send_2fa( // 3. Hash OTP let otp_hash = bcrypt::hash(&otp, bcrypt::DEFAULT_COST) - .map_err(|e| ApiError::Internal(anyhow::anyhow!("Failed to hash OTP: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("Failed to hash OTP: {e}")))?; let expires_at = Utc::now() + Duration::minutes(5); @@ -439,7 +439,7 @@ pub async fn verify_2fa_internal(db: &PgPool, user_id: Uuid, otp: &str) -> Resul // 4. Verify OTP let valid = bcrypt::verify(otp, &otp_hash) - .map_err(|e| ApiError::Internal(anyhow::anyhow!("Failed to verify OTP: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("Failed to verify OTP: {e}")))?; if !valid { // Increment attempts diff --git a/backend/src/compliance.rs b/backend/src/compliance.rs index 12e7aa4..0bddd8d 100644 --- a/backend/src/compliance.rs +++ b/backend/src/compliance.rs @@ -231,7 +231,7 @@ impl ComplianceEngine { &mut tx, user_id, notif_type::SUSPICIOUS_ACTIVITY_FLAGGED, - format!("ALARM: Your account has been flagged for abnormal activity: {}. A compliance officer has been notified.", reason) + format!("ALARM: Your account has been flagged for abnormal activity: {reason}. A compliance officer has been notified.") ).await?; tx.commit().await?; diff --git a/backend/src/event_handlers.rs b/backend/src/event_handlers.rs index 66487e4..285d514 100644 --- a/backend/src/event_handlers.rs +++ b/backend/src/event_handlers.rs @@ -80,7 +80,7 @@ pub async fn get_plan_events( let plan = crate::service::PlanService::get_plan_by_id(&state.db, plan_id, user.user_id).await?; if plan.is_none() { - return Err(ApiError::NotFound(format!("Plan {} not found", plan_id))); + return Err(ApiError::NotFound(format!("Plan {plan_id} not found"))); } let event_type = if let Some(et_str) = params.event_type { @@ -131,8 +131,7 @@ fn parse_event_type(s: &str) -> Result { "liquidation" => Ok(EventType::Liquidation), "interest_accrual" => Ok(EventType::InterestAccrual), _ => Err(ApiError::BadRequest(format!( - "Invalid event type: {}. Valid types: deposit, borrow, repay, liquidation, interest_accrual", - s + "Invalid event type: {s}. Valid types: deposit, borrow, repay, liquidation, interest_accrual" ))), } } diff --git a/backend/src/events.rs b/backend/src/events.rs index c9929d3..075bdaa 100644 --- a/backend/src/events.rs +++ b/backend/src/events.rs @@ -60,7 +60,7 @@ impl TryFrom for LendingEvent { plan_id: row.plan_id, asset_code: row.asset_code, amount: row.amount.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse amount: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse amount: {e}")) })?, metadata: row.metadata, transaction_hash: row.transaction_hash, @@ -144,7 +144,7 @@ impl EventService { block_number: Option, ) -> Result { let metadata_json = serde_json::to_value(metadata).map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {e}")) })?; Self::emit_event( @@ -176,7 +176,7 @@ impl EventService { block_number: Option, ) -> Result { let metadata_json = serde_json::to_value(metadata).map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {e}")) })?; Self::emit_event( @@ -208,7 +208,7 @@ impl EventService { block_number: Option, ) -> Result { let metadata_json = serde_json::to_value(metadata).map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {e}")) })?; Self::emit_event( @@ -240,7 +240,7 @@ impl EventService { block_number: Option, ) -> Result { let metadata_json = serde_json::to_value(metadata).map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {e}")) })?; Self::emit_event( @@ -272,7 +272,7 @@ impl EventService { block_number: Option, ) -> Result { let metadata_json = serde_json::to_value(metadata).map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to serialize metadata: {e}")) })?; Self::emit_event( diff --git a/backend/src/interest_reconciliation.rs b/backend/src/interest_reconciliation.rs index 10eb357..7ad4fa4 100644 --- a/backend/src/interest_reconciliation.rs +++ b/backend/src/interest_reconciliation.rs @@ -57,7 +57,7 @@ impl InterestReconciliationService { .fetch_all(&self.db) .await .map_err(|e| { - ApiError::Internal(anyhow::anyhow!("DB error loading expected yields: {}", e)) + ApiError::Internal(anyhow::anyhow!("DB error loading expected yields: {e}")) })?; for row in asset_yields { @@ -85,7 +85,7 @@ impl InterestReconciliationService { let mut tx = self.db.begin().await.map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Tx start error: {}", e)) + ApiError::Internal(anyhow::anyhow!("Tx start error: {e}")) })?; // Log discrepancy to audit logs @@ -104,7 +104,7 @@ impl InterestReconciliationService { tx.commit() .await - .map_err(|e| ApiError::Internal(anyhow::anyhow!("Tx commit error: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("Tx commit error: {e}")))?; } else { info!( "Yield reconciled for {}. Expected {}, On-Chain {}", diff --git a/backend/src/notifications.rs b/backend/src/notifications.rs index 82e2cef..c1d7641 100644 --- a/backend/src/notifications.rs +++ b/backend/src/notifications.rs @@ -144,7 +144,7 @@ impl NotificationService { .fetch_optional(db) .await?; - row.ok_or_else(|| ApiError::NotFound(format!("Notification {} not found", notif_id))) + row.ok_or_else(|| ApiError::NotFound(format!("Notification {notif_id} not found"))) } } // ─── Audit Log ─────────────────────────────────────────────────────────────── @@ -199,6 +199,7 @@ pub struct ActionLog { pub struct AuditLogService; impl AuditLogService { + #[allow(clippy::too_many_arguments)] pub async fn log( executor: impl sqlx::PgExecutor<'_>, user_id: Option, @@ -450,8 +451,7 @@ mod tests { // The `#[serde(rename = "type")]` on notif_type must produce `"type"` in JSON assert!( json.get("type").is_some(), - "Expected JSON key 'type', got: {}", - json + "Expected JSON key 'type', got: {json}" ); assert_eq!(json["type"], notif_type::KYC_APPROVED); // `notif_type` key must NOT appear (it's renamed) @@ -476,9 +476,13 @@ mod tests { let log = ActionLog { id: Uuid::new_v4(), user_id: Some(Uuid::new_v4()), + admin_id: None, action: audit_action::PLAN_CLAIMED.to_string(), entity_id: Some(Uuid::new_v4()), entity_type: Some(entity_type::PLAN.to_string()), + old_value: None, + new_value: None, + metadata: None, timestamp: Utc::now(), }; let json = serde_json::to_value(&log).unwrap(); @@ -491,9 +495,13 @@ mod tests { let log = ActionLog { id: Uuid::new_v4(), user_id: None, + admin_id: None, action: audit_action::KYC_APPROVED.to_string(), entity_id: None, entity_type: None, + old_value: None, + new_value: None, + metadata: None, timestamp: Utc::now(), }; let json = serde_json::to_value(&log).unwrap(); diff --git a/backend/src/price_feed.rs b/backend/src/price_feed.rs index c212d9f..421cfbd 100644 --- a/backend/src/price_feed.rs +++ b/backend/src/price_feed.rs @@ -185,7 +185,7 @@ impl PriceFeedService for DefaultPriceFeedService { })? .ok_or_else(|| { warn!("No price found for asset: {}", asset_code); - ApiError::NotFound(format!("Price not found for asset: {}", asset_code)) + ApiError::NotFound(format!("Price not found for asset: {asset_code}")) })?; let price = Decimal::from_str(&price_record.0).map_err(|e| { @@ -320,7 +320,7 @@ impl PriceFeedService for DefaultPriceFeedService { ApiError::Internal(anyhow::anyhow!("Database error")) })? .ok_or_else(|| { - ApiError::BadRequest(format!("Price feed not found for asset: {}", asset_code)) + ApiError::BadRequest(format!("Price feed not found for asset: {asset_code}")) })?; let now = Utc::now(); diff --git a/backend/src/price_feed_handlers.rs b/backend/src/price_feed_handlers.rs index 3aaf22c..28310de 100644 --- a/backend/src/price_feed_handlers.rs +++ b/backend/src/price_feed_handlers.rs @@ -254,7 +254,7 @@ pub async fn get_plan_valuation( tracing::error!("Failed to fetch plan: {}", e); ApiError::Internal(anyhow::anyhow!("Database error")) })? - .ok_or_else(|| ApiError::NotFound(format!("Plan {} not found", plan_id)))?; + .ok_or_else(|| ApiError::NotFound(format!("Plan {plan_id} not found")))?; let asset_code = plan.0; let amount = Decimal::from_str(&plan.1).map_err(|e| { diff --git a/backend/src/reputation.rs b/backend/src/reputation.rs index 544a7f3..77c03ed 100644 --- a/backend/src/reputation.rs +++ b/backend/src/reputation.rs @@ -48,7 +48,7 @@ impl ReputationService { .bind(user_id) .fetch_optional(pool) .await - .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB Error: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB Error: {e}")))?; if let Some(row) = rep_row { Ok(BorrowerReputation { @@ -133,7 +133,7 @@ impl ReputationService { .bind(add_liquidation) .fetch_one(&mut **tx) .await - .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB Error updating reputation: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB Error updating reputation: {e}")))?; Ok(BorrowerReputation { user_id: row.user_id, diff --git a/backend/src/risk_engine.rs b/backend/src/risk_engine.rs index a66840d..3f7c229 100644 --- a/backend/src/risk_engine.rs +++ b/backend/src/risk_engine.rs @@ -77,7 +77,7 @@ impl RiskEngine { ) .fetch_all(&self.db) .await - .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB error loading loan balances: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB error loading loan balances: {e}")))?; for loan in loans_health { // Get prices for evaluation @@ -133,7 +133,7 @@ impl RiskEngine { .bind(loan.plan_id) .execute(&self.db) .await - .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB error updating plan risk status: {}", e)))?; + .map_err(|e| ApiError::Internal(anyhow::anyhow!("DB error updating plan risk status: {e}")))?; // Notify if transitioned to risky (and not overridden) if is_now_risky && !loan.is_risky.unwrap_or(false) && !should_skip_risk_check { @@ -143,7 +143,7 @@ impl RiskEngine { ); let mut tx = self.db.begin().await.map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Tx start error: {}", e)) + ApiError::Internal(anyhow::anyhow!("Tx start error: {e}")) })?; NotificationService::create( @@ -167,7 +167,7 @@ impl RiskEngine { .await?; tx.commit().await.map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Tx commit error: {}", e)) + ApiError::Internal(anyhow::anyhow!("Tx commit error: {e}")) })?; } else if !is_now_risky && loan.is_risky.unwrap_or(false) { info!( diff --git a/backend/src/safe_math.rs b/backend/src/safe_math.rs index e0fd58a..1b31014 100644 --- a/backend/src/safe_math.rs +++ b/backend/src/safe_math.rs @@ -9,8 +9,7 @@ impl SafeMath { pub fn add(a: Decimal, b: Decimal) -> Result { a.checked_add(b).ok_or_else(|| { ApiError::BadRequest(format!( - "Arithmetic overflow: {} + {} exceeds maximum value", - a, b + "Arithmetic overflow: {a} + {b} exceeds maximum value" )) }) } @@ -19,16 +18,14 @@ impl SafeMath { pub fn sub(a: Decimal, b: Decimal) -> Result { let result = a.checked_sub(b).ok_or_else(|| { ApiError::BadRequest(format!( - "Arithmetic underflow: {} - {} results in overflow", - a, b + "Arithmetic underflow: {a} - {b} results in overflow" )) })?; // Also check if result is negative (which we consider underflow for financial operations) if result.is_sign_negative() { return Err(ApiError::BadRequest(format!( - "Arithmetic underflow: {} - {} results in negative value {}", - a, b, result + "Arithmetic underflow: {a} - {b} results in negative value {result}" ))); } @@ -39,8 +36,7 @@ impl SafeMath { pub fn mul(a: Decimal, b: Decimal) -> Result { a.checked_mul(b).ok_or_else(|| { ApiError::BadRequest(format!( - "Arithmetic overflow: {} * {} exceeds maximum value", - a, b + "Arithmetic overflow: {a} * {b} exceeds maximum value" )) }) } @@ -55,8 +51,7 @@ impl SafeMath { a.checked_div(b).ok_or_else(|| { ApiError::BadRequest(format!( - "Arithmetic overflow: {} / {} exceeds maximum value", - a, b + "Arithmetic overflow: {a} / {b} exceeds maximum value" )) }) } @@ -84,8 +79,7 @@ impl SafeMath { pub fn ensure_non_negative(value: Decimal, field_name: &str) -> Result { if value.is_sign_negative() { return Err(ApiError::BadRequest(format!( - "{} cannot be negative: {}", - field_name, value + "{field_name} cannot be negative: {value}" ))); } Ok(value) @@ -95,8 +89,7 @@ impl SafeMath { pub fn ensure_positive(value: Decimal, field_name: &str) -> Result { if value.is_zero() || value.is_sign_negative() { return Err(ApiError::BadRequest(format!( - "{} must be positive: {}", - field_name, value + "{field_name} must be positive: {value}" ))); } Ok(value) diff --git a/backend/src/service.rs b/backend/src/service.rs index 00bedcb..70f02dc 100644 --- a/backend/src/service.rs +++ b/backend/src/service.rs @@ -151,9 +151,9 @@ fn plan_row_to_plan_with_beneficiary(row: &PlanRowFull) -> Result plan_row_to_plan_with_beneficiary(&r)?, - None => return Err(ApiError::NotFound(format!("Plan {} not found", plan_id))), + None => return Err(ApiError::NotFound(format!("Plan {plan_id} not found"))), }; // Check if plan is paused @@ -553,10 +553,10 @@ impl PlanService { title: row.title, description: row.description, fee: row.fee.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {e}")) })?, net_amount: row.net_amount.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {e}")) })?, status: row.status, contract_plan_id: row.contract_plan_id, @@ -647,10 +647,10 @@ impl PlanService { title: row.title, description: row.description, fee: row.fee.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {e}")) })?, net_amount: row.net_amount.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {e}")) })?, status: row.status, contract_plan_id: row.contract_plan_id, @@ -740,10 +740,10 @@ impl PlanService { title: row.title, description: row.description, fee: row.fee.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse fee: {e}")) })?, net_amount: row.net_amount.parse().map_err(|e| { - ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {}", e)) + ApiError::Internal(anyhow::anyhow!("Failed to parse net_amount: {e}")) })?, status: row.status, contract_plan_id: row.contract_plan_id, @@ -798,7 +798,7 @@ impl PlanService { // Note: get_plan_by_id must also use the generic <'a, E> pattern let plan = Self::get_plan_by_id(&mut *tx, plan_id, user_id) .await? - .ok_or_else(|| ApiError::NotFound(format!("Plan {} not found", plan_id)))?; + .ok_or_else(|| ApiError::NotFound(format!("Plan {plan_id} not found")))?; // Business Logic Checks if plan.status == "deactivated" { @@ -876,7 +876,7 @@ impl fmt::Display for KycStatus { KycStatus::Approved => "approved", KycStatus::Rejected => "rejected", }; - write!(f, "{}", s) + write!(f, "{s}") } } @@ -1332,14 +1332,13 @@ impl RevenueMetricsService { let query = format!( r#" SELECT - DATE_TRUNC('{}', created_at)::DATE::TEXT as date, + DATE_TRUNC('{trunc}', created_at)::DATE::TEXT as date, COALESCE(SUM(fee), 0)::FLOAT8 as amount FROM plans - WHERE created_at >= NOW() - INTERVAL '{}' + WHERE created_at >= NOW() - INTERVAL '{interval}' GROUP BY 1 ORDER BY 1 - "#, - trunc, interval + "# ); let rows = sqlx::query_as::<_, Row>(&query).fetch_all(pool).await?; diff --git a/backend/tests/admin-reject-kyc.rs b/backend/tests/admin-reject-kyc.rs index 9c5863a..cd63da7 100644 --- a/backend/tests/admin-reject-kyc.rs +++ b/backend/tests/admin-reject-kyc.rs @@ -20,7 +20,7 @@ async fn reject_success() { let req = Request::builder() .method("POST") - .uri(format!("/claims/{}/reject", claim_id)) + .uri(format!("/claims/{claim_id}/reject")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&json!({})).unwrap())) .unwrap(); @@ -40,7 +40,7 @@ async fn cannot_reject_twice() { let req1 = Request::builder() .method("POST") - .uri(format!("/claims/{}/reject", claim_id)) + .uri(format!("/claims/{claim_id}/reject")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&json!({})).unwrap())) .unwrap(); @@ -50,7 +50,7 @@ async fn cannot_reject_twice() { let req2 = Request::builder() .method("POST") - .uri(format!("/claims/{}/reject", claim_id)) + .uri(format!("/claims/{claim_id}/reject")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&json!({})).unwrap())) .unwrap(); @@ -70,7 +70,7 @@ async fn cannot_approve_after_reject_without_reset() { let req_reject = Request::builder() .method("POST") - .uri(format!("/claims/{}/reject", claim_id)) + .uri(format!("/claims/{claim_id}/reject")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&json!({})).unwrap())) .unwrap(); @@ -85,7 +85,7 @@ async fn cannot_approve_after_reject_without_reset() { let req_approve = Request::builder() .method("POST") - .uri(format!("/claims/{}/approve", claim_id)) + .uri(format!("/claims/{claim_id}/approve")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&json!({})).unwrap())) .unwrap(); diff --git a/backend/tests/admin_audit_log.rs b/backend/tests/admin_audit_log.rs index ec4f82b..91163d9 100644 --- a/backend/tests/admin_audit_log.rs +++ b/backend/tests/admin_audit_log.rs @@ -14,7 +14,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("test-{}@example.com", user_id), + email: format!("test-{user_id}@example.com"), exp, }; encode( @@ -29,7 +29,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -56,7 +56,7 @@ async fn admin_can_fetch_logs() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -81,7 +81,7 @@ async fn user_cannot_fetch_logs() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -106,8 +106,8 @@ async fn user_cannot_access_kyc_status() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/admin/kyc/{}", user_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/admin/kyc/{user_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -133,7 +133,7 @@ async fn user_cannot_approve_kyc() { Request::builder() .method("POST") .uri("/api/admin/kyc/approve") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"user_id": user_id}).to_string())) .unwrap(), @@ -160,7 +160,7 @@ async fn user_cannot_reject_kyc() { Request::builder() .method("POST") .uri("/api/admin/kyc/reject") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"user_id": user_id}).to_string())) .unwrap(), @@ -184,7 +184,7 @@ async fn log_inserted_on_plan_create_and_claim() { // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -201,7 +201,7 @@ async fn log_inserted_on_plan_create_and_claim() { Request::builder() .method("POST") .uri("/api/admin/kyc/approve") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .header("Content-Type", "application/json") .body(Body::from(kyc_req.to_string())) .unwrap(), @@ -239,7 +239,7 @@ async fn log_inserted_on_plan_create_and_claim() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from(plan_req.to_string())) .unwrap(), @@ -275,8 +275,8 @@ async fn log_inserted_on_plan_create_and_claim() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", user_token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from(claim_req.to_string())) .unwrap(), diff --git a/backend/tests/admin_due_plans_tests.rs b/backend/tests/admin_due_plans_tests.rs index 6d3dc01..348fbe7 100644 --- a/backend/tests/admin_due_plans_tests.rs +++ b/backend/tests/admin_due_plans_tests.rs @@ -54,7 +54,7 @@ async fn admin_can_get_all_due_plans_returns_200() { .oneshot( Request::builder() .uri("/api/admin/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -77,7 +77,7 @@ async fn user_token_rejected_returns_401_or_403() { .oneshot( Request::builder() .uri("/api/admin/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/admin_metrics_tests.rs b/backend/tests/admin_metrics_tests.rs index bce9f39..1efc2a8 100644 --- a/backend/tests/admin_metrics_tests.rs +++ b/backend/tests/admin_metrics_tests.rs @@ -14,7 +14,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -30,7 +30,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }; encode( @@ -55,7 +55,7 @@ async fn admin_can_fetch_metrics_overview() { Request::builder() .method("GET") .uri("/admin/metrics/overview") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -90,7 +90,7 @@ async fn user_cannot_fetch_metrics_overview() { Request::builder() .method("GET") .uri("/admin/metrics/overview") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/auth_tests.rs b/backend/tests/auth_tests.rs index 2208810..4b7293b 100644 --- a/backend/tests/auth_tests.rs +++ b/backend/tests/auth_tests.rs @@ -38,7 +38,7 @@ async fn test_web3_login_success() { }); let client = reqwest::Client::new(); - let base_url = format!("http://{}", addr); + let base_url = format!("http://{addr}"); // 1. Generate a dummy Stellar-like Ed25519 keypair let rng = ring::rand::SystemRandom::new(); @@ -55,7 +55,7 @@ async fn test_web3_login_success() { // 2. Request Nonce let response = client - .post(format!("{}/api/auth/nonce", base_url)) + .post(format!("{base_url}/api/auth/nonce")) .json(&NonceRequest { wallet_address: wallet_address.to_string(), }) @@ -73,7 +73,7 @@ async fn test_web3_login_success() { // 4. Web3 Login let response = client - .post(format!("{}/api/auth/web3-login", base_url)) + .post(format!("{base_url}/api/auth/web3-login")) .json(&Web3LoginRequest { wallet_address: wallet_address.to_string(), signature: signature_hex, @@ -126,7 +126,7 @@ async fn test_get_nonce_returns_unique_nonce() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet)) + .uri(format!("/api/auth/nonce/{wallet}")) .body(Body::empty()) .unwrap(), ) @@ -156,7 +156,7 @@ async fn test_nonce_stored_in_db() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet)) + .uri(format!("/api/auth/nonce/{wallet}")) .body(Body::empty()) .unwrap(), ) @@ -195,7 +195,7 @@ async fn test_two_requests_generate_different_nonces() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet)) + .uri(format!("/api/auth/nonce/{wallet}")) .body(Body::empty()) .unwrap(), ) @@ -214,7 +214,7 @@ async fn test_two_requests_generate_different_nonces() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet)) + .uri(format!("/api/auth/nonce/{wallet}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/cancel_plan_tests.rs b/backend/tests/cancel_plan_tests.rs index 596e308..b5e34e1 100644 --- a/backend/tests/cancel_plan_tests.rs +++ b/backend/tests/cancel_plan_tests.rs @@ -103,8 +103,8 @@ async fn test_cancel_plan_success() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -138,8 +138,8 @@ async fn test_cancel_plan_not_found() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", non_existent_plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{non_existent_plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -175,8 +175,8 @@ async fn test_cancel_plan_unauthorized_different_user() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -211,8 +211,8 @@ async fn test_cancel_plan_already_deactivated() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -257,8 +257,8 @@ async fn test_cancel_plan_already_claimed() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -291,7 +291,7 @@ async fn test_cancel_plan_without_auth() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) + .uri(format!("/api/plans/{plan_id}")) .body(Body::empty()) .unwrap(), ) @@ -326,8 +326,8 @@ async fn test_cancel_plan_creates_audit_log() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -378,8 +378,8 @@ async fn test_cancel_plan_creates_notification() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -429,8 +429,8 @@ async fn test_cancel_plan_updates_database_correctly() { .oneshot( Request::builder() .method("DELETE") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/claim_metrics_tests.rs b/backend/tests/claim_metrics_tests.rs index e975a95..38268e7 100644 --- a/backend/tests/claim_metrics_tests.rs +++ b/backend/tests/claim_metrics_tests.rs @@ -16,7 +16,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -32,7 +32,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }; encode( @@ -59,7 +59,7 @@ async fn fetch_claim_metrics(app: &Router, token: &str) -> (StatusCode, Value) { Request::builder() .method("GET") .uri("/admin/metrics/claims") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .expect("failed to build request"), ) @@ -225,7 +225,7 @@ async fn claim_metrics_count_and_average_change_with_new_rows() { .expect("failed to count baseline processed claims"); let user_id = Uuid::new_v4(); - let email = format!("claim-metrics-{}@example.com", user_id); + let email = format!("claim-metrics-{user_id}@example.com"); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) .bind(email) diff --git a/backend/tests/claim_tests.rs b/backend/tests/claim_tests.rs index 67a5bbd..ca512a9 100644 --- a/backend/tests/claim_tests.rs +++ b/backend/tests/claim_tests.rs @@ -21,7 +21,7 @@ fn generate_user_token(user_id: Uuid) -> String { let claims = UserClaims { user_id, - email: format!("test-{}@example.com", user_id), + email: format!("test-{user_id}@example.com"), exp, }; @@ -111,7 +111,7 @@ async fn test_claim_before_maturity_returns_400() { let app = test_context.app.clone(); let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) .bind(&email) @@ -169,8 +169,8 @@ async fn test_claim_before_maturity_returns_400() { let token = generate_test_token(user_id, &email); let client = reqwest::Client::new(); let response = client - .post(format!("http://{}/api/plans/{}/claim", addr, plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .post(format!("http://{addr}/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .json(&json!({ "beneficiary_email": "beneficiary@example.com", "two_fa_code": otp @@ -213,8 +213,8 @@ async fn test_claim_plan_is_due() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( serde_json::to_string(&body).expect("Failed to serialize request body"), @@ -253,8 +253,8 @@ async fn test_claim_requires_kyc_approved() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( serde_json::to_string(&body).expect("Failed to serialize request body"), @@ -290,8 +290,8 @@ async fn test_claim_recorded_on_success() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( serde_json::to_string(&body).expect("Failed to serialize request body"), @@ -341,8 +341,8 @@ async fn test_claim_audit_log_inserted() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( serde_json::to_string(&body).expect("Failed to serialize request body"), @@ -403,8 +403,8 @@ async fn test_claim_notification_created() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( serde_json::to_string(&body).expect("Failed to serialize request body"), diff --git a/backend/tests/concurrent_claim_tests.rs b/backend/tests/concurrent_claim_tests.rs index df647c7..6c18cb2 100644 --- a/backend/tests/concurrent_claim_tests.rs +++ b/backend/tests/concurrent_claim_tests.rs @@ -56,7 +56,7 @@ async fn test_concurrent_claim_same_email_only_one_succeeds() { let app = test_context.app; let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -82,7 +82,7 @@ async fn test_concurrent_claim_same_email_only_one_succeeds() { let claim_req = || { Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( @@ -104,8 +104,7 @@ async fn test_concurrent_claim_same_email_only_one_succeeds() { let success_count = (status1 == StatusCode::OK) as i32 + (status2 == StatusCode::OK) as i32; assert_eq!( success_count, 1, - "Exactly one claim should succeed with same email. Got status1: {}, status2: {}", - status1, status2 + "Exactly one claim should succeed with same email. Got status1: {status1}, status2: {status2}" ); // Verify only one claim record exists in database @@ -133,7 +132,7 @@ async fn test_concurrent_claim_different_emails_only_one_succeeds() { let app = test_context.app; let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -158,7 +157,7 @@ async fn test_concurrent_claim_different_emails_only_one_succeeds() { let claim_req_with_email = |email: &str| { Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( @@ -182,8 +181,7 @@ async fn test_concurrent_claim_different_emails_only_one_succeeds() { let success_count = (status1 == StatusCode::OK) as i32 + (status2 == StatusCode::OK) as i32; assert_eq!( success_count, 1, - "Exactly one claim should succeed with different emails. Got status1: {}, status2: {}", - status1, status2 + "Exactly one claim should succeed with different emails. Got status1: {status1}, status2: {status2}" ); // Verify only one claim record exists in database (no duplicate payout) @@ -210,7 +208,7 @@ async fn test_concurrent_claim_updates_plan_status() { let app = test_context.app; let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -234,7 +232,7 @@ async fn test_concurrent_claim_updates_plan_status() { // Submit a claim request let claim_req = Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( @@ -273,7 +271,7 @@ async fn test_claim_after_concurrent_claims_fails() { let app = test_context.app; let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -297,7 +295,7 @@ async fn test_claim_after_concurrent_claims_fails() { // Submit first claim (should succeed) let claim_req = Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( @@ -316,7 +314,7 @@ async fn test_claim_after_concurrent_claims_fails() { // Submit second claim with different email (should fail - already claimed) let claim_req2 = Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( @@ -352,7 +350,7 @@ async fn test_concurrent_claim_creates_single_audit_log() { let app = test_context.app; let user_id = Uuid::new_v4(); - let email = format!("test_{}@example.com", user_id); + let email = format!("test_{user_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -377,7 +375,7 @@ async fn test_concurrent_claim_creates_single_audit_log() { let claim_req_with_email = |email: &str| { Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) + .uri(format!("/api/plans/{plan_id}/claim")) .header("Content-Type", "application/json") .header("X-User-Id", user_id.to_string()) .body(Body::from( diff --git a/backend/tests/create_plan_atomic_safety.rs b/backend/tests/create_plan_atomic_safety.rs index b141d1b..cc119d7 100644 --- a/backend/tests/create_plan_atomic_safety.rs +++ b/backend/tests/create_plan_atomic_safety.rs @@ -18,7 +18,7 @@ async fn test_create_plan_rollback_on_audit_failure() { // 1. Setup: Create a user let user_id = Uuid::new_v4(); - let email = format!("safety-{}@example.com", user_id); + let email = format!("safety-{user_id}@example.com"); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) .bind(&email) @@ -67,7 +67,7 @@ async fn test_create_plan_rollback_on_audit_failure() { Request::builder() .method("POST") .uri("/api/plans") // Adjust to your actual route - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&payload).unwrap())) .unwrap(), diff --git a/backend/tests/double_claim.rs b/backend/tests/double_claim.rs index c6635c7..9098224 100644 --- a/backend/tests/double_claim.rs +++ b/backend/tests/double_claim.rs @@ -93,7 +93,7 @@ async fn first_claim_succeeds_second_claim_fails() { }; let user_id = Uuid::new_v4(); - let email = format!("double-claim-{}@example.com", user_id); + let email = format!("double-claim-{user_id}@example.com"); seed_user_and_kyc(&ctx.pool, user_id, &email).await; let plan_id = seed_due_plan(&ctx.pool, user_id).await; let token = generate_user_token(user_id, &email); @@ -110,8 +110,8 @@ async fn first_claim_succeeds_second_claim_fails() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(claim_body_str.clone())) .expect("Failed to build first claim request"), @@ -127,8 +127,8 @@ async fn first_claim_succeeds_second_claim_fails() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(claim_body_str)) .expect("Failed to build second claim request"), diff --git a/backend/tests/fee_calculation_tests.rs b/backend/tests/fee_calculation_tests.rs index a5041c1..f01c198 100644 --- a/backend/tests/fee_calculation_tests.rs +++ b/backend/tests/fee_calculation_tests.rs @@ -20,7 +20,7 @@ const JWT_SECRET: &[u8] = b"test-jwt-secret"; fn user_token(user_id: Uuid) -> String { let claims = UserClaims { user_id, - email: format!("fee-test-{}@example.com", user_id), + email: format!("fee-test-{user_id}@example.com"), exp: 9_999_999_999, }; encode( @@ -32,7 +32,7 @@ fn user_token(user_id: Uuid) -> String { } async fn ensure_user_and_kyc(pool: &sqlx::PgPool, user_id: Uuid) { - let email = format!("fee-test-{}@example.com", user_id); + let email = format!("fee-test-{user_id}@example.com"); sqlx::query( "INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING", @@ -83,7 +83,7 @@ async fn create_plan_via_app( Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&body).unwrap())) .unwrap(), @@ -131,7 +131,7 @@ async fn fee_calculation_small_decimals() { let (status, json) = create_plan_via_app(&ctx.app, &token, "0.02", "1.09", "Small decimals plan").await; - assert_eq!(status, StatusCode::OK, "response: {:?}", json); + assert_eq!(status, StatusCode::OK, "response: {json:?}"); assert_eq!(json["status"], "success"); let (fee, net_amount) = fee_and_net_from_response(&json); @@ -166,7 +166,7 @@ async fn fee_calculation_large_values() { ) .await; - assert_eq!(status, StatusCode::OK, "response: {:?}", json); + assert_eq!(status, StatusCode::OK, "response: {json:?}"); assert_eq!(json["status"], "success"); let (fee, net_amount) = fee_and_net_from_response(&json); @@ -196,7 +196,7 @@ async fn fee_calculation_no_rounding_error() { // Total 100 => fee 2, net 98 (exact) let (status, json) = create_plan_via_app(&ctx.app, &token, "2", "98", "No rounding plan").await; - assert_eq!(status, StatusCode::OK, "response: {:?}", json); + assert_eq!(status, StatusCode::OK, "response: {json:?}"); assert_eq!(json["status"], "success"); let (fee, net_amount) = fee_and_net_from_response(&json); @@ -233,7 +233,7 @@ async fn fee_calculation_exactly_2_percent() { let (status, json) = create_plan_via_app(&ctx.app, &token, "10", "490", "Exactly 2% plan").await; - assert_eq!(status, StatusCode::OK, "response: {:?}", json); + assert_eq!(status, StatusCode::OK, "response: {json:?}"); assert_eq!(json["status"], "success"); let (fee, net_amount) = fee_and_net_from_response(&json); diff --git a/backend/tests/health_tests.rs b/backend/tests/health_tests.rs index 83d29bc..c4da687 100644 --- a/backend/tests/health_tests.rs +++ b/backend/tests/health_tests.rs @@ -89,7 +89,7 @@ async fn test_health_endpoint() { // Client let client = reqwest::Client::new(); - let url = format!("http://{}/health", addr); + let url = format!("http://{addr}/health"); // Give it a moment to start tokio::time::sleep(std::time::Duration::from_millis(50)).await; @@ -102,9 +102,7 @@ async fn test_health_endpoint() { assert_eq!( status, reqwest::StatusCode::OK, - "Status was {}, body: {}", - status, - body_text + "Status was {status}, body: {body_text}" ); let body: Value = serde_json::from_str(&body_text).expect("Failed to parse JSON"); diff --git a/backend/tests/integration_flow.rs b/backend/tests/integration_flow.rs index cbe6f5f..612e583 100644 --- a/backend/tests/integration_flow.rs +++ b/backend/tests/integration_flow.rs @@ -36,7 +36,7 @@ async fn test_full_lifecycle_flow() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) @@ -87,7 +87,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .body(Body::empty()) .unwrap(), ) @@ -139,7 +139,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/admin/kyc/approve") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -162,7 +162,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -203,8 +203,8 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", user_token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -226,7 +226,7 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .body(Body::empty()) .unwrap(), ) @@ -251,7 +251,7 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/invalid_signature_tests.rs b/backend/tests/invalid_signature_tests.rs index 3426612..4df1d21 100644 --- a/backend/tests/invalid_signature_tests.rs +++ b/backend/tests/invalid_signature_tests.rs @@ -35,7 +35,7 @@ async fn fetch_nonce(app: axum::Router, wallet_address: &str) -> String { let resp = app .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/kyc_submit_tests.rs b/backend/tests/kyc_submit_tests.rs index beb6d82..104539b 100644 --- a/backend/tests/kyc_submit_tests.rs +++ b/backend/tests/kyc_submit_tests.rs @@ -17,7 +17,7 @@ const JWT_SECRET: &[u8] = b"test-jwt-secret"; fn user_token(user_id: Uuid) -> String { let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), // Use a far-future timestamp so the token never expires in tests exp: 9_999_999_999, }; @@ -41,7 +41,7 @@ async fn submit_kyc_returns_pending_for_authenticated_user() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("kyc-submit-{}@example.com", user_id)) + .bind(format!("kyc-submit-{user_id}@example.com")) .bind("hashed_password") .execute(&ctx.pool) .await @@ -55,7 +55,7 @@ async fn submit_kyc_returns_pending_for_authenticated_user() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .header(header::CONTENT_TYPE, "application/json") .body(Body::empty()) .unwrap(), @@ -135,7 +135,7 @@ async fn submit_kyc_is_idempotent_for_same_user() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("kyc-idem-{}@example.com", user_id)) + .bind(format!("kyc-idem-{user_id}@example.com")) .bind("hashed_password") .execute(&ctx.pool) .await @@ -151,7 +151,7 @@ async fn submit_kyc_is_idempotent_for_same_user() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -165,7 +165,7 @@ async fn submit_kyc_is_idempotent_for_same_user() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -195,7 +195,7 @@ async fn submit_kyc_response_contains_expected_fields() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("kyc-fields-{}@example.com", user_id)) + .bind(format!("kyc-fields-{user_id}@example.com")) .bind("hashed_password") .execute(&ctx.pool) .await @@ -209,7 +209,7 @@ async fn submit_kyc_response_contains_expected_fields() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/kyc_tests.rs b/backend/tests/kyc_tests.rs index 9ed08e6..013b826 100644 --- a/backend/tests/kyc_tests.rs +++ b/backend/tests/kyc_tests.rs @@ -62,7 +62,7 @@ async fn admin_can_approve_kyc() { Request::builder() .uri("/api/admin/kyc/approve") .method("POST") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .header(header::CONTENT_TYPE, "application/json") .body(Body::from(json!({ "user_id": user_id }).to_string())) .unwrap(), @@ -102,7 +102,7 @@ async fn user_cannot_approve_kyc() { Request::builder() .uri("/api/admin/kyc/approve") .method("POST") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .header(header::CONTENT_TYPE, "application/json") .body(Body::from(json!({ "user_id": Uuid::new_v4() }).to_string())) .unwrap(), @@ -135,7 +135,7 @@ async fn invalid_uuid_rejected() { Request::builder() .uri("/api/admin/kyc/approve") .method("POST") - .header(header::AUTHORIZATION, format!("Bearer {}", token)) + .header(header::AUTHORIZATION, format!("Bearer {token}")) .header(header::CONTENT_TYPE, "application/json") .body(Body::from(json!({ "user_id": "not-a-uuid" }).to_string())) .unwrap(), diff --git a/backend/tests/lifecycle.rs b/backend/tests/lifecycle.rs index cbe6f5f..612e583 100644 --- a/backend/tests/lifecycle.rs +++ b/backend/tests/lifecycle.rs @@ -36,7 +36,7 @@ async fn test_full_lifecycle_flow() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) @@ -87,7 +87,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/kyc/submit") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .body(Body::empty()) .unwrap(), ) @@ -139,7 +139,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/admin/kyc/approve") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -162,7 +162,7 @@ async fn test_full_lifecycle_flow() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -203,8 +203,8 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/plans/{}/claim", plan_id)) - .header("Authorization", format!("Bearer {}", user_token)) + .uri(format!("/api/plans/{plan_id}/claim")) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -226,7 +226,7 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .body(Body::empty()) .unwrap(), ) @@ -251,7 +251,7 @@ async fn test_full_lifecycle_flow() { .oneshot( Request::builder() .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/loan_lifecycle_tests.rs b/backend/tests/loan_lifecycle_tests.rs index 65c696a..4134d0f 100644 --- a/backend/tests/loan_lifecycle_tests.rs +++ b/backend/tests/loan_lifecycle_tests.rs @@ -62,7 +62,7 @@ async fn test_create_loan_lifecycle_success() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -117,7 +117,7 @@ async fn test_get_loan_lifecycle_success() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -148,8 +148,8 @@ async fn test_get_loan_lifecycle_success() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/loans/lifecycle/{}", loan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/loans/lifecycle/{loan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -187,7 +187,7 @@ async fn test_list_loans_by_status() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -214,7 +214,7 @@ async fn test_list_loans_by_status() { Request::builder() .method("GET") .uri("/api/loans/lifecycle?status=active") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -250,7 +250,7 @@ async fn test_lifecycle_summary() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -276,7 +276,7 @@ async fn test_lifecycle_summary() { Request::builder() .method("GET") .uri("/api/loans/lifecycle/summary") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -313,7 +313,7 @@ async fn test_repay_loan_partial() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -344,8 +344,8 @@ async fn test_repay_loan_partial() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/loans/lifecycle/{}/repay", loan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/loans/lifecycle/{loan_id}/repay")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"amount": "300.00"}).to_string())) .unwrap(), @@ -383,7 +383,7 @@ async fn test_repay_loan_full() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -414,8 +414,8 @@ async fn test_repay_loan_full() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/loans/lifecycle/{}/repay", loan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/loans/lifecycle/{loan_id}/repay")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"amount": "500.00"}).to_string())) .unwrap(), @@ -456,7 +456,7 @@ async fn test_liquidate_loan_as_admin() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -487,8 +487,8 @@ async fn test_liquidate_loan_as_admin() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/admin/loans/lifecycle/{}/liquidate", loan_id)) - .header("Authorization", format!("Bearer {}", admin_token)) + .uri(format!("/api/admin/loans/lifecycle/{loan_id}/liquidate")) + .header("Authorization", format!("Bearer {admin_token}")) .body(Body::empty()) .unwrap(), ) @@ -527,7 +527,7 @@ async fn test_mark_overdue_loans() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", user_token)) + .header("Authorization", format!("Bearer {user_token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -553,7 +553,7 @@ async fn test_mark_overdue_loans() { Request::builder() .method("POST") .uri("/api/admin/loans/lifecycle/mark-overdue") - .header("Authorization", format!("Bearer {}", admin_token)) + .header("Authorization", format!("Bearer {admin_token}")) .body(Body::empty()) .unwrap(), ) @@ -589,7 +589,7 @@ async fn test_cannot_repay_already_repaid_loan() { Request::builder() .method("POST") .uri("/api/loans/lifecycle") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from( json!({ @@ -620,8 +620,8 @@ async fn test_cannot_repay_already_repaid_loan() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/loans/lifecycle/{}/repay", loan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/loans/lifecycle/{loan_id}/repay")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"amount": "100.00"}).to_string())) .unwrap(), @@ -636,8 +636,8 @@ async fn test_cannot_repay_already_repaid_loan() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/loans/lifecycle/{}/repay", loan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/loans/lifecycle/{loan_id}/repay")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(json!({"amount": "50.00"}).to_string())) .unwrap(), diff --git a/backend/tests/login_failure_tests.rs b/backend/tests/login_failure_tests.rs index 87705f1..2f0b713 100644 --- a/backend/tests/login_failure_tests.rs +++ b/backend/tests/login_failure_tests.rs @@ -22,7 +22,7 @@ async fn test_login_invalid_signature() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) @@ -69,7 +69,7 @@ async fn test_login_replayed_nonce() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) @@ -171,7 +171,7 @@ async fn test_login_expired_nonce() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet_address)) + .uri(format!("/api/auth/nonce/{wallet_address}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/notification_atomic_safety.rs b/backend/tests/notification_atomic_safety.rs index bdc0423..f9179f8 100644 --- a/backend/tests/notification_atomic_safety.rs +++ b/backend/tests/notification_atomic_safety.rs @@ -19,8 +19,8 @@ async fn test_update_kyc_rollback_on_notification_failure() { // 1. Setup: Create a user and an admin let user_id = Uuid::new_v4(); let admin_id = Uuid::new_v4(); - let user_email = format!("user-{}@example.com", user_id); - let admin_email = format!("admin-{}@example.com", admin_id); + let user_email = format!("user-{user_id}@example.com"); + let admin_email = format!("admin-{admin_id}@example.com"); // Insert user sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") @@ -66,8 +66,8 @@ async fn test_update_kyc_rollback_on_notification_failure() { .oneshot( Request::builder() .method("POST") - .uri(format!("/api/admin/users/{}/kyc", user_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/admin/users/{user_id}/kyc")) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&payload).unwrap())) .unwrap(), diff --git a/backend/tests/notification_tests.rs b/backend/tests/notification_tests.rs index 56bfd06..73e5085 100644 --- a/backend/tests/notification_tests.rs +++ b/backend/tests/notification_tests.rs @@ -36,7 +36,7 @@ async fn mark_notification_read_success() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -63,7 +63,7 @@ async fn mark_notification_read_success() { // 3. Generate token let claims = UserClaims { user_id, - email: format!("test-{}@example.com", user_id), + email: format!("test-{user_id}@example.com"), exp: expiration as usize, }; let token = encode( @@ -79,8 +79,8 @@ async fn mark_notification_read_success() { .oneshot( Request::builder() .method("PATCH") - .uri(format!("/api/notifications/{}/read", notif_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/notifications/{notif_id}/read")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -112,7 +112,7 @@ async fn test_retrieve_notifications_returns_only_users_notifications() { for &id in &[user_a_id, user_b_id] { sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(id) - .bind(format!("test-{}@example.com", id)) + .bind(format!("test-{id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -128,7 +128,7 @@ async fn test_retrieve_notifications_returns_only_users_notifications() { .bind(notif_id) .bind(user_a_id) .bind("plan_created") - .bind(format!("User A notification {}", i)) + .bind(format!("User A notification {i}")) .execute(&ctx.pool) .await .expect("Failed to create notification"); @@ -143,14 +143,14 @@ async fn test_retrieve_notifications_returns_only_users_notifications() { .bind(notif_id) .bind(user_b_id) .bind("plan_created") - .bind(format!("User B notification {}", i)) + .bind(format!("User B notification {i}")) .execute(&ctx.pool) .await .expect("Failed to create notification"); } // 4. Generate token for user A - let token = generate_user_token(user_a_id, format!("test-{}@example.com", user_a_id)); + let token = generate_user_token(user_a_id, format!("test-{user_a_id}@example.com")); // 5. Call list notifications endpoint let response = ctx @@ -159,7 +159,7 @@ async fn test_retrieve_notifications_returns_only_users_notifications() { Request::builder() .method("GET") .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -203,7 +203,7 @@ async fn test_retrieve_notifications_count_matches() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -219,7 +219,7 @@ async fn test_retrieve_notifications_count_matches() { .bind(notif_id) .bind(user_id) .bind("plan_created") - .bind(format!("Notification {}", i)) + .bind(format!("Notification {i}")) .bind(i % 2 == 0) // Some read, some unread .execute(&ctx.pool) .await @@ -227,7 +227,7 @@ async fn test_retrieve_notifications_count_matches() { } // 3. Generate token - let token = generate_user_token(user_id, format!("test-{}@example.com", user_id)); + let token = generate_user_token(user_id, format!("test-{user_id}@example.com")); // 4. Call list notifications endpoint let response = ctx @@ -236,7 +236,7 @@ async fn test_retrieve_notifications_count_matches() { Request::builder() .method("GET") .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -263,8 +263,7 @@ async fn test_retrieve_notifications_count_matches() { ); assert_eq!( count, notification_count, - "Should return all {} notifications", - notification_count + "Should return all {notification_count} notifications" ); } @@ -278,14 +277,14 @@ async fn test_retrieve_notifications_empty_list() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await .expect("Failed to create user"); // 2. Generate token - let token = generate_user_token(user_id, format!("test-{}@example.com", user_id)); + let token = generate_user_token(user_id, format!("test-{user_id}@example.com")); // 3. Call list notifications endpoint let response = ctx @@ -294,7 +293,7 @@ async fn test_retrieve_notifications_empty_list() { Request::builder() .method("GET") .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -350,7 +349,7 @@ async fn test_retrieve_notifications_ordered_by_created_at() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -367,7 +366,7 @@ async fn test_retrieve_notifications_ordered_by_created_at() { .bind(notif_id) .bind(user_id) .bind("plan_created") - .bind(format!("Notification {}", i)) + .bind(format!("Notification {i}")) .execute(&ctx.pool) .await .expect("Failed to create notification"); @@ -377,7 +376,7 @@ async fn test_retrieve_notifications_ordered_by_created_at() { } // 3. Generate token - let token = generate_user_token(user_id, format!("test-{}@example.com", user_id)); + let token = generate_user_token(user_id, format!("test-{user_id}@example.com")); // 4. Call list notifications endpoint let response = ctx @@ -386,7 +385,7 @@ async fn test_retrieve_notifications_ordered_by_created_at() { Request::builder() .method("GET") .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -426,7 +425,7 @@ async fn cannot_mark_another_user_notification() { for &id in &[user_a_id, user_b_id] { sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(id) - .bind(format!("test-{}@example.com", id)) + .bind(format!("test-{id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -454,7 +453,7 @@ async fn cannot_mark_another_user_notification() { // 3. Generate token for user A let claims = UserClaims { user_id: user_a_id, - email: format!("test-{}@example.com", user_a_id), + email: format!("test-{user_a_id}@example.com"), exp: expiration as usize, }; let token = encode( @@ -470,8 +469,8 @@ async fn cannot_mark_another_user_notification() { .oneshot( Request::builder() .method("PATCH") - .uri(format!("/api/notifications/{}/read", notif_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/notifications/{notif_id}/read")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -501,7 +500,7 @@ async fn mark_already_read_notification_safe_handling() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -528,7 +527,7 @@ async fn mark_already_read_notification_safe_handling() { // 3. Generate token let claims = UserClaims { user_id, - email: format!("test-{}@example.com", user_id), + email: format!("test-{user_id}@example.com"), exp: expiration as usize, }; let token = encode( @@ -544,8 +543,8 @@ async fn mark_already_read_notification_safe_handling() { .oneshot( Request::builder() .method("PATCH") - .uri(format!("/api/notifications/{}/read", notif_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/notifications/{notif_id}/read")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/ownership_protection_tests.rs b/backend/tests/ownership_protection_tests.rs index a82df7d..1165775 100644 --- a/backend/tests/ownership_protection_tests.rs +++ b/backend/tests/ownership_protection_tests.rs @@ -110,8 +110,8 @@ async fn test_fetch_own_plan() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -158,8 +158,8 @@ async fn test_fetch_other_user_plan() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", visitor_token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {visitor_token}")) .body(Body::empty()) .unwrap(), ) @@ -190,8 +190,8 @@ async fn test_fetch_nonexistent_plan() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", non_existent_plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{non_existent_plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -216,7 +216,7 @@ async fn test_fetch_invalid_uuid() { Request::builder() .method("GET") .uri("/api/plans/invalid-uuid-string") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/pagination_tests.rs b/backend/tests/pagination_tests.rs index e8feca9..ab04650 100644 --- a/backend/tests/pagination_tests.rs +++ b/backend/tests/pagination_tests.rs @@ -14,7 +14,7 @@ fn user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }; @@ -30,7 +30,7 @@ fn admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -46,7 +46,7 @@ fn admin_token(admin_id: Uuid) -> String { async fn create_user(pool: &sqlx::PgPool, user_id: Uuid) { sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("user-{}@example.com", user_id)) + .bind(format!("user-{user_id}@example.com")) .bind("hash") .execute(pool) .await @@ -84,7 +84,7 @@ async fn notifications_endpoint_supports_page_and_limit() { Request::builder() .method("GET") .uri("/api/notifications?page=1&limit=10") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .expect("failed to build request"), ) @@ -133,7 +133,7 @@ async fn admin_logs_endpoint_supports_page_and_limit() { Request::builder() .method("GET") .uri("/api/admin/logs?page=1&limit=10") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .expect("failed to build request"), ) @@ -200,7 +200,7 @@ async fn due_plans_endpoint_supports_page_and_limit() { Request::builder() .method("GET") .uri("/api/plans/due-for-claim?page=1&limit=10") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .expect("failed to build request"), ) @@ -262,7 +262,7 @@ async fn create_plan_accepts_query_pagination_params() { Request::builder() .method("POST") .uri("/api/plans?page=1&limit=10") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(body.to_string())) .expect("failed to build request"), diff --git a/backend/tests/plan_statistics_tests.rs b/backend/tests/plan_statistics_tests.rs index 8a90485..00a01ed 100644 --- a/backend/tests/plan_statistics_tests.rs +++ b/backend/tests/plan_statistics_tests.rs @@ -13,7 +13,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -29,7 +29,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("test-{}@example.com", user_id), + email: format!("test-{user_id}@example.com"), exp, }; encode( @@ -55,7 +55,7 @@ async fn admin_can_fetch_plan_statistics() { Request::builder() .method("GET") .uri("/api/admin/metrics/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -93,7 +93,7 @@ async fn user_cannot_fetch_plan_statistics() { Request::builder() .method("GET") .uri("/api/admin/metrics/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/plan_tests.rs b/backend/tests/plan_tests.rs index 1c8789f..83c732d 100644 --- a/backend/tests/plan_tests.rs +++ b/backend/tests/plan_tests.rs @@ -113,8 +113,8 @@ async fn test_retrieve_plan_success() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -151,8 +151,8 @@ async fn test_retrieve_plan_not_found() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", non_existent_plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{non_existent_plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -195,8 +195,8 @@ async fn test_retrieve_plan_unauthorized_different_user() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -219,7 +219,7 @@ async fn test_retrieve_plan_without_auth() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) + .uri(format!("/api/plans/{plan_id}")) .body(Body::empty()) .unwrap(), ) @@ -261,8 +261,8 @@ async fn test_retrieve_plan_with_beneficiary_details() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -315,8 +315,8 @@ async fn test_retrieve_plan_fee_calculation_2_percent() { .oneshot( Request::builder() .method("GET") - .uri(format!("/api/plans/{}", plan_id)) - .header("Authorization", format!("Bearer {}", token)) + .uri(format!("/api/plans/{plan_id}")) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -386,7 +386,7 @@ async fn test_create_plan_wallet_balance_check() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&create_request).unwrap())) .unwrap(), @@ -443,7 +443,7 @@ async fn test_create_plan_audit_log_inserted() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&create_request).unwrap())) .unwrap(), @@ -529,7 +529,7 @@ async fn test_create_plan_notification_created() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&create_request).unwrap())) .unwrap(), @@ -593,7 +593,7 @@ async fn test_create_plan_invalid_2fa() { Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_string(&create_request).unwrap())) .unwrap(), diff --git a/backend/tests/rate_limit_tests.rs b/backend/tests/rate_limit_tests.rs index afc6aa3..a6cd8b3 100644 --- a/backend/tests/rate_limit_tests.rs +++ b/backend/tests/rate_limit_tests.rs @@ -25,7 +25,7 @@ async fn governor_rate_limit_burst_and_reset() { .unwrap(); }); let client = reqwest::Client::new(); - let url = format!("http://{}/health", addr); + let url = format!("http://{addr}/health"); let mut statuses = Vec::new(); for _ in 0..6 { let resp = client.get(&url).send().await.expect("req"); diff --git a/backend/tests/replay_attack_tests.rs b/backend/tests/replay_attack_tests.rs index 8dff95c..16d8c92 100644 --- a/backend/tests/replay_attack_tests.rs +++ b/backend/tests/replay_attack_tests.rs @@ -29,7 +29,7 @@ async fn wallet_signature_cannot_be_reused() { .clone() .oneshot( Request::builder() - .uri(format!("/api/auth/nonce/{}", wallet)) + .uri(format!("/api/auth/nonce/{wallet}")) .body(Body::empty()) .expect("failed to build nonce request"), ) diff --git a/backend/tests/revenue_metrics_tests.rs b/backend/tests/revenue_metrics_tests.rs index a09b46f..3b1ebeb 100644 --- a/backend/tests/revenue_metrics_tests.rs +++ b/backend/tests/revenue_metrics_tests.rs @@ -14,7 +14,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -30,7 +30,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }; encode( @@ -57,7 +57,7 @@ async fn admin_can_fetch_revenue_metrics() { Request::builder() .method("GET") .uri("/admin/metrics/revenue") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -82,7 +82,7 @@ async fn admin_can_fetch_revenue_metrics() { Request::builder() .method("GET") .uri("/admin/metrics/revenue?range=weekly") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -103,7 +103,7 @@ async fn admin_can_fetch_revenue_metrics() { Request::builder() .method("GET") .uri("/admin/metrics/revenue?range=monthly") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -132,7 +132,7 @@ async fn user_cannot_fetch_revenue_metrics() { Request::builder() .method("GET") .uri("/admin/metrics/revenue") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -156,7 +156,7 @@ async fn admin_metrics_revenue_invalid_range() { Request::builder() .method("GET") .uri("/admin/metrics/revenue?range=yearly") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/security_tests.rs b/backend/tests/security_tests.rs index 8f9ad69..901d454 100644 --- a/backend/tests/security_tests.rs +++ b/backend/tests/security_tests.rs @@ -82,7 +82,7 @@ async fn expired_user_token_rejected_on_plans_endpoint() { Request::builder() .method("GET") .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -111,7 +111,7 @@ async fn expired_user_token_rejected_on_notifications_endpoint() { Request::builder() .method("GET") .uri("/api/notifications") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -140,7 +140,7 @@ async fn expired_admin_token_rejected_on_admin_logs_endpoint() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -187,7 +187,7 @@ async fn test_modified_jwt_signature_rejected_on_admin_route() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", tampered_token)) + .header("Authorization", format!("Bearer {tampered_token}")) .body(Body::empty()) .unwrap(), ) @@ -231,7 +231,7 @@ async fn test_valid_jwt_signature_accepted_on_admin_route() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", valid_token)) + .header("Authorization", format!("Bearer {valid_token}")) .body(Body::empty()) .unwrap(), ) @@ -318,7 +318,7 @@ async fn test_malformed_jwt_rejected() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", malformed_token)) + .header("Authorization", format!("Bearer {malformed_token}")) .body(Body::empty()) .unwrap(), ) @@ -365,7 +365,7 @@ async fn test_jwt_with_different_algorithm_rejected() { Request::builder() .method("GET") .uri("/api/admin/logs") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/token_transfer_failure.rs b/backend/tests/token_transfer_failure.rs index df7b435..f36a566 100644 --- a/backend/tests/token_transfer_failure.rs +++ b/backend/tests/token_transfer_failure.rs @@ -23,7 +23,7 @@ fn generate_user_token(user_id: Uuid) -> String { &Header::default(), &UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }, &EncodingKey::from_secret(b"secret_key_change_in_production"), @@ -36,7 +36,7 @@ async fn setup_user_with_kyc(pool: &sqlx::PgPool) -> Uuid { sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("user-{}@example.com", user_id)) + .bind(format!("user-{user_id}@example.com")) .bind("hash") .execute(pool) .await @@ -75,7 +75,7 @@ fn build_create_plan_request(token: &str, body: &Value, simulate_revert: &str) - Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .header("X-Simulate-Revert", simulate_revert) .body(Body::from(body.to_string())) @@ -419,7 +419,7 @@ async fn plan_creation_succeeds_without_revert_header() { let request = Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .body(Body::from(plan_request_body().to_string())) .expect("Failed to build request"); diff --git a/backend/tests/two_fa_tests.rs b/backend/tests/two_fa_tests.rs index dcb4595..0c98a4b 100644 --- a/backend/tests/two_fa_tests.rs +++ b/backend/tests/two_fa_tests.rs @@ -18,7 +18,7 @@ async fn test_2fa_full_flow() { // 1. Create a test user let user_id = Uuid::new_v4(); - let email = format!("test-{}@example.com", user_id); + let email = format!("test-{user_id}@example.com"); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) .bind(&email) @@ -98,7 +98,7 @@ async fn test_verify_2fa_invalid_otp() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("dummy-hash") .execute(&ctx.pool) .await @@ -161,7 +161,7 @@ async fn test_verify_2fa_too_many_attempts() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("dummy-hash") .execute(&ctx.pool) .await @@ -220,7 +220,7 @@ async fn test_verify_2fa_expired() { let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("test-{}@example.com", user_id)) + .bind(format!("test-{user_id}@example.com")) .bind("dummy-hash") .execute(&ctx.pool) .await diff --git a/backend/tests/user_due_plans_tests.rs b/backend/tests/user_due_plans_tests.rs index 4809d49..384416b 100644 --- a/backend/tests/user_due_plans_tests.rs +++ b/backend/tests/user_due_plans_tests.rs @@ -15,7 +15,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("due-test-{}@example.com", user_id), + email: format!("due-test-{user_id}@example.com"), exp, }; encode( @@ -126,7 +126,7 @@ async fn user_with_no_plans_returns_empty_array() { .oneshot( Request::builder() .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -172,7 +172,7 @@ async fn only_due_plans_returned() { .oneshot( Request::builder() .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -217,7 +217,7 @@ async fn count_matches_data_length() { .oneshot( Request::builder() .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -269,7 +269,7 @@ async fn claimed_plan_excluded_from_due_plans() { .oneshot( Request::builder() .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -334,7 +334,7 @@ async fn user_cannot_see_other_users_due_plans() { .oneshot( Request::builder() .uri("/api/plans/due-for-claim") - .header("Authorization", format!("Bearer {}", token_b)) + .header("Authorization", format!("Bearer {token_b}")) .body(Body::empty()) .unwrap(), ) diff --git a/backend/tests/user_growth_metrics_tests.rs b/backend/tests/user_growth_metrics_tests.rs index b240bd1..10ecc05 100644 --- a/backend/tests/user_growth_metrics_tests.rs +++ b/backend/tests/user_growth_metrics_tests.rs @@ -14,7 +14,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -30,7 +30,7 @@ fn generate_user_token(user_id: Uuid) -> String { let exp = (chrono::Utc::now() + chrono::Duration::hours(24)).timestamp() as usize; let claims = UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp, }; encode( @@ -45,7 +45,7 @@ fn build_get_request(uri: &str, token: &str) -> Request { Request::builder() .method("GET") .uri(uri) - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap() } diff --git a/backend/tests/wallet_balance_tests.rs b/backend/tests/wallet_balance_tests.rs index 9abb904..57b0301 100644 --- a/backend/tests/wallet_balance_tests.rs +++ b/backend/tests/wallet_balance_tests.rs @@ -17,7 +17,7 @@ async fn wallet_balance_less_than_required_returns_400_and_no_plan_or_audit_log( let user_id = Uuid::new_v4(); sqlx::query("INSERT INTO users (id, email, password_hash) VALUES ($1, $2, $3)") .bind(user_id) - .bind(format!("user-{}@example.com", user_id)) + .bind(format!("user-{user_id}@example.com")) .bind("hash") .execute(&ctx.pool) .await @@ -36,7 +36,7 @@ async fn wallet_balance_less_than_required_returns_400_and_no_plan_or_audit_log( &Header::default(), &inheritx_backend::auth::UserClaims { user_id, - email: format!("user-{}@example.com", user_id), + email: format!("user-{user_id}@example.com"), exp: 0, }, &EncodingKey::from_secret(b"secret_key_change_in_production"), @@ -60,7 +60,7 @@ async fn wallet_balance_less_than_required_returns_400_and_no_plan_or_audit_log( Request::builder() .method("POST") .uri("/api/plans") - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .header("Content-Type", "application/json") .header("X-Simulate-Wallet-Balance", "low") // Simulate low wallet balance .body(Body::from(body.to_string())) diff --git a/backend/tests/yield_reporting_tests.rs b/backend/tests/yield_reporting_tests.rs index 232ec00..991d13c 100644 --- a/backend/tests/yield_reporting_tests.rs +++ b/backend/tests/yield_reporting_tests.rs @@ -15,7 +15,7 @@ fn generate_admin_token(admin_id: Uuid) -> String { let exp = (Utc::now() + Duration::hours(24)).timestamp() as usize; let claims = AdminClaims { admin_id, - email: format!("admin-{}@example.com", admin_id), + email: format!("admin-{admin_id}@example.com"), role: "admin".to_string(), exp, }; @@ -36,7 +36,7 @@ async fn seed_user(ctx: &helpers::TestContext) -> Uuid { "#, ) .bind(user_id) - .bind(format!("{}@example.com", user_id)) + .bind(format!("{user_id}@example.com")) .bind("hashed-password") .execute(&ctx.pool) .await @@ -55,7 +55,7 @@ async fn seed_plan(ctx: &helpers::TestContext, user_id: Uuid, asset_code: &str) ) .bind(plan_id) .bind(user_id) - .bind(format!("Yield Plan {}", plan_id)) + .bind(format!("Yield Plan {plan_id}")) .bind("10.00") .bind("1000.00") .bind(asset_code) @@ -159,7 +159,7 @@ async fn admin_can_fetch_yield_summary_for_asset_vault() { Request::builder() .method("GET") .uri(format!("/api/admin/analytics/yield?assetCode={asset_code}")) - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) @@ -247,7 +247,7 @@ async fn admin_can_fetch_filtered_earnings_history() { .uri(format!( "/api/admin/analytics/yield/history?range=daily&assetCode={asset_code}&userId={user_id}&planId={plan_id}" )) - .header("Authorization", format!("Bearer {}", token)) + .header("Authorization", format!("Bearer {token}")) .body(Body::empty()) .unwrap(), ) From 66f9e1504ff2792c22c1c2be92434939536eda5c Mon Sep 17 00:00:00 2001 From: tali-creator Date: Sun, 29 Mar 2026 00:17:45 +0100 Subject: [PATCH 4/5] style: cargo fmt --- backend/Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 591e0d3..e901e97 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1928,6 +1928,7 @@ dependencies = [ "rust_decimal_macros", "serde", "serde_json", + "sha2", "soroban-sdk", "sqlx", "stellar-strkey 0.0.16", From 069506b98aca3ff05a1a8c2fd3dc880a4b9e624f Mon Sep 17 00:00:00 2001 From: tali-creator Date: Sun, 29 Mar 2026 00:28:52 +0100 Subject: [PATCH 5/5] fix/conflict --- .../20260221120000_add_plans_and_logs.sql | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/backend/migrations/20260221120000_add_plans_and_logs.sql b/backend/migrations/20260221120000_add_plans_and_logs.sql index e9f57e1..15ee016 100644 --- a/backend/migrations/20260221120000_add_plans_and_logs.sql +++ b/backend/migrations/20260221120000_add_plans_and_logs.sql @@ -1,20 +1,9 @@ --- Migration: Add plans and plan_logs tables +-- Migration: Add plan_logs table (plans already created in init) -CREATE TABLE plans ( +CREATE TABLE IF NOT EXISTS plan_logs ( id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL, - amount NUMERIC(20, 6) NOT NULL, - fee NUMERIC(20, 6) NOT NULL, - net_amount NUMERIC(20, 6) NOT NULL, - status VARCHAR(32) NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT NOW(), - updated_at TIMESTAMP NOT NULL DEFAULT NOW() -); - -CREATE TABLE plan_logs ( - id SERIAL PRIMARY KEY, - plan_id INTEGER NOT NULL REFERENCES plans(id), + plan_id UUID NOT NULL REFERENCES plans(id), action VARCHAR(64) NOT NULL, - performed_by INTEGER NOT NULL, + performed_by UUID NOT NULL, timestamp TIMESTAMP NOT NULL DEFAULT NOW() );