Skip to content

Multiple varied scripts for operational tasks#378

Open
pankajjagtapp wants to merge 12 commits into
masterfrom
pankaj/script/withdrawal-script
Open

Multiple varied scripts for operational tasks#378
pankajjagtapp wants to merge 12 commits into
masterfrom
pankaj/script/withdrawal-script

Conversation

@pankajjagtapp
Copy link
Copy Markdown
Contributor

@pankajjagtapp pankajjagtapp commented Apr 21, 2026

Note

Medium Risk
Adds and updates multiple mainnet operations scripts that generate Safe transactions and directly exercise privileged on-chain actions (rate limits, oracle cadence, redemptions, withdrawals), so misuse or wrong parameters could impact protocol operations despite no core contract changes.

Overview
Adds a large set of new script/operations/* runbooks to generate Safe JSON batches and fork-simulate privileged mainnet ops, including batch beacon-validator creation from a JSON payload, priority-queue whitelist/fee maintenance, oracle reportPeriodSlot update (640→1280) with validation flow, and rate-limiter capacity/refill adjustments.

Introduces several stETH/EigenLayer operational scripts to complete/queue withdrawals, redelegate restaked stETH, and temporarily raise EtherFiRedemptionManager stETH redemption capacity (with scheduled revert) including a whale-specific capacity change runbook. Also adds an end-to-end EigenLayer withdrawal completion + node sweep flow (Solidity scripts plus query_node_ids.py/node-ids.json) and updates foundry.toml FS permissions to allow writing under script/operations.

Updates Utils.MIN_DELAY_OPERATING_TIMELOCK from 8 hours to 2 days, affecting scripts that schedule via the operating timelock.

Reviewed by Cursor Bugbot for commit a87e276. Bugbot is set up for automated code reviews on this repo. Configure here.

@pankajjagtapp pankajjagtapp self-assigned this Apr 21, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 21, 2026

📊 Forge Coverage Report

| File                                       | % Lines            | % Statements       | % Branches       | % Funcs          |
| src/AssetRecovery.sol                      | 100.00% (16/16)    | 96.77% (30/31)     | 85.71% (6/7)     | 100.00% (3/3)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/AuctionManager.sol                     | 74.40% (93/125)    | 75.00% (81/108)    | 61.11% (33/54)   | 71.43% (20/28)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/BNFT.sol                               | 53.85% (14/26)     | 56.25% (9/16)      | 20.00% (2/10)    | 45.45% (5/11)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/BucketRateLimiter.sol                  | 100.00% (50/50)    | 100.00% (48/48)    | 100.00% (10/10)  | 100.00% (16/16)  |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/CumulativeMerkleRewardsDistributor.sol | 90.41% (66/73)     | 83.33% (70/84)     | 41.18% (7/17)    | 92.86% (13/14)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/DepositAdapter.sol                     | 0.00% (0/57)       | 0.00% (0/65)       | 0.00% (0/11)     | 0.00% (0/9)      |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EETH.sol                               | 97.41% (113/116)   | 97.27% (107/110)   | 90.91% (30/33)   | 96.77% (30/31)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EarlyAdopterPool.sol                   | 0.00% (0/92)       | 0.00% (0/81)       | 0.00% (0/34)     | 0.00% (0/15)     |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiAdmin.sol                       | 95.10% (136/143)   | 93.06% (161/173)   | 76.79% (43/56)   | 95.24% (20/21)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiNode.sol                        | 85.29% (58/68)     | 75.64% (59/78)     | 22.22% (2/9)     | 100.00% (16/16)  |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiNodesManager.sol                | 97.80% (178/182)   | 96.24% (205/213)   | 88.89% (32/36)   | 97.78% (44/45)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiOracle.sol                      | 97.92% (141/144)   | 99.24% (131/132)   | 90.32% (56/62)   | 96.77% (30/31)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiRateLimiter.sol                 | 100.00% (55/55)    | 100.00% (61/61)    | 100.00% (14/14)  | 100.00% (17/17)  |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiRedemptionManager.sol           | 45.75% (70/153)    | 45.56% (77/169)    | 24.56% (14/57)   | 54.55% (18/33)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiRestaker.sol                    | 83.33% (130/156)   | 86.77% (164/189)   | 35.00% (7/20)    | 64.71% (22/34)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/EtherFiRewardsRouter.sol               | 100.00% (28/28)    | 100.00% (27/27)    | 83.33% (5/6)     | 100.00% (8/8)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/LiquidityPool.sol                      | 95.48% (211/221)   | 91.39% (276/302)   | 76.12% (51/67)   | 95.45% (42/44)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/Liquifier.sol                          | 84.52% (131/155)   | 77.11% (128/166)   | 52.50% (21/40)   | 75.00% (30/40)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/MembershipManager.sol                  | 0.00% (0/348)      | 0.00% (0/389)      | 0.00% (0/31)     | 0.00% (0/69)     |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/MembershipNFT.sol                      | 22.73% (40/176)    | 16.42% (33/201)    | 20.69% (6/29)    | 31.71% (13/41)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/NodeOperatorManager.sol                | 89.23% (58/65)     | 92.00% (46/50)     | 80.00% (16/20)   | 80.00% (16/20)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/PriorityWithdrawalQueue.sol            | 92.83% (207/223)   | 83.33% (250/300)   | 50.85% (30/59)   | 95.24% (40/42)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/RestakingRewardsRouter.sol             | 100.00% (33/33)    | 100.00% (34/34)    | 100.00% (7/7)    | 100.00% (7/7)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/RoleRegistry.sol                       | 100.00% (24/24)    | 100.00% (18/18)    | 100.00% (2/2)    | 100.00% (11/11)  |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/StakingManager.sol                     | 93.81% (91/97)     | 87.02% (114/131)   | 50.00% (12/24)   | 87.50% (14/16)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/TNFT.sol                               | 58.33% (14/24)     | 60.00% (9/15)      | 25.00% (2/8)     | 50.00% (5/10)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/TVLOracle.sol                          | 100.00% (13/13)    | 100.00% (9/9)      | 75.00% (6/8)     | 100.00% (4/4)    |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/WeETH.sol                              | 92.00% (46/50)     | 89.36% (42/47)     | 86.67% (13/15)   | 85.71% (12/14)   |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| src/WithdrawRequestNFT.sol                 | 100.00% (139/139)  | 99.31% (143/144)   | 79.37% (50/63)   | 100.00% (29/29)  |
|--------------------------------------------+--------------------+--------------------+------------------+------------------|
| Total                                      | 70.61% (2155/3052) | 68.77% (2332/3391) | 58.96% (477/809) | 71.43% (485/679) |

---
Ran 2 tests for test/behaviour-tests/ELExitsForkTestingDeployment.t.sol:ELExitsForkTestingDeploymentTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.32ms (221.48µs CPU time)
Ran 5 tests for test/AddressProvider.t.sol:AddressProviderTest
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 45.30ms (7.73ms CPU time)
Ran 23 tests for test/AuctionManager.t.sol:AuctionManagerTest
Suite result: ok. 23 passed; 0 failed; 0 skipped; finished in 64.50ms (40.17ms CPU time)
Ran 2 tests for test/BNFT.t.sol:BNFTTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 28.44ms (2.87ms CPU time)
Ran 58 tests for test/BucketRaterLimiter.t.sol:BucketRateLimiterTest
Suite result: ok. 58 passed; 0 failed; 0 skipped; finished in 33.25ms (31.48ms CPU time)
Ran 2 tests for test/ContractCodeChecker.t.sol:ContractCodeCheckerTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.99s (200.67ms CPU time)
Ran 9 tests for test/CumulativeMerkleRewardsDistributor.t.sol:CumulativeMerkleRewardsDistributorTest
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 42.70ms (17.61ms CPU time)
Ran 2 tests for test/fork-tests/pectra-fork-tests/Consolidation-through-EOA.sol:ConsolidationThroughEOATest
Suite result: FAILED. 1 passed; 1 failed; 0 skipped; finished in 3.39s (1.98s CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferBtc.t.sol:LiquidReferBtcTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 4.18s (3.62s CPU time)
Ran 6 tests for test/DepositAdapter.t.sol:DepositAdapterTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 3.40s (2.88s CPU time)
Ran 17 tests for test/EETH.t.sol:EETHTest
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 51.63ms (26.78ms CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferEth.t.sol:LiquidReferETHScrollTest
Suite result: FAILED. 0 passed; 4 failed; 0 skipped; finished in 3.54s (2.35s CPU time)
Ran 1 test for test/behaviour-tests/pectra-fork-tests/EL-withdrawals.t.sol:ELExitsTest
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 800.27ms (625.15ms CPU time)
Ran 8 tests for test/integration-tests/Deposit.t.sol:DepositIntegrationTest
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 6.74s (6.57s CPU time)
Ran 1 test for test/EtherFiViewer.t.sol:EtherFiViewerTest
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.30s (719.15ms CPU time)
Ran 71 tests for test/EtherFiNodesManager.t.sol:EtherFiNodesManagerTest
Suite result: FAILED. 69 passed; 2 failed; 0 skipped; finished in 10.76s (6.55s CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferEth.t.sol:LiquidReferEthTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 3.27s (3.12s CPU time)
Ran 7 tests for test/EtherFiOperationParameters.t.sol:EtherFiOperationParametersTest
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 427.02ms (418.81ms CPU time)
Ran 58 tests for test/EtherFiOracle.t.sol:EtherFiOracleTest
Suite result: ok. 58 passed; 0 failed; 0 skipped; finished in 148.82ms (118.55ms CPU time)
Ran 56 tests for test/EtherFiRateLimiter.t.sol:EtherFiRateLimiterTest
Suite result: ok. 56 passed; 0 failed; 0 skipped; finished in 960.67ms (958.37ms CPU time)
Ran 10 tests for test/EtherFiRestaker.t.sol:EtherFiRestakerTest
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 6.48s (6.36s CPU time)
Ran 32 tests for test/EtherFiRewardsRouter.t.sol:EtherFiRewardsRouterTest
Suite result: ok. 32 passed; 0 failed; 0 skipped; finished in 14.00ms (11.56ms CPU time)
Ran 6 tests for test/liquid-tests/LiquidReferUsdPermit.t.sol:LiquidReferUsdPermitScrollTest
Suite result: FAILED. 0 passed; 6 failed; 0 skipped; finished in 3.90s (3.68s CPU time)
Ran 6 tests for test/EtherFiTimelock.t.sol:TimelockTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 2.06s (2.68s CPU time)
Ran 3 tests for test/integration-tests/Handle-Remainder-Shares.t.sol:HandleRemainderSharesIntegrationTest
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 8.87s (7.15s CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferBtc.t.sol:LiquidReferBtcScrollTest
Suite result: FAILED. 0 passed; 4 failed; 0 skipped; finished in 3.47s (2.45s CPU time)
Ran 6 tests for test/liquid-tests/LiquidReferUsdPermit.t.sol:LiquidReferUsdPermitTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 5.21s (5.10s CPU time)
Ran 12 tests for test/liquid-tests/LiquidReferWhitelist.t.sol:LiquidReferWhitelistTest
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 2.35s (2.01s CPU time)
Ran 79 tests for test/LiquidityPool.t.sol:LiquidityPoolTest
Suite result: ok. 79 passed; 0 failed; 0 skipped; finished in 167.30ms (133.68ms CPU time)
Ran 3 tests for test/behaviour-tests/pectra-fork-tests/Request-consolidation.t.sol:RequestConsolidationTest
Suite result: FAILED. 0 passed; 3 failed; 0 skipped; finished in 5.53s (2.58s CPU time)
Ran 27 tests for test/RestakingRewardsRouter.t.sol:RestakingRewardsRouterTest
Suite result: ok. 27 passed; 0 failed; 0 skipped; finished in 14.53ms (9.88ms CPU time)
Ran 9 tests for test/RoleRegistry.t.sol:RoleRegistryTest
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 2.96ms (2.06ms CPU time)
Ran 21 tests for test/StakingManager.t.sol:StakingManagerTest
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 3.46s (3.37s CPU time)
Ran 2 tests for test/TNFT.t.sol:TnftTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 37.93ms (2.64ms CPU time)
Ran 6 tests for test/TVLOracle.t.sol:TVLOracleTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 33.54ms (7.76ms CPU time)
Ran 4 tests for test/MembershipNFT.t.sol:MembershipNFTTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 30.51ms (5.77ms CPU time)
Ran 8 tests for test/NodeOperatorManager.t.sol:NodeOperatorManagerTest
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 36.70ms (11.83ms CPU time)
Ran 2 tests for test/integration-tests/Validator-Flows.t.sol:ValidatorFlowsIntegrationTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.60s (4.71s CPU time)
Ran 17 tests for test/WeETH.t.sol:WeETHTest
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 51.46ms (27.22ms CPU time)
Ran 32 tests for test/WithdrawRequestNFT.t.sol:WithdrawRequestNFTTest
Suite result: ok. 32 passed; 0 failed; 0 skipped; finished in 3.03s (3.00s CPU time)
Ran 59 tests for test/PriorityWithdrawalQueue.t.sol:PriorityWithdrawalQueueTest
Suite result: ok. 59 passed; 0 failed; 0 skipped; finished in 3.87s (2.46s CPU time)
Ran 11 tests for test/integration-tests/Withdraw.t.sol:WithdrawIntegrationTest
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 4.35s (5.50s CPU time)
Ran 24 tests for test/fork-tests/validator-key-gen.t.sol:ValidatorKeyGenTest
Suite result: ok. 24 passed; 0 failed; 0 skipped; finished in 7.90s (5.53s CPU time)
Ran 14 tests for test/Liquifier.t.sol:LiquifierTest
Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 24.54s (27.57s CPU time)
Ran 40 tests for test/behaviour-tests/prelude.t.sol:PreludeTest
Suite result: FAILED. 39 passed; 1 failed; 0 skipped; finished in 16.17s (23.09s CPU time)
Ran 41 tests for test/EtherFiRedemptionManager.t.sol:EtherFiRedemptionManagerTest
Suite result: ok. 41 passed; 0 failed; 0 skipped; finished in 34.85s (21.28s CPU time)
Ran 46 test suites in 47.20s (183.23s CPU time): 797 tests passed, 21 failed, 0 skipped (818 total tests)

Generated by workflow run #716

keccak256("CONSOLIDATION_REQUEST_LIMIT_ID");

uint256 internal constant FULL_EXIT_GWEI = 2_048_000_000_000;
uint256 internal constant SECONDS_PER_DAY = 86_400;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused SECONDS_PER_DAY constant in rate-limit scripts

Low Severity

SECONDS_PER_DAY is declared in both ReduceRateLimits.s.sol and RaiseRateLimits.s.sol but is never referenced in the code. The refill-rate divisions (e.g., 1_064_960_000_000_000 / 86_400) were computed offline and hardcoded as constants, leaving SECONDS_PER_DAY as dead code.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a9198f0. Configure here.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9198f0ad2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread script/utils/utils.sol
ICreate2Factory constant mainnetCreate2Factory = ICreate2Factory(0x356d1B83970CeF2018F2c9337cDdb67dff5AEF99);

uint256 constant MIN_DELAY_OPERATING_TIMELOCK = 28800; // 8 hours
uint256 constant MIN_DELAY_OPERATING_TIMELOCK = 172800; // 2 days
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep operating timelock delay aligned with production value

Changing MIN_DELAY_OPERATING_TIMELOCK from 28,800 to 172,800 in the shared Utils base alters every script that schedules through this constant to a 2-day delay, while the operational flow in this repo still assumes 8 hours (including the newly added whale-ops runbook). In practice this creates schedule/execute mismatches where execute transactions are attempted on the old window and revert as not-ready, delaying critical ops by an extra 40 hours. This shared constant should remain consistent with the actual timelock delay (or be read dynamically from getMinDelay()).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional because of the change on the mainnet

uint256 stEthAfter = IERC20(lido).balanceOf(address(restaker));
console2.log("stETH received:", stEthAfter - stEthBefore);

uint256 depositAmount = IERC20(lido).balanceOf(address(restaker));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid encoding a stale stETH deposit amount in STEP=2 batch

depositAmount is snapshotted during fork simulation and then hardcoded into the generated depositIntoStrategy calldata, but STEP=2 is executed later in production after a waiting period; if the restaker’s stETH balance changes in the meantime (e.g., redemptions or accounting drift), the batch can either fail on tx3 (insufficient balance) or leave funds undeployed. This makes the multi-tx redelegation flow brittle and should be replaced with a runtime balance-based deposit step.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1e69082. Configure here.

pick[picked++] = ws[j];
remaining -= amt;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unit mismatch defeats greedy-fit budget check

Medium Severity

budgetWei is computed as _readWithdrawableGwei(pod) * 1 gwei, converting the gwei value to wei (multiplying by 1e9). However, ws[j].scaledShares[0] for the BeaconChainETH strategy is denominated in gwei. The comparison amt <= remaining therefore compares a gwei-scale value against a wei-scale value, making the budget check always pass — the greedy fit includes every withdrawal regardless of the pod's actual withdrawable balance. The remaining -= amt subtraction also barely changes remaining since it subtracts gwei from wei. Either budgetWei should not be multiplied by 1 gwei, or amt should be multiplied by 1 gwei before comparison.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1e69082. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants