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 { ...@@ -32,16 +32,21 @@ struct LivenessModuleConfig {
address fallbackOwner; address fallbackOwner;
} }
/// @notice Configuration for the Security Council Safe.
struct SecurityCouncilConfig {
SafeConfig safeConfig;
LivenessModuleConfig livenessModuleConfig;
}
/// @notice Configuration for the Deputy Guardian Module /// @notice Configuration for the Deputy Guardian Module
struct DeputyGuardianModuleConfig { struct DeputyGuardianModuleConfig {
address deputyGuardian; address deputyGuardian;
SuperchainConfig superchainConfig; SuperchainConfig superchainConfig;
} }
/// @notice Configuration for the Security Council Safe. /// @notice Configuration for the Guardian Safe.
struct SecurityCouncilConfig { struct GuardianConfig {
SafeConfig safeConfig; SafeConfig safeConfig;
LivenessModuleConfig livenessModuleConfig;
DeputyGuardianModuleConfig deputyGuardianModuleConfig; DeputyGuardianModuleConfig deputyGuardianModuleConfig;
} }
...@@ -62,6 +67,8 @@ contract DeployOwnership is Deploy { ...@@ -62,6 +67,8 @@ contract DeployOwnership is Deploy {
deployFoundationSafe(); deployFoundationSafe();
deploySecurityCouncilSafe(); deploySecurityCouncilSafe();
deployGuardianSafe();
configureGuardianSafe();
configureSecurityCouncilSafe(); configureSecurityCouncilSafe();
console.log("Ownership contracts completed"); console.log("Ownership contracts completed");
...@@ -76,6 +83,19 @@ contract DeployOwnership is Deploy { ...@@ -76,6 +83,19 @@ contract DeployOwnership is Deploy {
safeConfig_ = SafeConfig({ threshold: 5, owners: exampleFoundationOwners }); 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. /// @notice Returns a SafeConfig similar to that of the Security Council Safe on Mainnet.
function _getExampleCouncilConfig() internal returns (SecurityCouncilConfig memory councilConfig_) { function _getExampleCouncilConfig() internal returns (SecurityCouncilConfig memory councilConfig_) {
address[] memory exampleCouncilOwners = new address[](13); address[] memory exampleCouncilOwners = new address[](13);
...@@ -90,10 +110,6 @@ contract DeployOwnership is Deploy { ...@@ -90,10 +110,6 @@ contract DeployOwnership is Deploy {
thresholdPercentage: 75, thresholdPercentage: 75,
minOwners: 8, minOwners: 8,
fallbackOwner: mustGetAddress("FoundationSafe") fallbackOwner: mustGetAddress("FoundationSafe")
}),
deputyGuardianModuleConfig: DeputyGuardianModuleConfig({
deputyGuardian: mustGetAddress("FoundationSafe"),
superchainConfig: SuperchainConfig(mustGetAddress("SuperchainConfig"))
}) })
}); });
} }
...@@ -147,7 +163,8 @@ contract DeployOwnership is Deploy { ...@@ -147,7 +163,8 @@ contract DeployOwnership is Deploy {
function deployDeputyGuardianModule() public returns (address addr_) { function deployDeputyGuardianModule() public returns (address addr_) {
SecurityCouncilConfig memory councilConfig = _getExampleCouncilConfig(); SecurityCouncilConfig memory councilConfig = _getExampleCouncilConfig();
Safe councilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe"))); Safe councilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe")));
DeputyGuardianModuleConfig memory deputyGuardianModuleConfig = councilConfig.deputyGuardianModuleConfig; DeputyGuardianModuleConfig memory deputyGuardianModuleConfig =
_getExampleGuardianConfig().deputyGuardianModuleConfig;
addr_ = address( addr_ = address(
new DeputyGuardianModule({ new DeputyGuardianModule({
_safe: councilSafe, _safe: councilSafe,
...@@ -174,18 +191,43 @@ contract DeployOwnership is Deploy { ...@@ -174,18 +191,43 @@ contract DeployOwnership is Deploy {
); );
} }
/// @notice Configure the Security Council Safe with the LivenessModule, DeputyGuardianModule, and LivenessGuard. /// @notice Deploy Guardian Safe.
function configureSecurityCouncilSafe() public broadcast returns (address addr_) { function deployGuardianSafe() public broadcast returns (address addr_) {
// Deploy and add the Deputy Guardian Module. // Config is hardcoded here as the Guardian Safe's configuration is inflexible.
SecurityCouncilConfig memory exampleCouncilConfig = _getExampleCouncilConfig(); address[] memory owners = new address[](1);
Safe safe = Safe(mustGetAddress("SecurityCouncilSafe")); 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(); address deputyGuardianModule = deployDeputyGuardianModule();
_callViaSafe({ _callViaSafe({
_safe: safe, _safe: safe,
_target: address(safe), _target: address(safe),
_data: abi.encodeCall(ModuleManager.enableModule, (deputyGuardianModule)) _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. // Deploy and add the Liveness Guard.
address guard = deployLivenessGuard(); address guard = deployLivenessGuard();
......
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
DeployOwnership, DeployOwnership,
SafeConfig, SafeConfig,
SecurityCouncilConfig, SecurityCouncilConfig,
GuardianConfig,
DeputyGuardianModuleConfig, DeputyGuardianModuleConfig,
LivenessModuleConfig LivenessModuleConfig
} from "scripts/DeployOwnership.s.sol"; } from "scripts/DeployOwnership.s.sol";
...@@ -29,6 +30,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { ...@@ -29,6 +30,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
run(); run();
} }
/// @dev Helper function to make assertions on basic Safe config properties.
function _checkSafeConfig(SafeConfig memory _safeConfig, Safe _safe) internal view { function _checkSafeConfig(SafeConfig memory _safeConfig, Safe _safe) internal view {
assertEq(_safe.getThreshold(), _safeConfig.threshold); assertEq(_safe.getThreshold(), _safeConfig.threshold);
...@@ -39,6 +41,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { ...@@ -39,6 +41,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
} }
} }
/// @dev Test the example Foundation Safe configuration.
function test_exampleFoundationSafe() public { function test_exampleFoundationSafe() public {
Safe foundationSafe = Safe(payable(mustGetAddress("FoundationSafe"))); Safe foundationSafe = Safe(payable(mustGetAddress("FoundationSafe")));
SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig(); SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig();
...@@ -46,6 +49,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { ...@@ -46,6 +49,7 @@ contract DeployOwnershipTest is Test, DeployOwnership {
_checkSafeConfig(exampleFoundationConfig, foundationSafe); _checkSafeConfig(exampleFoundationConfig, foundationSafe);
} }
/// @dev Test the example Security Council Safe configuration.
function test_exampleSecurityCouncilSafe() public { function test_exampleSecurityCouncilSafe() public {
Safe securityCouncilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe"))); Safe securityCouncilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe")));
SecurityCouncilConfig memory exampleSecurityCouncilConfig = _getExampleCouncilConfig(); SecurityCouncilConfig memory exampleSecurityCouncilConfig = _getExampleCouncilConfig();
...@@ -69,19 +73,11 @@ contract DeployOwnershipTest is Test, DeployOwnership { ...@@ -69,19 +73,11 @@ contract DeployOwnershipTest is Test, DeployOwnership {
address livenessModule = mustGetAddress("LivenessModule"); address livenessModule = mustGetAddress("LivenessModule");
address deputyGuardianModule = mustGetAddress("DeputyGuardianModule"); address deputyGuardianModule = mustGetAddress("DeputyGuardianModule");
(address[] memory modules, address nextModule) = (address[] memory modules, address nextModule) =
ModuleManager(securityCouncilSafe).getModulesPaginated(SENTINEL_MODULES, 3); ModuleManager(securityCouncilSafe).getModulesPaginated(SENTINEL_MODULES, 2);
assertEq(modules.length, 2); assertEq(modules.length, 1);
assertEq(modules[0], livenessModule); assertEq(modules[0], livenessModule);
assertEq(modules[1], deputyGuardianModule);
assertEq(nextModule, SENTINEL_MODULES); // ensures there are no more modules in the list 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 // LivenessModule checks
LivenessModuleConfig memory lmConfig = exampleSecurityCouncilConfig.livenessModuleConfig; LivenessModuleConfig memory lmConfig = exampleSecurityCouncilConfig.livenessModuleConfig;
assertEq(address(LivenessModule(livenessModule).livenessGuard()), livenessGuard); assertEq(address(LivenessModule(livenessModule).livenessGuard()), livenessGuard);
...@@ -92,4 +88,30 @@ contract DeployOwnershipTest is Test, DeployOwnership { ...@@ -92,4 +88,30 @@ contract DeployOwnershipTest is Test, DeployOwnership {
// Ensure the threshold on the safe agrees with the LivenessModule's required threshold // Ensure the threshold on the safe agrees with the LivenessModule's required threshold
assertEq(securityCouncilSafe.getThreshold(), LivenessModule(livenessModule).getRequiredThreshold(owners.length)); 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