Governor Timelock
Overview
Replaces a Governor EOA with a contract-based timelock so all governor-privileged transactions execute after a delay.
Separates responsibilities via roles and enforces a schedule → wait → execute lifecycle.
Prevents immediate parameter and role changes. Certain meta‑changes are themselves timelocked.
Key Roles
PROPOSER_ROLE: Schedules proposals viascheduleProposals(...)orproposeRoleUpdates(...).EXECUTOR_ROLE: Executes queued proposals during their execution window viaexecuteProposals(...).CANCELLER_ROLE: Unschedules proposals viaunscheduleProposals(...)(cannot unschedule role updates).ROLE_ADMIN: Proposes role changes usingproposeRoleUpdates(...)and manages token withdrawer pending address.tokenWithdrawer(separate address): Can rescue ERC20 tokens accidentally sent to the timelock.
Timelock Parameters
Defaults are set at deployment to at least
MIN_DELAY = 1 dayandMIN_EXECUTION_WINDOW = 1 day.Default parameters can be changed with
setDefaultTimelockParameters(delay, executionWindow). This function isonlySelfand must be executed via a timelocked proposal to the timelock itself.Per‑function overrides:
setFunctionTimelockParameters(target, selector, delay, executionWindow)supports either both values set to zero (use defaults) or both meeting minimums. This function isonlySelfand must be timelocked.Changing a function’s timelock uses that function’s prior timelock parameters to gate the change (cannot reduce a delay instantly).
Proposal Lifecycle
Schedule:
scheduleProposals(address[] targets, bytes[] data)records proposals withdelayedUntilandvalidUntiland computes aproposalHash = keccak256(target, data).Role updates: Must be scheduled via
proposeRoleUpdates(bytes32[] roles, address[] accounts, bool[] shouldGrant)(not viascheduleProposals). These cannot be unscheduled.Unschedule:
unscheduleProposals(uint256[] proposalIds)allowed only whenisUnschedulableis true (i.e., not role updates).Execute:
executeProposals(uint256[] ids, address[] targets, bytes[] data)checks existence, timing window, and data hash, deletes the proposal, then calls the target with the exactdata.Window semantics: Executable if
block.timestampis within[delayedUntil, validUntil]viaisExecutable(id).
Security Notes
onlySelfgates sensitive meta‑operations (updateRole, timelock config), ensuring they can only be changed through the timelock.Binds execution to exact calldata via the stored
proposalHash.Disallows scheduling to EOAs (
target.code.length > 0).Role updates, once queued, cannot be unscheduled.
Token Rescue
setPendingTokenWithdrawer(new)(ROLE_ADMIN) →acceptTokenWithdrawer()(new address) establishes the token withdrawer.withdrawERC20Token(token, amount)callable only bytokenWithdrawerto rescue funds sent to the timelock.
Typical Workflows
Schedule and execute a MapleGlobals change:
scheduleProposals([globals], [abi.encodeWithSelector(globals.setPlatformServiceFeeRate.selector, newRate)])(PROPOSER).Wait until
isExecutable(id)returns true within the execution window.executeProposals([id], [globals], [encodedData])(EXECUTOR).
Grant
EXECUTOR_ROLEto a new account:proposeRoleUpdates([EXECUTOR_ROLE], [newExecutor], [true])(ROLE_ADMIN).After delay,
executeProposals([id], [timelock], [abi.encodeWithSelector(timelock.updateRole.selector, EXECUTOR_ROLE, newExecutor, true)])(EXECUTOR).
Set a per‑function override (e.g., extend delay for
globals.setPriceOracle):Schedule
setFunctionTimelockParameters(globals, setPriceOracle.selector, 2 days, 1 day)to the timelock (PROPOSER).Execute after the prior timelock for that function has elapsed (EXECUTOR).
Events and Monitoring
ProposalScheduled,ProposalExecuted,ProposalUnscheduledfor lifecycle transitions.FunctionTimelockSet,DefaultTimelockSetfor configuration changes.RoleUpdatedfor access changes.PendingTokenWithdrawerSetandTokenWithdrawerAcceptedfor rescue admin.
Deployment and Setup
Constructor arguments:
tokenWithdrawer,proposer,executor,canceller,roleAdmin.Defaults initialize to minimums and can be increased later via timelocked calls.
Recommended mapping:
Governance multisig:
PROPOSER_ROLE,EXECUTOR_ROLE,ROLE_ADMIN.Security/ops multisig:
CANCELLER_ROLE(to unschedule non‑role proposals when needed).
Context
This contract replaces a Governor EOA so that all governor‑privileged transactions are enforced to pass through a timelock.
Pool Delegate–level timelocks (e.g., contract upgrades) remain documented separately. See
technical-resources/admin-functions/timelocks.md.
Last updated