From 2a69466b3d5c4e2e2466c69481db6e644d1891fe Mon Sep 17 00:00:00 2001 From: zeugh Date: Mon, 29 Jun 2026 19:14:56 -0300 Subject: [PATCH 1/2] fix(torn): correct quorum calc + governance-config facts (review follow-up) - TORNClient.calculateQuorum: count forVotes + againstVotes (matches the on-chain Governance.state() quorum rule); update status docstring. - dao-config: proposal threshold 1,000 TORN (was 25,000); voting delay 75s (was ~1 block/12s); changeVote=true (re-voting overwrites the prior receipt on-chain). Refs review on #2002. --- apps/api/src/clients/torn/index.ts | 6 ++++-- apps/dashboard/shared/dao-config/torn.ts | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/api/src/clients/torn/index.ts b/apps/api/src/clients/torn/index.ts index cfe91c682..8658409dc 100644 --- a/apps/api/src/clients/torn/index.ts +++ b/apps/api/src/clients/torn/index.ts @@ -105,7 +105,9 @@ export class TORNClient< againstVotes: bigint; abstainVotes: bigint; }): bigint { - return votes.forVotes; + // Tornado's Governance.state() reaches quorum on forVotes + againstVotes + // (both sides count toward QUORUM_VOTES), not forVotes alone. + return votes.forVotes + votes.againstVotes; } alreadySupportCalldataReview(): boolean { @@ -123,7 +125,7 @@ export class TORNClient< * EXECUTED → finalized (persisted by indexer) * now < startTime → PENDING * now < endTimestamp → ACTIVE - * forVotes < quorum → NO_QUORUM + * forVotes + againstVotes < quorum → NO_QUORUM * forVotes <= againstVotes → DEFEATED * now < endTimestamp + EXECUTION_DELAY → QUEUED * now < endTimestamp + EXECUTION_DELAY + EXECUTION_EXPIRATION → PENDING_EXECUTION diff --git a/apps/dashboard/shared/dao-config/torn.ts b/apps/dashboard/shared/dao-config/torn.ts index 4abfeec66..c6a46acbe 100644 --- a/apps/dashboard/shared/dao-config/torn.ts +++ b/apps/dashboard/shared/dao-config/torn.ts @@ -30,7 +30,7 @@ export const TORN: DaoConfiguration = { }, rules: { delay: true, - changeVote: false, + changeVote: true, timelock: true, cancelFunction: false, logic: "For", @@ -113,7 +113,7 @@ export const TORN: DaoConfiguration = { GOVERNANCE_IMPLEMENTATION_CONSTANTS[ GovernanceImplementationEnum.PROPOSAL_THRESHOLD ].description, - currentSetting: "The Proposal Threshold is set to 25,000 TORN.", + currentSetting: "The Proposal Threshold is set to 1,000 TORN.", impact: "Tornado Cash has a proposal threshold that adds a cost barrier to submitting proposals, but it may not be high enough relative to circulating supply to fully deter spam.", recommendedSetting: @@ -235,7 +235,7 @@ export const TORN: DaoConfiguration = { GovernanceImplementationEnum.VOTING_DELAY ].description, currentSetting: - "The Voting Delay is set to approximately 1 block (~12 seconds).", + "The Voting Delay is set to 75 seconds.", impact: "The Voting Delay period is extremely short. This gives delegates and stakeholders little time to coordinate their votes and for the DAO to protect itself against an attack. This poses a critical governance risk.", recommendedSetting: From 4e60b18e94bbe771c370650e1d3546c266b08269 Mon Sep 17 00:00:00 2001 From: zeugh Date: Mon, 29 Jun 2026 19:29:34 -0300 Subject: [PATCH 2/2] fix(torn): reconcile dashboard with quorum + re-vote changes (Codex) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rules.logic: "All Votes Cast" (was "For") to match calculateQuorum now counting forVotes + againstVotes — dashboard no longer explains the opposite quorum rule. - VOTE_MUTABILITY: LOW + copy reflecting that TORN allows changing votes (consistent with rules.changeVote=true); drop stale requirements. - attackExposure GOV_FRONTEND_RESILIENCE: remove the 'immutable votes' claim (votes are mutable) — keeps the unhardened-interface point. --- apps/dashboard/shared/dao-config/torn.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/dashboard/shared/dao-config/torn.ts b/apps/dashboard/shared/dao-config/torn.ts index c6a46acbe..8ba41d7a8 100644 --- a/apps/dashboard/shared/dao-config/torn.ts +++ b/apps/dashboard/shared/dao-config/torn.ts @@ -33,7 +33,7 @@ export const TORN: DaoConfiguration = { changeVote: true, timelock: true, cancelFunction: false, - logic: "For", + logic: "All Votes Cast", quorumCalculation: "Fixed at 100,000 TORN", }, }, @@ -210,23 +210,18 @@ export const TORN: DaoConfiguration = { "A veto mechanism or Security Council should be established to protect against malicious proposals.", }, [GovernanceImplementationEnum.VOTE_MUTABILITY]: { - riskLevel: RiskLevel.MEDIUM, + riskLevel: RiskLevel.LOW, description: GOVERNANCE_IMPLEMENTATION_CONSTANTS[ GovernanceImplementationEnum.VOTE_MUTABILITY ].description, currentSetting: - "The DAO does not allow changing votes once they have been cast.", + "The DAO allows voters to change their vote while a proposal is active; re-casting overwrites the prior ballot.", impact: - "Governance participants cannot change their votes after casting them. In the event of an interface hijack on the voting platform to support the attack, voters cannot revert their vote.", + "Voters can revise their vote until the voting period ends — e.g. to revert a ballot if a malicious proposal or an interface compromise is discovered.", recommendedSetting: RECOMMENDED_SETTINGS[GovernanceImplementationEnum.VOTE_MUTABILITY], - nextStep: - "Allow voters to change their vote until the Voting Period ends.", - requirements: [ - "If voters cannot revise their ballots, a last-minute interface exploit or late discovery of malicious code can trap delegates in a choice that now favors an attacker, weakening the DAO's defense.", - "The governance contract should let any voter overwrite their previous vote while the voting window is open.", - ], + nextStep: "The parameter is in its lowest-risk condition.", }, [GovernanceImplementationEnum.VOTING_DELAY]: { riskLevel: RiskLevel.HIGH, @@ -321,7 +316,7 @@ export const TORN: DaoConfiguration = { }, [RiskAreaEnum.GOV_FRONTEND_RESILIENCE]: { description: - "Interface protections are present but not fully hardened, and immutable votes limit recovery from front-end compromise, resulting in moderate governance interface risk.", + "Interface protections are present but not fully hardened (e.g. not served from immutable/decentralized storage), resulting in moderate governance interface risk. Mutable votes do allow recovery if a front-end compromise is caught during the voting window.", }, }, },