Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timelock manager role #575

Merged
merged 2 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"hatVaultsRegistryConf": {
Expand All @@ -36,6 +37,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"hatVaultsRegistryConf": {
Expand All @@ -55,6 +57,7 @@ module.exports = {
"executors": [
"0x0B7602011EC2B862Bc157fF08d27b1018aEb18d5"
],
"managers": [],
"rewardControllersConf": [{
"startBlock": null,
"epochLength": "195200",
Expand Down Expand Up @@ -163,6 +166,7 @@ module.exports = {
"0x56E889664F5961452E5f4183AA13AF568198eaD2",
"0x1885B7c7a3AE1F35BA71C0392C13153A95c4914f"
], // proposal executors - if this empty, governance will be an executor
"managers": [],
"hatVaultsRegistryConf": {
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0",
Expand Down Expand Up @@ -217,6 +221,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // USDC
"hatVaultsRegistryConf": {
Expand Down Expand Up @@ -245,6 +250,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
"hatVaultsRegistryConf": {
Expand Down Expand Up @@ -272,6 +278,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", // USDC
"hatVaultsRegistryConf": {
Expand Down Expand Up @@ -299,6 +306,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", // USDC
"hatVaultsRegistryConf": {
Expand Down Expand Up @@ -326,6 +334,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", // USDC
"hatVaultsRegistryConf": {
Expand Down Expand Up @@ -353,6 +362,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x4200000000000000000000000000000000000006", // WETH
"hatVaultsRegistryConf": {
Expand All @@ -378,6 +388,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "NEED ADDRESS", // USDC
"hatVaultsRegistryConf": {
Expand All @@ -403,6 +414,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0xd86e243fc0007e6226b07c9a50c9d70d78299eb5", // USDC
"hatVaultsRegistryConf": {
Expand All @@ -428,6 +440,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC
"hatVaultsRegistryConf": {
Expand All @@ -453,6 +466,7 @@ module.exports = {
"0xF6aEF099e4473E08bed75E0BB1252C4cdAd96416",
"0x42eefBC05794e71a0f7e7B63E5EcB52320345eBE"
],
"managers": [],
"rewardControllersConf": [],
"hatToken": "0x0000000000000000000000000000000000000000", // USDC
"hatVaultsRegistryConf": {
Expand Down
17 changes: 13 additions & 4 deletions contracts/HATTimelockController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ import "@openzeppelin/contracts/governance/TimelockController.sol";
import "./HATGovernanceArbitrator.sol";

contract HATTimelockController is TimelockController {
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");

constructor(
uint256 _minDelay,
address[] memory _proposers,
address[] memory _executors
address[] memory _executors,
address[] memory _managers
// solhint-disable-next-line no-empty-blocks
) TimelockController(_minDelay, _proposers, _executors, address(0)) {}
) TimelockController(_minDelay, _proposers, _executors, address(0)) {
_setRoleAdmin(MANAGER_ROLE, TIMELOCK_ADMIN_ROLE);

// register managers
for (uint256 i = 0; i < _managers.length; ++i) {
_setupRole(MANAGER_ROLE, _managers[i]);
}
}

// The following functions are not subject to the timelock

Expand All @@ -29,15 +38,15 @@ contract HATTimelockController is TimelockController {
_claimsManager.setCommittee(_committee);
}

function setVaultDescription(IHATVault _vault, string memory _descriptionHash) external onlyRole(PROPOSER_ROLE) {
function setVaultDescription(IHATVault _vault, string memory _descriptionHash) external onlyRole(MANAGER_ROLE) {
_vault.setVaultDescription(_descriptionHash);
}

function setDepositPause(IHATVault _vault, bool _depositPause) external onlyRole(PROPOSER_ROLE) {
_vault.setDepositPause(_depositPause);
}

function setVaultVisibility(IHATVault _vault, bool _visible) external onlyRole(PROPOSER_ROLE) {
function setVaultVisibility(IHATVault _vault, bool _visible) external onlyRole(MANAGER_ROLE) {
_vault.registry().setVaultVisibility(address(_vault), _visible);
}

Expand Down
12 changes: 11 additions & 1 deletion deploy/001_deploy_hattimelockcontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,22 @@ const func = async function (hre) {
executors.push(governance);
}

let managers = config.managers;
if (!managers && network.name === "hardhat") {
managers = [governance];
}

if (managers.indexOf(governance) === -1) {
managers.push(governance);
}

await deploy('HATTimelockController', {
from: deployer,
args: [
hatGovernanceDelay, // minDelay
[governance], // proposers
executors // executors
executors, // executors
managers // managers
],
log: true,
});
Expand Down
31 changes: 29 additions & 2 deletions deploy/013_verify_deployment.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,35 @@ const func = async function (hre) {
executors.push(governance);
}

let managers = config["managers"];
if (!managers || managers.length === 0) {
managers = [governance];
}

if (managers.indexOf(governance) === -1) {
managers.push(governance);
}

let hatGovernanceDelay = config["timelockDelay"];

const TIMELOCK_ADMIN_ROLE = await read('HATTimelockController', {}, 'TIMELOCK_ADMIN_ROLE');
const PROPOSER_ROLE = await read('HATTimelockController', {}, 'PROPOSER_ROLE');
const CANCELLER_ROLE = await read('HATTimelockController', {}, 'CANCELLER_ROLE');
const EXECUTOR_ROLE = await read('HATTimelockController', {}, 'EXECUTOR_ROLE');
const MANAGER_ROLE = await read('HATTimelockController', {}, 'MANAGER_ROLE');

// print some general info before diagnosing
console.log("************************************************");
console.log("deployer: ", deployer);
console.log("governance: ", governance);
console.log("executors: ", executors);
console.log("managers: ", managers);
console.log("************************************************");
console.log("TIMELOCK_ADMIN_ROLE", TIMELOCK_ADMIN_ROLE);
console.log("PROPOSER_ROLE", PROPOSER_ROLE);
console.log("CANCELLER_ROLE", CANCELLER_ROLE);
console.log("EXECUTOR_ROLE", EXECUTOR_ROLE);
console.log("MANAGER_ROLE", MANAGER_ROLE);
console.log("************************************************");
console.log("HATTimelockController", (await deployments.get('HATTimelockController')).address);
console.log("************************************************");
Expand Down Expand Up @@ -81,6 +93,14 @@ const func = async function (hre) {
);
}

for (manager of managers) {
// Each executor has the execute role
verify(
await read('HATTimelockController', {}, 'hasRole', MANAGER_ROLE, manager),
"Manager " + manager + " has the manager role"
);
}

// Min delay is correct
verify(
(await read('HATTimelockController', {}, 'getMinDelay')).toString() === hatGovernanceDelay.toString(),
Expand Down Expand Up @@ -124,8 +144,8 @@ const func = async function (hre) {
`TIMELOCK_ADMIN_ROLE should NOT be the admin role of the deployer ${deployer}`
);
// Roles granted should be the 4 + number of executors
// (renounced deployer role, timelock admin of itself, governance proposer and canceller roles, and executor role to the executors)
const roleGrantEventsCount = 3 + executors.length;
// (renounced deployer role, timelock admin of itself, governance proposer and canceller roles, executor role to the executors, and manager role to the managers)
const roleGrantEventsCount = 3 + executors.length + managers.length;
verify(
logs.length === roleGrantEventsCount,
`No unexpected roles were granted (expected ${roleGrantEventsCount}, got ${logs.length})`
Expand All @@ -142,6 +162,13 @@ const func = async function (hre) {
for (executor of executors) {
EXPECTED_ROLES[executor] = [EXECUTOR_ROLE];
}
for (manager of managers) {
if (EXPECTED_ROLES[manager]) {
EXPECTED_ROLES[manager].push(MANAGER_ROLE);
} else {
EXPECTED_ROLES[manager] = [MANAGER_ROLE];
}
}
for (log of logs) {
const role = log.args.role;
const account = log.args.account;
Expand Down
1 change: 1 addition & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ In the file [config.js](../config.js), we add a section for the sepolia network:
"governance": "0xFc9F1d127f8047B0F41e9eAC2Adc2e5279C568B7",
"timelockDelay": 300,
"executors": [], // proposal executors - if this empty, governance will be an executor
"managers": [], // system managers - if this empty, governance will be a manager
"rewardControllersConf": [], // no reward controllers
"hatToken": "", // deploy a fresh HATToken contract
"hatVaultsRegistryConf": {
Expand Down
14 changes: 0 additions & 14 deletions docs/develop.md

This file was deleted.

17 changes: 17 additions & 0 deletions docs/dodoc/HATTimelockController.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ function EXECUTOR_ROLE() external view returns (bytes32)



#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | bytes32 | undefined |

### MANAGER_ROLE

```solidity
function MANAGER_ROLE() external view returns (bytes32)
```






#### Returns

| Name | Type | Description |
Expand Down
5 changes: 5 additions & 0 deletions docs/roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ See [parameters](./parameters.md) for the list of parameters managed by the owne
- set to governance multisig
- can call `cancel` and cancel any pending operation

## `HATTimelockController.MANAGER_ROLE`

- set to "anyone"
- can call `setVaultDescription` and `setVaultVisibility`


## The following functions in HATVaults are **not** subject to a timelock:
- `approveClaim`
Expand Down
46 changes: 0 additions & 46 deletions scripts/deployments/addresses.json

This file was deleted.

Loading
Loading