Skip to content
Merged
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
2 changes: 2 additions & 0 deletions contracts/governance-dao/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
8 changes: 8 additions & 0 deletions contracts/governance-dao/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 5 additions & 7 deletions fix.md
Original file line number Diff line number Diff line change
@@ -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
Guard: load the proposal and panic if not found
Test: execute a proposal_id that was never created, expect error
Loading