Commit df2aebaf authored by Maurelian's avatar Maurelian Committed by GitHub

ctb: Add Guardian Safe to ownership deployment (#10616)

parent 94b97363
......@@ -32,16 +32,21 @@ struct LivenessModuleConfig {
address fallbackOwner;
}
/// @notice Configuration for the Security Council Safe.
struct SecurityCouncilConfig {
SafeConfig safeConfig;
LivenessModuleConfig livenessModuleConfig;
}
/// @notice Configuration for the Deputy Guardian Module
struct DeputyGuardianModuleConfig {
address deputyGuardian;
SuperchainConfig superchainConfig;
}
/// @notice Configuration for the Security Council Safe.
struct SecurityCouncilConfig {
/// @notice Configuration for the Guardian Safe.
struct GuardianConfig {
SafeConfig safeConfig;
LivenessModuleConfig livenessModuleConfig;
DeputyGuardianModuleConfig deputyGuardianModuleConfig;
}
......@@ -62,6 +67,8 @@ contract DeployOwnership is Deploy {
deployFoundationSafe();
deploySecurityCouncilSafe();
deployGuardianSafe();
configureGuardianSafe();
configureSecurityCouncilSafe();
console.log("Ownership contracts completed");
......@@ -76,6 +83,19 @@ contract DeployOwnership is Deploy {
safeConfig_ = SafeConfig({ threshold: 5, owners: exampleFoundationOwners });
}
/// @notice Returns a GuardianConfig similar to that of the Guardian Safe on Mainnet.
function _getExampleGuardianConfig() internal returns (GuardianConfig memory guardianConfig_) {
address[] memory exampleGuardianOwners = new address[](1);
exampleGuardianOwners[0] = mustGetAddress("SecurityCouncilSafe");
guardianConfig_ = GuardianConfig({
safeConfig: SafeConfig({ threshold: 1, owners: exampleGuardianOwners }),
deputyGuardianModuleConfig: DeputyGuardianModuleConfig({
deputyGuardian: mustGetAddress("FoundationSafe"),
superchainConfig: SuperchainConfig(mustGetAddress("SuperchainConfig"))
})
});
}
/// @notice Returns a SafeConfig similar to that of the Security Council Safe on Mainnet.
function _getExampleCouncilConfig() internal returns (SecurityCouncilConfig memory councilConfig_) {
address[] memory exampleCouncilOwners = new address[](13);
......@@ -90,10 +110,6 @@ contract DeployOwnership is Deploy {
thresholdPercentage: 75,
minOwners: 8,
fallbackOwner: mustGetAddress("FoundationSafe")
}),
deputyGuardianModuleConfig: DeputyGuardianModuleConfig({
deputyGuardian: mustGetAddress("FoundationSafe"),
superchainConfig: SuperchainConfig(mustGetAddress("SuperchainConfig"))
})
});
}
......@@ -147,7 +163,8 @@ contract DeployOwnership is Deploy {
function deployDeputyGuardianModule() public returns (address addr_) {
SecurityCouncilConfig memory councilConfig = _getExampleCouncilConfig();
Safe councilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe")));
DeputyGuardianModuleConfig memory deputyGuardianModuleConfig = councilConfig.deputyGuardianModuleConfig;
DeputyGuardianModuleConfig memory deputyGuardianModuleConfig =
_getExampleGuardianConfig().deputyGuardianModuleConfig;
addr_ = address(
new DeputyGuardianModule({
_safe: councilSafe,
......@@ -174,18 +191,43 @@ contract DeployOwnership is Deploy {
);
}
/// @notice Configure the Security Council Safe with the LivenessModule, DeputyGuardianModule, and LivenessGuard.
function configureSecurityCouncilSafe() public broadcast returns (address addr_) {
// Deploy and add the Deputy Guardian Module.
SecurityCouncilConfig memory exampleCouncilConfig = _getExampleCouncilConfig();
Safe safe = Safe(mustGetAddress("SecurityCouncilSafe"));
/// @notice Deploy Guardian Safe.
function deployGuardianSafe() public broadcast returns (address addr_) {
// Config is hardcoded here as the Guardian Safe's configuration is inflexible.
address[] memory owners = new address[](1);
owners[0] = mustGetAddress("SecurityCouncilSafe");
addr_ = deploySafe({ _name: "GuardianSafe", _owners: owners, _threshold: 1, _keepDeployer: true });
console.log("Deployed and configured the Guardian Safe!");
}
/// @notice Configure the Guardian Safe with the DeputyGuardianModule.
function configureGuardianSafe() public broadcast returns (address addr_) {
Safe safe = Safe(payable(mustGetAddress("GuardianSafe")));
address deputyGuardianModule = deployDeputyGuardianModule();
_callViaSafe({
_safe: safe,
_target: address(safe),
_data: abi.encodeCall(ModuleManager.enableModule, (deputyGuardianModule))
});
console.log("DeputyGuardianModule enabled on SecurityCouncilSafe");
// Remove the deployer address (msg.sender) which was used to setup the Security Council Safe thus far
// this call is also used to update the threshold.
// Because deploySafe() always adds msg.sender first (if keepDeployer is true), we know that the previousOwner
// will be SENTINEL_OWNERS.
_callViaSafe({
_safe: safe,
_target: address(safe),
_data: abi.encodeCall(OwnerManager.removeOwner, (SENTINEL_OWNERS, msg.sender, 1))
});
console.log("DeputyGuardianModule enabled on GuardianSafe");
}
/// @notice Configure the Security Council Safe with the LivenessModule and LivenessGuard.
function configureSecurityCouncilSafe() public broadcast returns (address addr_) {
// Deploy and add the Deputy Guardian Module.
SecurityCouncilConfig memory exampleCouncilConfig = _getExampleCouncilConfig();
Safe safe = Safe(mustGetAddress("SecurityCouncilSafe"));
// Deploy and add the Liveness Guard.
address guard = deployLivenessGuard();
......
......@@ -5,6 +5,7 @@ import {
DeployOwnership,
SafeConfig,
SecurityCouncilConfig,
GuardianConfig,
DeputyGuardianModuleConfig,
LivenessModuleConfig
} from "scripts/DeployOwnership.s.sol";
......@@ -29,6 +30,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
run();
}
/// @dev Helper function to make assertions on basic Safe config properties.
function _checkSafeConfig(SafeConfig memory _safeConfig, Safe _safe) internal view {
assertEq(_safe.getThreshold(), _safeConfig.threshold);
......@@ -39,6 +41,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
}
}
/// @dev Test the example Foundation Safe configuration.
function test_exampleFoundationSafe() public {
Safe foundationSafe = Safe(payable(mustGetAddress("FoundationSafe")));
SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig();
......@@ -46,6 +49,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
_checkSafeConfig(exampleFoundationConfig, foundationSafe);
}
/// @dev Test the example Security Council Safe configuration.
function test_exampleSecurityCouncilSafe() public {
Safe securityCouncilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe")));
SecurityCouncilConfig memory exampleSecurityCouncilConfig = _getExampleCouncilConfig();
......@@ -69,19 +73,11 @@ contract DeployOwnershipTest is Test, DeployOwnership {
address livenessModule = mustGetAddress("LivenessModule");
address deputyGuardianModule = mustGetAddress("DeputyGuardianModule");
(address[] memory modules, address nextModule) =
ModuleManager(securityCouncilSafe).getModulesPaginated(SENTINEL_MODULES, 3);
assertEq(modules.length, 2);
ModuleManager(securityCouncilSafe).getModulesPaginated(SENTINEL_MODULES, 2);
assertEq(modules.length, 1);
assertEq(modules[0], livenessModule);
assertEq(modules[1], deputyGuardianModule);
assertEq(nextModule, SENTINEL_MODULES); // ensures there are no more modules in the list
// DeputyGuardianModule checks
DeputyGuardianModuleConfig memory dgmConfig = exampleSecurityCouncilConfig.deputyGuardianModuleConfig;
assertEq(DeputyGuardianModule(deputyGuardianModule).deputyGuardian(), dgmConfig.deputyGuardian);
assertEq(
address(DeputyGuardianModule(deputyGuardianModule).superchainConfig()), address(dgmConfig.superchainConfig)
);
// LivenessModule checks
LivenessModuleConfig memory lmConfig = exampleSecurityCouncilConfig.livenessModuleConfig;
assertEq(address(LivenessModule(livenessModule).livenessGuard()), livenessGuard);
......@@ -92,4 +88,30 @@ contract DeployOwnershipTest is Test, DeployOwnership {
// Ensure the threshold on the safe agrees with the LivenessModule's required threshold
assertEq(securityCouncilSafe.getThreshold(), LivenessModule(livenessModule).getRequiredThreshold(owners.length));
}
/// @dev Test the example Guardian Safe configuration.
function test_exampleGuardianSafe() public {
Safe guardianSafe = Safe(payable(mustGetAddress("GuardianSafe")));
address[] memory owners = new address[](1);
owners[0] = mustGetAddress("SecurityCouncilSafe");
GuardianConfig memory guardianConfig = _getExampleGuardianConfig();
_checkSafeConfig(guardianConfig.safeConfig, guardianSafe);
// DeputyGuardianModule checks
address deputyGuardianModule = mustGetAddress("DeputyGuardianModule");
(address[] memory modules, address nextModule) =
ModuleManager(guardianSafe).getModulesPaginated(SENTINEL_MODULES, 2);
assertEq(modules.length, 1);
assertEq(modules[0], deputyGuardianModule);
assertEq(nextModule, SENTINEL_MODULES); // ensures there are no more modules in the list
assertEq(
DeputyGuardianModule(deputyGuardianModule).deputyGuardian(),
guardianConfig.deputyGuardianModuleConfig.deputyGuardian
);
assertEq(
address(DeputyGuardianModule(deputyGuardianModule).superchainConfig()),
address(guardianConfig.deputyGuardianModuleConfig.superchainConfig)
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment