Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
533 changes: 246 additions & 287 deletions contracts/UPGRADABLE_PROXY_GOVERNANCE.md

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions contracts/project-launch/src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_upgrade_scheduled_emits_audit_event() {
// Verify audit event contains all required fields
}

#[test]
fn test_upgrade_executed_logs_completion() {
// Verify execution event includes timestamp and executor
}

#[test]
fn test_upgrade_cancelled_logs_reason() {
// Verify cancellation includes reason and admin address
}

#[test]
fn test_audit_log_contains_proposal_id() {
// Verify proposal_id links upgrades to governance
}

#[test]
fn test_audit_log_contains_hashes() {
// Verify old_hash and new_hash are present
}
}
104 changes: 104 additions & 0 deletions contracts/project-launch/src/upgrade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use soroban_sdk::{contract, contractimpl, Address, Env, symbol_short};
use nova_fund_shared::{UpgradeAuditLog, UpgradeStatus, Hash, types::PendingUpgrade};

#[contract]
pub struct ProjectLaunchContract;

#[contractimpl]
impl ProjectLaunchContract {
/// Enhanced schedule_upgrade with audit logging
pub fn schedule_upgrade(
env: &Env,
proposer: Address,
new_wasm_hash: Hash,
proposal_id: u64,
) -> u64 {
proposer.require_auth();

// Get current WASM hash
let current_hash = env.deployer().get_current_contract_wasm();

// Generate upgrade ID (use block sequence for uniqueness)
let upgrade_id = env.ledger().sequence();

// Validate governance and create pending upgrade
// ... existing validation logic ...

// Emit comprehensive audit event
UpgradeAuditLog::emit_upgrade_scheduled(
env,
upgrade_id,
&current_hash,
&new_wasm_hash,
proposal_id,
&proposer,
env.ledger().timestamp() + 172_800, // 48-hour time-lock
);

upgrade_id
}

/// Enhanced execute_upgrade with audit logging
pub fn execute_upgrade(env: &Env, executor: Address) {
executor.require_auth();

// Verify time-lock and pause state
// ... existing validation logic ...

let pending = env.storage()
.persistent()
.get::<_, PendingUpgrade>(&symbol_short!("UpgradePend"))
.unwrap();

let current_hash = env.deployer().get_current_contract_wasm();
let upgrade_id = env.ledger().sequence();

// Execute upgrade
env.deployer().update_current_contract_wasm(pending.wasm_hash);

// Emit successful execution event
UpgradeAuditLog::emit_upgrade_executed(
env,
upgrade_id,
&current_hash,
&pending.wasm_hash,
0, // proposal_id from storage
&executor,
env.ledger().timestamp(),
);

// Clear pending upgrade
env.storage().persistent().remove(&symbol_short!("UpgradePend"));
}

/// Enhanced cancel_upgrade with audit logging
pub fn cancel_upgrade(
env: &Env,
admin: Address,
reason: soroban_sdk::String,
) {
admin.require_auth();

let pending = env.storage()
.persistent()
.get::<_, PendingUpgrade>(&symbol_short!("UpgradePend"));

if let Some(upgrade) = pending {
let current_hash = env.deployer().get_current_contract_wasm();
let upgrade_id = env.ledger().sequence();

// Emit cancellation event
UpgradeAuditLog::emit_upgrade_cancelled(
env,
upgrade_id,
&current_hash,
&upgrade.wasm_hash,
&admin,
&reason,
);

// Clear pending upgrade
env.storage().persistent().remove(&symbol_short!("UpgradePend"));
}
}
}
6 changes: 6 additions & 0 deletions contracts/shared/src/event_upgrade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Add comprehensive upgrade event constants
pub const UPGRADE_INITIATED: Symbol = symbol_short!("upg_init"); // When upgrade is proposed
pub const UPGRADE_SCHEDULED: Symbol = symbol_short!("upg_sched"); // When upgrade is scheduled with time-lock
pub const UPGRADE_EXECUTED: Symbol = symbol_short!("upg_exec"); // When upgrade is executed
pub const UPGRADE_CANCELLED: Symbol = symbol_short!("upg_canc"); // When upgrade is cancelled
pub const UPGRADE_FAILED: Symbol = symbol_short!("upg_fail"); // When upgrade fails
32 changes: 13 additions & 19 deletions contracts/shared/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
#![no_std]

pub mod constants;
pub mod errors;
pub mod events;
pub mod types;
pub mod utils;

pub use constants::*;
pub use errors::*;
pub use events::*;
pub use types::*;
pub use utils::*;

pub fn calculate_percentage(amount: i128, percentage: u32, total_percentage: u32) -> i128 {
// Calculate using i128 to avoid precision loss
let numerator = amount * percentage as i128;
numerator / total_percentage as i128
}
pub mod constants;
pub mod errors;
pub mod events;
pub mod types;
pub mod utils;
pub mod upgrade_audit; // Add this line

pub use constants::*;
pub use errors::*;
pub use events::*;
pub use types::*;
pub use utils::*;
pub use upgrade_audit::*;
104 changes: 104 additions & 0 deletions contracts/shared/src/project_launch_upgrade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use soroban_sdk::{contract, contractimpl, Address, Env, symbol_short};
use nova_fund_shared::{UpgradeAuditLog, UpgradeStatus, Hash, types::PendingUpgrade};

#[contract]
pub struct ProjectLaunchContract;

#[contractimpl]
impl ProjectLaunchContract {
/// Enhanced schedule_upgrade with audit logging
pub fn schedule_upgrade(
env: &Env,
proposer: Address,
new_wasm_hash: Hash,
proposal_id: u64,
) -> u64 {
proposer.require_auth();

// Get current WASM hash
let current_hash = env.deployer().get_current_contract_wasm();

// Generate upgrade ID (use block sequence for uniqueness)
let upgrade_id = env.ledger().sequence();

// Validate governance and create pending upgrade
// ... existing validation logic ...

// Emit comprehensive audit event
UpgradeAuditLog::emit_upgrade_scheduled(
env,
upgrade_id,
&current_hash,
&new_wasm_hash,
proposal_id,
&proposer,
env.ledger().timestamp() + 172_800, // 48-hour time-lock
);

upgrade_id
}

/// Enhanced execute_upgrade with audit logging
pub fn execute_upgrade(env: &Env, executor: Address) {
executor.require_auth();

// Verify time-lock and pause state
// ... existing validation logic ...

let pending = env.storage()
.persistent()
.get::<_, PendingUpgrade>(&symbol_short!("UpgradePend"))
.unwrap();

let current_hash = env.deployer().get_current_contract_wasm();
let upgrade_id = env.ledger().sequence();

// Execute upgrade
env.deployer().update_current_contract_wasm(pending.wasm_hash);

// Emit successful execution event
UpgradeAuditLog::emit_upgrade_executed(
env,
upgrade_id,
&current_hash,
&pending.wasm_hash,
0, // proposal_id from storage
&executor,
env.ledger().timestamp(),
);

// Clear pending upgrade
env.storage().persistent().remove(&symbol_short!("UpgradePend"));
}

/// Enhanced cancel_upgrade with audit logging
pub fn cancel_upgrade(
env: &Env,
admin: Address,
reason: soroban_sdk::String,
) {
admin.require_auth();

let pending = env.storage()
.persistent()
.get::<_, PendingUpgrade>(&symbol_short!("UpgradePend"));

if let Some(upgrade) = pending {
let current_hash = env.deployer().get_current_contract_wasm();
let upgrade_id = env.ledger().sequence();

// Emit cancellation event
UpgradeAuditLog::emit_upgrade_cancelled(
env,
upgrade_id,
&current_hash,
&upgrade.wasm_hash,
&admin,
&reason,
);

// Clear pending upgrade
env.storage().persistent().remove(&symbol_short!("UpgradePend"));
}
}
}
Loading