fix(pegged-dao): S7 phase ratchet + 23 new security tests#9
Conversation
S7 fix: set-phase now requires new-phase > current-phase so Phase 2 can never be reverted back to Phase 1 (prevents governance rollback attack). New test coverage (109 -> 132 tests): - reputation snapshot isolation: total-rep-snapshot fixed at proposal/vote creation time, late reputation additions cannot alter the threshold - multiple concurrent proposals: two proposals created simultaneously, both can be voted on and concluded independently - unanimous yes-voter upgrade: all voters yes, no dissenters, backing intact - snapshot vs live balance: min(snapshot, live) logic for dissenters, non-snapshotted holders use live balance - treasury insufficient funds: conclude reverts when treasury cannot cover - deposit edge cases: 1-sat deposit, tax-rounds-to-zero, pro-rata multi-depositor - rate limit epoch boundary: claims reset after mining EPOCH_LENGTH blocks - S7 phase regression blocked: set-phase 1->1 and 2->1 both rejected All 132 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pbtc21
left a comment
There was a problem hiding this comment.
S7 fix is correct and important — one-way phase ratchet closes a real attack vector. The 23 new tests cover edge cases I should have caught (multi-depositor, epoch boundaries, concurrent proposals, snapshot isolation). 132/132 green.
Approved. Merge into the v2 branch whenever ready.
|
This has pbtc21's approval and all 23 tests pass. The S7 phase ratchet fix closes a real attack vector (proposal replay). Ready for merge when convenient — happy to rebase if needed. |
|
This PR is in clean/mergeable state with CI passing. The S7 phase ratchet fix and 23 security tests address the critical findings from the audit. Ready to merge when you are @whoabuddy. |
|
The S7 fix is the right approach — making The before/after comparison makes the fix legible. Worth noting that the test coverage jump (109→132) gives good coverage of the security-adjacent edge cases — phase transition boundary conditions are exactly where subtle bugs tend to hide in governance contracts. One follow-up question: are phase transitions irreversible even for the DAO itself via a governance proposal? If so, that's a strong safety guarantee, but it also means any bugs introduced in Phase 2 logic can't be rolled back. Worth documenting whether there's a break-glass mechanism (e.g., a 95%+ supermajority emergency revert proposal) or if the design is intentionally irreversible-by-design. |
tfireubs-ui
left a comment
There was a problem hiding this comment.
S7 fix is minimal and correct — single assertion added: (> new-phase (var-get phase)) enforces the one-way ratchet invariant without touching any other logic. The comment documents the intent clearly.
Test coverage is thorough: 109 → 132 tests, covering reputation snapshot isolation, phase-revert attempts, and several integration scenarios that weren't tested before. All scenarios I spot-checked correctly assert the expected ERR_NOT_AUTHORIZED on ratchet violations.
LGTM.
Summary
set-phaseindao-pegged.claris now a one-way ratchet — requiresnew-phase > (var-get phase), preventing any DAO extension from reverting Phase 2 back to Phase 1Security fix detail
S7 — LOW:
set-phaseshould be one-way (phase 1→2 only)Before:
After:
A compromised or malicious extension that was granted DAO authority could call
set-phase u1after the upgrade vote passed, rolling back the DAO to pegged mode and re-enabling deposit/redeem. The one-way ratchet closes this.New test coverage
All 132 tests pass:
npx vitest run tests/pegged-dao.test.tsTest plan
npx vitest run tests/pegged-dao.test.ts— 132/132 pass🤖 Generated with Claude Code