Skip to content

feat(din-dao): DIN DAO staged governance contracts — Stages A–D#27

Open
robertocarlous wants to merge 14 commits into
InfiniteZeroFoundation:feat/din-daofrom
robertocarlous:feat/din-dao
Open

feat(din-dao): DIN DAO staged governance contracts — Stages A–D#27
robertocarlous wants to merge 14 commits into
InfiniteZeroFoundation:feat/din-daofrom
robertocarlous:feat/din-dao

Conversation

@robertocarlous

@robertocarlous robertocarlous commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

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.

  • Stage ADinMultisig.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)
  • Stage BDinTimelock.sol: thin OZ TimelockController wrapper, deployed as two instances — 24 h short delay (parameter/operational) and 48 h long delay (treasury/upgrade)
  • Stage CDinGovernanceStaking.sol (stDIN): lock DIN → non-transferable checkpointed voting power via OZ ERC20Votes; DinGovernor.sol: full OZ Governor stack (GovernorSettings + GovernorCountingSimple + GovernorVotes + GovernorVotesQuorumFraction + GovernorTimelockControl)
  • Stage DDinGuardian.sol: narrow emergency authority with 7-day ratification window; unratified actions are automatically reversed

Activation schedule

Stage Contracts Target milestone
A DinMultisig Devnet 2.0 (shadow-only)
B DinTimelockShort + DinTimelockLong Devnet 3.0
C DinGovernanceStaking + DinGovernor Testnet 1.0
D DinGuardian Testnet 1.0–2.0

Notes

  • Governance contracts are intentionally non-upgradeable
  • Stage D requires a follow-up onlyGuardian integration on platform contracts before activation
  • Validator stake in DinValidatorStake is excluded from governance voting power in v1 (conflict-of-interest with slashing governance)
  • DinMultisig is designed for devnet; Safe migration path for mainnet is documented in the design doc

umeradl and others added 14 commits May 15, 2026 02:42
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
@umeradl umeradl added this to the Devnet 3.0 milestone Jul 12, 2026
@umeradl umeradl added the Draft label Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants