Upgrade Mechanism
TimelockController-gated UUPS proxy upgrade flow with Safe multisig governance
Deploy implementation
Schedule (multisig proposal)
Execute after delay
Proxy upgrade call
| Step | Who | Action | Effect |
|---|---|---|---|
| ① | Deployer | Run deployImplementation.ts |
New logic contract deployed (bare, no proxy) |
| ② | Safe Multisig | Run scheduleUpgrade.ts → TimelockController.schedule() |
Upgrade queued, MIN_DELAY countdown begins |
| ③ | Anyone | Run executeUpgrade.ts → TimelockController.execute() |
AccessManager verifies UPGRADER_ROLE |
| ④ | TimelockController | proxy.upgradeToAndCall(newImpl) |
Proxy now delegates to V2 implementation |
Security Properties
Time delay
All upgrades must wait
All upgrades must wait
MIN_DELAY seconds after scheduling. Community and auditors can inspect the queued implementation before execution.
No admin backdoor
TimelockController's
TimelockController's
admin = address(0). Role changes to the timelock must go through the timelock itself — fully self-sovereign.
Multisig governance
Only the Safe multisig can propose upgrade implementations (
Only the Safe multisig can propose upgrade implementations (
TIMELOCK_PROPOSER_ROLE) by scheduling the upgrade payload. Requires M-of-N signers to reach consensus before scheduling.
Open execution
UPGRADE_EXECUTOR_ROLE = address(0) — anyone can trigger execution after the delay. No single point of failure at execution time.