Skip to content

Fix balance_at snapshot stub — token-weighted snapshot voting is non-functional #501

Description

@PrincessnJoy

Description

The token contract exposes a balance_at(owner, ledger) function intended to return a voter's token balance at a specific historical ledger (snapshot), which the governance contract uses to prevent vote manipulation via flash-loan or last-minute token acquisition.

The current implementation is a stub that ignores the ledger parameter and simply returns the current balance:

pub fn balance_at(env: Env, owner: Address, _ledger: u64) -> i128 {
    // TODO: implement historical snapshot
    GovernanceStorage::balance(&env, &owner)  // returns CURRENT balance, not snapshot
}

The governance contract stores a snapshot_ledger on each proposal (set at proposal creation time) and passes it to balance_at when computing a voter's voting power. Since the snapshot is not honored, an attacker can:

  1. Acquire a large token position after a proposal is created
  2. Vote with that inflated balance
  3. Transfer tokens away after voting

This undermines the entire voting-power fairness model.

Acceptance Criteria

  • Implement a real balance snapshot mechanism. Possible approaches:
    • Checkpointing: Store balance checkpoints (ledger → balance) per address on every transfer/mint/burn; balance_at binary-searches checkpoints
    • Off-chain oracle / Merkle proof: Acceptable only if the trust model is explicitly documented
  • balance_at(owner, ledger) returns the balance the owner held at ledger, not the current balance
  • Governance contract's cast_vote correctly uses proposal.snapshot_ledger to query historical voting power
  • Add unit tests: voter acquires tokens after snapshot — their extra balance is NOT counted
  • Add unit tests: voter transfers tokens after snapshot — their original balance IS still counted
  • Gas cost of balance_at is documented in docs/gas-budgeting.md
  • Storage growth from checkpointing is analyzed and documented in docs/storage.md

Security Impact

Without snapshot voting, the system is vulnerable to vote manipulation via token transfers between voters within the voting window. This is a security issue, not just a correctness issue.

Priority

Critical

Estimated Effort

Large — requires storage schema changes, migration strategy, and new tests.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions