1+ // SPDX-License-Identifier: MIT
2+ pragma solidity ^ 0.8.27 ;
3+
4+ import "../../../src/EtherFiTimelock.sol " ;
5+ import "../../../src/interfaces/IEtherFiNode.sol " ;
6+ // import {IEtherFiNodesManager} from "../../../src/interfaces/IEtherFiNodesManager.sol";
7+ import "../../../src/EtherFiNodesManager.sol " ;
8+ import {IEigenPod, IEigenPodTypes} from "../../../src/eigenlayer-interfaces/IEigenPod.sol " ;
9+ import "forge-std/Script.sol " ;
10+ import "forge-std/console2.sol " ;
11+
12+ /**
13+ forge script script/el-exits/pectra-executions/EL-withdrawal-for-node.s.sol:ELWithdrawalForNode --fork-url <mainnet-rpc> -vvvv
14+ */
15+
16+ contract ELWithdrawalForNode is Script {
17+ EtherFiTimelock etherFiTimelock =
18+ EtherFiTimelock (payable (0x9f26d4C958fD811A1F59B01B86Be7dFFc9d20761 ));
19+ EtherFiTimelock etherFiOperatingTimelock = EtherFiTimelock (payable (0xcD425f44758a08BaAB3C4908f3e3dE5776e45d7a ));
20+
21+ //--------------------------------------------------------------------------------------
22+ //------------------------- Existing Users/Proxies -------------------------------------
23+ //--------------------------------------------------------------------------------------
24+ address constant ETHERFI_NODES_MANAGER_ADDRESS =
25+ 0x8B71140AD2e5d1E7018d2a7f8a288BD3CD38916F ;
26+
27+ EtherFiNodesManager etherFiNodesManager = EtherFiNodesManager (payable (ETHERFI_NODES_MANAGER_ADDRESS));
28+
29+ address constant ETHERFI_NODES_MANAGER_ADMIN_ROLE = 0x2aCA71020De61bb532008049e1Bd41E451aE8AdC ;
30+
31+ address constant EIGEN_POD_ADDRESS = 0x9563794BEf554667f4650eaAe192FfeC1C656C23 ; // 20 validators
32+
33+ address constant ETHERFI_OPERATING_ADMIN =
34+ 0x2aCA71020De61bb532008049e1Bd41E451aE8AdC ;
35+ address constant TIMELOCK_CONTROLLER = 0xcdd57D11476c22d265722F68390b036f3DA48c21 ;
36+
37+ address constant EL_TRIGGER_EXITER = 0x12582A27E5e19492b4FcD194a60F8f5e1aa31B0F ;
38+
39+ uint256 MIN_DELAY_OPERATING_TIMELOCK = 28800 ; // 8 hours
40+ uint256 MIN_DELAY_TIMELOCK = 259200 ; // 72 hours
41+
42+ bytes constant PK_54043 = hex "8014c4704f081bd4b8470cb93722601095a314c3db7ccf79c129189d01c432db968a64131f23a94c8ff1e280500ae3d3 " ;
43+ bytes constant PK_54045 = hex "820cf0499d0d908d10c19d85027ed4077322096cd4fb322a763c3bf5e4eb70db30b44ef1284e6fb713421a195735d942 " ;
44+ bytes constant PK_54041 = hex "87d657860a8b0450d7e700d60aa88a42ee5e6fdedeeb25dd3aee7e1112697f837b4b2e94d37167a900921e6b90c7f3ac " ;
45+ bytes constant PK_54050 = hex "8838691e23c67fc8a3021d1dfe49abdbd803469dd3471960f973fa6ed08eb180104d1ddd66938b4dc6264f04e489c6e7 " ;
46+ bytes constant PK_54040 = hex "895186127b42e8202949b9fff00c112df8070c25d96fbe4238fab3a133c49f4a6401dc55828ad5b89093af7602487a2c " ;
47+ bytes constant PK_54049 = hex "8c64ee1865c48b01ef1af561c41b0e3b363f2a83d99b835d6312638b380d2f698c78f2d405133d8b2aec8c439820f50e " ;
48+ bytes constant PK_54044 = hex "917f7c7916ee8ba15289810ea118d458c8b4fefb88caa5bef970aa972f7605ed47b54451d9b7c5128c484cf3ce989c1c " ;
49+ bytes constant PK_54048 = hex "9310d317f4df0b52f8fa2191b6826e93ccd613b2fb4f4e1463c5b112be9102b689ad628c717f201ededf18555d775b43 " ;
50+ bytes constant PK_54035 = hex "936dfac756c52488607b7f07d8905cbff4ae647aaeea75645f28f73a46ae3f6cc9dd55be57ea8ebbf1052197be97bb28 " ;
51+ bytes constant PK_54053 = hex "a160a281269a464e89ca8cdd0521200232c2d37140f218daaa9393aa008c6b3b5ed48040a3e4f46b059532c6b07af360 " ;
52+ bytes constant PK_54039 = hex "a3b265189b2cb571a2d48043a7da96c918df480983c89f86480a1ae5af8a6aa14c381ef091387c201fe5c886b8c27755 " ;
53+ bytes constant PK_54051 = hex "a3e60bce7da064113757a74572909242403654e11ad48c9ee646ea926c026ebf9e60bde5054117b0c74600762693f90c " ;
54+ bytes constant PK_54047 = hex "a3fb69cd6685e6df16d9dc6e5a0fd174d4460e393bf151b62d4ed62fc4524125f665c3ef91e8673154ce30a934562127 " ;
55+ bytes constant PK_54042 = hex "a481a9553e9cd70a28685c3c86da72cb7cc47fc4132aa79609bc121f3d1c1fe693fb82b70ab1792267837f03fd8b480a " ;
56+ bytes constant PK_54036 = hex "a702539fb750fa7524a382f0a80572161786be488e77cd680d41d3ba47acd2bd9218036e218e61f7a397b25f6fd473b9 " ;
57+ bytes constant PK_54052 = hex "a9e0d47715165646896c9dd1eaad3822824340f9432978fe2220d1d849509711fa822080d69a5604a7df372dcd7290ff " ;
58+ bytes constant PK_54037 = hex "ab82fc4c1eee2b1c26d3adcf6a1240beb18aafe86ac0ca897cd94611eefae7a88e3b3c80dd768b6f2da9326ecebfcc54 " ;
59+ bytes constant PK_54054 = hex "b72d2761774961ee47a8b9a917110a70425b4500909ccd972f72c7219e3f0c76f086de76cb80a4598ecb44245effeaa9 " ;
60+ bytes constant PK_54046 = hex "b7ca7c4dccc74cc17a1b2325a95e690aca40fd4d2980bd65180d98bf0da447cf84254da073c28c1b1efc959611e5cfe1 " ;
61+ bytes constant PK_54038 = hex "b974967fa38e82a9983019ccdb754df1c176edf5e542ec7377c23bcce730c094007fb84d9816f5fb22f09b725e46d99a " ;
62+
63+ function run () public {
64+ console2.log ("================================================ " );
65+ console2.log ("======================== Running EL Withdrawal For Node Transactions ======================== " );
66+ console2.log ("================================================ " );
67+ console2.log ("" );
68+
69+ // vm.startBroadcast(ETHERFI_OPERATING_ADMIN);
70+ // vm.prank(ETHERFI_OPERATING_ADMIN);
71+ linkLegacyValidatorIds ();
72+ // vm.stopPrank();
73+ // vm.stopBroadcast();
74+
75+ // vm.startBroadcast(EL_TRIGGER_EXITER);
76+ executeELWithdrawalForNodeTransactions ();
77+ // vm.stopBroadcast();
78+ }
79+
80+ function linkLegacyValidatorIds () public {
81+ uint256 [] memory legacyIdsForOneValidator = new uint256 [](1 );
82+ legacyIdsForOneValidator[0 ] = 54043 ;
83+ bytes [] memory pubkeysForOneValidator = new bytes [](1 );
84+ pubkeysForOneValidator[0 ] = PK_54043;
85+
86+ address [] memory targets = new address [](1 );
87+ targets[0 ] = address (etherFiNodesManager);
88+ uint256 [] memory values = new uint256 [](1 );
89+ values[0 ] = 0 ;
90+ bytes [] memory data = new bytes [](1 );
91+ data[0 ] = abi.encodeWithSelector (
92+ etherFiNodesManager.linkLegacyValidatorIds.selector ,
93+ legacyIdsForOneValidator,
94+ pubkeysForOneValidator
95+ );
96+
97+ bytes32 timelockSalt = keccak256 (
98+ abi.encode (targets, data, block .number )
99+ );
100+
101+ bytes memory scheduleCalldata = abi.encodeWithSelector (
102+ etherFiOperatingTimelock.scheduleBatch.selector ,
103+ targets,
104+ values,
105+ data,
106+ bytes32 (0 ), //predecessor
107+ timelockSalt,
108+ MIN_DELAY_OPERATING_TIMELOCK
109+ );
110+ console2.log ("Scheduled linkLegacyValidatorIds Tx " );
111+ console2.log ("================================================ " );
112+ console2.logBytes (scheduleCalldata);
113+ console2.log ("================================================ " );
114+ console2.log ("" );
115+
116+ bytes memory executeCalldata = abi.encodeWithSelector (
117+ etherFiOperatingTimelock.executeBatch.selector ,
118+ targets,
119+ values,
120+ data,
121+ bytes32 (0 ), //predecessor
122+ timelockSalt,
123+ MIN_DELAY_OPERATING_TIMELOCK
124+ );
125+ console2.log ("Executed linkLegacyValidatorIds Tx " );
126+ console2.log ("================================================ " );
127+ console2.logBytes (executeCalldata);
128+ console2.log ("================================================ " );
129+ console2.log ("" );
130+
131+ vm.prank (address (ETHERFI_OPERATING_ADMIN));
132+ etherFiNodesManager.linkLegacyValidatorIds (legacyIdsForOneValidator, pubkeysForOneValidator);
133+ vm.stopPrank ();
134+
135+ // uncomment to run against fork
136+ // console2.log("=== SCHEDULING BATCH ===");
137+ // // console2.log("Current timestamp:", block.timestamp);
138+ // etherFiOperatingTimelock.scheduleBatch(targets, values, data, bytes32(0), timelockSalt, MIN_DELAY_OPERATING_TIMELOCK);
139+
140+ // console2.log("=== FAST FORWARDING TIME ===");
141+ // vm.warp(block.timestamp + MIN_DELAY_OPERATING_TIMELOCK + 1); // +1 to ensure it's past the delay
142+ // // console2.log("New timestamp:", block.timestamp);
143+ // etherFiOperatingTimelock.executeBatch(targets, values, data, bytes32(0), timelockSalt);
144+ }
145+
146+ function executeELWithdrawalForNodeTransactions () public {
147+ console2.log ("Executing EL Withdrawal For Node Transactions " );
148+
149+ // STEP 1: GET EIGEN POD
150+ IEigenPod pod = IEigenPod (EIGEN_POD_ADDRESS);
151+
152+ // STEP 2: GET WITHDRAWAL REQUESTS
153+ IEigenPodTypes.WithdrawalRequest[] memory withdrawalRequests = _getWithdrawalsRequests ();
154+
155+ // STEP 3: GET WITHDRAWAL REQUEST FEE
156+ uint256 feePer = pod.getWithdrawalRequestFee ();
157+ uint256 n = withdrawalRequests.length ;
158+ uint256 valueToSend = feePer * n;
159+
160+ // STEP 4: EXECUTE EL WITHDRAWAL FOR NODE TRANSACTIONS
161+ vm.prank (address (EL_TRIGGER_EXITER));
162+ etherFiNodesManager.requestExecutionLayerTriggeredWithdrawal {value: valueToSend}(withdrawalRequests);
163+ vm.stopPrank ();
164+ }
165+
166+ function _getWithdrawalsRequests () public pure returns (IEigenPodTypes.WithdrawalRequest[] memory withdrawalRequests ) {
167+ bytes [] memory pubkeys = new bytes [](20 );
168+ uint64 [] memory amountsGwei = new uint64 [](20 );
169+
170+ pubkeys[0 ] = PK_54043;
171+ amountsGwei[0 ] = 0 ;
172+ pubkeys[1 ] = PK_54045;
173+ amountsGwei[1 ] = 0 ;
174+ pubkeys[2 ] = PK_54041;
175+ amountsGwei[2 ] = 0 ;
176+ pubkeys[3 ] = PK_54050;
177+ amountsGwei[3 ] = 0 ;
178+ pubkeys[4 ] = PK_54040;
179+ amountsGwei[4 ] = 0 ;
180+ pubkeys[5 ] = PK_54049;
181+ amountsGwei[5 ] = 0 ;
182+ pubkeys[6 ] = PK_54044;
183+ amountsGwei[6 ] = 0 ;
184+ pubkeys[7 ] = PK_54048;
185+ amountsGwei[7 ] = 0 ;
186+ pubkeys[8 ] = PK_54035;
187+ amountsGwei[8 ] = 0 ;
188+ pubkeys[9 ] = PK_54053;
189+ amountsGwei[9 ] = 0 ;
190+ pubkeys[10 ] = PK_54039;
191+ amountsGwei[10 ] = 0 ;
192+ pubkeys[11 ] = PK_54051;
193+ amountsGwei[11 ] = 0 ;
194+ pubkeys[12 ] = PK_54047;
195+ amountsGwei[12 ] = 0 ;
196+ pubkeys[13 ] = PK_54042;
197+ amountsGwei[13 ] = 0 ;
198+ pubkeys[14 ] = PK_54036;
199+ amountsGwei[14 ] = 0 ;
200+ pubkeys[15 ] = PK_54052;
201+ amountsGwei[15 ] = 0 ;
202+ pubkeys[16 ] = PK_54037;
203+ amountsGwei[16 ] = 0 ;
204+ pubkeys[17 ] = PK_54054;
205+ amountsGwei[17 ] = 0 ;
206+ pubkeys[18 ] = PK_54046;
207+ amountsGwei[18 ] = 0 ;
208+ pubkeys[19 ] = PK_54038;
209+ amountsGwei[19 ] = 0 ;
210+
211+ withdrawalRequests = new IEigenPodTypes.WithdrawalRequest [](pubkeys.length );
212+ for (uint256 i = 0 ; i < pubkeys.length ; i++ ) {
213+ withdrawalRequests[i] = IEigenPodTypes.WithdrawalRequest ({
214+ pubkey: pubkeys[i],
215+ amountGwei: amountsGwei[i]
216+ });
217+ }
218+ return withdrawalRequests;
219+ }
220+ }
0 commit comments