feat(timelock): permissionless execution - #302
Conversation
|
Warning Review limit reached
Next review available in: 6 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
10b932c to
e79c442
Compare
1e1d1c4 to
01762e7
Compare
Execution is permissionless, so the Safe never holds EXECUTOR_ROLE and revoking it from the Safe is a no-op rather than a detectable break. The executor requirement is pinned against address(0) by testAssertRejectsClosedExecutorRole instead.
01762e7 to
4e84176
Compare
The open-executor property was pinned only as a role bit (hasRole(EXECUTOR_ROLE, address(0))), relying on OZ's onlyRoleOrOpenRole semantics transitively. Prove it end-to-end: a roleless caller executes a matured operation and its effect lands, and the same caller can neither schedule nor cancel — the privileged/open asymmetry the design claims. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed 001f815: KEEP — permissionless execution done the OZ-sanctioned way (executors = [address(0)] at construction, onlyRoleOrOpenRole open role), invariant correctly inverted (open executor REQUIRED, closed executor rejected by test; proposer/canceller/root-admin still closed), all three new CREATE2 pins verified live on-chain with the OZ runtime code, superseded timelocks abandoned clean (nothing was ever migrated to them), and the property is now proven behaviourally: a roleless anon executes a matured operation end-to-end and the same anon can neither schedule nor cancel. Full fork suite green at this head, including on the restack merge commit. Rulings-conformance: checked against the repo CLAUDE.md rulings and the rulings stated for this work —
|
|
Reviewed 001f815: KEEP — permissionless execution done the OZ-sanctioned way (executors = [address(0)] at construction, onlyRoleOrOpenRole open role), invariant correctly inverted (open executor REQUIRED, closed executor rejected by test; proposer/canceller/root-admin still closed), all three new CREATE2 pins verified live on-chain with the OZ runtime code, superseded timelocks abandoned clean (nothing was ever migrated to them), and the property is now proven behaviourally: a roleless anon executes a matured operation end-to-end and the same anon can neither schedule nor cancel. Full fork suite green at this head, including on the restack merge commit. Rulings-conformance: checked against the repo CLAUDE.md rulings and the rulings stated for this work —
|

Clearstar want a 48h lock with permissionless execution.
EXECUTOR_ROLEis now granted toaddress(0)at construction, which OZ'sonlyRoleOrOpenRolereads as "open to everyone": once the delay has run anyone may execute, so the operator cannot censor a matured operation. The Safe keepsPROPOSERandCANCELLERand executes as a member of the public rather than by privilege.cancel()has no open-role path in OZ, so vetoing stays privileged — that asymmetry is the design. No separate canceller for now;TIMELOCK_CANCELLERstays a placeholder and the Safe cancels.This moves every address
Executors are a constructor argument, so the CREATE2 address changes on all three chains. The permissionless timelocks are deployed and live on Base, Ethereum and HyperEVM, and this PR records their pins —
testPinsMatchDerivedAddressesties each pin to the derivation. The superseded timelocks hold no power — nothing was migrated to them, so they are abandoned in place.Invariant inverted
assertTimelockStatepreviously rejected an open executor. It now requires one, and the test that pinned the old policy is inverted to reject a closed executor — so silently re-closing execution fails rather than passing.The property is also proven behaviourally, not just as a role bit: a roleless anon executes a matured operation end-to-end (and its effect lands), and the same anon can neither schedule nor cancel — the open/privileged asymmetry as tests.
Hazard recorded
OZ operations never expire. With open execution an abandoned operation stays executable by anyone indefinitely, so an operation you decide against must be cancelled, not merely left unexecuted. Written into the runbook.
Local: build, fmt, 18/18 timelock lib, 13/13 script suites, 6/6 forcing function — all three chains.