Skip to content

[governance-dao] update_config can change total_supply mid-vote — quorum calculation in finalize() uses new supply, invalidating ongoing proposals #138

Description

@nonsobethel0-dev

Summary

contracts/governance-dao/src/lib.rs stores total_supply inside DaoConfig in instance storage. Admin can call update_config() at any time, including during an active vote. finalize() reads config.total_supply at finalization time to compute quorum, not the supply at proposal creation.

Code

finalize (line 229–232):

let config: DaoConfig = env.storage().instance().get(&StorageKey::Config).unwrap();
let total_supply = config.total_supply;  // ← reads CURRENT supply
let quorum_needed = total_supply * config.quorum_bps as i128 / 10_000;

Attack Scenarios

Reducing quorum to force a pass:

  1. Proposal is active; votes_for = 500, total_supply = 10,000 (quorum = 1,000 → proposal fails)
  2. Admin calls update_config setting total_supply = 5,000
  3. quorum_needed = 5,000 × 10% = 500 → proposal now passes with only 500 votes

Increasing quorum to force a fail:

  1. Proposal is 90% approved with high participation
  2. Admin inflates total_supply to make the quorum unreachable, causing the proposal to fail

Impact

  • Governance integrity is undermined — admin can unilaterally decide the outcome of any proposal by adjusting total_supply
  • total_supply is particularly sensitive because it cannot be verified on-chain against the actual token's total supply (no oracle)

Fix

Snapshot total_supply at proposal creation and store it on the Proposal struct:

// In Proposal struct
pub total_supply_at_creation: i128,

// In finalize
let quorum_needed = proposal.total_supply_at_creation * config.quorum_bps as i128 / 10_000;

Severity: High

Metadata

Metadata

Assignees

Labels

Stellar WaveIssues in the Stellar wave programbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions