Skip to content

Commit 2e73c48

Browse files
committed
feat: correct roles transfer for the DG deployment
1 parent d7844ec commit 2e73c48

File tree

7 files changed

+172
-44
lines changed

7 files changed

+172
-44
lines changed

contracts/0.4.24/template/LidoTemplate.sol

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ contract LidoTemplate is IsContract {
4141
string private constant ERROR_BAD_AMOUNTS_LEN = "TMPL_BAD_AMOUNTS_LEN";
4242
string private constant ERROR_INVALID_ID = "TMPL_INVALID_ID";
4343
string private constant ERROR_UNEXPECTED_TOTAL_SUPPLY = "TMPL_UNEXPECTED_TOTAL_SUPPLY";
44+
string private constant ERROR_INVALID_DG_ADMIN_EXECUTOR = "TMPL_INVALID_DG_ADMIN_EXECUTOR";
4445

4546
// Operational errors
4647
string private constant ERROR_PERMISSION_DENIED = "TMPL_PERMISSION_DENIED";
@@ -420,13 +421,50 @@ contract LidoTemplate is IsContract {
420421

421422
_setupPermissions(state, repos);
422423
_transferRootPermissionsFromTemplateAndFinalizeDAO(state.dao, state.voting);
423-
_resetState();
424424

425425
aragonID.register(keccak256(abi.encodePacked(_daoName)), state.dao);
426426

427427
emit TmplDaoFinalized();
428428
}
429429

430+
function finalizePermissionsAfterDGDeployment(address dgAdminExecutor) external onlyOwner {
431+
require(dgAdminExecutor != address(0), ERROR_INVALID_DG_ADMIN_EXECUTOR);
432+
433+
DeployState memory state = deployState;
434+
435+
state.acl.grantPermission(dgAdminExecutor, address(state.agent), state.agent.RUN_SCRIPT_ROLE());
436+
state.acl.grantPermission(dgAdminExecutor, address(state.agent), state.agent.EXECUTE_ROLE());
437+
438+
state.acl.revokePermission(address(state.voting), address(state.agent), state.agent.RUN_SCRIPT_ROLE());
439+
state.acl.revokePermission(address(state.voting), address(state.agent), state.agent.EXECUTE_ROLE());
440+
441+
state.acl.setPermissionManager(address(state.agent), address(state.agent), state.agent.RUN_SCRIPT_ROLE());
442+
state.acl.setPermissionManager(address(state.agent), address(state.agent), state.agent.EXECUTE_ROLE());
443+
444+
Kernel apmDAO = Kernel(state.lidoRegistry.kernel());
445+
ACL apmACL = ACL(apmDAO.acl());
446+
_transferPermissionFromTemplate(apmACL, apmACL, address(state.agent), apmACL.CREATE_PERMISSIONS_ROLE());
447+
448+
_transferPermissionFromTemplate(state.acl, address(state.acl), address(state.agent), state.acl.CREATE_PERMISSIONS_ROLE(), address(state.agent));
449+
450+
_resetState();
451+
}
452+
453+
function finalizePermissionsWithoutDGDeployment() external onlyOwner {
454+
DeployState memory state = deployState;
455+
456+
state.acl.setPermissionManager(address(state.voting), address(state.agent), state.agent.RUN_SCRIPT_ROLE());
457+
state.acl.setPermissionManager(address(state.voting), address(state.agent), state.agent.EXECUTE_ROLE());
458+
459+
Kernel apmDAO = Kernel(state.lidoRegistry.kernel());
460+
ACL apmACL = ACL(apmDAO.acl());
461+
_transferPermissionFromTemplate(apmACL, apmACL, address(state.agent), apmACL.CREATE_PERMISSIONS_ROLE());
462+
463+
_transferPermissionFromTemplate(state.acl, address(state.acl), address(state.voting), state.acl.CREATE_PERMISSIONS_ROLE(), address(state.voting));
464+
465+
_resetState();
466+
}
467+
430468
/* DAO AND APPS */
431469

432470
/**
@@ -580,7 +618,6 @@ contract LidoTemplate is IsContract {
580618

581619
_transferPermissionFromTemplate(apmACL, _state.lidoRegistry, voting, _state.lidoRegistry.CREATE_REPO_ROLE());
582620
apmACL.setPermissionManager(agent, apmDAO, apmDAO.APP_MANAGER_ROLE());
583-
_transferPermissionFromTemplate(apmACL, apmACL, agent, apmACL.CREATE_PERMISSIONS_ROLE());
584621
apmACL.setPermissionManager(voting, apmRegistrar, apmRegistrar.CREATE_NAME_ROLE());
585622
apmACL.setPermissionManager(voting, apmRegistrar, apmRegistrar.POINT_ROOTNODE_ROLE());
586623

@@ -651,8 +688,8 @@ contract LidoTemplate is IsContract {
651688
}
652689

653690
function _createAgentPermissions(ACL _acl, Agent _agent, address _voting) internal {
654-
_createPermissionForVoting(_acl, _agent, _agent.EXECUTE_ROLE(), _voting);
655-
_createPermissionForVoting(_acl, _agent, _agent.RUN_SCRIPT_ROLE(), _voting);
691+
_acl.createPermission(_voting, _agent, _agent.EXECUTE_ROLE(), address(this));
692+
_acl.createPermission(_voting, _agent, _agent.RUN_SCRIPT_ROLE(), address(this));
656693
}
657694

658695
function _createVaultPermissions(ACL _acl, Vault _vault, address _finance, address _voting) internal {
@@ -695,7 +732,6 @@ contract LidoTemplate is IsContract {
695732
function _transferRootPermissionsFromTemplateAndFinalizeDAO(Kernel _dao, address _voting) private {
696733
ACL _acl = ACL(_dao.acl());
697734
_transferPermissionFromTemplate(_acl, _dao, _voting, _dao.APP_MANAGER_ROLE(), _voting);
698-
_transferPermissionFromTemplate(_acl, _acl, _voting, _acl.CREATE_PERMISSIONS_ROLE(), _voting);
699735
}
700736

701737
function _transferPermissionFromTemplate(ACL _acl, address _app, address _to, bytes32 _permission) private {

lib/dg-installation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
33
import util from "node:util";
44

55
const DG_REPOSITORY_URL = "https://github.com/lidofinance/dual-governance.git";
6-
const DG_REPOSITORY_BRANCH = "feature/scratch-deploy-support"; // TODO: use release branch
6+
const DG_REPOSITORY_BRANCH = "feature/scratch-deploy-support2"; // TODO: use release branch
77
const DG_INSTALL_DIR = `${process.cwd()}/dg`;
88

99
async function main() {

scripts/dao-local-deploy.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ yarn hardhat --network $NETWORK run --no-compile scripts/utils/mine.ts
2323

2424
# Run acceptance tests
2525
yarn test:integration:fork:local
26+
27+
# If Dual Governance was deployed
28+
if grep "dg:dual_governance" $NETWORK_STATE_FILE -q; then
29+
# Run DG regression tests
30+
echo "Run Dual Governance regression tests"
31+
(cd dg && npm run test:regressions)
32+
fi

scripts/dao-local-upgrade.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,10 @@ yarn hardhat --network $NETWORK run --no-compile scripts/utils/mine.ts
2222

2323
# Run acceptance tests
2424
yarn test:integration:fork:local
25+
26+
# If Dual Governance was deployed
27+
if grep "dg:dual_governance" $NETWORK_STATE_FILE -q; then
28+
# Run DG regression tests
29+
echo "Run Dual Governance regression tests"
30+
(cd dg && npm run test:regressions)
31+
fi

scripts/scratch/deployed-testnet-defaults.json

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -152,46 +152,46 @@
152152
},
153153
"dualGovernanceConfig": {
154154
"dual_governance": {
155-
"tiebreaker_activation_timeout": 31536000,
155+
"tiebreaker_activation_timeout": 900,
156156
"sanity_check_params": {
157-
"max_min_assets_lock_duration": 4147200,
157+
"max_min_assets_lock_duration": 3600,
158158
"max_sealable_withdrawal_blockers_count": 255,
159-
"max_tiebreaker_activation_timeout": 63072000,
160-
"min_tiebreaker_activation_timeout": 15768000,
161-
"min_withdrawals_batch_size": 4
159+
"max_tiebreaker_activation_timeout": 1800,
160+
"min_tiebreaker_activation_timeout": 300,
161+
"min_withdrawals_batch_size": 1
162162
}
163163
},
164164
"dual_governance_config_provider": {
165165
"first_seal_rage_quit_support": "10000000000000000",
166166
"second_seal_rage_quit_support": "100000000000000000",
167-
"min_assets_lock_duration": 18000,
167+
"min_assets_lock_duration": 300,
168168
"rage_quit_eth_withdrawals_delay_growth": 1296000,
169-
"rage_quit_eth_withdrawals_min_delay": 5184000,
170-
"rage_quit_eth_withdrawals_max_delay": 15552000,
171-
"rage_quit_extension_period_duration": 604800,
172-
"veto_cooldown_duration": 18000,
173-
"veto_signalling_deactivation_max_duration": 259200,
174-
"veto_signalling_min_active_duration": 18000,
175-
"veto_signalling_min_duration": 432000,
176-
"veto_signalling_max_duration": 3888000
169+
"rage_quit_eth_withdrawals_min_delay": 300,
170+
"rage_quit_eth_withdrawals_max_delay": 1800,
171+
"rage_quit_extension_period_duration": 300,
172+
"veto_cooldown_duration": 300,
173+
"veto_signalling_deactivation_max_duration": 1800,
174+
"veto_signalling_min_active_duration": 300,
175+
"veto_signalling_min_duration": 300,
176+
"veto_signalling_max_duration": 1500
177177
},
178178
"timelock": {
179-
"after_submit_delay": 259200,
180-
"after_schedule_delay": 86400,
179+
"after_submit_delay": 300,
180+
"after_schedule_delay": 300,
181181
"sanity_check_params": {
182-
"min_execution_delay": 259200,
183-
"max_after_submit_delay": 2592000,
184-
"max_after_schedule_delay": 864000,
185-
"max_emergency_mode_duration": 31536000,
186-
"max_emergency_protection_duration": 94608000
182+
"min_execution_delay": 300,
183+
"max_after_submit_delay": 1800,
184+
"max_after_schedule_delay": 1800,
185+
"max_emergency_mode_duration": 1800,
186+
"max_emergency_protection_duration": 31536000
187187
},
188188
"emergency_protection": {
189-
"emergency_mode_duration": 2592000,
189+
"emergency_mode_duration": 900,
190190
"emergency_protection_end_date": 1781913600
191191
}
192192
},
193193
"tiebreaker": {
194-
"execution_delay": 2592000
194+
"execution_delay": 900
195195
}
196196
}
197197
}

scripts/scratch/steps/0150-transfer-roles.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ export async function main() {
2828
for (const contract of ozAdminTransfers) {
2929
const contractInstance = await loadContract(contract.name, contract.address);
3030
await makeTx(contractInstance, "grantRole", [DEFAULT_ADMIN_ROLE, agent], { from: deployer });
31-
await makeTx(contractInstance, "renounceRole", [DEFAULT_ADMIN_ROLE, deployer], { from: deployer });
31+
if (process.env.DG_DEPLOYMENT_ENABLED == "false" || contract.name !== "WithdrawalQueueERC721") {
32+
await makeTx(contractInstance, "renounceRole", [DEFAULT_ADMIN_ROLE, deployer], { from: deployer });
33+
}
3234
}
3335

3436
// Change admin for OssifiableProxy contracts

scripts/scratch/steps/0160-deploy-dual-governance.ts

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import util from "node:util";
44

55
import { ethers } from "hardhat";
66

7+
import { LidoTemplate, WithdrawalQueueERC721 } from "typechain-types";
8+
79
import { log } from "lib";
10+
import { loadContract } from "lib/contract";
11+
import { makeTx } from "lib/deploy";
812
import { DeploymentState, getAddress, readNetworkState, Sk, updateObjectInState } from "lib/state-file";
913

1014
const DG_INSTALL_DIR = `${process.cwd()}/dg`;
@@ -13,6 +17,7 @@ const DG_DEPLOY_ARTIFACTS_DIR = `${DG_INSTALL_DIR}/deploy-artifacts`;
1317
export async function main() {
1418
if (process.env.DG_DEPLOYMENT_ENABLED == "false") {
1519
log.header("DG deployment disabled");
20+
await finalizePermissionsWithoutDGDeployment();
1621
return;
1722
}
1823

@@ -70,33 +75,102 @@ AND
7075
etherscanApiKey = process.env.ETHERSCAN_API_KEY;
7176
}
7277

78+
await unpauseWithdrawalQueue(deployer, state);
79+
7380
await runCommand(
7481
`DEPLOY_CONFIG_FILE_NAME="${dgDeployConfigFilename}" RPC_URL="${process.env.LOCAL_RPC_URL}" ETHERSCAN_API_KEY="${etherscanApiKey}" DEPLOYER_ADDRESS="${deployer}" npm run forge:script scripts/deploy/DeployConfigurable.s.sol -- --broadcast --slow ${etherscanVerifyOption} --private-key ${deployerPrivateKey}`,
7582
DG_INSTALL_DIR,
7683
);
7784

78-
await runDGRegressionTests(chainId, state, process.env.LOCAL_RPC_URL);
79-
8085
const dgDeployArtifacts = await getDGDeployArtifacts(chainId);
8186

87+
await transferRoles(deployer, dgDeployArtifacts, state);
88+
89+
await prepareDGRegressionTestsRun(chainId, state, process.env.LOCAL_RPC_URL);
90+
8291
saveDGNetworkState(dgDeployArtifacts);
8392
}
8493

85-
async function runDGRegressionTests(networkChainId: string, networkState: DeploymentState, rpcUrl: string) {
86-
log.header("Run DG regression tests");
94+
async function finalizePermissionsWithoutDGDeployment() {
95+
const deployer = (await ethers.provider.getSigner()).address;
96+
const networkState = readNetworkState({ deployer });
97+
98+
const lidoTemplateAddress = getAddress(Sk.lidoTemplate, networkState);
99+
const lidoTemplate = await loadContract<LidoTemplate>("LidoTemplate", lidoTemplateAddress);
100+
101+
await makeTx(lidoTemplate, "finalizePermissionsWithoutDGDeployment", [], { from: deployer });
102+
}
103+
104+
async function transferRoles(deployer: string, dgDeployArtifacts: DGDeployArtifacts, networkState: DeploymentState) {
105+
const aragonAgentAddress = getAddress(Sk.appAgent, networkState);
106+
const votingAddress = getAddress(Sk.appVoting, networkState);
107+
const withdrawalQueueAddress = getAddress(Sk.withdrawalQueueERC721, networkState);
108+
const lidoTemplateAddress = getAddress(Sk.lidoTemplate, networkState);
109+
110+
const lidoTemplate = await loadContract<LidoTemplate>("LidoTemplate", lidoTemplateAddress);
111+
const withdrawalQueue = await loadContract<WithdrawalQueueERC721>("WithdrawalQueueERC721", withdrawalQueueAddress);
112+
113+
const DEFAULT_ADMIN_ROLE = ethers.ZeroHash;
114+
115+
await makeTx(withdrawalQueue, "grantRole", [DEFAULT_ADMIN_ROLE, aragonAgentAddress], {
116+
from: deployer,
117+
});
118+
119+
await makeTx(
120+
withdrawalQueue,
121+
"grantRole",
122+
[await withdrawalQueue.PAUSE_ROLE(), votingAddress /* = reseal_committee */],
123+
{
124+
from: deployer,
125+
},
126+
);
127+
128+
await makeTx(
129+
withdrawalQueue,
130+
"grantRole",
131+
[await withdrawalQueue.RESUME_ROLE(), votingAddress /* = reseal_committee */],
132+
{
133+
from: deployer,
134+
},
135+
);
136+
137+
await makeTx(withdrawalQueue, "grantRole", [await withdrawalQueue.PAUSE_ROLE(), dgDeployArtifacts.reseal_manager], {
138+
from: deployer,
139+
});
140+
141+
await makeTx(withdrawalQueue, "grantRole", [await withdrawalQueue.RESUME_ROLE(), dgDeployArtifacts.reseal_manager], {
142+
from: deployer,
143+
});
144+
145+
await makeTx(withdrawalQueue, "renounceRole", [await withdrawalQueue.DEFAULT_ADMIN_ROLE(), deployer], {
146+
from: deployer,
147+
});
148+
149+
await makeTx(lidoTemplate, "finalizePermissionsAfterDGDeployment", [dgDeployArtifacts.admin_executor], {
150+
from: deployer,
151+
});
152+
}
153+
154+
async function unpauseWithdrawalQueue(deployer: string, networkState: DeploymentState) {
155+
const withdrawalQueueAddress = getAddress(Sk.withdrawalQueueERC721, networkState);
156+
const withdrawalQueue = await loadContract<WithdrawalQueueERC721>("WithdrawalQueueERC721", withdrawalQueueAddress);
157+
158+
await makeTx(withdrawalQueue, "grantRole", [await withdrawalQueue.RESUME_ROLE(), deployer], {
159+
from: deployer,
160+
});
161+
162+
await makeTx(withdrawalQueue, "resume", [], {
163+
from: deployer,
164+
});
165+
}
166+
167+
async function prepareDGRegressionTestsRun(networkChainId: string, networkState: DeploymentState, rpcUrl: string) {
168+
log.header("Prepare DG regression tests run: update DG .env file");
87169

88170
const deployArtifactFilename = await getLatestDGDeployArtifactFilename(networkChainId);
89171

90172
const dotEnvFile = getDGDotEnvFile(deployArtifactFilename, networkState, rpcUrl);
91173
await writeDGDotEnvFile(dotEnvFile);
92-
93-
try {
94-
await runCommand("npm run test:regressions", DG_INSTALL_DIR);
95-
} catch (error) {
96-
// TODO: some of regression tests don't work at the moment, need to fix it.
97-
log.error("DG regression tests run failed");
98-
log(`${error}`);
99-
}
100174
}
101175

102176
async function runCommand(command: string, workingDirectory: string) {
@@ -168,7 +242,7 @@ function getDGConfig(chainId: string, networkState: DeploymentState) {
168242
dual_governance: {
169243
admin_proposer: daoVoting,
170244
proposals_canceller: daoVoting,
171-
sealable_withdrawal_blockers: [], // TODO: add withdrawalQueue
245+
sealable_withdrawal_blockers: [withdrawalQueue],
172246
reseal_committee: daoVoting,
173247
tiebreaker_activation_timeout:
174248
networkState[Sk.dualGovernanceConfig].dual_governance.tiebreaker_activation_timeout,
@@ -266,6 +340,7 @@ function getDGDotEnvFile(deployArtifactFilename: string, networkState: Deploymen
266340
const elRewardsVault = getAddress(Sk.executionLayerRewardsVault, networkState);
267341
const withdrawalVault = getAddress(Sk.withdrawalVault, networkState);
268342
const oracleReportSanityChecker = getAddress(Sk.oracleReportSanityChecker, networkState);
343+
const stakingRouter = getAddress(Sk.stakingRouter, networkState);
269344
const acl = getAddress(Sk.aragonAcl, networkState);
270345
const ldo = getAddress(Sk.ldo, networkState);
271346
const daoAgent = getAddress(Sk.appAgent, networkState);
@@ -283,11 +358,13 @@ DG_TESTS_LIDO_ACCOUNTING_ORACLE=${accountingOracle}
283358
DG_TESTS_LIDO_EL_REWARDS_VAULT=${elRewardsVault}
284359
DG_TESTS_LIDO_WITHDRAWAL_VAULT=${withdrawalVault}
285360
DG_TESTS_LIDO_ORACLE_REPORT_SANITY_CHECKER=${oracleReportSanityChecker}
361+
DG_TESTS_LIDO_STAKING_ROUTER=${stakingRouter}
286362
DG_TESTS_LIDO_DAO_ACL=${acl}
287363
DG_TESTS_LIDO_LDO_TOKEN=${ldo}
288364
DG_TESTS_LIDO_DAO_AGENT=${daoAgent}
289365
DG_TESTS_LIDO_DAO_VOTING=${daoVoting}
290366
DG_TESTS_LIDO_DAO_TOKEN_MANAGER=${daoTokenManager}
367+
DG_DISABLE_REGRESSION_TESTS_FOR_SCRATCH_DEPLOY=true
291368
`;
292369
}
293370

@@ -357,7 +434,6 @@ async function getDGDeployArtifacts(networkChainId: string): Promise<DGDeployArt
357434

358435
(Object.keys(contractsAddressesRe) as (keyof DGDeployArtifacts)[]).forEach((key) => {
359436
const address = deployArtifactFile.match(contractsAddressesRe[key]);
360-
log("ADDRESS", (address && address[0]) || "", (address && address[1]) || "");
361437
if (!address || address.length < 2 || !address[1].length) {
362438
throw new Error(`DG deploy artifact file corrupted: ${key} not found`);
363439
}

0 commit comments

Comments
 (0)