Skip to content

Commit 15506d5

Browse files
committed
feat: slashing patch upgrade script (#967)
* feat: initial deploy * feat: slashing patch
1 parent 499859d commit 15506d5

File tree

3 files changed

+276
-0
lines changed

3 files changed

+276
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import {EOADeployer} from "zeus-templates/templates/EOADeployer.sol";
5+
import "../Env.sol";
6+
7+
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
8+
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
9+
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10+
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
11+
12+
contract Deploy is EOADeployer {
13+
using Env for *;
14+
15+
function _runAsEOA() internal override {
16+
vm.startBroadcast();
17+
deployImpl({
18+
name: type(AllocationManager).name,
19+
deployedTo: address(new AllocationManager({
20+
_delegation: Env.proxy.delegationManager(),
21+
_pauserRegistry: Env.impl.pauserRegistry(),
22+
_permissionController: Env.proxy.permissionController(),
23+
_DEALLOCATION_DELAY: Env.MIN_WITHDRAWAL_DELAY(),
24+
_ALLOCATION_CONFIGURATION_DELAY: Env.ALLOCATION_CONFIGURATION_DELAY()
25+
}))
26+
});
27+
28+
deployImpl({
29+
name: type(DelegationManager).name,
30+
deployedTo: address(new DelegationManager({
31+
_strategyManager: Env.proxy.strategyManager(),
32+
_eigenPodManager: Env.proxy.eigenPodManager(),
33+
_allocationManager: Env.proxy.allocationManager(),
34+
_pauserRegistry: Env.impl.pauserRegistry(),
35+
_permissionController: Env.proxy.permissionController(),
36+
_MIN_WITHDRAWAL_DELAY: Env.MIN_WITHDRAWAL_DELAY()
37+
}))
38+
});
39+
40+
vm.stopBroadcast();
41+
}
42+
43+
function testDeploy() public virtual {
44+
_runAsEOA();
45+
_validateNewImplAddresses(false);
46+
_validateImplConstructors();
47+
_validateImplsInitialized();
48+
}
49+
50+
51+
/// @dev Validate that the `Env.impl` addresses are updated to be distinct from what the proxy
52+
/// admin reports as the current implementation address.
53+
///
54+
/// Note: The upgrade script can call this with `areMatching == true` to check that these impl
55+
/// addresses _are_ matches.
56+
function _validateNewImplAddresses(bool areMatching) internal view {
57+
function (address, address, string memory) internal pure assertion =
58+
areMatching ? _assertMatch : _assertNotMatch;
59+
60+
61+
assertion(
62+
_getProxyImpl(address(Env.proxy.delegationManager())),
63+
address(Env.impl.delegationManager()),
64+
"delegationManager impl failed"
65+
);
66+
67+
assertion(
68+
_getProxyImpl(address(Env.proxy.allocationManager())),
69+
address(Env.impl.allocationManager()),
70+
"allocationManager impl failed"
71+
);
72+
}
73+
74+
/// @dev Validate the immutables set in the new implementation constructors
75+
function _validateImplConstructors() internal view {
76+
AllocationManager allocationManager = Env.impl.allocationManager();
77+
assertTrue(allocationManager.delegation() == Env.proxy.delegationManager(), "alm.dm invalid");
78+
assertTrue(allocationManager.pauserRegistry() == Env.impl.pauserRegistry(), "alm.pR invalid");
79+
assertTrue(allocationManager.permissionController() == Env.proxy.permissionController(), "alm.pc invalid");
80+
assertTrue(allocationManager.DEALLOCATION_DELAY() == Env.MIN_WITHDRAWAL_DELAY(), "alm.deallocDelay invalid");
81+
assertTrue(allocationManager.ALLOCATION_CONFIGURATION_DELAY() == Env.ALLOCATION_CONFIGURATION_DELAY(), "alm.configDelay invalid");
82+
83+
84+
DelegationManager delegation = Env.impl.delegationManager();
85+
assertTrue(delegation.strategyManager() == Env.proxy.strategyManager(), "dm.sm invalid");
86+
assertTrue(delegation.eigenPodManager() == Env.proxy.eigenPodManager(), "dm.epm invalid");
87+
assertTrue(delegation.allocationManager() == Env.proxy.allocationManager(), "dm.alm invalid");
88+
assertTrue(delegation.pauserRegistry() == Env.impl.pauserRegistry(), "dm.pR invalid");
89+
assertTrue(delegation.permissionController() == Env.proxy.permissionController(), "dm.pc invalid");
90+
assertTrue(delegation.minWithdrawalDelayBlocks() == Env.MIN_WITHDRAWAL_DELAY(), "dm.withdrawalDelay invalid");
91+
}
92+
93+
/// @dev Call initialize on all deployed implementations to ensure initializers are disabled
94+
function _validateImplsInitialized() internal {
95+
bytes memory errInit = "Initializable: contract is already initialized";
96+
97+
AllocationManager allocationManager = Env.impl.allocationManager();
98+
vm.expectRevert(errInit);
99+
allocationManager.initialize(address(0), 0);
100+
101+
DelegationManager delegation = Env.impl.delegationManager();
102+
vm.expectRevert(errInit);
103+
delegation.initialize(address(0), 0);
104+
}
105+
106+
/// @dev Query and return `proxyAdmin.getProxyImplementation(proxy)`
107+
function _getProxyImpl(address proxy) internal view returns (address) {
108+
return ProxyAdmin(Env.proxyAdmin()).getProxyImplementation(ITransparentUpgradeableProxy(proxy));
109+
}
110+
111+
/// @dev Query and return `proxyAdmin.getProxyAdmin(proxy)`
112+
function _getProxyAdmin(address proxy) internal view returns (address) {
113+
return ProxyAdmin(Env.proxyAdmin()).getProxyAdmin(ITransparentUpgradeableProxy(proxy));
114+
}
115+
116+
function _assertMatch(address a, address b, string memory err) private pure {
117+
assertEq(a, b, err);
118+
}
119+
120+
function _assertNotMatch(address a, address b, string memory err) private pure {
121+
assertNotEq(a, b, err);
122+
}
123+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import {Deploy} from "./1-eoa.s.sol";
5+
import "../Env.sol";
6+
7+
import {MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol";
8+
import "zeus-templates/utils/Encode.sol";
9+
10+
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
11+
12+
contract Queue is MultisigBuilder, Deploy {
13+
using Env for *;
14+
using Encode for *;
15+
16+
function _runAsMultisig() prank(Env.opsMultisig()) internal virtual override {
17+
bytes memory calldata_to_executor = _getCalldataToExecutor();
18+
19+
TimelockController timelock = Env.timelockController();
20+
timelock.schedule({
21+
target: Env.executorMultisig(),
22+
value: 0,
23+
data: calldata_to_executor,
24+
predecessor: 0,
25+
salt: 0,
26+
delay: timelock.getMinDelay()
27+
});
28+
}
29+
30+
/// @dev Get the calldata to be sent from the timelock to the executor
31+
function _getCalldataToExecutor() internal returns (bytes memory) {
32+
MultisigCall[] storage executorCalls = Encode.newMultisigCalls()
33+
/// core/
34+
.append({
35+
to: Env.proxyAdmin(),
36+
data: Encode.proxyAdmin.upgrade({
37+
proxy: address(Env.proxy.allocationManager()),
38+
impl: address(Env.impl.allocationManager())
39+
})
40+
})
41+
.append({
42+
to: Env.proxyAdmin(),
43+
data: Encode.proxyAdmin.upgrade({
44+
proxy: address(Env.proxy.delegationManager()),
45+
impl: address(Env.impl.delegationManager())
46+
})
47+
});
48+
49+
return Encode.gnosisSafe.execTransaction({
50+
from: address(Env.timelockController()),
51+
to: address(Env.multiSendCallOnly()),
52+
op: Encode.Operation.DelegateCall,
53+
data: Encode.multiSend(executorCalls)
54+
});
55+
}
56+
57+
function testScript() public virtual {
58+
runAsEOA();
59+
60+
TimelockController timelock = Env.timelockController();
61+
bytes memory calldata_to_executor = _getCalldataToExecutor();
62+
bytes32 txHash = timelock.hashOperation({
63+
target: Env.executorMultisig(),
64+
value: 0,
65+
data: calldata_to_executor,
66+
predecessor: 0,
67+
salt: 0
68+
});
69+
70+
// Check that the upgrade does not exist in the timelock
71+
assertFalse(timelock.isOperationPending(txHash), "Transaction should NOT be queued.");
72+
73+
execute();
74+
75+
// Check that the upgrade has been added to the timelock
76+
assertTrue(timelock.isOperationPending(txHash), "Transaction should be queued.");
77+
}
78+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import "../Env.sol";
5+
import {Queue} from "./2-multisig.s.sol";
6+
7+
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
8+
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
9+
10+
contract Execute is Queue {
11+
using Env for *;
12+
13+
function _runAsMultisig() prank(Env.protocolCouncilMultisig()) internal override(Queue) {
14+
bytes memory calldata_to_executor = _getCalldataToExecutor();
15+
16+
TimelockController timelock = Env.timelockController();
17+
timelock.execute({
18+
target: Env.executorMultisig(),
19+
value: 0,
20+
payload: calldata_to_executor,
21+
predecessor: 0,
22+
salt: 0
23+
});
24+
}
25+
26+
function testScript() public virtual override(Queue){
27+
// 0. Deploy Impls
28+
runAsEOA();
29+
30+
TimelockController timelock = Env.timelockController();
31+
bytes memory calldata_to_executor = _getCalldataToExecutor();
32+
bytes32 txHash = timelock.hashOperation({
33+
target: Env.executorMultisig(),
34+
value: 0,
35+
data: calldata_to_executor,
36+
predecessor: 0,
37+
salt: 0
38+
});
39+
assertFalse(timelock.isOperationPending(txHash), "Transaction should NOT be queued.");
40+
41+
// 1. Queue Upgrade
42+
Queue._runAsMultisig();
43+
_unsafeResetHasPranked(); // reset hasPranked so we can use it again
44+
45+
// 2. Warp past delay
46+
vm.warp(block.timestamp + timelock.getMinDelay()); // 1 tick after ETA
47+
assertEq(timelock.isOperationReady(txHash), true, "Transaction should be executable.");
48+
49+
// 3- execute
50+
execute();
51+
52+
assertTrue(timelock.isOperationDone(txHash), "Transaction should be complete.");
53+
54+
// 4. Validate
55+
_validateNewImplAddresses(true);
56+
_validateProxyConstructors();
57+
}
58+
59+
function _validateProxyConstructors() internal view {
60+
AllocationManager allocationManager = Env.proxy.allocationManager();
61+
assertTrue(allocationManager.delegation() == Env.proxy.delegationManager(), "alm.dm invalid");
62+
assertTrue(allocationManager.pauserRegistry() == Env.impl.pauserRegistry(), "alm.pR invalid");
63+
assertTrue(allocationManager.permissionController() == Env.proxy.permissionController(), "alm.pc invalid");
64+
assertTrue(allocationManager.DEALLOCATION_DELAY() == Env.MIN_WITHDRAWAL_DELAY(), "alm.deallocDelay invalid");
65+
assertTrue(allocationManager.ALLOCATION_CONFIGURATION_DELAY() == Env.ALLOCATION_CONFIGURATION_DELAY(), "alm.configDelay invalid");
66+
67+
DelegationManager delegation = Env.proxy.delegationManager();
68+
assertTrue(delegation.strategyManager() == Env.proxy.strategyManager(), "dm.sm invalid");
69+
assertTrue(delegation.eigenPodManager() == Env.proxy.eigenPodManager(), "dm.epm invalid");
70+
assertTrue(delegation.allocationManager() == Env.proxy.allocationManager(), "dm.alm invalid");
71+
assertTrue(delegation.pauserRegistry() == Env.impl.pauserRegistry(), "dm.pR invalid");
72+
assertTrue(delegation.permissionController() == Env.proxy.permissionController(), "dm.pc invalid");
73+
assertTrue(delegation.minWithdrawalDelayBlocks() == Env.MIN_WITHDRAWAL_DELAY(), "dm.withdrawalDelay invalid");
74+
}
75+
}

0 commit comments

Comments
 (0)