Skip to content

Commit

Permalink
Merge pull request #575 from hats-finance/timelock-manager-role
Browse files Browse the repository at this point in the history
Add timelock manager role
  • Loading branch information
jellegerbrandy authored Jun 27, 2024
2 parents 9f0f6c4 + 00fde3e commit 385bf0a
Show file tree
Hide file tree
Showing 17 changed files with 107 additions and 633 deletions.
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

0 comments on commit 385bf0a

Please sign in to comment.