Skip to content

Commit 7ecc83c

Browse files
ypatil120xrajath
andauthored
feat: final testnet upgrade scripts (#1594)
**Motivation:** We need upgrade scripts for testnet **Modifications:** Add a `v1.8.0-multichain-testnet-final` folder with scripts to upgrade source and destination chain. Run tests: ```bash zeus test script/releases/v1.8.0-multichain-testnet-final/*.s.sol --env preprod --rpcUrl $RPC_HOLESKY ``` **Result:** Final v1.8.0 ready --------- Co-authored-by: 0xrajath <[email protected]>
1 parent fc1984e commit 7ecc83c

File tree

7 files changed

+939
-0
lines changed

7 files changed

+939
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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+
11+
/**
12+
* Purpose: use an EOA to deploy all of the new source chain contracts for this upgrade.
13+
*/
14+
contract DeploySourceChain is EOADeployer {
15+
using Env for *;
16+
17+
/// forgefmt: disable-next-item
18+
function _runAsEOA() internal override {
19+
// If we're not on a source chain, we don't need to deploy any contracts
20+
if (!Env.isSourceChain()) {
21+
return;
22+
}
23+
24+
vm.startBroadcast();
25+
26+
// Deploy KeyRegistrar implementation
27+
deployImpl({
28+
name: type(KeyRegistrar).name,
29+
deployedTo: address(
30+
new KeyRegistrar({
31+
_permissionController: Env.proxy.permissionController(),
32+
_allocationManager: Env.proxy.allocationManager(),
33+
_version: Env.deployVersion()
34+
})
35+
)
36+
});
37+
38+
// Deploy CrossChainRegistry implementation
39+
deployImpl({
40+
name: type(CrossChainRegistry).name,
41+
deployedTo: address(
42+
new CrossChainRegistry({
43+
_allocationManager: Env.proxy.allocationManager(),
44+
_keyRegistrar: Env.proxy.keyRegistrar(),
45+
_permissionController: Env.proxy.permissionController(),
46+
_pauserRegistry: Env.impl.pauserRegistry(),
47+
_version: Env.deployVersion()
48+
})
49+
)
50+
});
51+
52+
// Deploy ReleaseManager implementation
53+
deployImpl({
54+
name: type(ReleaseManager).name,
55+
deployedTo: address(
56+
new ReleaseManager({_permissionController: Env.proxy.permissionController(), _version: Env.deployVersion()})
57+
)
58+
});
59+
60+
vm.stopBroadcast();
61+
}
62+
63+
function testScript() public virtual {
64+
if (!Env.isSourceChain()) {
65+
return;
66+
}
67+
68+
// Set the mode to EOA so we can deploy the contracts
69+
runAsEOA();
70+
71+
_validateNewImplAddresses({areMatching: false});
72+
_validateProxyAdmins();
73+
_validateImplConstructors();
74+
_validateImplsInitialized();
75+
_validateVersion();
76+
}
77+
78+
/// @dev Validate that the `Env.impl` addresses are updated to be distinct from what the proxy
79+
/// admin reports as the current implementation address.
80+
///
81+
/// Note: The upgrade script can call this with `areMatching == true` to check that these impl
82+
/// addresses _are_ matches.
83+
function _validateNewImplAddresses(
84+
bool areMatching
85+
) internal view {
86+
function (bool, string memory) internal pure assertion = areMatching ? _assertTrue : _assertFalse;
87+
88+
// KeyRegistrar
89+
assertion(
90+
Env._getProxyImpl(address(Env.proxy.keyRegistrar())) == address(Env.impl.keyRegistrar()),
91+
"keyRegistrar impl failed"
92+
);
93+
94+
// CrossChainRegistry
95+
assertion(
96+
Env._getProxyImpl(address(Env.proxy.crossChainRegistry())) == address(Env.impl.crossChainRegistry()),
97+
"crossChainRegistry impl failed"
98+
);
99+
100+
// ReleaseManager
101+
assertion(
102+
Env._getProxyImpl(address(Env.proxy.releaseManager())) == address(Env.impl.releaseManager()),
103+
"releaseManager impl failed"
104+
);
105+
}
106+
107+
/// @dev Ensure each deployed TUP/beacon is owned by the proxyAdmin/executorMultisig
108+
function _validateProxyAdmins() internal view {
109+
address pa = Env.proxyAdmin();
110+
111+
assertTrue(Env._getProxyAdmin(address(Env.proxy.keyRegistrar())) == pa, "keyRegistrar proxyAdmin incorrect");
112+
assertTrue(
113+
Env._getProxyAdmin(address(Env.proxy.crossChainRegistry())) == pa, "crossChainRegistry proxyAdmin incorrect"
114+
);
115+
assertTrue(Env._getProxyAdmin(address(Env.proxy.releaseManager())) == pa, "releaseManager proxyAdmin incorrect");
116+
}
117+
118+
/// @dev Validate the immutables set in the new implementation constructors
119+
function _validateImplConstructors() internal view {
120+
{
121+
/// KeyRegistrar
122+
KeyRegistrar keyRegistrar = Env.impl.keyRegistrar();
123+
assertTrue(
124+
address(keyRegistrar.permissionController()) == address(Env.proxy.permissionController()),
125+
"kr.permissionController invalid"
126+
);
127+
assertTrue(
128+
address(keyRegistrar.allocationManager()) == address(Env.proxy.allocationManager()),
129+
"kr.allocationManager invalid"
130+
);
131+
assertEq(keyRegistrar.version(), Env.deployVersion(), "kr.version failed");
132+
}
133+
134+
{
135+
/// CrossChainRegistry
136+
CrossChainRegistry crossChainRegistry = Env.impl.crossChainRegistry();
137+
assertTrue(
138+
address(crossChainRegistry.allocationManager()) == address(Env.proxy.allocationManager()),
139+
"ccr.allocationManager invalid"
140+
);
141+
assertTrue(
142+
address(crossChainRegistry.keyRegistrar()) == address(Env.proxy.keyRegistrar()),
143+
"ccr.keyRegistrar invalid"
144+
);
145+
assertTrue(
146+
address(crossChainRegistry.permissionController()) == address(Env.proxy.permissionController()),
147+
"ccr.permissionController invalid"
148+
);
149+
assertTrue(
150+
address(crossChainRegistry.pauserRegistry()) == address(Env.impl.pauserRegistry()),
151+
"ccr.pauserRegistry invalid"
152+
);
153+
assertEq(crossChainRegistry.version(), Env.deployVersion(), "ccr.version failed");
154+
}
155+
156+
{
157+
/// ReleaseManager
158+
ReleaseManager releaseManager = Env.impl.releaseManager();
159+
assertTrue(
160+
releaseManager.permissionController() == Env.proxy.permissionController(),
161+
"rm.permissionController invalid"
162+
);
163+
assertEq(releaseManager.version(), Env.deployVersion(), "rm.version failed");
164+
}
165+
}
166+
167+
/// @dev Call initialize on all deployed implementations to ensure initializers are disabled
168+
function _validateImplsInitialized() internal {
169+
bytes memory errInit = "Initializable: contract is already initialized";
170+
171+
/// CrossChainRegistry
172+
CrossChainRegistry crossChainRegistry = Env.impl.crossChainRegistry();
173+
vm.expectRevert(errInit);
174+
crossChainRegistry.initialize(address(0), 1 days, 0);
175+
176+
// KeyRegistrar and ReleaseManager don't have initialize functions
177+
}
178+
179+
function _validateVersion() internal view {
180+
// On future upgrades, just tick the major/minor/patch to validate
181+
string memory expected = Env.deployVersion();
182+
183+
assertEq(Env.impl.keyRegistrar().version(), expected, "keyRegistrar version mismatch");
184+
assertEq(Env.impl.crossChainRegistry().version(), expected, "crossChainRegistry version mismatch");
185+
assertEq(Env.impl.releaseManager().version(), expected, "releaseManager version mismatch");
186+
}
187+
188+
function _assertTrue(bool b, string memory err) internal pure {
189+
assertTrue(b, err);
190+
}
191+
192+
function _assertFalse(bool b, string memory err) internal pure {
193+
assertFalse(b, err);
194+
}
195+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.12;
3+
4+
import {DeploySourceChain} from "./1-deploySourceChain.s.sol";
5+
import "../Env.sol";
6+
7+
import {MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol";
8+
import {MultisigCall, Encode} from "zeus-templates/utils/Encode.sol";
9+
10+
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
11+
12+
/**
13+
* Purpose:
14+
* * enqueue a multisig transaction which;
15+
* - upgrades KeyRegistrar, CrossChainRegistry, ReleaseManager
16+
* This should be run via the protocol council multisig.
17+
*/
18+
contract QueueSourceChain is MultisigBuilder, DeploySourceChain {
19+
using Env for *;
20+
using Encode for *;
21+
22+
function _runAsMultisig() internal virtual override prank(Env.opsMultisig()) {
23+
if (!Env.isSourceChain()) {
24+
return;
25+
}
26+
27+
bytes memory calldata_to_executor = _getCalldataToExecutor();
28+
29+
TimelockController timelock = Env.timelockController();
30+
timelock.schedule({
31+
target: Env.executorMultisig(),
32+
value: 0,
33+
data: calldata_to_executor,
34+
predecessor: 0,
35+
salt: 0,
36+
delay: timelock.getMinDelay()
37+
});
38+
}
39+
40+
/// @dev Get the calldata to be sent from the timelock to the executor
41+
function _getCalldataToExecutor() internal returns (bytes memory) {
42+
/// forgefmt: disable-next-item
43+
MultisigCall[] storage executorCalls = Encode.newMultisigCalls().append({
44+
to: Env.proxyAdmin(),
45+
data: Encode.proxyAdmin.upgrade({
46+
proxy: address(Env.proxy.keyRegistrar()),
47+
impl: address(Env.impl.keyRegistrar())
48+
})
49+
}).append({
50+
to: Env.proxyAdmin(),
51+
data: Encode.proxyAdmin.upgrade({
52+
proxy: address(Env.proxy.crossChainRegistry()),
53+
impl: address(Env.impl.crossChainRegistry())
54+
})
55+
}).append({
56+
to: Env.proxyAdmin(),
57+
data: Encode.proxyAdmin.upgrade({
58+
proxy: address(Env.proxy.releaseManager()),
59+
impl: address(Env.impl.releaseManager())
60+
})
61+
});
62+
63+
return Encode.gnosisSafe.execTransaction({
64+
from: address(Env.timelockController()),
65+
to: Env.multiSendCallOnly(),
66+
op: Encode.Operation.DelegateCall,
67+
data: Encode.multiSend(executorCalls)
68+
});
69+
}
70+
71+
function testScript() public virtual override {
72+
if (!Env.isSourceChain()) {
73+
return;
74+
}
75+
76+
// Deploy contracts first
77+
runAsEOA();
78+
79+
TimelockController timelock = Env.timelockController();
80+
bytes memory calldata_to_executor = _getCalldataToExecutor();
81+
bytes32 txHash = timelock.hashOperation({
82+
target: Env.executorMultisig(),
83+
value: 0,
84+
data: calldata_to_executor,
85+
predecessor: 0,
86+
salt: 0
87+
});
88+
89+
// Check that the upgrade does not exist in the timelock
90+
assertFalse(timelock.isOperationPending(txHash), "Transaction should NOT be queued.");
91+
92+
execute();
93+
94+
// Check that the upgrade has been added to the timelock
95+
assertTrue(timelock.isOperationPending(txHash), "Transaction should be queued.");
96+
}
97+
}

0 commit comments

Comments
 (0)