Skip to content

Commit 53c00e9

Browse files
authored
ctb: Move threshold check from LivenessModule constructor (ethereum-optimism#10516)
* ctb: Update snapshots and semver-lock * ctb: Move threshold check from LivenessModule constructor Perform the check in the deployment scripts instead. * ctb: Add check to LM deploy script * ctb: Update snapshots and semver-lock
1 parent db3871d commit 53c00e9

File tree

6 files changed

+30
-38
lines changed

6 files changed

+30
-38
lines changed

packages/contracts-bedrock/scripts/DeployOwnership.s.sol

+13-11
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,14 @@ contract DeployOwnership is Deploy {
186186
_callViaSafe({ _safe: safe, _target: address(safe), _data: abi.encodeCall(GuardManager.setGuard, (guard)) });
187187
console.log("LivenessGuard setup on SecurityCouncilSafe");
188188

189+
// Deploy and add the Liveness Module.
190+
address livenessModule = deployLivenessModule();
191+
_callViaSafe({
192+
_safe: safe,
193+
_target: address(safe),
194+
_data: abi.encodeCall(ModuleManager.enableModule, (livenessModule))
195+
});
196+
189197
// Remove the deployer address (msg.sender) which was used to setup the Security Council Safe thus far
190198
// this call is also used to update the threshold.
191199
// Because deploySafe() always adds msg.sender first (if keepDeployer is true), we know that the previousOwner
@@ -197,17 +205,11 @@ contract DeployOwnership is Deploy {
197205
OwnerManager.removeOwner, (SENTINEL_OWNERS, msg.sender, exampleCouncilConfig.safeConfig.threshold)
198206
)
199207
});
200-
201-
// Deploy and add the Liveness Module.
202-
address livenessModule = deployLivenessModule();
203-
vm.stopBroadcast();
204-
205-
// Since we don't have private keys for the safe owners, we instead use 'startBroadcast' to do something
206-
// similar to pranking as the safe. This simulates a quorum of signers executing a transation from the safe to
207-
// call it's own 'enableModule' method.
208-
vm.startBroadcast(address(safe));
209-
safe.enableModule(livenessModule);
210-
vm.stopBroadcast();
208+
address[] memory owners = safe.getOwners();
209+
require(
210+
safe.getThreshold() == LivenessModule(livenessModule).getRequiredThreshold(owners.length),
211+
"Safe threshold must be equal to the LivenessModule's required threshold"
212+
);
211213
addr_ = address(safe);
212214
console.log("Deployed and configured the Security Council Safe!");
213215
}

packages/contracts-bedrock/semver-lock.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@
112112
"sourceCodeHash": "0xea3872d8f196ae3c863363dfa4b57803cb2a24b0c100244d8f861891e901e03f"
113113
},
114114
"src/Safe/LivenessModule.sol": {
115-
"initCodeHash": "0xa8b233f0f26f8a73b997b12ba06d64cefa8ee98d523f68cd63320e9787468fae",
116-
"sourceCodeHash": "0x15dfd32e92577f4cb5ab05def834a5a1b183e30ca249184f282fca6441be8788"
115+
"initCodeHash": "0x6c3d47fdce3dcd5b8499da08061f3ee4ddd126b726bedec601210667bf73db1d",
116+
"sourceCodeHash": "0x6bdfa1a9fe8a7bc6e032c2448b911ca3bd55ece0856866042e29a20e270dd0a3"
117117
},
118118
"src/cannon/MIPS.sol": {
119119
"initCodeHash": "0xa5d36fc67170ad87322f358f612695f642757bbf5280800d5d878da21402579a",

packages/contracts-bedrock/src/Safe/LivenessModule.sol

-4
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ contract LivenessModule is ISemver {
6767
MIN_OWNERS = _minOwners;
6868
address[] memory owners = _safe.getOwners();
6969
require(_minOwners <= owners.length, "LivenessModule: minOwners must be less than the number of owners");
70-
require(
71-
_safe.getThreshold() >= getRequiredThreshold(owners.length),
72-
"LivenessModule: Insufficient threshold for the number of owners"
73-
);
7470
require(_thresholdPercentage > 0, "LivenessModule: thresholdPercentage must be greater than 0");
7571
require(_thresholdPercentage <= 100, "LivenessModule: thresholdPercentage must be less than or equal to 100");
7672
}

packages/contracts-bedrock/test/Safe/DeployOwnership.t.sol

+3
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,8 @@ contract DeployOwnershipTest is Test, DeployOwnership {
8888
assertEq(LivenessModule(livenessModule).livenessInterval(), lmConfig.livenessInterval);
8989
assertEq(LivenessModule(livenessModule).thresholdPercentage(), lmConfig.thresholdPercentage);
9090
assertEq(LivenessModule(livenessModule).minOwners(), lmConfig.minOwners);
91+
92+
// Ensure the threshold on the safe agrees with the LivenessModule's required threshold
93+
assertEq(securityCouncilSafe.getThreshold(), LivenessModule(livenessModule).getRequiredThreshold(owners.length));
9194
}
9295
}

packages/contracts-bedrock/test/Safe/LivenessGuard.t.sol

+12-4
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@ contract LivenessGuard_TestInit is Test, SafeTestTools {
2828

2929
event OwnerRecorded(address owner);
3030

31-
uint256 initTime = 10;
3231
WrappedGuard livenessGuard;
3332
SafeInstance safeInstance;
3433

34+
// This needs to be non-zero so that the `lastLive` mapping can record non-zero timestamps
35+
uint256 initTime = 10;
36+
// These values reflect the planned state of the mainnet Security Council Safe.
37+
uint256 threshold = 10;
38+
uint256 ownerCount = 13;
39+
3540
/// @dev Sets up the test environment
3641
function setUp() public {
3742
vm.warp(initTime);
38-
safeInstance = _setupSafe();
43+
(, uint256[] memory privKeys) = SafeTestLib.makeAddrsAndKeys("test-owners", ownerCount);
44+
safeInstance = _setupSafe(privKeys, threshold);
3945
livenessGuard = new WrappedGuard(safeInstance.safe);
4046
safeInstance.setGuard(address(livenessGuard));
4147
}
@@ -88,8 +94,10 @@ contract LivenessGuard_CheckTx_Test is LivenessGuard_TestInit {
8894
// Create an array of the addresses who will sign the transaction. SafeTestTools
8995
// will generate these signatures up to the threshold by iterating over the owners array.
9096
address[] memory signers = new address[](safeInstance.threshold);
91-
signers[0] = safeInstance.owners[0];
92-
signers[1] = safeInstance.owners[1];
97+
// copy the first threshold owners into the signers array
98+
for (uint256 i; i < safeInstance.threshold; i++) {
99+
signers[i] = safeInstance.owners[i];
100+
}
93101

94102
// Record the timestamps before the transaction
95103
uint256[] memory beforeTimestamps = new uint256[](safeInstance.owners.length);

packages/contracts-bedrock/test/Safe/LivenessModule.t.sol

-17
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,6 @@ contract LivenessModule_Constructor_TestFail is LivenessModule_TestInit {
101101
_fallbackOwner: address(0)
102102
});
103103
}
104-
105-
/// @dev Tests that the constructor fails if the minOwners is greater than the number of owners
106-
function test_constructor_wrongThreshold_reverts() external {
107-
uint256 wrongThreshold = livenessModule.getRequiredThreshold(safeInstance.owners.length) - 1;
108-
vm.mockCall(
109-
address(safeInstance.safe), abi.encodeCall(OwnerManager.getThreshold, ()), abi.encode(wrongThreshold)
110-
);
111-
vm.expectRevert("LivenessModule: Insufficient threshold for the number of owners");
112-
new LivenessModule({
113-
_safe: safeInstance.safe,
114-
_livenessGuard: livenessGuard,
115-
_livenessInterval: LIVENESS_INTERVAL,
116-
_thresholdPercentage: THRESHOLD_PERCENTAGE,
117-
_minOwners: MIN_OWNERS,
118-
_fallbackOwner: address(0)
119-
});
120-
}
121104
}
122105

123106
contract LivenessModule_Getters_Test is LivenessModule_TestInit {

0 commit comments

Comments
 (0)