Skip to content

feat(gov): governance script suite — per-contract ops + runbooks + Safe/Timelock#4

Open
jardenx wants to merge 2 commits intomainfrom
feat/governance-scripts
Open

feat(gov): governance script suite — per-contract ops + runbooks + Safe/Timelock#4
jardenx wants to merge 2 commits intomainfrom
feat/governance-scripts

Conversation

@jardenx
Copy link
Copy Markdown
Contributor

@jardenx jardenx commented Apr 23, 2026

Implements the APEX v1 governance stack per
docs/superpowers/specs/2026-04-23-governance-scripts-design.md:

Lib layer (scripts/gov/lib/):

  • types.ts shared CallItem / ExecMode / GovContext / AnyViem
  • cli.ts parseGovArgs — per-script booleanFlags, checksummed
    requireAddress, zero-addr rejection, --flag=value guard
  • config.ts pickMode (dry-run / eoa / propose / calldata) + buildContext
  • exec.ts 4-mode dispatcher; dry-run exits 1 on any revert
  • safe.ts @safe-global protocol-kit + api-kit wrapper; MultiSend
    batch; chainId-aware Safe UI short name
  • is-main.ts argv-based entry detection (works under Bun + Hardhat 3)

Per-contract CLIs (scripts/gov/):

  • commerce.ts setPlatformFee | pause | unpause | transferOwnership
  • router.ts setPolicyWhitelist | setCommerce | pause | unpause |
    transferOwnership
  • policy.ts addVoter | removeVoter | setQuorum | transferAdmin

Runbooks (scripts/gov/runbooks/):

  • deploy-timelock.ts OZ TimelockController, delay=0 for testnet
  • transfer-ownership.ts 3-call Safe batch: commerce + router + policy
    → timelockProxy
  • rotate-policy.ts deploy new OptimisticPolicy (EOA) + whitelist new
    + revoke old (batch); --skip-revoke supported
  • upgrade.ts deploy impl(s) (EOA) + upgradeToAndCall (batch);
    --commerce / --router / --all modes

Contract:

  • contracts/TimelockExport.sol concrete subclass surfacing the OZ
    TimelockController artifact for Hardhat

Config:

  • scripts/addresses.ts + timelockProxy + multisig optional fields
  • package.json 11 gov:* scripts (local + testnet)

Tests (test/unit/gov/, 46 tests total):

  • cli (17), is-main (4), pickMode (4), exec (3)
  • commerce (3), router (4), policy (4)
  • runbooks/ deploy-timelock (1), transfer-ownership (1),
    rotate-policy (2), upgrade (3)

Docs:

  • scripts/gov/README.md operator invocation
  • docs/superpowers/specs/...-design.md (EN + zh) design
  • docs/superpowers/plans/...-governance-scripts.md implementation plan

Deps (devDependencies):

  • @safe-global/protocol-kit ^5
  • @safe-global/api-kit ^2

Hardhat 3 note: bunx hardhat run does not forward CLI args after the script
path. The gov scripts read GOV_ARGS env var when present; README documents
the invocation pattern. Direct bun script.ts invocation also works.

jardenx added 2 commits April 23, 2026 16:24
…fe/Timelock

Implements the APEX v1 governance stack per
docs/superpowers/specs/2026-04-23-governance-scripts-design.md:

Lib layer (scripts/gov/lib/):
  - types.ts        shared CallItem / ExecMode / GovContext / AnyViem
  - cli.ts          parseGovArgs — per-script booleanFlags, checksummed
                    requireAddress, zero-addr rejection, --flag=value guard
  - config.ts       pickMode (dry-run / eoa / propose / calldata) + buildContext
  - exec.ts         4-mode dispatcher; dry-run exits 1 on any revert
  - safe.ts         @safe-global protocol-kit + api-kit wrapper; MultiSend
                    batch; chainId-aware Safe UI short name
  - is-main.ts      argv-based entry detection (works under Bun + Hardhat 3)

Per-contract CLIs (scripts/gov/):
  - commerce.ts     setPlatformFee | pause | unpause | transferOwnership
  - router.ts       setPolicyWhitelist | setCommerce | pause | unpause |
                    transferOwnership
  - policy.ts       addVoter | removeVoter | setQuorum | transferAdmin

Runbooks (scripts/gov/runbooks/):
  - deploy-timelock.ts       OZ TimelockController, delay=0 for testnet
  - transfer-ownership.ts    3-call Safe batch: commerce + router + policy
                             → timelockProxy
  - rotate-policy.ts         deploy new OptimisticPolicy (EOA) + whitelist new
                             + revoke old (batch); --skip-revoke supported
  - upgrade.ts               deploy impl(s) (EOA) + upgradeToAndCall (batch);
                             --commerce / --router / --all modes

Contract:
  - contracts/TimelockExport.sol   concrete subclass surfacing the OZ
                                   TimelockController artifact for Hardhat

Config:
  - scripts/addresses.ts           + timelockProxy + multisig optional fields
  - package.json                   11 gov:* scripts (local + testnet)

Tests (test/unit/gov/, 46 tests total):
  - cli (17), is-main (4), pickMode (4), exec (3)
  - commerce (3), router (4), policy (4)
  - runbooks/ deploy-timelock (1), transfer-ownership (1),
              rotate-policy (2), upgrade (3)

Docs:
  - scripts/gov/README.md                                  operator invocation
  - docs/superpowers/specs/...-design.md  (EN + zh)        design
  - docs/superpowers/plans/...-governance-scripts.md       implementation plan

Deps (devDependencies):
  - @safe-global/protocol-kit ^5
  - @safe-global/api-kit ^2

Hardhat 3 note: bunx hardhat run does not forward CLI args after the script
path. The gov scripts read GOV_ARGS env var when present; README documents
the invocation pattern. Direct bun script.ts invocation also works.
These were brainstorming-stage artifacts generated by the superpowers skill
chain (spec → plan). They lived in the repo long enough for me to implement
from, but don't belong in long-term source of truth. Removing from tracking.
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