Skip to content

feat(autocrat): on-chain governance with safety rails#36

Open
hellno wants to merge 4 commits intoJejuNetwork:mainfrom
hellno:autocrat-fixes
Open

feat(autocrat): on-chain governance with safety rails#36
hellno wants to merge 4 commits intoJejuNetwork:mainfrom
hellno:autocrat-fixes

Conversation

@hellno
Copy link
Contributor

@hellno hellno commented Feb 10, 2026

Summary

  • Adds full on-chain governance lifecycle: proposal submission, board voting, immutable director decisions, and trustless execution via BoardGovernance contract
  • Fixes P0 bugs (double parseEther, wrong contract addresses, memory leak) and P1 issues (terminal state protection, director status guards, spam protection, hardcoded localnet config)
  • ProposalService reads contract address from config and supports localnet/testnet/mainnet chains

Changes

Contract (BoardGovernance.sol + IBoardGovernance.sol)

  • On-chain proposal submission, status lifecycle, board voting, director decisions, trustless execution
  • Terminal state protection: COMPLETED/REJECTED/VETOED/DUPLICATE/SPAM block further transitions
  • Director status guard: approval only allowed from DIRECTOR_QUEUE or AUTOCRAT_FINAL
  • submitProposal gated with onlyAutocrat to block spam

API (proposal-service.ts)

  • Full ProposalService with submit, vote, director decision, execute methods
  • Treasury call encoding helpers for spend/recurring/cancel proposals
  • Reads boardGovernance address from contracts.json (fail-fast on missing)
  • getChain() supports chain IDs 31337, 420690, 420691

Config (contracts.json)

  • Added boardGovernance to autocrat category for all 3 networks
  • Localnet address set after deploy

Tests (BoardGovernance.t.sol)

  • 15 Forge tests covering terminal states, director guards, access control

Test plan

  • forge build compiles
  • forge test --match-contract BoardGovernanceTest — 15/15 pass
  • Deployed to localnet, address updated in contracts.json
  • E2E via cast: submit → vote → director approve → advance time → execute → verify COMPLETED
  • Terminal state verified: updateProposalStatus on COMPLETED → reverts InvalidStatusTransition
  • Spam protection verified: submitProposal from random address → reverts NotAuthorized

- Add executeProposal() - permissionless, anyone can call after grace period
- Add canExecuteProposal() and timeUntilExecutable() view functions
- Add executionWindow (7 days default) for proposal expiration
- Proposals without targetContract mark COMPLETED without external call
- Follow GovernanceTimelock pattern with proper guards

Validated: submitted proposal, approved, advanced time, executed from
different address - confirmed permissionless execution works.

Reviewed by codex: goal achieved, security model sound.
1. Auth provider enum: passkey was inserted at position 1, shifting all
   other providers and corrupting on-chain attestation mappings. Moved
   passkey to position 9 (append) to preserve backward compatibility.

2. parseEther removal: the route handler was correctly converting
   frontend ETH strings ('0.01') to wei via parseEther(). Removing it
   caused BigInt('0.01') to throw at runtime. Restored parseEther.

3. autocrat contract category: code changed lookups from 'governance'
   to 'autocrat' but testnet/mainnet contracts.json lacked this
   category. Added autocrat category to both networks.
- Terminal state protection: block transitions out of COMPLETED/REJECTED/VETOED/DUPLICATE/SPAM
- Director status guard: require DIRECTOR_QUEUE or AUTOCRAT_FINAL for director approval
- Spam protection: gate submitProposal with onlyAutocrat modifier
- ProposalService: read address from config instead of hardcoded, support testnet/mainnet chains
- Add boardGovernance field to contracts.json for all networks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant