Skip to content

Multiple varied scripts for operational tasks#378

Open
pankajjagtapp wants to merge 8 commits intomasterfrom
pankaj/script/withdrawal-script
Open

Multiple varied scripts for operational tasks#378
pankajjagtapp wants to merge 8 commits intomasterfrom
pankaj/script/withdrawal-script

Conversation

@pankajjagtapp
Copy link
Copy Markdown
Contributor

@pankajjagtapp pankajjagtapp commented Apr 21, 2026

Note

Medium Risk
Adds multiple mainnet operations scripts that generate and simulate Gnosis Safe/timelock transactions affecting whitelists, fee params, rate-limiter buckets, and redemption capacity; mistakes in constants/addresses or the updated operating timelock delay could lead to incorrect governance actions.

Overview
Adds several new forge script operational utilities that generate Gnosis Safe JSON + fork-simulate batched transactions for: (1) Priority withdrawal queue admin/whitelist and per-user fee parameter updates (including a 7-tx combined batch), (2) temporary raise/reduce of EtherFiRateLimiter capacities/refill settings for exits/consolidations/unrestaking, and (3) stETH management workflows including writing Safe JSON for claiming Lido withdrawals and a 2-step EigenLayer stETH redelegation (undelegate, then complete+delegate+re-deposit).

Introduces timelock-driven stETH redemption capacity “burst then revert” scripts (plus an ops checklist doc) that schedule/execute EtherFiRedemptionManager parameter changes via the operating timelock and validate via fork redemption tests. Updates Utils.MIN_DELAY_OPERATING_TIMELOCK from 8 hours to 2 days, and broadens Foundry fs_permissions to allow writes under script/operations.

Reviewed by Cursor Bugbot for commit a9198f0. 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

📊 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                    | 46.15% (72/156)    | 47.62% (90/189)    | 25.00% (5/20)    | 35.29% (12/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                                      | 68.71% (2097/3052) | 66.59% (2258/3391) | 58.71% (475/809) | 69.96% (475/679) |

---
Ran 2 tests for test/behaviour-tests/ELExitsForkTestingDeployment.t.sol:ELExitsForkTestingDeploymentTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.33ms (221.51µs CPU time)
Ran 5 tests for test/AddressProvider.t.sol:AddressProviderTest
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 43.02ms (7.73ms CPU time)
Ran 23 tests for test/AuctionManager.t.sol:AuctionManagerTest
Suite result: ok. 23 passed; 0 failed; 0 skipped; finished in 59.26ms (36.23ms CPU time)
Ran 2 tests for test/BNFT.t.sol:BNFTTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 26.96ms (2.35ms CPU time)
Ran 58 tests for test/BucketRaterLimiter.t.sol:BucketRateLimiterTest
Suite result: ok. 58 passed; 0 failed; 0 skipped; finished in 28.34ms (26.74ms 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 2.45s (1.42s CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferBtc.t.sol:LiquidReferBtcTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.79s (2.44s CPU time)
Ran 2 tests for test/ContractCodeChecker.t.sol:ContractCodeCheckerTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.44s (131.52ms CPU time)
Ran 9 tests for test/CumulativeMerkleRewardsDistributor.t.sol:CumulativeMerkleRewardsDistributorTest
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 37.67ms (14.45ms 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.31s (2.22s CPU time)
Ran 71 tests for test/EtherFiNodesManager.t.sol:EtherFiNodesManagerTest
Suite result: FAILED. 69 passed; 2 failed; 0 skipped; finished in 7.13s (4.12s CPU time)
Ran 7 tests for test/EtherFiOperationParameters.t.sol:EtherFiOperationParametersTest
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 431.29ms (423.02ms CPU time)
Ran 58 tests for test/EtherFiOracle.t.sol:EtherFiOracleTest
Suite result: ok. 58 passed; 0 failed; 0 skipped; finished in 167.37ms (142.85ms CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferEth.t.sol:LiquidReferEthTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.58s (2.41s CPU time)
Ran 56 tests for test/EtherFiRateLimiter.t.sol:EtherFiRateLimiterTest
Suite result: ok. 56 passed; 0 failed; 0 skipped; finished in 1.14s (1.14s CPU time)
Ran 8 tests for test/integration-tests/Deposit.t.sol:DepositIntegrationTest
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 5.68s (5.59s CPU time)
Ran 6 tests for test/DepositAdapter.t.sol:DepositAdapterTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 418.18ms (285.64ms CPU time)
Ran 17 tests for test/EETH.t.sol:EETHTest
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 56.12ms (29.31ms 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 1.81s (1.70s CPU time)
Ran 6 tests for test/liquid-tests/LiquidReferUsdPermit.t.sol:LiquidReferUsdPermitScrollTest
Suite result: FAILED. 0 passed; 6 failed; 0 skipped; finished in 4.68s (3.72s 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 3.93s (1.64s CPU time)
Ran 27 tests for test/RestakingRewardsRouter.t.sol:RestakingRewardsRouterTest
Suite result: ok. 27 passed; 0 failed; 0 skipped; finished in 12.93ms (10.05ms CPU time)
Ran 9 tests for test/RoleRegistry.t.sol:RoleRegistryTest
Suite result: ok. 9 passed; 0 failed; 0 skipped; finished in 3.56ms (2.66ms CPU time)
Ran 6 tests for test/liquid-tests/LiquidReferUsdPermit.t.sol:LiquidReferUsdPermitTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 3.75s (3.49s CPU time)
Ran 12 tests for test/liquid-tests/LiquidReferWhitelist.t.sol:LiquidReferWhitelistTest
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 1.32s (1.24s CPU time)
Ran 10 tests for test/EtherFiRestaker.t.sol:EtherFiRestakerTest
Suite result: FAILED. 3 passed; 7 failed; 0 skipped; finished in 18.45s (16.70s CPU time)
Ran 32 tests for test/EtherFiRewardsRouter.t.sol:EtherFiRewardsRouterTest
Suite result: ok. 32 passed; 0 failed; 0 skipped; finished in 22.68ms (18.90ms CPU time)
Ran 79 tests for test/LiquidityPool.t.sol:LiquidityPoolTest
Suite result: ok. 79 passed; 0 failed; 0 skipped; finished in 152.44ms (113.33ms CPU time)
Ran 21 tests for test/StakingManager.t.sol:StakingManagerTest
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 2.74s (2.65s CPU time)
Ran 2 tests for test/TNFT.t.sol:TnftTest
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 25.85ms (2.31ms CPU time)
Ran 6 tests for test/TVLOracle.t.sol:TVLOracleTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 29.97ms (7.16ms CPU time)
Ran 6 tests for test/EtherFiTimelock.t.sol:TimelockTest
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 929.92ms (1.20s CPU time)
Ran 1 test for test/EtherFiViewer.t.sol:EtherFiViewerTest
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 186.19ms (168.10ms 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 2.35s (1.76s CPU time)
Ran 17 tests for test/WeETH.t.sol:WeETHTest
Suite result: ok. 17 passed; 0 failed; 0 skipped; finished in 52.39ms (29.12ms CPU time)
Ran 41 tests for test/EtherFiRedemptionManager.t.sol:EtherFiRedemptionManagerTest
Suite result: ok. 41 passed; 0 failed; 0 skipped; finished in 13.26s (13.24s 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 3.93s (3.85s CPU time)
Ran 11 tests for test/integration-tests/Withdraw.t.sol:WithdrawIntegrationTest
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 3.48s (3.38s CPU time)
Ran 32 tests for test/WithdrawRequestNFT.t.sol:WithdrawRequestNFTTest
Suite result: ok. 32 passed; 0 failed; 0 skipped; finished in 4.67s (4.64s CPU time)
Ran 4 tests for test/MembershipNFT.t.sol:MembershipNFTTest
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 29.97ms (5.68ms CPU time)
Ran 8 tests for test/NodeOperatorManager.t.sol:NodeOperatorManagerTest
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 36.58ms (12.15ms CPU time)
Ran 59 tests for test/PriorityWithdrawalQueue.t.sol:PriorityWithdrawalQueueTest
Suite result: FAILED. 58 passed; 1 failed; 0 skipped; finished in 3.40s (2.33s 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 3.93s (3.49s CPU time)
Ran 4 tests for test/liquid-tests/LiquidReferBtc.t.sol:LiquidReferBtcScrollTest
Suite result: FAILED. 0 passed; 4 failed; 0 skipped; finished in 7.30s (2.34s CPU time)
Ran 14 tests for test/Liquifier.t.sol:LiquifierTest
Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 13.39s (13.38s CPU time)
Ran 40 tests for test/behaviour-tests/prelude.t.sol:PreludeTest
Suite result: ok. 40 passed; 0 failed; 0 skipped; finished in 11.21s (18.26s CPU time)
Ran 46 test suites in 35.90s (132.88s CPU time): 790 tests passed, 28 failed, 0 skipped (818 total tests)

Generated by workflow run #685

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.

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 a9198f0. Configure here.

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 👍 / 👎.

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 👍 / 👎.

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.

1 participant