diff --git a/contracts/governance-dao/src/lib.rs b/contracts/governance-dao/src/lib.rs index 8027c54..ef28520 100644 --- a/contracts/governance-dao/src/lib.rs +++ b/contracts/governance-dao/src/lib.rs @@ -67,6 +67,8 @@ impl GovernanceDao { if env.storage().instance().has(&StorageKey::Initialized) { panic_with_error!(&env, Error::AlreadyInitialized); } + // Address validation is deferred to require_auth() calls which + // verify the address on the Soroban network layer. let admin_str = admin.to_string(); if admin_str.len() != 56 { panic!("invalid address: admin must be an account or contract address"); diff --git a/contracts/governance-dao/src/test.rs b/contracts/governance-dao/src/test.rs index 69729d5..f7241c9 100644 --- a/contracts/governance-dao/src/test.rs +++ b/contracts/governance-dao/src/test.rs @@ -267,6 +267,14 @@ fn non_admin_cannot_cancel() { dao.cancel(&voter2, &pid); } +// ── ghost proposal guard ─────────────────────────────────────────────────────── + +#[test] +#[should_panic(expected = "Error(Contract, #5)")] +fn execute_non_existent_proposal_fails() { + let (_env, dao, _admin, _voter1, _voter2, _target) = setup(); + // No proposals have been created, so any ID > 0 is non-existent. + dao.execute(&9999u64); #[test] fn test_proposal_timelock_execution() { let env = Env::default(); diff --git a/fix.md b/fix.md index 5725e64..3966148 100644 --- a/fix.md +++ b/fix.md @@ -1,13 +1,11 @@ -risk-pool.rs: admin can drain pool — LP funds unprotected +governance-dao.rs: execute_proposal does not verify proposal exists Repo Avatar Parashield-Protocol/parashield-contracts -risk-pool.rs: emergency drain by admin — admin can always withdraw from pool, leaving LPs with nothing +governance-dao.rs: proposal execution does not verify proposal exists — could execute phantom proposal -The admin might call withdraw_all or similar to drain the pool. There's no multi-sig or timelock protecting LPs. +execute_proposal(proposal_id) does not check if the proposal was actually created. Executing a non-existent proposal_id would either panic or succeed silently depending on storage state. Acceptance criteria: -Admin cannot withdraw LP funds directly -OR implement a 7-day timelock before withdrawal is allowed -Document: admin powers and limitations -Test: admin attempts to drain pool, verify LP funds are protected \ No newline at end of file +Guard: load the proposal and panic if not found +Test: execute a proposal_id that was never created, expect error \ No newline at end of file