Skip to content

Commit e0a79f1

Browse files
authored
feat(op sets): upgrade and migrate script (#303)
* feat: upgrade and test pre prod upgrade and migration * fix: add param introduced in merge
1 parent f6ad20e commit e0a79f1

File tree

5 files changed

+340
-0
lines changed

5 files changed

+340
-0
lines changed

foundry.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ via_ir = false
1717
# Override the Solidity version (this overrides `auto_detect_solc`)
1818
solc_version = '0.8.12'
1919

20+
[etherscan]
21+
mainnet = { key = "${ETHERSCAN_API_KEY}" }
22+
holesky = { key = "${ETHERSCAN_API_KEY}" }
23+
2024
[fmt]
2125
bracket_spacing = false
2226
int_types = "long"

script/OperatorSetUpgrade.s.sol

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import {Script, console2} from "forge-std/Script.sol";
5+
import {OperatorSetUpgradeLib} from "./utils/UpgradeLib.sol";
6+
import {stdJson} from "forge-std/StdJson.sol";
7+
import {ServiceManagerMock, IServiceManager} from "../test/mocks/ServiceManagerMock.sol";
8+
import {StakeRegistry, IStakeRegistry} from "../src/StakeRegistry.sol";
9+
import {RegistryCoordinator, IRegistryCoordinator} from "../src/RegistryCoordinator.sol";
10+
import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
11+
import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol";
12+
import {IIndexRegistry} from "../src/interfaces/IIndexRegistry.sol";
13+
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
14+
import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol";
15+
import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
16+
interface IServiceManagerMigration {
17+
function getOperatorsToMigrate()
18+
external
19+
view
20+
returns (
21+
uint32[] memory operatorSetIdsToCreate,
22+
uint32[][] memory operatorSetIds,
23+
address[] memory allOperators
24+
);
25+
function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) external;
26+
function migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) external;
27+
function finalizeMigration() external;
28+
function migrationFinalized() external returns (bool);
29+
}
30+
31+
32+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
33+
34+
contract OperatorSetUpgradeScript is Script {
35+
using stdJson for string;
36+
37+
address private constant DEFAULT_FORGE_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38;
38+
39+
address public proxyAdminOwner;
40+
address public serviceManagerOwner;
41+
address public serviceManager;
42+
address public stakeRegistry;
43+
address public registryCoordinator;
44+
address public avsDirectory;
45+
address public rewardsCoordinator;
46+
address public delegationManager;
47+
address public blsApkRegistry;
48+
address public indexRegistry;
49+
50+
function setUp() public {
51+
vm.label(DEFAULT_FORGE_SENDER, "DEFAULT FORGE SENDER");
52+
53+
// Note: Ensure that the following environment variables are set before running the script:
54+
// - PROXY_ADMIN_OWNER: The private key of the proxy admin owner.
55+
// - SERVICE_MANAGER_OWNER: The private key of the service manager owner.
56+
// These environment variables are crucial for the proper execution of the upgrade and migration processes.
57+
/// TODO: improve DEVX of gnosis safe. Would like to do an tx service integration for SafeAPI
58+
proxyAdminOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER"));
59+
serviceManagerOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER"));
60+
61+
string memory middlewareJson = vm.readFile(vm.envString("MIDDLEWARE_JSON_PATH"));
62+
string memory coreJson = vm.readFile(vm.envString("CORE_JSON_PATH"));
63+
64+
/*
65+
* Note: Ensure that the structure of the configuration JSON files matches the structure
66+
* of `core_testdata.json`. If you rename any of the files, you will need to update the
67+
* corresponding key values in the code.
68+
*/
69+
loadAddressesSetup(middlewareJson, coreJson);
70+
labelAndLogAddressesSetup();
71+
}
72+
73+
function run() public {
74+
vm.startBroadcast(proxyAdminOwner);
75+
76+
_upgrade();
77+
78+
vm.stopBroadcast();
79+
80+
vm.startBroadcast(serviceManagerOwner);
81+
82+
_migrateToOperatorSets();
83+
84+
vm.stopBroadcast();
85+
}
86+
// forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgrade()" -vvv
87+
function simulateUpgrade() public {
88+
89+
address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager);
90+
proxyAdminOwner = Ownable(proxyAdmin).owner();
91+
vm.startPrank(proxyAdminOwner);
92+
93+
_upgrade();
94+
95+
vm.stopPrank();
96+
97+
}
98+
99+
// forge script script/OperatorSetUpgrade.s.sol --sig "simulateMigrate()" -vvv
100+
function simulateMigrate() public {
101+
_upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet
102+
103+
serviceManagerOwner = Ownable(serviceManager).owner();
104+
vm.startPrank(serviceManagerOwner);
105+
106+
_migrateToOperatorSets();
107+
108+
vm.stopPrank();
109+
}
110+
111+
// forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgradeAndMigrate()" -vvv
112+
function simulateUpgradeAndMigrate() public {
113+
_upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet
114+
115+
address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager);
116+
proxyAdminOwner = Ownable(proxyAdmin).owner();
117+
118+
console2.log(proxyAdminOwner, "Pranker");
119+
vm.startPrank(proxyAdminOwner);
120+
121+
_upgrade();
122+
123+
vm.stopPrank();
124+
125+
serviceManagerOwner = Ownable(serviceManager).owner();
126+
vm.startPrank(serviceManagerOwner);
127+
128+
_migrateToOperatorSets();
129+
130+
vm.stopPrank();
131+
132+
// Assert that serviceManager is an operatorSetAVS
133+
require(
134+
IAVSDirectory(avsDirectory).isOperatorSetAVS(serviceManager),
135+
"simulateUpgradeAndMigrate: serviceManager is not an operatorSetAVS"
136+
);
137+
138+
// Assert that the migration is finalized
139+
require(
140+
IServiceManagerMigration(serviceManager).migrationFinalized(),
141+
"simulateUpgradeAndMigrate: Migration is not finalized"
142+
);
143+
}
144+
145+
function _upgradeAvsDirectory() internal {
146+
address proxyAdmin = OperatorSetUpgradeLib.getAdmin(avsDirectory);
147+
address avsDirectoryOwner = Ownable(proxyAdmin).owner();
148+
AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager));
149+
150+
vm.startPrank(avsDirectoryOwner);
151+
OperatorSetUpgradeLib.upgrade(avsDirectory, address(avsDirectoryImpl));
152+
vm.stopPrank();
153+
}
154+
155+
function labelAndLogAddressesSetup() internal virtual {
156+
vm.label(proxyAdminOwner, "Proxy Admin Owner Account");
157+
vm.label(serviceManagerOwner, "Service Manager Owner Account");
158+
vm.label(serviceManager, "Service Manager Proxy");
159+
vm.label(stakeRegistry, "Stake Registry Proxy");
160+
vm.label(registryCoordinator, "Registry Coordinator Proxy");
161+
vm.label(indexRegistry, "Index Registry Proxy");
162+
vm.label(blsApkRegistry, "BLS APK Registry Proxy");
163+
vm.label(avsDirectory, "AVS Directory Proxy");
164+
vm.label(delegationManager, "Delegation Manager Proxy");
165+
vm.label(rewardsCoordinator, "Rewards Coordinator Proxy");
166+
167+
console2.log("Proxy Admin Owner Account", proxyAdminOwner);
168+
console2.log("ServiceManager Owner Account", serviceManagerOwner);
169+
console2.log("Service Manager:", serviceManager);
170+
console2.log("Stake Registry:", stakeRegistry);
171+
console2.log("Registry Coordinator:", registryCoordinator);
172+
console2.log("Index Registry:", indexRegistry);
173+
console2.log("BLS APK Registry:", blsApkRegistry);
174+
console2.log("AVS Directory:", avsDirectory);
175+
console2.log("Delegation Manager:", delegationManager);
176+
console2.log("Rewards Coordinator:", rewardsCoordinator);
177+
178+
address oldServiceManagerImpl = OperatorSetUpgradeLib.getImplementation(serviceManager);
179+
address oldStakeRegistryImpl = OperatorSetUpgradeLib.getImplementation(stakeRegistry);
180+
address oldRegistryCoordinatorImpl = OperatorSetUpgradeLib.getImplementation(registryCoordinator);
181+
address oldAvsDirectoryImpl = OperatorSetUpgradeLib.getImplementation(avsDirectory);
182+
address oldDelegationManagerImpl = OperatorSetUpgradeLib.getImplementation(delegationManager);
183+
184+
vm.label(oldServiceManagerImpl, "Old Service Manager Implementation");
185+
vm.label(oldStakeRegistryImpl, "Old Stake Registry Implementation");
186+
vm.label(oldRegistryCoordinatorImpl, "Old Registry Coordinator Implementation");
187+
vm.label(oldAvsDirectoryImpl, "Old AVS Directory Implementation");
188+
vm.label(oldDelegationManagerImpl, "Old Delegation Manager Implementation");
189+
190+
console2.log("Old Service Manager Implementation:", oldServiceManagerImpl);
191+
console2.log("Old Stake Registry Implementation:", oldStakeRegistryImpl);
192+
console2.log("Old Registry Coordinator Implementation:", oldRegistryCoordinatorImpl);
193+
console2.log("Old AVS Directory Implementation:", oldAvsDirectoryImpl);
194+
console2.log("Old Delegation Manager Implementation:", oldDelegationManagerImpl);
195+
}
196+
197+
function loadAddressesSetup(string memory middlewareJson, string memory coreJson) internal virtual {
198+
serviceManager = middlewareJson.readAddress(".addresses.eigenDAServiceManager");
199+
stakeRegistry = middlewareJson.readAddress(".addresses.stakeRegistry");
200+
registryCoordinator = middlewareJson.readAddress(".addresses.registryCoordinator");
201+
blsApkRegistry = middlewareJson.readAddress(".addresses.blsApkRegistry");
202+
indexRegistry = middlewareJson.readAddress(".addresses.indexRegistry");
203+
204+
avsDirectory = coreJson.readAddress(".addresses.avsDirectory");
205+
delegationManager = coreJson.readAddress(".addresses.delegationManager");
206+
rewardsCoordinator = coreJson.readAddress(".addresses.rewardsCoordinator");
207+
}
208+
209+
function _upgrade() internal virtual {
210+
address newServiceManagerImpl = address(new ServiceManagerMock(
211+
IAVSDirectory(avsDirectory),
212+
IRewardsCoordinator(rewardsCoordinator),
213+
IRegistryCoordinator(registryCoordinator),
214+
IStakeRegistry(stakeRegistry)
215+
));
216+
address newRegistryCoordinatorImpl = address(new RegistryCoordinator(
217+
IServiceManager(serviceManager),
218+
IStakeRegistry(stakeRegistry),
219+
IBLSApkRegistry(blsApkRegistry),
220+
IIndexRegistry(indexRegistry),
221+
IAVSDirectory(avsDirectory)
222+
));
223+
address newStakeRegistryImpl = address(new StakeRegistry(
224+
IRegistryCoordinator(registryCoordinator),
225+
IDelegationManager(delegationManager),
226+
IAVSDirectory(avsDirectory),
227+
IServiceManager(serviceManager)
228+
));
229+
230+
console2.log("New Service Manager Implementation:", newServiceManagerImpl);
231+
console2.log("New Registry Coordinator Implementation:", newRegistryCoordinatorImpl);
232+
console2.log("New Stake Registry Implementation:", newStakeRegistryImpl);
233+
234+
vm.label(newServiceManagerImpl, "New Service Manager Implementation");
235+
vm.label(newRegistryCoordinatorImpl, "New Registry Coordinator Implementation");
236+
vm.label(newStakeRegistryImpl, "New Stake Registry Implementation");
237+
238+
OperatorSetUpgradeLib.upgrade(serviceManager, newServiceManagerImpl);
239+
OperatorSetUpgradeLib.upgrade(registryCoordinator, newRegistryCoordinatorImpl);
240+
OperatorSetUpgradeLib.upgrade(stakeRegistry, newStakeRegistryImpl);
241+
}
242+
243+
function _migrateToOperatorSets() internal virtual {
244+
IServiceManagerMigration serviceManager = IServiceManagerMigration(serviceManager);
245+
(
246+
uint32[] memory operatorSetsToCreate,
247+
uint32[][] memory operatorSetIdsToMigrate,
248+
address[] memory operators
249+
) = serviceManager.getOperatorsToMigrate();
250+
251+
serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate);
252+
serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators);
253+
serviceManager.finalizeMigration();
254+
}
255+
}

script/utils/UpgradeLib.sol

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
// Deploy L2AVS proxy
4+
5+
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
6+
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
7+
8+
import {Vm} from "forge-std/Vm.sol";
9+
import {stdJson} from "forge-std/StdJson.sol";
10+
11+
library OperatorSetUpgradeLib {
12+
using stdJson for string;
13+
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
14+
bytes32 internal constant IMPLEMENTATION_SLOT =
15+
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
16+
17+
bytes32 internal constant ADMIN_SLOT =
18+
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
19+
20+
21+
function upgrade(address proxy, address implementation, bytes memory data) internal {
22+
ProxyAdmin admin = ProxyAdmin(getAdmin(proxy));
23+
admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), implementation, data);
24+
}
25+
26+
function upgrade(address proxy, address implementation) internal {
27+
ProxyAdmin admin = ProxyAdmin(getAdmin(proxy));
28+
admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), implementation);
29+
}
30+
31+
function getAdmin(address proxy) internal view returns (address){
32+
bytes32 value = vm.load(proxy, ADMIN_SLOT);
33+
return address(uint160(uint256(value)));
34+
}
35+
36+
function getImplementation(address proxy) internal view returns (address) {
37+
bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT);
38+
return address(uint160(uint256(value)));
39+
}
40+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"addresses":{
3+
"avsDirectory": "0x141d6995556135D4997b2ff72EB443Be300353bC",
4+
"avsDirectoryImplementation": "0x357978adC03375BD6a3605DE055fABb84695d79A",
5+
"baseStrategyImplementation": "0x62450517EfA1CE60d79801daf8f95973865e8D40",
6+
"beaconOracle": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25",
7+
"delayedWithdrawalRouter": "0xC4BC46a87A67a531eCF7f74338E1FA79533334Fa",
8+
"delayedWithdrawalRouterImplementation": "0x0011FA2c512063C495f77296Af8d195F33A8Dd38",
9+
"delegationManager": "0x75dfE5B44C2E530568001400D3f704bC8AE350CC",
10+
"delegationManagerImplementation": "0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1",
11+
"eigenLayerPauserReg": "0x9Ab2FEAf0465f0eD51Fc2b663eF228B418c9Dad1",
12+
"eigenLayerProxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B",
13+
"eigenPodBeacon": "0x92Cc4a800A1513E85C481dDDf3A06C6921211eaC",
14+
"eigenPodImplementation": "0x2D6c7f9862BD80Cf0d9d93FC6b513D69E7Db7869",
15+
"eigenPodManager": "0xB8d8952f572e67B11e43bC21250967772fa883Ff",
16+
"eigenPodManagerImplementation": "0xc5B857A92245f64e9D90cCc5b096Db82eB77eB5c",
17+
"emptyContract": "0x9690d52B1Ce155DB2ec5eCbF5a262ccCc7B3A6D2",
18+
"rewardsCoordinator": "0xb22Ef643e1E067c994019A4C19e403253C05c2B0",
19+
"rewardsCoordinatorImplementation": "0x76d4D84c90a2AFf213F7D859d2a288685A1a2Ede",
20+
"slasher": "0x12699471dF8dca329C76D72823B1b79d55709384",
21+
"slasherImplementation": "0x9460fCe11E1e0365419fa860599903B4E5097cf0"
22+
}
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"addresses":{
3+
"blsApkRegistry": "0xAd7f9e558170a149Ca8E90f41Ab2444A5d3bd6aD",
4+
"blsApkRegistryImplementation": "0x482a96D5879e32347d8df125f038D7eC8Ab358dd",
5+
"eigenDAProxyAdmin": "0x9Fd7E279f5bD692Dc04792151E14Ad814FC60eC1",
6+
"eigenDAServiceManager": "0x54A03db2784E3D0aCC08344D05385d0b62d4F432",
7+
"eigenDAServiceManagerImplementation": "0xEB11a0f320E39d3371Fec4Bf5C76944DfBA8ee10",
8+
"indexRegistry": "0x8cE5F2a53cBd29710eb94A04e40C07A4DdF15d10",
9+
"indexRegistryImplementation": "0x1D4d6054BD11A5711ad7c5d3E376C987a603e17C",
10+
"mockRollup": "0x0433646AdCeE95fbF89b3BFDb8157e75c19b6C2e",
11+
"operatorStateRetriever": "0x17cA8C41a59466710443143b2ECF08CaA35d80ad",
12+
"registryCoordinator": "0x2c61EA360D6500b58E7f481541A36B443Bc858c6",
13+
"registryCoordinatorImplementation": "0x6f21A84E7f185cCBA248B436e3b583E609d1dE1D",
14+
"serviceManagerRouter": "0xDb028E067fe81e9f406C2DE382Ba82e9cD7cBD03",
15+
"stakeRegistry": "0x53668EBf2e28180e38B122c641BC51Ca81088871",
16+
"stakeRegistryImplementation": "0x854dc9e5d011B060bf77B1a492302C349f2f00b5"
17+
}
18+
}

0 commit comments

Comments
 (0)