feat(din-dao): DIN DAO staged governance contracts — Stages A–D#27
Open
robertocarlous wants to merge 14 commits into
Open
feat(din-dao): DIN DAO staged governance contracts — Stages A–D#27robertocarlous wants to merge 14 commits into
robertocarlous wants to merge 14 commits into
Conversation
Introduces Documentation/technical/din-dao/README.md as the primary design specification for progressive DAO governance of the DIN platform. Covers: four-stage rollout (multisig → timelock → token-vote governor → guardian) mapped to devnet/testnet milestones; category threshold table; locked-DIN voting power decision; Safe-vs-own-multisig tradeoff; two- timelock delay model (24 h / 48 h); CLI command mapping for dincli dindao; integration points for PR InfiniteZeroFoundation#13, P3-5.x, slashing spec, and indexer; and resolution of all open design questions from decentralized-governance.md. No contracts yet — design-doc-first per issue sequencing guidance.
…egory thresholds Implements DinMultisig.sol: an N-of-M multisig with four proposal categories (Parameter, Operational, Treasury, Upgrade), independent confirmation thresholds per category, and an explicit NotExist → Open → Executable → Executed / Cancelled state machine. Inspired by the typed-proposal pattern in DAOFLcode MultiSigC, modernised to solc 0.8.28 conventions: custom errors, full NatSpec, events on every state transition (indexer-first per Developer/issues/indexer.md). Also includes: - IDinMultisig.sol interface with ProposalCategory and ProposalState enums - DinMultisig.t.sol: 22 unit tests covering constructor validation, full propose/confirm/revoke/execute/cancel lifecycle, category threshold enforcement, and failure paths - foundry/.gitignore: unblock test/dao/ so DAO tests are tracked
Thin DinTimelock.sol instantiation of OZ TimelockController, deployed as two instances at Stage B activation (devnet 3.0): DinTimelockShort — 24 h delay for Parameter and Operational proposals DinTimelockLong — 48 h delay for Treasury and Upgrade proposals At deployment both instances receive DinMultisig as PROPOSER_ROLE and CANCELLER_ROLE; EXECUTOR_ROLE is open (address(0)) so any address may execute once the delay has elapsed. DEFAULT_ADMIN_ROLE is renounced by passing address(0) as admin_ — no post-deploy admin authority exists. DinTimelock.t.sol covers: role assignment, open-executor grant, admin renouncement, short and long delay enforcement, schedule-and-execute lifecycle, pre-delay execution rejection, and canceller path.
DinGovernanceStaking.sol (stDIN): - Lock DIN → mint 1:1 non-transferable stDIN implementing OZ IVotes via ERC20Votes - transfer() and transferFrom() unconditionally revert (GS_NonTransferable) - Block-number clock (CLOCK_MODE = blocknumber) aligned with DinGovernor - Accounts must self-delegate or delegate to activate voting power; undelegated stDIN does not count toward Governor quorum - Validator stake in DinValidatorStake excluded from governance power in v1 DinGovernor.sol: - Composes OZ Governor + GovernorSettings + GovernorCountingSimple + GovernorVotes + GovernorVotesQuorumFraction + GovernorTimelockControl - All governance parameters (votingDelay, votingPeriod, proposalThreshold, quorumNumerator) are constructor-configurable and governance-settable post-deploy - Executes through DinTimelock; proposal routing to short/long delay via encoded timelock target in proposal targets array Tests: - DinGovernanceStaking.t.sol: lock/unlock mechanics, non-transferability, delegation + checkpoint invariants, totalLocked == DIN balance invariant - DinGovernor.t.sol: full lifecycle (propose → vote → queue → execute), quorum-not-met defeat, below-threshold proposal rejection
…o-reversal DinGuardian.sol provides narrow, time-limited emergency authority for the DIN platform. Guardian role held by DinMultisig; ratification authority held by DinGovernor. Each emergency action carries a reversal payload and a 7-day ratification window. Lifecycle: performAction() — guardian dispatches emergency call; window starts ratifyAction() — governor confirms action was appropriate; no reversal expireAction() — anyone triggers reversal if window elapses unratified Scope is intentionally restrictive: protective actions only (disable model, deauthorize slasher, pause dangerous flows). Restorative actions always go through normal governance — no emergency path for unblacklisting or re-enabling. Platform contracts will need a follow-up `onlyGuardian` integration task before Stage D can be activated on devnet 3.0 / testnet 1.0. DinGuardian.t.sol covers: construction, performAction dispatch and failure paths, ratifyAction guard, expireAction with auto-reversal, window enforcement, empty-reversal noop, setGovernor, action count, and invalid-ID rejection.
…ecisions Documentation/dindao.md §5a — Step-by-step runbook for transferring owner() of each platform contract (DinCoordinator, DinToken, DinValidatorStake, DINModelRegistry) and ProxyAdmin to DinTimelockLong at Stage B activation (devnet 3.0). Includes verification commands, rollback notes, and prerequisite checklist. Rehearsal on Optimism Sepolia devnet required before any testnet execution. Developer/issues/decentralized-governance.md — Append Decisions Made section recording all open design questions resolved during feat/din-dao: voting power model (locked DIN stDIN), quadratic voting rejection, UUPS proxy migration plan, multisig choice, timelock delays, blacklist/unblacklist asymmetry, supermajority thresholds, single-chamber governance, and stage activation schedule.
DaoInvariants.t.sol — four test suites:
I. StakingInvariantTest (stateful invariant via StakingHandler)
- invariant_TotalSupplyEqualsLockedDIN: stDIN.totalSupply() always equals
DIN held by the staking contract — no mint or burn without a matching
token transfer
- invariant_GhostLockedMatchesContract: ghost variable tracking every
lock/unlock matches both totalLocked() and totalSupply()
- invariant_TotalVotesNeverExceedSupply: sum of votes across all actors
never exceeds stDIN totalSupply — voting power cannot be conjured
II. TimelockFuzzTest
- testFuzz_CannotExecuteBeforeMinDelay: for any elapsed time in [0, MIN_DELAY),
execution always reverts — covers the full sub-delay range
- testFuzz_AlwaysExecutesAfterDelay: for any extra time >= 0 after MIN_DELAY,
execution always succeeds
III. MultisigFuzzTest
- testFuzz_ConfirmCountBounded: random confirm/revoke sequences from 3 signers
never produce a count outside [0, 3]
- testFuzz_ExecutableRequiresThreshold: a proposal reaches Executable only when
at least threshold (2) unrevoked confirms exist
IV. GuardianFuzzTest
- testFuzz_CannotExpireBeforeWindow: expireAction reverts for any elapsed
time in [0, WINDOW) regardless of proximity to boundary
- testFuzz_AlwaysExpiresAfterWindow: reversal is applied for any time >= WINDOW
- testFuzz_CannotRatifyTwice: double-ratify always reverts with DG_ActionNotActive
Brings in all upstream changes (Developer/ tree, dincli updates, foundry lib submodules, new tests, documentation) and merges with the DIN DAO contract work on this branch. Conflict resolutions: - foundry/.gitignore: take upstream (no test/* block needed) - dincli/main.py + dincli/cli/dindao.py: take upstream (newer CLI code) - README.md: take upstream wording, drop HEAD-only phrasing - Documentation/dindao.md: keep both — upstream base + our §5a runbook - Developer/issues/decentralized-governance.md: keep both — upstream base + our Decisions Made section appended at the end - dist/ binaries: take upstream build artifacts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the full DIN DAO contract stack per issue #23 (P3-5.1). Progressive decentralisation in four independently shippable stages, each mapped to a network milestone. No platform contracts were modified — all DAO contracts are purely additive.
DinMultisig.sol: N-of-M multisig with per-category typed proposals (Parameter / Operational / Treasury / Upgrade), independent confirmation thresholds, and an explicit state machine (Open → Executable → Executed / Cancelled)DinTimelock.sol: thin OZTimelockControllerwrapper, deployed as two instances — 24 h short delay (parameter/operational) and 48 h long delay (treasury/upgrade)DinGovernanceStaking.sol(stDIN): lock DIN → non-transferable checkpointed voting power via OZERC20Votes;DinGovernor.sol: full OZ Governor stack (GovernorSettings + GovernorCountingSimple + GovernorVotes + GovernorVotesQuorumFraction + GovernorTimelockControl)DinGuardian.sol: narrow emergency authority with 7-day ratification window; unratified actions are automatically reversedActivation schedule
Notes
onlyGuardianintegration on platform contracts before activationDinValidatorStakeis excluded from governance voting power in v1 (conflict-of-interest with slashing governance)DinMultisigis designed for devnet; Safe migration path for mainnet is documented in the design doc