A minimal, gas-efficient timelock controller for Ethereum governance.
- Role-based access control: Admin, Proposer, Executor, Canceller roles
- Configurable delays: 1 hour minimum, 30 days maximum
- Batch operations: Schedule and execute multiple calls atomically
- Operation chaining: Predecessor dependencies for ordered execution
- Open execution mode: Allow anyone to execute (optional)
| Role | Permissions |
|---|---|
ADMIN_ROLE |
Grant/revoke roles |
PROPOSER_ROLE |
Schedule operations, auto-granted canceller |
EXECUTOR_ROLE |
Execute ready operations |
CANCELLER_ROLE |
Cancel pending operations |
address[] memory proposers = new address[](1);
proposers[0] = 0x...; // Your proposer
address[] memory executors = new address[](1);
executors[0] = 0x...; // Your executor (or address(0) for open execution)
Timelock timelock = new Timelock(
1 days, // Minimum delay
proposers,
executors,
msg.sender // Admin
);bytes memory data = abi.encodeCall(Target.setValue, (42));
bytes32 id = timelock.schedule(
targetAddress, // Target contract
0, // ETH value
data, // Calldata
bytes32(0), // No predecessor
salt, // Unique salt
1 days // Delay (>= minDelay)
);// Wait for delay to pass...
vm.warp(block.timestamp + 1 days);
timelock.execute(
targetAddress,
0,
data,
bytes32(0),
salt
);address[] memory targets = new address[](2);
uint256[] memory values = new uint256[](2);
bytes[] memory datas = new bytes[](2);
// Fill arrays...
bytes32 id = timelock.scheduleBatch(targets, values, datas, bytes32(0), salt, delay);
// After delay...
timelock.executeBatch(targets, values, datas, bytes32(0), salt);forge buildforge testforge snapshot- Operations cannot be re-scheduled once executed
- Minimum delay floor of 1 hour prevents instant execution
- Maximum delay of 30 days prevents locking funds indefinitely
- Only the timelock itself can update the delay (requires going through the timelock)
MIT