chore: AVS deregistration script (167 calls, 119 operator/AVS pairs) - #501
Open
pankajjagtapp wants to merge 2 commits into
Open
chore: AVS deregistration script (167 calls, 119 operator/AVS pairs)#501pankajjagtapp wants to merge 2 commits into
pankajjagtapp wants to merge 2 commits into
Conversation
Deregisters ether.fi's AvsOperator proxies from their EigenLayer AVSs. 167 adminForwardCall operations covering 119 (operator, AVS) pairs across 15 operators and 16 AVSs, all on the legacy AVSDirectory. AVSDirectory.deregisterOperatorFromAVS is AVS-only, so each deregistration is driven operator-side through that AVS's own middleware and forwarded by AvsOperatorManager. Middleware and arguments are not uniform across AVSs, so the call list is enumerated and fork-verified offline and committed as avs-deregistration-calls.json; the script replays it, asserts every pair reads UNREGISTERED afterwards, and packs the calls into Safe txs under a 12M gas ceiling. Routing is a direct call from the Operating Safe: adminForwardCall is gated by OPERATION_MULTISIG_ROLE, which the UPGRADE_TIMELOCK does not hold, so it cannot be batched with a timelock upgrade.
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
📊 Forge Coverage ReportGenerated by workflow run #818 |
AvsDeregistration.s.sol only exercises the inner adminForwardCall list. This executes the actual Safe transactions instead: execTransaction -> delegatecall MultiSendCallOnly -> N x adminForwardCall, which is what signers sign. Signatures come from Safe's approved-hash type (v = 1), so no private key is needed: the threshold is forced to 1 via vm.store and one owner calls approveHash. Real exec gas per batch is 7.14M / 4.67M / 4.63M / 3.52M, about half the per-call estimate, since a batch pays one intrinsic cost and shares warm storage rather than 167 separate transactions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Deregisters ether.fi's
AvsOperatorproxies from their EigenLayer AVSs. Branches offmaster; independent of #485 / #500.Governance proposal: 3CP-secure#664.
Scope
167
adminForwardCalloperations covering 119 (operator, AVS) pairs — 15 operators, 16 AVSs. Not "14 AVSs": the 14 refers to registered operator proxies, and there are 15 with live registrations.All registrations are on the legacy AVSDirectory (
0x135DDa56);AllocationManager.getRegisteredSetsis empty for every operator, so there is no operator-set path to unwind.AVSDirectory.deregisterOperatorFromAVSrequiresmsg.sender == the AVS, so ether.fi cannot call it. Each deregistration is driven operator-side through that AVS's own middleware and forwarded byAvsOperatorManager.adminForwardCall. The middleware and arguments are not uniform, so the list is enumerated and fork-verified offline and committed asavs-deregistration-calls.json.Non-standard AVSs
deregisterOperatorFromAVS(address)deregisterOperator()deregisterOperator()deregisterOperator()unsubscribe(10),unsubscribe(8453),unsubscribe(42161), thenderegister()unregisterAsOperatorFromEigenLayer()startDeregisterOperator()+finishDeregisterOperator()Lagrange State Committee is why the call count exceeds the pair count:
deregister()reverts with "operator is not able to deregister" untilsubscribedChainCount == 0, and all 12 operators are subscribed to 3 chains. UniFi's delay is currently 0, so start and finish fit one batch; if the AVS raises it, they must be split across blocks.Blocked — 6 pairs need someone else to act
ServiceManager 0xacb91045deregisterOperatorFromAVS(address)behindonlyOwner; the StakeRegistry isonlyRegistryCoordinator. No operator path — the AVS team must eject.NodeRegistry.nodeQuit()keys onmsg.sender. The AvsOperator is only ARPA's asset account; the node EOAs0x961cAA85…(op4) and0x13f24BEC…(op11) must call it.These are excluded from the batches. Closing them needs coordination outside this repo.
Verification
forge script script/upgrades/avs-deregistration/AvsDeregistration.s.sol:AvsDeregistration --fork-url $MAINNET_RPC_URL— all 167 calls succeed and all 119 pairs readavsOperatorStatus == 0afterwards.Tenderly VNET pinned to the enumeration block: 167/167 mined, 0 failures.
Batching is on real anvil tx gas carried in the data file, not
gasleft()inside the script —gasleft()excludes intrinsic and calldata cost and under-counts by ~2x, which would have produced 3 oversized batches instead of 4 safe ones.All under the 12M ceiling. The script's MultiSend payloads were cross-checked byte-for-byte against an independent encoder.
Caveat
The call list is state-sensitive — quorum bitmaps and registration status change as operators and AVSs act. Re-run the script immediately before signing and confirm 167/167 still pass. A VNET forked at
latestrather than a pinned block produced spurious failures, so pin the block when simulating.Note
Medium Risk
No production contract changes, but committed calldata drives a large privileged mainnet multisig operation; stale state or a wrong/missing call could leave operators partially registered or waste Safe nonces.
Overview
Adds mainnet upgrade tooling to deregister ether.fi
AvsOperatorproxies from legacy EigenLayer AVSs via the Operating Safe (ETHERFI_OPERATING_ADMIN) andAvsOperatorManager.adminForwardCall, without timelock batching.avs-deregistration-calls.jsonpins 167 fork-verified calls (block25875000) with per-call gas measurements, covering 119 operator/AVS pairs across heterogeneous AVS middleware. Ablockedsection documents 6 pairs that cannot be cleared throughadminForwardCall(bare ServiceManager / ARPAnodeQuit).AvsDeregistration.s.solloads the manifest, simulates every call as the Operating Safe, assertsAVSDirectory.avsOperatorStatus == 0for each touched pair, and greedy-packs calls into Safe MultiSendCallOnly batches under a 12M gas cap (using measured tx gas + per-call overhead).VerifyAvsBatches.s.solre-runs the same packing on a fork using the real Safe path (execTransaction→ delegatecall MultiSend → inneradminForwardCall), with threshold forced to 1 and approved-hash signatures for fork testing, then re-checks directory status and batch gas against the cap.Reviewed by Cursor Bugbot for commit b658524. Bugbot is set up for automated code reviews on this repo. Configure here.