From 9abcba49b060cac14f4c382e789b18d80affd5c1 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Mon, 16 Sep 2024 19:53:36 -0400 Subject: [PATCH] feat: storage report (#753) chore: move custom errors to sep branch chore: forge fmt src/contracts fix: ci and bindings chore: dmgr error tweaks chore: error tweaks for consistency and clarity feat: bump oz version (#755) * feat: bump oz version -> 0.4.9 - also moved remappings -> foundry.toml - removes remappings.txt * bindings --------- Co-authored-by: gpsanant test: custom errors passing (#783) * test: custom errors AVSDir * test: custom errors IPausable * test: custom errors Delegation * test: custom errors EigenPodManager * test: custom errors EigenPod * test: custom errors Pausable * test: custom errors RewardsCoordinator * test: custom errors IStrategy * test: custom errors StrategyManager * test: custom errors DelegationManager * test: custom errors refactor: review reconciliation refactor: review reconciliation refactor: review reconciliation chore: forge fmt src/contracts fix: compile feat: squashed slashing for devnet chore: forge fmt src/contracts fix: ci and bindings chore: dmgr error tweaks chore: error tweaks for consistency and clarity feat: bump oz version (#755) * feat: bump oz version -> 0.4.9 - also moved remappings -> foundry.toml - removes remappings.txt * bindings --------- Co-authored-by: gpsanant test: custom errors passing (#783) * test: custom errors AVSDir * test: custom errors IPausable * test: custom errors Delegation * test: custom errors EigenPodManager * test: custom errors EigenPod * test: custom errors Pausable * test: custom errors RewardsCoordinator * test: custom errors IStrategy * test: custom errors StrategyManager * test: custom errors DelegationManager * test: custom errors refactor: review reconciliation refactor: review reconciliation refactor: review reconciliation chore: forge fmt src/contracts feat: slashing * chore: pending delay calc cleanup * chore: storage pointer cleanup * eigenpods slashing updates (#745) * squash yet again * change again * update checkpoint struct * feat: AllocationManager Storage Simplification (#787) * feat: cleanup * feat: add helper func * fix: simplification * chore: clean up magnitude info usage and type conversions * refactor: review changes * fix: order struct params by size * fix: correct and simplify calc for slashed pending magnitude * fix: storage gap * feat: cleanup * chore: remove some type conversion bs and minor formatting * chore: clean up free magnitude logic * chore: rename pending deallocations and fix stack too deep * feat: slashing magnitudes cleanup (#786) * refactor: slashing magnitudes cleanup * refactor: assert `bipToSlash` is bounded * assert `bipsToSlash` is lte 100% and gt 0%. * refactor: move `isOperatorSlashable` -> AVSD * refactor: batch validate opsets on allocations - adds `AVSD.isOperatorSetBatch(operatorSets)` * feat: add pausing to ALM * refactor: remove single use helper - removes `_getLatestTotalMagnitude(operator, strategy)` * refactor: rename `ALLOCATION_DELAY_CONFIGURATION_DELAY` * refactor: remove `Slasher` * refactor: move constants + immutables to storage contracts * refactor: custom errors `RewardsCoordinatorStorage` * chore: dependency cleanup * fix: remove unused internal getter * chore: batch validate operator sets and minor cleanup * fix: fix stack too deep and compiler errors --------- Co-authored-by: wadealexc feat: dm cleanup (#788) Co-authored-by: wadealexc Revert "feat: dm cleanup (#788)" (#799) This reverts commit c27004ea11943e488af22e0b5f2b4b45ae105550. fix: compiles (#800) fix: refactor (#801) * fix: refactor * default was history * reline * rename rename test: generally compiling + AVSM unit tests compiling chore: forge fmt src/contracts add events, fix bugs, abstract better (#806) * fix bugs, add events, cleanup * wrap conditional * fmt * only one slash per timestamp test(wip): generally compiling update docs (#804) fix: revert change to event feat: am refactor add to wads to slash cleanup refactor: change totalMagnitude to maxMagnitude * condense slashOperator params * some struct field renaming remove unused eigenpod storage chore: storage report (#809) * chore: storage report * patch eigenpod --------- Co-authored-by: gpsanant feat: eip712 fixes (#808) * feat: use OZ SignatureChecker * feat: add `SignatureUtils` mixin * refactor: cleanup * feat: make storage report * storage report --------- Co-authored-by: gpsanant test: slashing tests passing (#812) fix: merge issues update events refactor: rename total magnitudes to max magnitudes * various formatting and cleanup * standardize allocation manager getter functions * update and improve commenting refactor: reorder functions to match interface fix: remove memory overwrite bug in delegation manager chore: forge fmt refactor: clean up getDepositedShare logic chore: remove old oz + forge update foundry-rs/forge-std feat: replace getSlashableMagnitudes with general purpose allocation info query Feat: SM/StrategyBase Unit Tests + Formatting (#813) refactor: delegation manager refactors test: AllocationManager progress feat: change event names feat: update doc fix: compile test: AllocationManager progress fix: tests progress add Strategy <> OperatorSet mapping in storage, and APIs and events (#814) * feat: add strategy to operator set mapping with corresponding functions and events * fix: update * fix: remove pagination of getStrategiesInOperatorSet * fix: update * fix: compiles * fix: add checks * fix: address -> IStrategy * fix: storage gap --------- Co-authored-by: gpsanant Slashing: DM Happy Path Test Cases (#815) * test: basic dm tests * test: start on share increase/decrease delegated shares tests * test: add DM unit tests passing except queue/complete * test: undelegate tests * test: queue withdrawals * test: completed DM happy path test cases * fix: compilation, rebase errors * chore: format Add view funcs (#816) * fix: add new view funcs * fix: update docs test: fix avsD tests (#817) chore: format fix: from scratch deploy feat: add shares to slashing event Slashing: Modify Allocations Happy Path Tests (#821) * refactor: add test contract per func * test: modify allocations * chore: format slashing: allocation delay happy path tests (#822) feat: wadSlashed (#820) Slashing: Clear Modification Queue Happy Path Tests (#823) test: basic allocation tests (#824) feat: inheritdoc refactor: alm test cleanup test: multiple allocations, only one slashed test: one pending alloc, slash test: revert bound refactor so tests pass Slashing: Add additional happy path AM test cases (#828) * test: happy path AM tests * chore: format Slashing: Get all tests passing (#829) * test: all tests passing * fix: mainnet integration test comment out Fix misset storage gaps (#831) * fix: misset storage gaps from #814 * fix: update gap to account for previous refactor fix: update coverage yml name (#833) Fix: Single Deallocation Queue (#827) * test: base regression * test: regression * fix: remove console * test: logs * test: add actual regression * fix: use a single deallocation queue * fix: comments * refactor: use deallocation queue everywhere * fix: address test comments * fix: test comment Feat: Update legacy withdrawal timestamp param to legacy withdrawal check (#836) * fix: make comment on timestamp clearer * chore: format Feat: Public Devnet Deploy (#838) * feat: slashing public devnet * fix: filepath * test: validation * fix: add test * fix: test fix: compile chore: format feat: add shares to queue event (#847) * feat: add shares to queue event * fix: submodule * chore: rename feat: named mapping params (#848) * feat: named mapping params * refactor: natspec * refactor: natspec * chore: forge fmt * refactor: nits chore: new storage (#851) Gpsanant/current stakes (#846) * feat: add getCurrent * chore: fmt * chore: storoage report * chore: new storage slashing: cleanup (#842) * chore: cleanup * chore: comments and add legacy view * chore: complete => clear * chore: reorder require check * fix: round up for slashed magnitudes * chore: nits and legacy complete withdrawals * feat: allow alloc delay 0 and fix tests * chore: clarify comment * chore: fmt * fix: fork test * chore: nits * test: roundup slashed magnitudes slashing: fully slashed strategies (#850) * feat: handling fully slashed scenarios * fix: unit test descriptions * fix: nits EigenPod/EPM Happy Path Test Cases (#857) * test: fix epm and ep unit tests * fix: remove unused contracts * test: get basic slash integration working * test: get ep integration tests passing * test: add rounding down test * chore: add TODO * chore: formatting * test: fix additional slash tests * chore: remove fork tests * fix: address comments * test: fix check on `withdrawSharesAsTokens` slashing: revert timestamps delegation (#861) * fix: back to blocks for withdrawals * refactor: queued legacy withdrawals are extended refactor: optimize pausable (#854) * refactor: optimize pausable * chore: forge fmt * refactor: nits * chore: make storage-report * fix: rebase * refactor: review changes - check pauser reg is non-zero on construction * fix: ci feat: small delegation refactors (#866) * refactor: small refactor to move duplicate expiry checks into signature utils * refactor: improve clarity of fully-slashed logic * refactor: improve readability of operator slashed amount calculation * todo: off-by-one error in test due to rounding issue * fix: correct amount of shares slashed * wip: comment out test so michael gets to it in his pr slashing: change queue withdrawal input to deposit shares (#869) * feat: queue withdraw uses deposit shares * fix: tests and removed old test files * chore: forge ftm * test: redelegate shares from rounding * chore: remove unused import feat: remove delegate to by signature (#871) feat: track staker withdrawals (#864) * feat: track staker withdrawals * chore: forge fmt * feat: track staker withdrawals * chore: forge fmt * fix: `pendingWithdrawals` arrangement * fix: ci Fix: Flaky DM Test (#875) * fix: test * fix: remove log feat: move operator set functionality to alm (#860) * feat: move operator set functionality to alm * feat: clarify registration states * fix: allow operators to deallocate from strategies that are not in operator set * fix: add enumeration for operator allocations * feat: remove deallocations on deregistration * chore: cleanup src/test (#863) * feat: add configurable avs registrar * feat: remove bloated getters * feat: use existing set method to get set values * test: avsd alm refactor (#867) * test: ALM compiling + but not passing * test(wip): avsd alm refactor * chore: update forge-std * fix: compile * test(wip): avsd passing * nit: cleanup * test: get alm tests passing * test: fix delegation tests * feat: add lib `Random` * test: add allocation enumeration checks to tests * test: reg/dereg + use `Random` * refactor: small refactor to reuse getters * test: `addStrategiesToOperatorSet` - also adds missing state mutation checks on previous tests * test: `removeStrategiesFromOperatorSet` * test: `createOperatorSets` * test: `setAVSRegistrar` --------- Co-authored-by: wadealexc * feat: add AVS metadata URI to ALM * chore: update comments * chore: address comments fix: change to sharesToWithdraw (#878) * fix: change to sharesToWithdraw * fix: test feat: add tasks to prepare chain state ready for slashing (#868) * feat: add tasks to prepare chain state ready for slashing * feat: add queueWithdrawal and completeWithdrawal tasks * fix: extract addresses from output after deploy * fix: upgrade scripts to account for AVS/ALM operatorSet changes * fix: add additional deposit * fix: add additional slashing between withdrawal queued and completed * fix: update slashing on top of alex/avsd-alm-refactor * chore: correct readme and formatting * fix: PascalCase contract names and update forge-std * feat: replace console with emit * feat: remove additional use of console --------- Co-authored-by: wadealexc test: slashing todos (#880) * test(wip): todos * test: remove unused utils * feat: foundry `sparse_mode=true` * test(wip): todos * test(wip): todos * test(wip): todos * test(wip): todos * test(wip): todos * fix: cherry-pick errors * fix: forge-std * test(wip): todos feat: add getMinimumSlashableStake (#889) * feat: add getMinimumSlashableStake * fix: only account for deallocation when calculating minimum slashable refactor: pull beacon chain slashing out of slashing lib (#876) * fix: correctly update dsf when increasing delegation * fix: fix bug where we modify an array while iterating over it * chore: address review nits * refactor: minor refactors for codesize * refactor(nit): function ordering * fix: only check input lengths when receiving tokens * refactor: remove callstack indirection when completing a withdrawal * chore: update comment test: slashing test todos (#885) * test(wip): todos * chore: remove lcov * test(wip): remaining alm todos * test: final todos * test(wip): todos * chore: remove lcov feat: burn erc20s on slashing (#881) * refactor: pull beacon chain slashing out of slashing lib * feat: initial draft for sync slashing * fix: existing tests * fix: cumulative shares and fmt * fix: missing operator key in mapping * refactor: cumulative scaled shares * chore: cleanup * chore: storage report * fix: rename and beacon strategy * fix: rebase * fix: rounding * test: happy path test cases for burn erc20s * fix: address comments * test: timing regression test and comments * fix: slashable shares in queue amount * refactor: burn refactor (#897) * refactor: remove unused return values from _insert * also removes safe cast * refactor: pull unrelated operations out and condense library method usage * test: additional unit test with multiple withdrawals --------- Co-authored-by: wadealexc Co-authored-by: Alex <18387287+wadealexc@users.noreply.github.com> test: DelegationManager unit tests (#886) * feat: initial draft for sync slashing * refactor: cumulative scaled shares * feat: initial draft for sync slashing * fix: cumulative shares and fmt * chore: cleanup src/test * fix: delegation tests * test: rebased and refactored tests fix: rebase tests test: delegation unit refactoring fix: rounding tests fix: continue fixing delegation tests * test: include fuzz underflow tests * fix: tests and rebase * chore: comment nit * fix: failing ci test: fix env requirement (#899) * fix: remove env required * fix: use envOr * fix: remove env from CI for being required fix: compile warnings (#900) fix: slashing local deploy (#898) * feat: local deploy * fix: transfer ownership * fix: comment test: slashing integration framework (#894) * feat: add `AVS` user * test(wip): slashing integration * test(wip): slashing integration * test(wip): slashing integration * test(wip): slashing integration * fix: make tracing useful * test(wip): slashing integration * fix: toStringWad * fix: eigenpods * test(wip): slashing integration * refactor: revert change * test(review): changes * fix: compile * test(review): changes * refactor: improve logging * refactor: review changes * fix: roll in `modifyAllocations` * fix: roll in `modifyAllocations` * refactor: review changes * refactor: add back pause constants --------- Co-authored-by: Yash Patil refactor: EigenPods and beacon chain slashing (#892) * refactor: eigenpod and beacon chain slashing * checkpoints are not deleted on completion, saving gas when creating a new checkpoint * refactor: pull bcsf out of delegationManager * chore: formatting * refactor: rename withdrawableRestakedExecutionLayerGwei * maintains old interface, only state variable is renamed * this is to reduce line length when using this variable * refactor: remove branching and slashing math from eigenpod * fix: clean up balance update conditions and ensure shares==0 is handled * refactor: remove input validation and explicitly document assumptions * fix: tests and roundup (#901) * chore: address feedback * chore: address feedback again * chore: cleanup EPM withdrawSharesAsTokens --------- Co-authored-by: Michael Sun <35479365+8sunyuan@users.noreply.github.com> refactor: remove deprecated methods (#903) * refactor: rename parameter to be more accurate * refactor: remove deprecated methods from dm * refactor: remove operator details usage * chore: nit word test: `withdrawSharesAsTokens` regression (#904) * fix: commented out integration * test: call into EP for withdrawing as tokens chore: remove unnecessary delegate checks (#908) * feat: remove checks on approver/operator sender on delegate * chore: update interface feat: user access management (#870) * feat: unified access management fix: test/compile chore: use helper func in modifier chore: remove extra * test: add UAM to unit tests * refactor: delegate -> appointee * refactor: setAdmin -> addAdmin * fix: prevent 0 admins * refactor: bitshift encode/decode * feat: short-circuit _checkCanCall * test: basic reversability * feat: admin 2-step fix: remove external call * chore: fix compile/test * feat: use opSet length as avs check * chore: format * refactor: getoperatorsetcount * fix: msg.sender in delegatoinapproverupdated * chore: format fix: modify allocation tests + effect block fix: push more fixes test: add more tests fix: events test: add slashing check helpers (greg) (#910) * refactor(wip): alm unit tests * fix: am tests passing --------- Co-authored-by: clandestine.eth <96172957+0xClandestine@users.noreply.github.com> test: allocation test refactor test: fix slashing tests fix: test/compile chore: format --- .github/workflows/certora-prover.yml | 2 +- .github/workflows/coverage.yml | 26 +- .github/workflows/testinparallel.yml | 17 +- .gitignore | 4 + .gitmodules | 6 - .solhintignore | 1 - .../harnesses/DelegationManagerHarness.sol | 2 +- certora/harnesses/EigenPodHarness.sol | 2 +- certora/harnesses/EigenPodManagerHarness.sol | 2 +- certora/harnesses/PausableHarness.sol | 2 +- certora/harnesses/SlasherHarness.sol | 85 - certora/harnesses/StrategyManagerHarness.sol | 2 +- .../scripts/core/verifyDelegationManager.sh | 4 +- certora/scripts/core/verifyStrategyManager.sh | 4 +- .../libraries/verifyStructuredLinkedList.sh | 2 +- certora/scripts/permissions/verifyPausable.sh | 2 +- certora/scripts/pods/verifyEigenPod.sh | 4 +- certora/scripts/pods/verifyEigenPodManager.sh | 4 +- .../scripts/strategies/verifyStrategyBase.sh | 3 +- certora/specs/core/DelegationManager.spec | 14 +- docs/core/DelegationManager.md | 35 +- docs/core/EigenPod.md | 2 +- docs/release/slashing/AVSDirectory.md | 145 + docs/release/slashing/AllocationManager.md | 169 + docs/storage-report/AVSDirectory.md | 32 +- docs/storage-report/AVSDirectoryStorage.md | 12 +- docs/storage-report/AllocationManager.md | 26 + .../AllocationManagerStorage.md | 16 + docs/storage-report/BackingEigen.md | 1 + docs/storage-report/DelegationManager.md | 53 +- .../DelegationManagerStorage.md | 33 +- docs/storage-report/EigenPod.md | 42 +- docs/storage-report/EigenPodManager.md | 4 +- docs/storage-report/EigenPodManagerStorage.md | 2 +- docs/storage-report/EigenPodStorage.md | 34 +- docs/storage-report/EigenStrategy.md | 24 +- docs/storage-report/Pausable.md | 10 +- docs/storage-report/RewardsCoordinator.md | 8 +- .../RewardsCoordinatorStorage.md | 6 +- docs/storage-report/SignatureUtils.md | 2 + docs/storage-report/StrategyBase.md | 20 +- docs/storage-report/StrategyBaseTVLLimits.md | 26 +- docs/storage-report/StrategyFactory.md | 28 +- docs/storage-report/StrategyManager.md | 48 +- docs/storage-report/StrategyManagerStorage.md | 28 +- foundry.toml | 9 +- lib/openzeppelin-contracts | 1 - lib/openzeppelin-contracts-upgradeable | 1 - pkg/bindings/AVSDirectory/binding.go | 4 +- pkg/bindings/AVSDirectoryStorage/binding.go | 2 +- pkg/bindings/BackingEigen/binding.go | 2 +- pkg/bindings/BeaconChainProofs/binding.go | 4 +- pkg/bindings/BytesLib/binding.go | 4 +- pkg/bindings/Checkpoints/binding.go | 203 + .../DelayedWithdrawalRouter/binding.go | 1969 +++++ pkg/bindings/DelegationManager/binding.go | 4 +- .../DelegationManagerStorage/binding.go | 2 +- pkg/bindings/EIP1271SignatureUtils/binding.go | 4 +- pkg/bindings/Eigen/binding.go | 2 +- pkg/bindings/EigenPod/binding.go | 4 +- pkg/bindings/EigenPodManager/binding.go | 4 +- .../EigenPodManagerStorage/binding.go | 2 +- pkg/bindings/EigenPodStorage/binding.go | 2 +- pkg/bindings/EigenStrategy/binding.go | 4 +- pkg/bindings/Endian/binding.go | 2 +- pkg/bindings/IAVSDirectory/binding.go | 2 +- pkg/bindings/IDelegationManager/binding.go | 2 +- pkg/bindings/IEigenPod/binding.go | 2 +- pkg/bindings/IEigenPodManager/binding.go | 2 +- pkg/bindings/IPausable/binding.go | 2 +- pkg/bindings/IPauserRegistry/binding.go | 2 +- pkg/bindings/IRewardsCoordinator/binding.go | 2 +- pkg/bindings/IStrategy/binding.go | 2 +- pkg/bindings/IStrategyFactory/binding.go | 2 +- pkg/bindings/IStrategyManager/binding.go | 2 +- pkg/bindings/MagnitudeCheckpoints/binding.go | 203 + pkg/bindings/Merkle/binding.go | 4 +- pkg/bindings/Pausable/binding.go | 4 +- pkg/bindings/PauserRegistry/binding.go | 4 +- pkg/bindings/RewardsCoordinator/binding.go | 4 +- .../RewardsCoordinatorStorage/binding.go | 2 +- pkg/bindings/SlashingConstants/binding.go | 327 + pkg/bindings/StrategyBase/binding.go | 4 +- pkg/bindings/StrategyBaseTVLLimits/binding.go | 4 +- pkg/bindings/StrategyFactory/binding.go | 4 +- .../StrategyFactoryStorage/binding.go | 2 +- pkg/bindings/StrategyManager/binding.go | 4 +- .../StrategyManagerStorage/binding.go | 2 +- pkg/bindings/StructuredLinkedList/binding.go | 2 +- remappings.txt | 6 - .../mainnet/Mainnet_Unpause_Deposits.s.sol | 2 +- .../deploy_from_scratch.anvil.config.json | 55 + .../deploy_from_scratch.holesky.config.json | 55 + ..._from_scratch.holesky.slashing.config.json | 47 + ...loy_RewardsCoordinator.holesky.config.json | 60 + .../deploy_from_scratch.anvil.config.json | 5 + ...oy_from_scratch.slashing.anvil.config.json | 61 + script/deploy/devnet/Upgrade.s.sol | 24 + .../deploy/devnet/deploy_from_scratch.s.sol | 653 ++ .../Deploy_Preprod_RewardsCoordinator.s.sol | 2 +- .../Deploy_Test_RewardsCoordinator.s.sol | 14 +- .../holesky/Eigen_Strategy_Deploy.s.sol | 11 +- .../deploy/holesky/Eigen_Token_Deploy.s.sol | 10 +- .../holesky/M2_Deploy_From_Scratch.s.sol | 67 +- script/deploy/holesky/M2_Deploy_Preprod.s.sol | 2 +- .../Preprod_Upgrade_bEIGEN_and_EIGEN.s.sol | 8 +- .../holesky/bEIGEN_and_EIGEN_upgrade.s.sol | 8 +- .../holesky/longtail-preprod-upgrade.s.sol | 10 +- ...3-upgrade_testnet_rewardsCoordinator.s.sol | 7 +- script/deploy/holesky/v040-holesky-pepe.s.sol | 9 +- script/deploy/local/Deploy_From_Scratch.s.sol | 172 +- .../local/deploy_from_scratch.slashing.s.sol | 657 ++ .../local/operatorSets/DeployStrategies.s.sol | 79 + .../mainnet/Deploy_Strategy_Factory.s.sol | 61 + script/deploy/mainnet/EIGEN_upgrade.s.sol | 2 +- .../EigenPod_Minor_Upgrade_Deploy.s.sol | 7 +- .../deploy/mainnet/M2_Mainnet_Upgrade.s.sol | 335 - script/deploy/mainnet/bEIGEN_upgrade.s.sol | 2 +- .../mainnet/v0.3.0-mainnet-rewards.s.sol | 11 +- .../deploy/mainnet/v0.4.2-mainnet-pepe.s.sol | 8 +- .../v0.4.3-upgrade_rewardsCoordinator.s.sol | 11 +- ...G_deploy_from_scratch_deployment_data.json | 52 + script/tasks/README.md | 155 + script/tasks/allocate_operatorSet.s.sol | 59 + .../complete_withdrawal_from_strategy.s.sol | 122 + script/tasks/deposit_into_strategy.s.sol | 50 + script/tasks/register_as_operator.s.sol | 42 + .../register_operator_to_operatorSet.s.sol | 84 + script/tasks/run.sh | 125 + script/tasks/slash_operatorSet.s.sol | 43 + script/tasks/unpause_avsDirectory.s.sol | 48 + script/tasks/withdraw_from_strategy.s.sol | 70 + script/utils/ExistingDeploymentParser.sol | 85 +- script/utils/TimelockEncoding.sol | 2 +- script/whitelist/Staker.sol | 2 +- .../delegationFaucet/DelegationFaucet.sol | 216 - .../DelegationFaucetStaker.sol | 26 - .../DeployDelegationFaucet.sol | 84 - src/contracts/core/AVSDirectory.sol | 152 +- src/contracts/core/AVSDirectoryStorage.sol | 50 +- src/contracts/core/AllocationManager.sol | 832 +++ .../core/AllocationManagerStorage.sol | 108 + src/contracts/core/DelegationManager.sol | 1168 +-- .../core/DelegationManagerStorage.sol | 159 +- src/contracts/core/RewardsCoordinator.sol | 271 +- .../core/RewardsCoordinatorStorage.sol | 108 +- src/contracts/core/Slasher.sol | 76 - src/contracts/core/StrategyManager.sol | 293 +- src/contracts/core/StrategyManagerStorage.sol | 102 +- src/contracts/interfaces/IAVSDirectory.sol | 158 +- src/contracts/interfaces/IAVSRegistrar.sol | 22 + .../interfaces/IAllocationManager.sol | 538 ++ src/contracts/interfaces/IBackingEigen.sol | 8 +- .../interfaces/IDelegationFaucet.sol | 4 +- .../interfaces/IDelegationManager.sol | 501 +- src/contracts/interfaces/IEigen.sol | 14 +- src/contracts/interfaces/IEigenPod.sol | 145 +- src/contracts/interfaces/IEigenPodManager.sol | 115 +- src/contracts/interfaces/IPausable.sol | 27 +- src/contracts/interfaces/IPauserRegistry.sol | 7 +- .../interfaces/IPermissionController.sol | 154 + .../interfaces/IRewardsCoordinator.sol | 323 +- src/contracts/interfaces/IShareManager.sol | 40 + src/contracts/interfaces/ISignatureUtils.sol | 3 + src/contracts/interfaces/ISlasher.sol | 24 +- src/contracts/interfaces/ISocketUpdater.sol | 6 +- src/contracts/interfaces/IStrategy.sol | 65 +- src/contracts/interfaces/IStrategyFactory.sol | 29 +- src/contracts/interfaces/IStrategyManager.sol | 161 +- src/contracts/interfaces/IWhitelister.sol | 12 +- src/contracts/libraries/BeaconChainProofs.sol | 58 +- src/contracts/libraries/BytesLib.sol | 25 +- .../libraries/EIP1271SignatureUtils.sol | 41 - src/contracts/libraries/Endian.sol | 4 +- src/contracts/libraries/Merkle.sol | 13 +- src/contracts/libraries/OperatorSetLib.sol | 25 + src/contracts/libraries/SlashingLib.sol | 170 + src/contracts/libraries/Snapshots.sol | 184 + .../libraries/StructuredLinkedList.sol | 258 - .../mixins/PermissionControllerMixin.sol | 38 + src/contracts/mixins/SignatureUtils.sol | 83 + src/contracts/permissions/Pausable.sol | 125 +- src/contracts/permissions/PauserRegistry.sol | 16 +- .../permissions/PermissionController.sol | 231 + .../PermissionControllerStorage.sol | 32 + src/contracts/pods/EigenPod.sol | 247 +- src/contracts/pods/EigenPodManager.sol | 360 +- src/contracts/pods/EigenPodManagerStorage.sol | 22 +- .../pods/EigenPodPausingConstants.sol | 2 +- src/contracts/pods/EigenPodStorage.sol | 6 +- src/contracts/strategies/EigenStrategy.sol | 15 +- src/contracts/strategies/StrategyBase.sol | 73 +- .../strategies/StrategyBaseTVLLimits.sol | 21 +- src/contracts/strategies/StrategyFactory.sol | 55 +- .../strategies/StrategyFactoryStorage.sol | 2 +- src/contracts/token/BackingEigen.sol | 22 +- src/contracts/token/Eigen.sol | 20 +- .../UpgradeableSignatureCheckingUtils.sol | 52 - src/test/Delegation.t.sol | 501 -- src/test/DelegationFaucet.t.sol | 513 -- src/test/DepositWithdraw.t.sol | 503 -- src/test/DevnetLifecycle.t.sol | 255 + src/test/EigenLayerDeployer.t.sol | 272 - src/test/EigenLayerTestHelper.t.sol | 505 -- src/test/Pausable.t.sol | 90 - src/test/Strategy.t.sol | 58 - src/test/Withdrawals.t.sol | 285 - src/test/events/IAVSDirectoryEvents.sol | 15 - src/test/events/IDelegationManagerEvents.sol | 61 - src/test/events/IEigenPodEvents.sol | 38 - src/test/events/IEigenPodManagerEvents.sol | 16 - src/test/events/IRewardsCoordinatorEvents.sol | 73 - src/test/events/IStrategyManagerEvents.sol | 63 - src/test/harnesses/EigenHarness.sol | 2 +- src/test/harnesses/EigenPodHarness.sol | 2 +- src/test/harnesses/EigenPodManagerWrapper.sol | 19 +- src/test/harnesses/PausableHarness.sol | 10 +- src/test/integration/IntegrationBase.t.sol | 274 +- src/test/integration/IntegrationChecks.t.sol | 69 +- .../integration/IntegrationDeployer.t.sol | 534 +- src/test/integration/README.md | 46 +- src/test/integration/TimeMachine.t.sol | 10 +- .../mainnet/BeaconChainProofs.sol | 2 +- .../mainnet/IBeaconChainOracle.sol | 2 +- .../mainnet/IDelayedWithdrawalRouter.sol | 2 +- .../mainnet/IEigenPod.sol | 2 +- .../mainnet/IEigenPodManager.sol | 7 +- .../mainnet/IStrategyManager.sol | 8 +- .../integration/mocks/BeaconChainMock.t.sol | 69 +- .../mocks/EIP_4788_Oracle_Mock.t.sol | 2 +- .../Delegate_Deposit_Queue_Complete.t.sol | 11 +- .../tests/Deposit_Delegate_Allocate.t.sol | 46 + .../Deposit_Delegate_Queue_Complete.t.sol | 23 +- ...Deposit_Delegate_Redelegate_Complete.t.sol | 68 +- ...Deposit_Delegate_Undelegate_Complete.t.sol | 31 +- .../Deposit_Delegate_UpdateBalance.t.sol | 104 +- .../tests/Deposit_Queue_Complete.t.sol | 13 +- ...it_Register_QueueWithdrawal_Complete.t.sol | 10 +- .../integration/tests/Upgrade_Setup.t.sol | 9 +- .../VerifyWC_StartCP_CompleteCP.t.sol | 54 +- src/test/integration/users/AVS.t.sol | 171 + src/test/integration/users/User.t.sol | 470 +- src/test/integration/users/User_M1.t.sol | 14 +- src/test/integration/utils/PrintUtils.t.sol | 119 - src/test/mocks/AVSDirectoryMock.sol | 11 + src/test/mocks/AllocationManagerMock.sol | 77 + src/test/mocks/DelegationManagerMock.sol | 183 +- src/test/mocks/Dummy.sol | 2 +- src/test/mocks/ERC20Mock.sol | 2 +- src/test/mocks/ERC20_OneWeiFeeOnTransfer.sol | 2 +- .../mocks/ERC20_SetTransferReverting_Mock.sol | 2 +- src/test/mocks/ETHDepositMock.sol | 2 +- src/test/mocks/EigenPodManagerMock.sol | 89 +- src/test/mocks/EmptyContract.sol | 2 +- src/test/mocks/MockAVSRegistrar.sol | 6 + src/test/mocks/MockDecimals.sol | 2 +- src/test/mocks/OwnableMock.sol | 2 +- src/test/mocks/SlasherMock.sol | 78 - src/test/mocks/StrategyManagerMock.sol | 159 +- .../token/EigenTransferRestrictions.t.sol | 8 +- src/test/token/EigenWrapping.t.sol | 6 +- src/test/token/bEIGEN.t.sol | 6 +- src/test/tree/AllocationManagerUnit.tree | 86 + src/test/tree/DelegationManagerUnit.tree | 143 +- src/test/tree/PermissionControllerUnit.tree | 27 + src/test/unit/AVSDirectoryUnit.t.sol | 401 +- src/test/unit/AllocationManagerUnit.t.sol | 3726 ++++++++++ src/test/unit/DelegationUnit.t.sol | 6615 ++++++++++++----- src/test/unit/EigenPodManagerUnit.t.sol | 338 +- src/test/unit/EigenPodUnit.t.sol | 176 +- src/test/unit/PausableUnit.t.sol | 33 +- src/test/unit/PauserRegistryUnit.t.sol | 13 +- src/test/unit/PermissionControllerUnit.t.sol | 430 ++ src/test/unit/RewardsCoordinatorUnit.t.sol | 317 +- src/test/unit/StrategyBaseTVLLimitsUnit.sol | 69 +- src/test/unit/StrategyBaseUnit.t.sol | 91 +- src/test/unit/StrategyFactoryUnit.t.sol | 43 +- src/test/unit/StrategyManagerUnit.t.sol | 678 +- src/test/utils/BeaconChainProofsWrapper.sol | 41 - src/test/utils/EigenLayerUnitTestBase.sol | 35 - src/test/utils/EigenLayerUnitTestSetup.sol | 119 +- src/test/utils/EigenPodUser.t.sol | 36 +- src/test/utils/Logger.t.sol | 286 + src/test/utils/Operators.sol | 48 - src/test/utils/Owners.sol | 47 - src/test/utils/ProofParsing.sol | 26 +- src/test/utils/Random.sol | 320 + src/test/utils/SignatureCompaction.sol | 29 - src/test/utils/SingleItemArrayLib.sol | 126 + src/test/utils/Utils.sol | 23 - 290 files changed, 24412 insertions(+), 11414 deletions(-) delete mode 100644 certora/harnesses/SlasherHarness.sol create mode 100644 docs/release/slashing/AVSDirectory.md create mode 100644 docs/release/slashing/AllocationManager.md create mode 100644 docs/storage-report/AllocationManager.md create mode 100644 docs/storage-report/AllocationManagerStorage.md create mode 100644 docs/storage-report/SignatureUtils.md delete mode 160000 lib/openzeppelin-contracts delete mode 160000 lib/openzeppelin-contracts-upgradeable create mode 100644 pkg/bindings/Checkpoints/binding.go create mode 100644 pkg/bindings/DelayedWithdrawalRouter/binding.go create mode 100644 pkg/bindings/MagnitudeCheckpoints/binding.go create mode 100644 pkg/bindings/SlashingConstants/binding.go delete mode 100644 remappings.txt create mode 100644 script/configs/devnet/deploy_from_scratch.anvil.config.json create mode 100644 script/configs/devnet/deploy_from_scratch.holesky.config.json create mode 100644 script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json create mode 100644 script/configs/holesky/Deploy_RewardsCoordinator.holesky.config.json create mode 100644 script/configs/local/deploy_from_scratch.slashing.anvil.config.json create mode 100644 script/deploy/devnet/Upgrade.s.sol create mode 100644 script/deploy/devnet/deploy_from_scratch.s.sol create mode 100644 script/deploy/local/deploy_from_scratch.slashing.s.sol create mode 100644 script/deploy/local/operatorSets/DeployStrategies.s.sol create mode 100644 script/deploy/mainnet/Deploy_Strategy_Factory.s.sol delete mode 100644 script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol create mode 100644 script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json create mode 100644 script/tasks/README.md create mode 100644 script/tasks/allocate_operatorSet.s.sol create mode 100644 script/tasks/complete_withdrawal_from_strategy.s.sol create mode 100644 script/tasks/deposit_into_strategy.s.sol create mode 100644 script/tasks/register_as_operator.s.sol create mode 100644 script/tasks/register_operator_to_operatorSet.s.sol create mode 100755 script/tasks/run.sh create mode 100644 script/tasks/slash_operatorSet.s.sol create mode 100644 script/tasks/unpause_avsDirectory.s.sol create mode 100644 script/tasks/withdraw_from_strategy.s.sol delete mode 100644 script/whitelist/delegationFaucet/DelegationFaucet.sol delete mode 100644 script/whitelist/delegationFaucet/DelegationFaucetStaker.sol delete mode 100644 script/whitelist/delegationFaucet/DeployDelegationFaucet.sol create mode 100644 src/contracts/core/AllocationManager.sol create mode 100644 src/contracts/core/AllocationManagerStorage.sol delete mode 100644 src/contracts/core/Slasher.sol create mode 100644 src/contracts/interfaces/IAVSRegistrar.sol create mode 100644 src/contracts/interfaces/IAllocationManager.sol create mode 100644 src/contracts/interfaces/IPermissionController.sol create mode 100644 src/contracts/interfaces/IShareManager.sol delete mode 100644 src/contracts/libraries/EIP1271SignatureUtils.sol create mode 100644 src/contracts/libraries/OperatorSetLib.sol create mode 100644 src/contracts/libraries/SlashingLib.sol create mode 100644 src/contracts/libraries/Snapshots.sol delete mode 100644 src/contracts/libraries/StructuredLinkedList.sol create mode 100644 src/contracts/mixins/PermissionControllerMixin.sol create mode 100644 src/contracts/mixins/SignatureUtils.sol create mode 100644 src/contracts/permissions/PermissionController.sol create mode 100644 src/contracts/permissions/PermissionControllerStorage.sol delete mode 100644 src/contracts/utils/UpgradeableSignatureCheckingUtils.sol delete mode 100644 src/test/Delegation.t.sol delete mode 100644 src/test/DelegationFaucet.t.sol delete mode 100644 src/test/DepositWithdraw.t.sol create mode 100644 src/test/DevnetLifecycle.t.sol delete mode 100644 src/test/EigenLayerDeployer.t.sol delete mode 100644 src/test/EigenLayerTestHelper.t.sol delete mode 100644 src/test/Pausable.t.sol delete mode 100644 src/test/Strategy.t.sol delete mode 100644 src/test/Withdrawals.t.sol delete mode 100644 src/test/events/IAVSDirectoryEvents.sol delete mode 100644 src/test/events/IDelegationManagerEvents.sol delete mode 100644 src/test/events/IEigenPodEvents.sol delete mode 100644 src/test/events/IEigenPodManagerEvents.sol delete mode 100644 src/test/events/IRewardsCoordinatorEvents.sol delete mode 100644 src/test/events/IStrategyManagerEvents.sol create mode 100644 src/test/integration/tests/Deposit_Delegate_Allocate.t.sol create mode 100644 src/test/integration/users/AVS.t.sol delete mode 100644 src/test/integration/utils/PrintUtils.t.sol create mode 100644 src/test/mocks/AVSDirectoryMock.sol create mode 100644 src/test/mocks/AllocationManagerMock.sol create mode 100644 src/test/mocks/MockAVSRegistrar.sol delete mode 100644 src/test/mocks/SlasherMock.sol create mode 100644 src/test/tree/AllocationManagerUnit.tree create mode 100644 src/test/tree/PermissionControllerUnit.tree create mode 100644 src/test/unit/AllocationManagerUnit.t.sol create mode 100644 src/test/unit/PermissionControllerUnit.t.sol delete mode 100644 src/test/utils/BeaconChainProofsWrapper.sol delete mode 100644 src/test/utils/EigenLayerUnitTestBase.sol create mode 100644 src/test/utils/Logger.t.sol delete mode 100644 src/test/utils/Operators.sol delete mode 100644 src/test/utils/Owners.sol create mode 100644 src/test/utils/Random.sol delete mode 100644 src/test/utils/SignatureCompaction.sol create mode 100644 src/test/utils/SingleItemArrayLib.sol delete mode 100644 src/test/utils/Utils.sol diff --git a/.github/workflows/certora-prover.yml b/.github/workflows/certora-prover.yml index f8556b756..39a62830a 100644 --- a/.github/workflows/certora-prover.yml +++ b/.github/workflows/certora-prover.yml @@ -50,7 +50,7 @@ jobs: - name: Install solc run: | pip install solc-select - solc-select use 0.8.12 --always-install + solc-select use 0.8.27 --always-install - name: Verify rule ${{ matrix.params }} run: | bash ${{ matrix.params }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index dc241a5e2..e38cb2902 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -26,19 +26,20 @@ jobs: id: get_issue_number with: script: | - if (context.issue && context.issue.number) { - // Return issue number if present - return context.issue.number; + let issue_number; + // Attempt to find a pull request associated with the commit + const pullRequests = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + commit_sha: context.sha, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + if (pullRequests.data.length > 0) { + issue_number = pullRequests.data[0].number; } else { - // Otherwise return issue number from commit - return ( - await github.rest.repos.listPullRequestsAssociatedWithCommit({ - commit_sha: context.sha, - owner: context.repo.owner, - repo: context.repo.repo, - }) - ).data[0].number; + throw new Error('No associated issue or pull request found.'); } + return issue_number; result-encoding: string - name: Checkout code uses: actions/checkout@v2 @@ -52,6 +53,9 @@ jobs: version: nightly - name: Run coverage run: forge coverage --report lcov + env: + RPC_MAINNET: ${{ secrets.RPC_MAINNET }} + RPC_HOLESKY: ${{ secrets.RPC_HOLESKY }} - name: Prune coverage report run: lcov --remove ./lcov.info -o ./lcov.info.pruned 'src/test/*' 'script/*' '*Storage.sol' --ignore-errors inconsistent - name: Generate reports diff --git a/.github/workflows/testinparallel.yml b/.github/workflows/testinparallel.yml index 8ae97b9a4..dd7a5b72e 100644 --- a/.github/workflows/testinparallel.yml +++ b/.github/workflows/testinparallel.yml @@ -39,7 +39,7 @@ jobs: - name: Run Forge build run: | forge --version - forge build --sizes + forge build id: build - name: Run unit tests @@ -56,10 +56,11 @@ jobs: RPC_HOLESKY: ${{ secrets.RPC_HOLESKY }} CHAIN_ID: ${{ secrets.CHAIN_ID }} - - name: Run integration mainnet fork tests - run: forge test --match-contract Integration - env: - FOUNDRY_PROFILE: "forktest" - RPC_MAINNET: ${{ secrets.RPC_MAINNET }} - RPC_HOLESKY: ${{ secrets.RPC_HOLESKY }} - CHAIN_ID: ${{ secrets.CHAIN_ID }} \ No newline at end of file + # TODO: uncomment this item once we've added the proper upgrade tests + # - name: Run integration mainnet fork tests + # run: forge test --match-contract Integration + # env: + # FOUNDRY_PROFILE: "forktest" + # RPC_MAINNET: ${{ secrets.RPC_MAINNET }} + # RPC_HOLESKY: ${{ secrets.RPC_HOLESKY }} + # CHAIN_ID: ${{ secrets.CHAIN_ID }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index cb82d385c..3213174f1 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,7 @@ InheritanceGraph.png surya_report.md .idea + +*state.json +deployed_strategies.json +populate_src* \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index e729e9fc1..4ccf6fa8b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,9 @@ -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable [submodule "lib/ds-test"] path = lib/ds-test url = https://github.com/dapphub/ds-test [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/openzeppelin-contracts"] - path = lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts [submodule "lib/openzeppelin-contracts-v4.9.0"] path = lib/openzeppelin-contracts-v4.9.0 url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/.solhintignore b/.solhintignore index 497fd271c..e69de29bb 100644 --- a/.solhintignore +++ b/.solhintignore @@ -1 +0,0 @@ -Slasher.sol \ No newline at end of file diff --git a/certora/harnesses/DelegationManagerHarness.sol b/certora/harnesses/DelegationManagerHarness.sol index 9f2366ee6..05143f537 100644 --- a/certora/harnesses/DelegationManagerHarness.sol +++ b/certora/harnesses/DelegationManagerHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/core/DelegationManager.sol"; diff --git a/certora/harnesses/EigenPodHarness.sol b/certora/harnesses/EigenPodHarness.sol index 1845cff7a..a000e4954 100644 --- a/certora/harnesses/EigenPodHarness.sol +++ b/certora/harnesses/EigenPodHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/pods/EigenPod.sol"; diff --git a/certora/harnesses/EigenPodManagerHarness.sol b/certora/harnesses/EigenPodManagerHarness.sol index 84576ec9f..034425449 100644 --- a/certora/harnesses/EigenPodManagerHarness.sol +++ b/certora/harnesses/EigenPodManagerHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/pods/EigenPodManager.sol"; diff --git a/certora/harnesses/PausableHarness.sol b/certora/harnesses/PausableHarness.sol index fc0095ebe..2719eba6f 100644 --- a/certora/harnesses/PausableHarness.sol +++ b/certora/harnesses/PausableHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/permissions/Pausable.sol"; diff --git a/certora/harnesses/SlasherHarness.sol b/certora/harnesses/SlasherHarness.sol deleted file mode 100644 index 519895780..000000000 --- a/certora/harnesses/SlasherHarness.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../../src/contracts/core/Slasher.sol"; - -contract SlasherHarness is Slasher { - - constructor(IStrategyManager _strategyManager, IDelegationManager _delegation) Slasher(_strategyManager, _delegation) {} - - /// Harnessed functions - function get_is_operator(address staker) public returns (bool) { - return delegation.isOperator(staker); - } - - function get_is_delegated(address staker) public returns (bool) { - return delegation.isDelegated(staker); - } - - - // Linked List Functions - function get_list_exists(address operator) public returns (bool) { - return StructuredLinkedList.listExists(_operatorToWhitelistedContractsByUpdate[operator]); - } - - function get_next_node_exists(address operator, uint256 node) public returns (bool) { - (bool res, ) = StructuredLinkedList.getNextNode(_operatorToWhitelistedContractsByUpdate[operator], node); - return res; - } - - function get_next_node(address operator, uint256 node) public returns (uint256) { - (, uint256 res) = StructuredLinkedList.getNextNode(_operatorToWhitelistedContractsByUpdate[operator], node); - return res; - } - - function get_previous_node_exists(address operator, uint256 node) public returns (bool) { - (bool res, ) = StructuredLinkedList.getPreviousNode(_operatorToWhitelistedContractsByUpdate[operator], node); - return res; - } - - function get_previous_node(address operator, uint256 node) public returns (uint256) { - (, uint256 res) = StructuredLinkedList.getPreviousNode(_operatorToWhitelistedContractsByUpdate[operator], node); - return res; - } - - function get_list_head(address operator) public returns (uint256) { - return StructuredLinkedList.getHead(_operatorToWhitelistedContractsByUpdate[operator]); - } - - function get_lastest_update_block_at_node(address operator, uint256 node) public returns (uint256) { - return _whitelistedContractDetails[operator][_uintToAddress(node)].latestUpdateBlock; - } - - function get_lastest_update_block_at_head(address operator) public returns (uint256) { - return get_lastest_update_block_at_node(operator, get_list_head(operator)); - } - - function get_linked_list_entry(address operator, uint256 node, bool direction) public returns (uint256) { - return (_operatorToWhitelistedContractsByUpdate[operator].list[node][direction]); - } - - // // uses that _HEAD = 0. Similar to StructuredLinkedList.nodeExists but slightly better defined - // function nodeDoesExist(address operator, uint256 node) public returns (bool) { - // if (get_next_node(operator, node) == 0 && get_previous_node(operator, node) == 0) { - // // slightly stricter check than that defined in StructuredLinkedList.nodeExists - // if (get_next_node(operator, 0) == node && get_previous_node(operator, 0) == node) { - // return true; - // } else { - // return false; - // } - // } else { - // return true; - // } - // } - - // // uses that _PREV = false, _NEXT = true - // function nodeIsWellLinked(address operator, uint256 node) public returns (bool) { - // return ( - // // node is not linked to itself - // get_previous_node(operator, node) != node && get_next_node(operator, node) != node - // && - // // node is the previous node's next node and the next node's previous node - // get_linked_list_entry(operator, get_previous_node(operator, node), true) == node && get_linked_list_entry(operator, get_next_node(operator, node), false) == node - // ); - // } -} diff --git a/certora/harnesses/StrategyManagerHarness.sol b/certora/harnesses/StrategyManagerHarness.sol index 441037032..a8c1ba2a0 100644 --- a/certora/harnesses/StrategyManagerHarness.sol +++ b/certora/harnesses/StrategyManagerHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/core/StrategyManager.sol"; diff --git a/certora/scripts/core/verifyDelegationManager.sh b/certora/scripts/core/verifyDelegationManager.sh index 678b5a37c..d58112103 100644 --- a/certora/scripts/core/verifyDelegationManager.sh +++ b/certora/scripts/core/verifyDelegationManager.sh @@ -3,12 +3,12 @@ then RULE="--rule $2" fi -solc-select use 0.8.12 +solc-select use 0.8.27 certoraRun certora/harnesses/DelegationManagerHarness.sol \ lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol \ src/contracts/pods/EigenPodManager.sol src/contracts/pods/EigenPod.sol src/contracts/strategies/StrategyBase.sol src/contracts/core/StrategyManager.sol \ - src/contracts/core/Slasher.sol src/contracts/permissions/PauserRegistry.sol \ + src/contracts/permissions/PauserRegistry.sol \ --verify DelegationManagerHarness:certora/specs/core/DelegationManager.spec \ --solc_via_ir \ --solc_optimize 1 \ diff --git a/certora/scripts/core/verifyStrategyManager.sh b/certora/scripts/core/verifyStrategyManager.sh index 7f3b1c5d2..1e404ea4c 100644 --- a/certora/scripts/core/verifyStrategyManager.sh +++ b/certora/scripts/core/verifyStrategyManager.sh @@ -3,13 +3,13 @@ then RULE="--rule $2" fi -solc-select use 0.8.12 +solc-select use 0.8.27 certoraRun certora/harnesses/StrategyManagerHarness.sol \ lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol \ src/contracts/pods/EigenPodManager.sol src/contracts/pods/EigenPod.sol \ src/contracts/strategies/StrategyBase.sol src/contracts/core/DelegationManager.sol \ - src/contracts/core/Slasher.sol src/contracts/permissions/PauserRegistry.sol \ + src/contracts/permissions/PauserRegistry.sol \ --verify StrategyManagerHarness:certora/specs/core/StrategyManager.spec \ --solc_via_ir \ --solc_optimize 1 \ diff --git a/certora/scripts/libraries/verifyStructuredLinkedList.sh b/certora/scripts/libraries/verifyStructuredLinkedList.sh index c03c593d4..25615e4e0 100644 --- a/certora/scripts/libraries/verifyStructuredLinkedList.sh +++ b/certora/scripts/libraries/verifyStructuredLinkedList.sh @@ -3,7 +3,7 @@ then RULE="--rule $2" fi -solc-select use 0.8.12 +solc-select use 0.8.27 certoraRun certora/harnesses/StructuredLinkedListHarness.sol \ --verify StructuredLinkedListHarness:certora/specs/libraries/StructuredLinkedList.spec \ diff --git a/certora/scripts/permissions/verifyPausable.sh b/certora/scripts/permissions/verifyPausable.sh index c9d23f965..29cc4c1ad 100644 --- a/certora/scripts/permissions/verifyPausable.sh +++ b/certora/scripts/permissions/verifyPausable.sh @@ -3,7 +3,7 @@ then RULE="--rule $2" fi -solc-select use 0.8.12 +solc-select use 0.8.27 certoraRun certora/harnesses/PausableHarness.sol \ src/contracts/permissions/PauserRegistry.sol \ diff --git a/certora/scripts/pods/verifyEigenPod.sh b/certora/scripts/pods/verifyEigenPod.sh index d4bc140a8..812d26bf2 100644 --- a/certora/scripts/pods/verifyEigenPod.sh +++ b/certora/scripts/pods/verifyEigenPod.sh @@ -3,11 +3,11 @@ then RULE="--rule $2" fi -# solc-select use 0.8.12 +# solc-select use 0.8.27 # certoraRun certora/harnesses/EigenPodHarness.sol \ # src/contracts/core/DelegationManager.sol src/contracts/pods/EigenPodManager.sol \ -# src/contracts/core/Slasher.sol src/contracts/permissions/PauserRegistry.sol \ +# src/contracts/permissions/PauserRegistry.sol \ # src/contracts/core/StrategyManager.sol \ # src/contracts/strategies/StrategyBase.sol \ # lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol \ diff --git a/certora/scripts/pods/verifyEigenPodManager.sh b/certora/scripts/pods/verifyEigenPodManager.sh index 428f89ba3..6d0b90e4c 100644 --- a/certora/scripts/pods/verifyEigenPodManager.sh +++ b/certora/scripts/pods/verifyEigenPodManager.sh @@ -3,11 +3,11 @@ then RULE="--rule $2" fi -# solc-select use 0.8.12 +# solc-select use 0.8.27 # certoraRun certora/harnesses/EigenPodManagerHarness.sol \ # src/contracts/core/DelegationManager.sol src/contracts/pods/EigenPod.sol src/contracts/strategies/StrategyBase.sol src/contracts/core/StrategyManager.sol \ -# src/contracts/core/Slasher.sol src/contracts/permissions/PauserRegistry.sol \ +# src/contracts/permissions/PauserRegistry.sol \ # --verify EigenPodManagerHarness:certora/specs/pods/EigenPodManager.spec \ # --optimistic_loop \ # --optimistic_fallback \ diff --git a/certora/scripts/strategies/verifyStrategyBase.sh b/certora/scripts/strategies/verifyStrategyBase.sh index 5c3d2683f..8d966e540 100644 --- a/certora/scripts/strategies/verifyStrategyBase.sh +++ b/certora/scripts/strategies/verifyStrategyBase.sh @@ -3,13 +3,12 @@ then RULE="--rule $2" fi -solc-select use 0.8.12 +solc-select use 0.8.27 certoraRun src/contracts/strategies/StrategyBase.sol \ lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol \ src/contracts/core/StrategyManager.sol \ src/contracts/permissions/PauserRegistry.sol \ - src/contracts/core/Slasher.sol \ --verify StrategyBase:certora/specs/strategies/StrategyBase.spec \ --solc_via_ir \ --solc_optimize 1 \ diff --git a/certora/specs/core/DelegationManager.spec b/certora/specs/core/DelegationManager.spec index f607b75fd..17eee6566 100644 --- a/certora/specs/core/DelegationManager.spec +++ b/certora/specs/core/DelegationManager.spec @@ -78,7 +78,7 @@ in this case, the end state is that: isOperator(staker) == false, delegatedTo(staker) != staker && delegatedTo(staker) != 0, and isDelegated(staker) == true (redundant with above) --only allowed when calling `delegateTo` or `delegateToBySignature` +-only allowed when calling `delegateTo` 2) FROM not delegated AND not registered as an operator @@ -172,7 +172,7 @@ rule cannotChangeDelegationWithoutUndelegating(address staker) { } } -// verifies that an undelegated address can only delegate when calling `delegateTo`, `delegateToBySignature` or `registerAsOperator` +// verifies that an undelegated address can only delegate when calling `delegateTo` or `registerAsOperator` rule canOnlyDelegateWithSpecificFunctions(address staker) { requireInvariant operatorsAlwaysDelegatedToSelf(staker); // assume the staker begins as undelegated @@ -192,16 +192,6 @@ rule canOnlyDelegateWithSpecificFunctions(address staker) { } else { assert (!isDelegated(staker), "staker delegated to inappropriate address?"); } - } else if (f.selector == sig:delegateToBySignature(address, address, ISignatureUtils.SignatureWithExpiry, ISignatureUtils.SignatureWithExpiry, bytes32).selector) { - address toDelegateFrom; - address operator; - require(operator != 0); - ISignatureUtils.SignatureWithExpiry stakerSignatureAndExpiry; - ISignatureUtils.SignatureWithExpiry approverSignatureAndExpiry; - bytes32 salt; - delegateToBySignature(e, toDelegateFrom, operator, stakerSignatureAndExpiry, approverSignatureAndExpiry, salt); - // TODO: this check could be stricter! need to filter when the block timestamp is appropriate for expiry and signature is valid - assert (!isDelegated(staker) || delegatedTo(staker) == operator, "delegateToBySignature bug?"); } else if (f.selector == sig:registerAsOperator(IDelegationManager.OperatorDetails, string).selector) { IDelegationManager.OperatorDetails operatorDetails; string metadataURI; diff --git a/docs/core/DelegationManager.md b/docs/core/DelegationManager.md index 8569deae4..f53179a4e 100644 --- a/docs/core/DelegationManager.md +++ b/docs/core/DelegationManager.md @@ -112,7 +112,6 @@ Allows an Operator to emit an `OperatorMetadataURIUpdated` event. No other state Stakers interact with the following functions to delegate their shares to an Operator: * [`DelegationManager.delegateTo`](#delegateto) -* [`DelegationManager.delegateToBySignature`](#delegatetobysignature) #### `delegateTo` @@ -138,30 +137,6 @@ Allows the caller (a Staker) to delegate their shares to an Operator. Delegation * The `operator` MUST already be an Operator * If the `operator` has a `delegationApprover`, the caller MUST provide a valid `approverSignatureAndExpiry` and `approverSalt` -#### `delegateToBySignature` - -```solidity -function delegateToBySignature( - address staker, - address operator, - SignatureWithExpiry memory stakerSignatureAndExpiry, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt -) - external -``` - -Allows a Staker to delegate to an Operator by way of signature. This function can be called by three different parties: -* If the Operator calls this method, they need to submit only the `stakerSignatureAndExpiry` -* If the Operator's `delegationApprover` calls this method, they need to submit only the `stakerSignatureAndExpiry` -* If the anyone else calls this method, they need to submit both the `stakerSignatureAndExpiry` AND `approverSignatureAndExpiry` - -*Effects*: See `delegateTo` above. - -*Requirements*: See `delegateTo` above. Additionally: -* If caller is either the Operator's `delegationApprover` or the Operator, the `approverSignatureAndExpiry` and `approverSalt` can be empty -* `stakerSignatureAndExpiry` MUST be a valid, unexpired signature over the correct hash and nonce - --- ### Undelegating and Withdrawing @@ -275,9 +250,9 @@ For each strategy/share pair in the `Withdrawal`: `Withdrawals` concerning `EigenPodManager` shares have some additional nuance depending on whether a withdrawal is specified to be received as tokens vs shares (read more about "why" in [`EigenPodManager.md`](./EigenPodManager.md)): * `EigenPodManager` withdrawals received as shares: - * Shares ALWAYS go back to the originator of the withdrawal (rather than the `withdrawer` address). - * Shares are also delegated to the originator's Operator, rather than the `withdrawer's` Operator. - * Shares received by the originator may be lower than the shares originally withdrawn if the originator has debt. + * OwnedShares ALWAYS go back to the originator of the withdrawal (rather than the `withdrawer` address). + * OwnedShares are also delegated to the originator's Operator, rather than the `withdrawer's` Operator. + * OwnedShares received by the originator may be lower than the shares originally withdrawn if the originator has debt. * `EigenPodManager` withdrawals received as tokens: * Before the withdrawal can be completed, the originator needs to prove that a withdrawal occurred on the beacon chain (see [`EigenPod.verifyAndProcessWithdrawals`](./EigenPodManager.md#eigenpodverifyandprocesswithdrawals)). @@ -288,10 +263,10 @@ For each strategy/share pair in the `Withdrawal`: * See [`EigenPodManager.withdrawSharesAsTokens`](./EigenPodManager.md#eigenpodmanagerwithdrawsharesastokens) * If `!receiveAsTokens`: * For `StrategyManager` strategies: - * Shares are awarded to the `withdrawer` and delegated to the `withdrawer's` Operator + * OwnedShares are awarded to the `withdrawer` and delegated to the `withdrawer's` Operator * See [`StrategyManager.addShares`](./StrategyManager.md#addshares) * For the native beacon chain ETH strategy (`EigenPodManager`): - * Shares are awarded to `withdrawal.staker`, and delegated to the Staker's Operator + * OwnedShares are awarded to `withdrawal.staker`, and delegated to the Staker's Operator * See [`EigenPodManager.addShares`](./EigenPodManager.md#eigenpodmanageraddshares) *Requirements*: diff --git a/docs/core/EigenPod.md b/docs/core/EigenPod.md index b33e5d5da..4c80c7fe3 100644 --- a/docs/core/EigenPod.md +++ b/docs/core/EigenPod.md @@ -150,7 +150,7 @@ Checkpoint proofs comprise the bulk of proofs submitted to an `EigenPod`. Comple * when the pod has accumulated fees / partial withdrawals from validators * whether any validators on the beacon chain have increased/decreased in balance -When a checkpoint is completed, shares are updated accordingly for each of these events. Shares can be withdrawn via the `DelegationManager` withdrawal queue (see [DelegationManager: Undelegating and Withdrawing](./DelegationManager.md#undelegating-and-withdrawing)), which means an `EigenPod's` checkpoint proofs also play an important role in allowing Pod Owners to exit funds from the system. +When a checkpoint is completed, shares are updated accordingly for each of these events. OwnedShares can be withdrawn via the `DelegationManager` withdrawal queue (see [DelegationManager: Undelegating and Withdrawing](./DelegationManager.md#undelegating-and-withdrawing)), which means an `EigenPod's` checkpoint proofs also play an important role in allowing Pod Owners to exit funds from the system. _Important Notes:_ * `EigenPods` can only have **one active checkpoint** at a given time, and once started, checkpoints **cannot be cancelled** (only completed) diff --git a/docs/release/slashing/AVSDirectory.md b/docs/release/slashing/AVSDirectory.md new file mode 100644 index 000000000..f55178f9a --- /dev/null +++ b/docs/release/slashing/AVSDirectory.md @@ -0,0 +1,145 @@ +# AVSDirectory + +## Overview + +The AVSDirectory contract is where registration relationships are defined between AVSs, operatorSets, and operators. Registration and deregistration are used in the protocol to activate and deactivate slashable stake allocations. They're also used to make the protocol more legible to external integrations. + +The slashing release introduces the concept of operatorSets, which are simply an (address, uint32) pair that the define an AVS and an operator set ID. OperatorSets are used to group operators by different tasks and sets of tokens. For example, EigenDA has an ETH/LST operatorSet and an Eigen operatorSet. A bridge may have on operatorSet for all operators that serve a particular chain. Overall, operatorSets are mainly used for protocol legibility. + +Functionality is provided for AVSs to migrate from an pre-operatorSet registration model to an operatorSet model. Direct to AVS registration is still supported for AVSs that have not migrated to the operatorSet model, but is slated to be deprecated soon in the future. + +## `becomeOperatorSetAVS` +```solidity +/** + * @notice Sets the AVS as an operator set AVS, preventing legacy M2 operator registrations. + * + * @dev msg.sender must be the AVS. + */ +function becomeOperatorSetAVS() external; +``` + +AVSs call this to become an operator set AVS. Once an AVS becomes an operator set AVS, they can no longer register operators via the legacy M2 registration path. This is a seperate function to help avoid accidental migrations to the operator set AVS model. + +## `createOperatorSets` +```solidity +/** + * @notice Called by an AVS to create a list of new operatorSets. + * + * @param operatorSetIds The IDs of the operator set to initialize. + * + * @dev msg.sender must be the AVS. + */ +function createOperatorSets( + uint32[] calldata operatorSetIds +) external; +``` + +AVSs use this function to create a list of new operator sets.They must call this function before they add any operators to the operator sets. The operator set IDs must be not already exist. + +This can be called before the AVS becomes an operator set AVS. (TODO: we should make this so that it can only be called after the AVS becomes an operator set AVS?) + +## `migrateOperatorsToOperatorSets` +```solidity +/** + * @notice Called by an AVS to migrate operators that have a legacy M2 registration to operator sets. + * + * @param operators The list of operators to migrate + * @param operatorSetIds The list of operatorSets to migrate the operators to + * + * @dev The msg.sender used is the AVS + * @dev The operator can only be migrated at most once per AVS + * @dev The AVS can no longer register operators via the legacy M2 registration path once it begins migration + * @dev The operator is deregistered from the M2 legacy AVS once migrated + */ +function migrateOperatorsToOperatorSets( + address[] calldata operators, + uint32[][] calldata operatorSetIds +) external; +``` + +AVSs that launched before the slashing release can use this function to migrate operators that have a legacy M2 registration to operator sets. Each operator can only be migrated once for the AVS and the AVS can no longer register operators via the legacy M2 registration path once it begins migration. + +## `registerOperatorToOperatorSets` +```solidity +/** + * @notice Called by AVSs to add an operator to list of operatorSets. + * + * @param operator The address of the operator to be added to the operator set. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature The signature of the operator on their intent to register. + * + * @dev msg.sender is used as the AVS. + */ +function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature +) external; +``` + +AVSs use this function to add an operator to a list of operator sets. The operator's signature is required to confirm their intent to register. If the operator has a slashable stake allocation to the AVS, it takes effect when the operator is registered (and up to `DEALLOCATION_DELAY` seconds after the operator is deregistered). + +The operator set must exist before the operator can be added to it and the AVS must be an operator set AVS. + +## `deregisterOperatorFromOperatorSets` +```solidity +/** + * @notice Called by AVSs to remove an operator from an operator set. + * + * @param operator The address of the operator to be removed from the operator set. + * @param operatorSetIds The IDs of the operator sets. + * + * @dev msg.sender is used as the AVS. + */ +function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external; +``` + +AVSs use this function to remove an operator from an operator set. The operator is still slashable for its slashable stake allocation to the AVS until `DEALLOCATION_DELAY` seconds after the operator is deregistered. + +The operator must be registered to the operator set before they can be deregistered from it. + + +## `forceDeregisterFromOperatorSets` +```solidity +/** + * @notice Called by an operator to deregister from an operator set + * + * @param operator The operator to deregister from the operatorSets. + * @param avs The address of the AVS to deregister the operator from. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature the signature of the operator on their intent to deregister or empty if the operator itself is calling + * + * @dev if the operatorSignature is empty, the caller must be the operator + * @dev this will likely only be called in case the AVS contracts are in a state that prevents operators from deregistering + */ +function forceDeregisterFromOperatorSets( + address operator, + address avs, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature +) external; +``` + +Operators can use this function to deregister from an operator set without requiring the AVS to sign off on the deregistration. This function is intended to be used in cases where the AVS contracts are in a state that prevents operators from deregistering (either malicious or unintentional). + +Operators can also deallocate their slashable stake allocation seperately to avoid slashing risk, so this function is mainly for external integrations to interpret the correct state of the protocol. + +## `updateAVSMetadataURI` +```solidity +/** + * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated. + * + * @param metadataURI The URI for metadata associated with an AVS. + * + * @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event. + */ +function updateAVSMetadataURI( + string calldata metadataURI +) external; +``` + +This function allows an AVS to update the metadata URI associated with the AVS. The metadata URI is never stored on-chain and is only emitted in the `AVSMetadataURIUpdated` event. + +## View Functions + +See the [AVS Directory Inteface](../../../src/contracts/interfaces/IAVSDirectory.sol) for view functions. \ No newline at end of file diff --git a/docs/release/slashing/AllocationManager.md b/docs/release/slashing/AllocationManager.md new file mode 100644 index 000000000..945432fb3 --- /dev/null +++ b/docs/release/slashing/AllocationManager.md @@ -0,0 +1,169 @@ +# AllocationManager + +## Prerequisites + +- [The Mechanics of Allocating and Slashing Unique Stake](https://forum.eigenlayer.xyz/t/the-mechanics-of-allocating-and-slashing-unique-stake/13870) + +## Overview +The AllocationManager contract manages the allocation and reallocation of operators' slashable stake across various strategies and operator sets. It enforces allocation and deallocation delays and handles the slashing process initiated by AVSs. + +## Parameterization + +- `ALLOCATION_CONFIGURATION_DELAY`: The delay in seconds before allocations take effect. + - Mainnet: `21 days`. Very TBD + - Testnet: `1 hour`. Very TBD + - Public Devnet: `10 minutes` +- `DEALLOCATION_DELAY`: The delay in seconds before deallocations take effect. + - Mainnet: `17.5 days`. Slightly TBD + - Testnet: `3 days`. Very TBD + - Public Devnet: `1 days` + +## `setAllocationDelay` + +```solidity +/** + * @notice Called by operators or the delegation manager to set their allocation delay. + * @param operator The operator to set the delay on behalf of. + * @param delay The allocation delay in seconds. + */ +function setAllocationDelay(address operator, uint32 delay) external; + +These functions allow operators to set their allocation delay. The first variant is called by the DelegationManager upon operator registration for all new operators created after the slashing release. The second variant is called by operators themselves to update their allocation delay or set it for the first time if they joined before the slashing release. + +The allocation delay takes effect in `ALLOCATION_CONFIGURATION_DELAY` seconds. + +The allocation delay can be any positive uint32. + +The allocation delay's primary purpose is to give stakers delegated to an operator the chance to withdraw their stake before the operator can change the risk profile to something they're not comfortable with. + +## `modifyAllocations` + +```solidity +/** + * @notice struct used to modify the allocation of slashable magnitude to list of operatorSets + * @param strategy the strategy to allocate magnitude for + * @param expectedMaxMagnitude the expected max magnitude of the operator used to combat against race conditions with slashing + * @param operatorSets the operatorSets to allocate magnitude for + * @param magnitudes the magnitudes to allocate for each operatorSet + */ +struct MagnitudeAllocation { + IStrategy strategy; + uint64 expectedMaxMagnitude; + OperatorSet[] operatorSets; + uint64[] magnitudes; +} + +/** + * @notice Modifies the propotions of slashable stake allocated to a list of operatorSets for a set of strategies + * @param allocations array of magnitude adjustments for multiple strategies and corresponding operator sets + * @dev Updates encumberedMagnitude for the updated strategies + * @dev msg.sender is used as operator + */ +function modifyAllocations(MagnitudeAllocation[] calldata allocations) external +``` + +This function is called by operators to adjust the proportions of their slashable stake allocated to different operator sets for different strategies. + +The operator provides their expected max magnitude for each strategy they're adjusting the allocation for. This is used to combat race conditions with slashings for the strategy, which may result in larger than expected slashable proportions allocated to operator sets. + +Each `(operator, operatorSet, strategy)` tuple can have at most 1 pending modification at a time. The function will revert is there is a pending modification for any of the tuples in the input. + +The contract keeps track of the total magnitude in pending allocations, active allocations, and pending deallocations. This is called the **_encumbered magnitude_** for a strategy. The contract verifies that the allocations made in this call do not make the encumbered magnitude exceed the operator's max magnitude for the strategy. If the encumbered magnitude exceeds the max magnitude, the function reverts. + +Any _allocations_ (i.e. increases in the proportion of slashable stake allocated to an AVS) take effect after the operator's allocation delay. The allocation delay must be set for the operator before they can call this function. + +Any _deallocations_ (i.e. decreases in the proportion of slashable stake allocated to an AVS) take effect after `DEALLOCATION_DELAY` seconds. This enables AVSs enough time to update their view of stakes to the new proportions and have any tasks created against previous stakes to expire. + +## `clearDeallocationQueue` + +```solidity +/** + * @notice This function takes a list of strategies and adds all completable deallocations for each strategy, + * updating the encumberedMagnitude of the operator as needed. + * + * @param operator address to complete deallocations for + * @param strategies a list of strategies to complete deallocations for + * @param numToComplete a list of number of pending deallocations to complete for each strategy + * + * @dev can be called permissionlessly by anyone + */ +function clearDeallocationQueue( + address operator, + IStrategy[] calldata strategies, + uint16[] calldata numToComplete +) external; +``` + +This function is used to complete pending deallocations for a list of strategies for an operator. The function takes a list of strategies and the number of pending deallocations to complete for each strategy. For each strategy, the function completes pending deallocations if their effect timestamps have passed. + +Completing a deallocation decreases the encumbered magnitude for the strategy, allowing them to make allocations with that magnitude. Encumbered magnitude must be decreased only upon completion because pending deallocations can be slashed before they are completable. + +## `slashOperator` + +```solidity +/** + * @notice Struct containing parameters to slashing + * @param operator the address to slash + * @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of + * @param strategies the set of strategies to slash + * @param wadToSlash the parts in 1e18 to slash, this will be proportional to the operator's + * slashable stake allocation for the operatorSet + * @param description the description of the slashing provided by the AVS for legibility + */ +struct SlashingParams { + address operator; + uint32 operatorSetId; + IStrategy[] strategies; + uint256 wadToSlash; + string description; +} + +/** + * @notice Called by an AVS to slash an operator for given operatorSetId, list of strategies, and wadToSlash. + * For each given (operator, operatorSetId, strategy) tuple, bipsToSlash + * bips of the operatorSet's slashable stake allocation will be slashed + * + * @param operator the address to slash + * @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of + * @param strategies the set of strategies to slash + * @param wadToSlash the parts in 1e18 to slash, this will be proportional to the + * operator's slashable stake allocation for the operatorSet + * @param description the description of the slashing provided by the AVS for legibility + */ +function slashOperator( + SlashingParams calldata params +) external +``` + +This function is called by AVSs to slash an operator for a given operator set and list of strategies. The AVS provides the proportion of the operator's slashable stake allocation to slash for each strategy. The proportion is given in parts in 1e18 and is with respect to the operator's _current_ slashable stake allocation for the operator set (i.e. `wadsToSlash=5e17` means 50% of the operator's slashable stake allocation for the operator set will be slashed). The AVS also provides a description of the slashing for legibility by outside integrations. + +Slashing is instant and irreversable. Slashed funds remain unrecoverable in the protocol but will be burned/redistributed in a future release. Slashing by one operatorSet does not effect the slashable stake allocation of other operatorSets for the same operator and strategy. + +Slashing updates storage in a way that instantly updates all view functions to reflect the correct values. + +## View Functions + +### `getMinDelegatedAndSlashableOperatorSharesBefore` + +```solidity +/** + * @notice returns the minimum operatorShares and the slashableOperatorShares for an operator, list of strategies, + * and an operatorSet before a given timestamp. This is used to get the shares to weight operators by given ones slashing window. + * @param operatorSet the operatorSet to get the shares for + * @param operators the operators to get the shares for + * @param strategies the strategies to get the shares for + * @param beforeTimestamp the timestamp to get the shares at + */ +function getMinDelegatedAndSlashableOperatorSharesBefore( + OperatorSet calldata operatorSet, + address[] calldata operators, + IStrategy[] calldata strategies, + uint32 beforeTimestamp +) external view returns (uint256[][] memory, uint256[][] memory) +``` + +This function returns the minimum operator shares and the slashable operator shares for an operator, list of strategies, and an operator set before a given timestamp. This is used by AVSs to pessimistically estimate the operator's slashable stake allocation for a given strategy and operator set within their slashability windows. If an AVS calls this function every week and creates tasks that are slashable for a week after they're created, then `beforeTimestamp` should be 2 weeks in the future to account for the latest task that may be created against stale stakes. More on this in new docs soon. + +### Additional View Functions + +See the [AllocationManager Interface](../../../src/contracts/interfaces/IAllocationManager.sol) for additional view functions. \ No newline at end of file diff --git a/docs/storage-report/AVSDirectory.md b/docs/storage-report/AVSDirectory.md index cf36169ac..349366030 100644 --- a/docs/storage-report/AVSDirectory.md +++ b/docs/storage-report/AVSDirectory.md @@ -1,16 +1,16 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|---------------------|------------------------------------------------------------------------------------------|------|--------|-------|--------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| _initializing | bool | 0 | 1 | 1 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| _owner | address | 51 | 0 | 20 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| _paused | uint256 | 102 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| _DOMAIN_SEPARATOR | bytes32 | 151 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| avsOperatorStatus | mapping(address => mapping(address => enum IAVSDirectory.OperatorAVSRegistrationStatus)) | 152 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| operatorSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 153 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| __gap | uint256[47] | 154 | 0 | 1504 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| _status | uint256 | 201 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | -| __gap | uint256[49] | 202 | 0 | 1568 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| Name | Type | Slot | Offset | Bytes | Contract | +|-------------------------------|-----------------------------------------------------------------------------------------------|------|--------|-------|--------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| _initializing | bool | 0 | 1 | 1 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| _owner | address | 51 | 0 | 20 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __deprecated_pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| _paused | uint256 | 102 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 151 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| avsOperatorStatus | mapping(address => mapping(address => enum IAVSDirectoryTypes.OperatorAVSRegistrationStatus)) | 152 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| operatorSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 153 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __gap | uint256[41] | 154 | 0 | 1312 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| _status | uint256 | 195 | 0 | 32 | src/contracts/core/AVSDirectory.sol:AVSDirectory | +| __gap | uint256[49] | 196 | 0 | 1568 | src/contracts/core/AVSDirectory.sol:AVSDirectory | diff --git a/docs/storage-report/AVSDirectoryStorage.md b/docs/storage-report/AVSDirectoryStorage.md index a337342d0..3e02bf7f2 100644 --- a/docs/storage-report/AVSDirectoryStorage.md +++ b/docs/storage-report/AVSDirectoryStorage.md @@ -1,6 +1,6 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|---------------------|------------------------------------------------------------------------------------------|------|--------|-------|----------------------------------------------------------------| -| _DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | -| avsOperatorStatus | mapping(address => mapping(address => enum IAVSDirectory.OperatorAVSRegistrationStatus)) | 1 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | -| operatorSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 2 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | -| __gap | uint256[47] | 3 | 0 | 1504 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | +| Name | Type | Slot | Offset | Bytes | Contract | +|-------------------------------|-----------------------------------------------------------------------------------------------|------|--------|-------|----------------------------------------------------------------| +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | +| avsOperatorStatus | mapping(address => mapping(address => enum IAVSDirectoryTypes.OperatorAVSRegistrationStatus)) | 1 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | +| operatorSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 2 | 0 | 32 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | +| __gap | uint256[41] | 3 | 0 | 1312 | src/contracts/core/AVSDirectoryStorage.sol:AVSDirectoryStorage | diff --git a/docs/storage-report/AllocationManager.md b/docs/storage-report/AllocationManager.md new file mode 100644 index 000000000..5af24bfff --- /dev/null +++ b/docs/storage-report/AllocationManager.md @@ -0,0 +1,26 @@ +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|------------------------------------------------------------------------------------------------------------------|------|--------|-------|------------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _initializing | bool | 0 | 1 | 1 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _owner | address | 51 | 0 | 20 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __deprecated_pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _paused | uint256 | 102 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _avsRegistrar | mapping(address => contract IAVSRegistrar) | 151 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _operatorSets | mapping(address => struct EnumerableSet.UintSet) | 152 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _operatorSetStrategies | mapping(bytes32 => struct EnumerableSet.AddressSet) | 153 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _operatorSetMembers | mapping(bytes32 => struct EnumerableSet.AddressSet) | 154 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _allocationDelayInfo | mapping(address => struct IAllocationManagerTypes.AllocationDelayInfo) | 155 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| registeredSets | mapping(address => struct EnumerableSet.Bytes32Set) | 156 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| allocatedSets | mapping(address => struct EnumerableSet.Bytes32Set) | 157 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| registrationStatus | mapping(address => mapping(bytes32 => struct IAllocationManagerTypes.RegistrationStatus)) | 158 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| allocatedStrategies | mapping(address => mapping(bytes32 => struct EnumerableSet.AddressSet)) | 159 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| allocations | mapping(address => mapping(bytes32 => mapping(contract IStrategy => struct IAllocationManagerTypes.Allocation))) | 160 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _maxMagnitudeHistory | mapping(address => mapping(contract IStrategy => struct Snapshots.DefaultWadHistory)) | 161 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| encumberedMagnitude | mapping(address => mapping(contract IStrategy => uint64)) | 162 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| deallocationQueue | mapping(address => mapping(contract IStrategy => struct DoubleEndedQueue.Bytes32Deque)) | 163 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __gap | uint256[37] | 164 | 0 | 1184 | src/contracts/core/AllocationManager.sol:AllocationManager | +| _status | uint256 | 201 | 0 | 32 | src/contracts/core/AllocationManager.sol:AllocationManager | +| __gap | uint256[49] | 202 | 0 | 1568 | src/contracts/core/AllocationManager.sol:AllocationManager | diff --git a/docs/storage-report/AllocationManagerStorage.md b/docs/storage-report/AllocationManagerStorage.md new file mode 100644 index 000000000..6d099d44f --- /dev/null +++ b/docs/storage-report/AllocationManagerStorage.md @@ -0,0 +1,16 @@ +| Name | Type | Slot | Offset | Bytes | Contract | +|------------------------|------------------------------------------------------------------------------------------------------------------|------|--------|-------|--------------------------------------------------------------------------| +| _avsRegistrar | mapping(address => contract IAVSRegistrar) | 0 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| _operatorSets | mapping(address => struct EnumerableSet.UintSet) | 1 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| _operatorSetStrategies | mapping(bytes32 => struct EnumerableSet.AddressSet) | 2 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| _operatorSetMembers | mapping(bytes32 => struct EnumerableSet.AddressSet) | 3 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| _allocationDelayInfo | mapping(address => struct IAllocationManagerTypes.AllocationDelayInfo) | 4 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| registeredSets | mapping(address => struct EnumerableSet.Bytes32Set) | 5 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| allocatedSets | mapping(address => struct EnumerableSet.Bytes32Set) | 6 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| registrationStatus | mapping(address => mapping(bytes32 => struct IAllocationManagerTypes.RegistrationStatus)) | 7 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| allocatedStrategies | mapping(address => mapping(bytes32 => struct EnumerableSet.AddressSet)) | 8 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| allocations | mapping(address => mapping(bytes32 => mapping(contract IStrategy => struct IAllocationManagerTypes.Allocation))) | 9 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| _maxMagnitudeHistory | mapping(address => mapping(contract IStrategy => struct Snapshots.DefaultWadHistory)) | 10 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| encumberedMagnitude | mapping(address => mapping(contract IStrategy => uint64)) | 11 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| deallocationQueue | mapping(address => mapping(contract IStrategy => struct DoubleEndedQueue.Bytes32Deque)) | 12 | 0 | 32 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | +| __gap | uint256[37] | 13 | 0 | 1184 | src/contracts/core/AllocationManagerStorage.sol:AllocationManagerStorage | diff --git a/docs/storage-report/BackingEigen.md b/docs/storage-report/BackingEigen.md index 14adcdc6e..648f111b2 100644 --- a/docs/storage-report/BackingEigen.md +++ b/docs/storage-report/BackingEigen.md @@ -26,3 +26,4 @@ | transferRestrictionsDisabledAfter | uint256 | 304 | 0 | 32 | src/contracts/token/BackingEigen.sol:BackingEigen | | allowedFrom | mapping(address => bool) | 305 | 0 | 32 | src/contracts/token/BackingEigen.sol:BackingEigen | | allowedTo | mapping(address => bool) | 306 | 0 | 32 | src/contracts/token/BackingEigen.sol:BackingEigen | +| isMinter | mapping(address => bool) | 307 | 0 | 32 | src/contracts/token/BackingEigen.sol:BackingEigen | diff --git a/docs/storage-report/DelegationManager.md b/docs/storage-report/DelegationManager.md index 61594f32a..fe037fae0 100644 --- a/docs/storage-report/DelegationManager.md +++ b/docs/storage-report/DelegationManager.md @@ -1,24 +1,29 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-------------------------------|---------------------------------------------------------------|------|--------|-------|------------------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _initializing | bool | 0 | 1 | 1 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _owner | address | 51 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/DelegationManager.sol:DelegationManager | -| pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _paused | uint256 | 102 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _DOMAIN_SEPARATOR | bytes32 | 151 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| operatorShares | mapping(address => mapping(contract IStrategy => uint256)) | 152 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _operatorDetails | mapping(address => struct IDelegationManager.OperatorDetails) | 153 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| delegatedTo | mapping(address => address) | 154 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| stakerNonce | mapping(address => uint256) | 155 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| delegationApproverSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 156 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| minWithdrawalDelayBlocks | uint256 | 157 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| pendingWithdrawals | mapping(bytes32 => bool) | 158 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| cumulativeWithdrawalsQueued | mapping(address => uint256) | 159 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __deprecated_stakeRegistry | address | 160 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | -| strategyWithdrawalDelayBlocks | mapping(contract IStrategy => uint256) | 161 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __gap | uint256[39] | 162 | 0 | 1248 | src/contracts/core/DelegationManager.sol:DelegationManager | -| _status | uint256 | 201 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | -| __gap | uint256[49] | 202 | 0 | 1568 | src/contracts/core/DelegationManager.sol:DelegationManager | +| Name | Type | Slot | Offset | Bytes | Contract | +|--------------------------------------------|---------------------------------------------------------------------------------------|------|--------|-------|------------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _initializing | bool | 0 | 1 | 1 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _owner | address | 51 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _paused | uint256 | 102 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 151 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| operatorShares | mapping(address => mapping(contract IStrategy => uint256)) | 152 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _operatorDetails | mapping(address => struct IDelegationManagerTypes.OperatorDetails) | 153 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| delegatedTo | mapping(address => address) | 154 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_stakerNonce | mapping(address => uint256) | 155 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| delegationApproverSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 156 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_minWithdrawalDelayBlocks | uint256 | 157 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| pendingWithdrawals | mapping(bytes32 => bool) | 158 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| cumulativeWithdrawalsQueued | mapping(address => uint256) | 159 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_stakeRegistry | address | 160 | 0 | 20 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __deprecated_strategyWithdrawalDelayBlocks | mapping(contract IStrategy => uint256) | 161 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _depositScalingFactor | mapping(address => mapping(contract IStrategy => struct DepositScalingFactor)) | 162 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _beaconChainSlashingFactor | mapping(address => struct IDelegationManagerTypes.BeaconChainSlashingFactor) | 163 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _stakerQueuedWithdrawalRoots | mapping(address => struct EnumerableSet.Bytes32Set) | 164 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| queuedWithdrawals | mapping(bytes32 => struct IDelegationManagerTypes.Withdrawal) | 165 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _cumulativeScaledSharesHistory | mapping(address => mapping(contract IStrategy => struct Snapshots.WithdrawalHistory)) | 166 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __gap | uint256[34] | 167 | 0 | 1088 | src/contracts/core/DelegationManager.sol:DelegationManager | +| _status | uint256 | 201 | 0 | 32 | src/contracts/core/DelegationManager.sol:DelegationManager | +| __gap | uint256[49] | 202 | 0 | 1568 | src/contracts/core/DelegationManager.sol:DelegationManager | diff --git a/docs/storage-report/DelegationManagerStorage.md b/docs/storage-report/DelegationManagerStorage.md index 2ae1eb04b..c91985146 100644 --- a/docs/storage-report/DelegationManagerStorage.md +++ b/docs/storage-report/DelegationManagerStorage.md @@ -1,14 +1,19 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-------------------------------|---------------------------------------------------------------|------|--------|-------|--------------------------------------------------------------------------| -| _DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| operatorShares | mapping(address => mapping(contract IStrategy => uint256)) | 1 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| _operatorDetails | mapping(address => struct IDelegationManager.OperatorDetails) | 2 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| delegatedTo | mapping(address => address) | 3 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| stakerNonce | mapping(address => uint256) | 4 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| delegationApproverSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 5 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| minWithdrawalDelayBlocks | uint256 | 6 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| pendingWithdrawals | mapping(bytes32 => bool) | 7 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| cumulativeWithdrawalsQueued | mapping(address => uint256) | 8 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| __deprecated_stakeRegistry | address | 9 | 0 | 20 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| strategyWithdrawalDelayBlocks | mapping(contract IStrategy => uint256) | 10 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | -| __gap | uint256[39] | 11 | 0 | 1248 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| Name | Type | Slot | Offset | Bytes | Contract | +|--------------------------------------------|---------------------------------------------------------------------------------------|------|--------|-------|--------------------------------------------------------------------------| +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| operatorShares | mapping(address => mapping(contract IStrategy => uint256)) | 1 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| _operatorDetails | mapping(address => struct IDelegationManagerTypes.OperatorDetails) | 2 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| delegatedTo | mapping(address => address) | 3 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| __deprecated_stakerNonce | mapping(address => uint256) | 4 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| delegationApproverSaltIsSpent | mapping(address => mapping(bytes32 => bool)) | 5 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| __deprecated_minWithdrawalDelayBlocks | uint256 | 6 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| pendingWithdrawals | mapping(bytes32 => bool) | 7 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| cumulativeWithdrawalsQueued | mapping(address => uint256) | 8 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| __deprecated_stakeRegistry | address | 9 | 0 | 20 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| __deprecated_strategyWithdrawalDelayBlocks | mapping(contract IStrategy => uint256) | 10 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| _depositScalingFactor | mapping(address => mapping(contract IStrategy => struct DepositScalingFactor)) | 11 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| _beaconChainSlashingFactor | mapping(address => struct IDelegationManagerTypes.BeaconChainSlashingFactor) | 12 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| _stakerQueuedWithdrawalRoots | mapping(address => struct EnumerableSet.Bytes32Set) | 13 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| queuedWithdrawals | mapping(bytes32 => struct IDelegationManagerTypes.Withdrawal) | 14 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| _cumulativeScaledSharesHistory | mapping(address => mapping(contract IStrategy => struct Snapshots.WithdrawalHistory)) | 15 | 0 | 32 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | +| __gap | uint256[34] | 16 | 0 | 1088 | src/contracts/core/DelegationManagerStorage.sol:DelegationManagerStorage | diff --git a/docs/storage-report/EigenPod.md b/docs/storage-report/EigenPod.md index 02b88e0c6..c54eb750a 100644 --- a/docs/storage-report/EigenPod.md +++ b/docs/storage-report/EigenPod.md @@ -1,21 +1,21 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-------------------------------------------------|----------------------------------------------------|------|--------|-------|------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | -| _initializing | bool | 0 | 1 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | -| _status | uint256 | 1 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| __gap | uint256[49] | 2 | 0 | 1568 | src/contracts/pods/EigenPod.sol:EigenPod | -| podOwner | address | 51 | 0 | 20 | src/contracts/pods/EigenPod.sol:EigenPod | -| __deprecated_mostRecentWithdrawalTimestamp | uint64 | 51 | 20 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | -| withdrawableRestakedExecutionLayerGwei | uint64 | 52 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | -| __deprecated_hasRestaked | bool | 52 | 8 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | -| __deprecated_provenWithdrawal | mapping(bytes32 => mapping(uint64 => bool)) | 53 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| _validatorPubkeyHashToInfo | mapping(bytes32 => struct IEigenPod.ValidatorInfo) | 54 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| __deprecated_nonBeaconChainETHBalanceWei | uint256 | 55 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| __deprecated_sumOfPartialWithdrawalsClaimedGwei | uint64 | 56 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | -| activeValidatorCount | uint256 | 57 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| lastCheckpointTimestamp | uint64 | 58 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | -| currentCheckpointTimestamp | uint64 | 58 | 8 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | -| checkpointBalanceExitedGwei | mapping(uint64 => uint64) | 59 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | -| _currentCheckpoint | struct IEigenPod.Checkpoint | 60 | 0 | 64 | src/contracts/pods/EigenPod.sol:EigenPod | -| proofSubmitter | address | 62 | 0 | 20 | src/contracts/pods/EigenPod.sol:EigenPod | -| __gap | uint256[36] | 63 | 0 | 1152 | src/contracts/pods/EigenPod.sol:EigenPod | +| Name | Type | Slot | Offset | Bytes | Contract | +|-------------------------------------------------|---------------------------------------------------------|------|--------|-------|------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | +| _initializing | bool | 0 | 1 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | +| _status | uint256 | 1 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| __gap | uint256[49] | 2 | 0 | 1568 | src/contracts/pods/EigenPod.sol:EigenPod | +| podOwner | address | 51 | 0 | 20 | src/contracts/pods/EigenPod.sol:EigenPod | +| __deprecated_mostRecentWithdrawalTimestamp | uint64 | 51 | 20 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | +| withdrawableRestakedExecutionLayerGwei | uint64 | 52 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | +| __deprecated_hasRestaked | bool | 52 | 8 | 1 | src/contracts/pods/EigenPod.sol:EigenPod | +| __deprecated_provenWithdrawal | mapping(bytes32 => mapping(uint64 => bool)) | 53 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| _validatorPubkeyHashToInfo | mapping(bytes32 => struct IEigenPodTypes.ValidatorInfo) | 54 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| __deprecated_nonBeaconChainETHBalanceWei | uint256 | 55 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| __deprecated_sumOfPartialWithdrawalsClaimedGwei | uint64 | 56 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | +| activeValidatorCount | uint256 | 57 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| lastCheckpointTimestamp | uint64 | 58 | 0 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | +| currentCheckpointTimestamp | uint64 | 58 | 8 | 8 | src/contracts/pods/EigenPod.sol:EigenPod | +| checkpointBalanceExitedGwei | mapping(uint64 => uint64) | 59 | 0 | 32 | src/contracts/pods/EigenPod.sol:EigenPod | +| _currentCheckpoint | struct IEigenPodTypes.Checkpoint | 60 | 0 | 64 | src/contracts/pods/EigenPod.sol:EigenPod | +| proofSubmitter | address | 62 | 0 | 20 | src/contracts/pods/EigenPod.sol:EigenPod | +| __gap | uint256[35] | 63 | 0 | 1120 | src/contracts/pods/EigenPod.sol:EigenPod | diff --git a/docs/storage-report/EigenPodManager.md b/docs/storage-report/EigenPodManager.md index e4df1d088..4ca04143f 100644 --- a/docs/storage-report/EigenPodManager.md +++ b/docs/storage-report/EigenPodManager.md @@ -5,14 +5,14 @@ | __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | _owner | address | 51 | 0 | 20 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | -| pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | +| __deprecated_pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | _paused | uint256 | 102 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __deprecated_beaconChainOracle | address | 151 | 0 | 20 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | ownerToPod | mapping(address => contract IEigenPod) | 152 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | numPods | uint256 | 153 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __deprecated_maxPods | uint256 | 154 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | -| podOwnerShares | mapping(address => int256) | 155 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | +| podOwnerDepositShares | mapping(address => int256) | 155 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __deprecated_denebForkTimestamp | uint64 | 156 | 0 | 8 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | __gap | uint256[44] | 157 | 0 | 1408 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | | _status | uint256 | 201 | 0 | 32 | src/contracts/pods/EigenPodManager.sol:EigenPodManager | diff --git a/docs/storage-report/EigenPodManagerStorage.md b/docs/storage-report/EigenPodManagerStorage.md index 8ada2fbef..33625ee6b 100644 --- a/docs/storage-report/EigenPodManagerStorage.md +++ b/docs/storage-report/EigenPodManagerStorage.md @@ -4,6 +4,6 @@ | ownerToPod | mapping(address => contract IEigenPod) | 1 | 0 | 32 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | | numPods | uint256 | 2 | 0 | 32 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | | __deprecated_maxPods | uint256 | 3 | 0 | 32 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | -| podOwnerShares | mapping(address => int256) | 4 | 0 | 32 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | +| podOwnerDepositShares | mapping(address => int256) | 4 | 0 | 32 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | | __deprecated_denebForkTimestamp | uint64 | 5 | 0 | 8 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | | __gap | uint256[44] | 6 | 0 | 1408 | src/contracts/pods/EigenPodManagerStorage.sol:EigenPodManagerStorage | diff --git a/docs/storage-report/EigenPodStorage.md b/docs/storage-report/EigenPodStorage.md index f0ddef8ed..fa5d04cd3 100644 --- a/docs/storage-report/EigenPodStorage.md +++ b/docs/storage-report/EigenPodStorage.md @@ -1,17 +1,17 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-------------------------------------------------|----------------------------------------------------|------|--------|-------|--------------------------------------------------------| -| podOwner | address | 0 | 0 | 20 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __deprecated_mostRecentWithdrawalTimestamp | uint64 | 0 | 20 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| withdrawableRestakedExecutionLayerGwei | uint64 | 1 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __deprecated_hasRestaked | bool | 1 | 8 | 1 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __deprecated_provenWithdrawal | mapping(bytes32 => mapping(uint64 => bool)) | 2 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| _validatorPubkeyHashToInfo | mapping(bytes32 => struct IEigenPod.ValidatorInfo) | 3 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __deprecated_nonBeaconChainETHBalanceWei | uint256 | 4 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __deprecated_sumOfPartialWithdrawalsClaimedGwei | uint64 | 5 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| activeValidatorCount | uint256 | 6 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| lastCheckpointTimestamp | uint64 | 7 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| currentCheckpointTimestamp | uint64 | 7 | 8 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| checkpointBalanceExitedGwei | mapping(uint64 => uint64) | 8 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| _currentCheckpoint | struct IEigenPod.Checkpoint | 9 | 0 | 64 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| proofSubmitter | address | 11 | 0 | 20 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | -| __gap | uint256[36] | 12 | 0 | 1152 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| Name | Type | Slot | Offset | Bytes | Contract | +|-------------------------------------------------|---------------------------------------------------------|------|--------|-------|--------------------------------------------------------| +| podOwner | address | 0 | 0 | 20 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __deprecated_mostRecentWithdrawalTimestamp | uint64 | 0 | 20 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| withdrawableRestakedExecutionLayerGwei | uint64 | 1 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __deprecated_hasRestaked | bool | 1 | 8 | 1 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __deprecated_provenWithdrawal | mapping(bytes32 => mapping(uint64 => bool)) | 2 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| _validatorPubkeyHashToInfo | mapping(bytes32 => struct IEigenPodTypes.ValidatorInfo) | 3 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __deprecated_nonBeaconChainETHBalanceWei | uint256 | 4 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __deprecated_sumOfPartialWithdrawalsClaimedGwei | uint64 | 5 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| activeValidatorCount | uint256 | 6 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| lastCheckpointTimestamp | uint64 | 7 | 0 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| currentCheckpointTimestamp | uint64 | 7 | 8 | 8 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| checkpointBalanceExitedGwei | mapping(uint64 => uint64) | 8 | 0 | 32 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| _currentCheckpoint | struct IEigenPodTypes.Checkpoint | 9 | 0 | 64 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| proofSubmitter | address | 11 | 0 | 20 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | +| __gap | uint256[35] | 12 | 0 | 1120 | src/contracts/pods/EigenPodStorage.sol:EigenPodStorage | diff --git a/docs/storage-report/EigenStrategy.md b/docs/storage-report/EigenStrategy.md index 5ca2fde70..30425c192 100644 --- a/docs/storage-report/EigenStrategy.md +++ b/docs/storage-report/EigenStrategy.md @@ -1,12 +1,12 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-----------------|--------------------------|------|--------|-------|----------------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| EIGEN | contract IEigen | 100 | 0 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | -| __gap | uint256[49] | 101 | 0 | 1568 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|--------------------------|------|--------|-------|----------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| EIGEN | contract IEigen | 100 | 0 | 20 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | +| __gap | uint256[49] | 101 | 0 | 1568 | src/contracts/strategies/EigenStrategy.sol:EigenStrategy | diff --git a/docs/storage-report/Pausable.md b/docs/storage-report/Pausable.md index 8fc12e109..465bfceef 100644 --- a/docs/storage-report/Pausable.md +++ b/docs/storage-report/Pausable.md @@ -1,5 +1,5 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|----------------|--------------------------|------|--------|-------|-------------------------------------------------| -| pauserRegistry | contract IPauserRegistry | 0 | 0 | 20 | src/contracts/permissions/Pausable.sol:Pausable | -| _paused | uint256 | 1 | 0 | 32 | src/contracts/permissions/Pausable.sol:Pausable | -| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/permissions/Pausable.sol:Pausable | +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|--------------------------|------|--------|-------|-------------------------------------------------| +| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 0 | 20 | src/contracts/permissions/Pausable.sol:Pausable | +| _paused | uint256 | 1 | 0 | 32 | src/contracts/permissions/Pausable.sol:Pausable | +| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/permissions/Pausable.sol:Pausable | diff --git a/docs/storage-report/RewardsCoordinator.md b/docs/storage-report/RewardsCoordinator.md index c3ac38649..fae52cff4 100644 --- a/docs/storage-report/RewardsCoordinator.md +++ b/docs/storage-report/RewardsCoordinator.md @@ -5,13 +5,13 @@ | __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | _owner | address | 51 | 0 | 20 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | -| pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | +| __deprecated_pauserRegistry | contract IPauserRegistry | 101 | 0 | 20 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | _paused | uint256 | 102 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | __gap | uint256[48] | 103 | 0 | 1536 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | _status | uint256 | 151 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | __gap | uint256[49] | 152 | 0 | 1568 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | -| _DOMAIN_SEPARATOR | bytes32 | 201 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | -| _distributionRoots | struct IRewardsCoordinator.DistributionRoot[] | 202 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 201 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | +| _distributionRoots | struct IRewardsCoordinatorTypes.DistributionRoot[] | 202 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | rewardsUpdater | address | 203 | 0 | 20 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | activationDelay | uint32 | 203 | 20 | 4 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | currRewardsCalculationEndTimestamp | uint32 | 203 | 24 | 4 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | @@ -23,4 +23,4 @@ | isRewardsSubmissionForAllHash | mapping(address => mapping(bytes32 => bool)) | 208 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | isRewardsForAllSubmitter | mapping(address => bool) | 209 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | | isRewardsSubmissionForAllEarnersHash | mapping(address => mapping(bytes32 => bool)) | 210 | 0 | 32 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | -| __gap | uint256[39] | 211 | 0 | 1248 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | +| __gap | uint256[40] | 211 | 0 | 1280 | src/contracts/core/RewardsCoordinator.sol:RewardsCoordinator | diff --git a/docs/storage-report/RewardsCoordinatorStorage.md b/docs/storage-report/RewardsCoordinatorStorage.md index e5f8f26bc..94b75a727 100644 --- a/docs/storage-report/RewardsCoordinatorStorage.md +++ b/docs/storage-report/RewardsCoordinatorStorage.md @@ -1,7 +1,7 @@ | Name | Type | Slot | Offset | Bytes | Contract | |--------------------------------------|---------------------------------------------------------|------|--------|-------|----------------------------------------------------------------------------| -| _DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | -| _distributionRoots | struct IRewardsCoordinator.DistributionRoot[] | 1 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | +| _distributionRoots | struct IRewardsCoordinatorTypes.DistributionRoot[] | 1 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | | rewardsUpdater | address | 2 | 0 | 20 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | | activationDelay | uint32 | 2 | 20 | 4 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | | currRewardsCalculationEndTimestamp | uint32 | 2 | 24 | 4 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | @@ -13,4 +13,4 @@ | isRewardsSubmissionForAllHash | mapping(address => mapping(bytes32 => bool)) | 7 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | | isRewardsForAllSubmitter | mapping(address => bool) | 8 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | | isRewardsSubmissionForAllEarnersHash | mapping(address => mapping(bytes32 => bool)) | 9 | 0 | 32 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | -| __gap | uint256[39] | 10 | 0 | 1248 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | +| __gap | uint256[40] | 10 | 0 | 1280 | src/contracts/core/RewardsCoordinatorStorage.sol:RewardsCoordinatorStorage | diff --git a/docs/storage-report/SignatureUtils.md b/docs/storage-report/SignatureUtils.md new file mode 100644 index 000000000..55eed362d --- /dev/null +++ b/docs/storage-report/SignatureUtils.md @@ -0,0 +1,2 @@ +| Name | Type | Slot | Offset | Bytes | Contract | +|------|------|------|--------|-------|----------| diff --git a/docs/storage-report/StrategyBase.md b/docs/storage-report/StrategyBase.md index 0ac0efc41..00d37321b 100644 --- a/docs/storage-report/StrategyBase.md +++ b/docs/storage-report/StrategyBase.md @@ -1,10 +1,10 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|-----------------|--------------------------|------|--------|-------|--------------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/StrategyBase.sol:StrategyBase | -| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|--------------------------|------|--------|-------|--------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/StrategyBase.sol:StrategyBase | +| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/StrategyBase.sol:StrategyBase | diff --git a/docs/storage-report/StrategyBaseTVLLimits.md b/docs/storage-report/StrategyBaseTVLLimits.md index a4bad1456..a9ebdcf63 100644 --- a/docs/storage-report/StrategyBaseTVLLimits.md +++ b/docs/storage-report/StrategyBaseTVLLimits.md @@ -1,13 +1,13 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|------------------|--------------------------|------|--------|-------|--------------------------------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| maxPerDeposit | uint256 | 100 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| maxTotalDeposits | uint256 | 101 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | -| __gap | uint256[48] | 102 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|--------------------------|------|--------|-------|--------------------------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| _initializing | bool | 0 | 1 | 1 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| _paused | uint256 | 1 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| __gap | uint256[48] | 2 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| underlyingToken | contract IERC20 | 50 | 0 | 20 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| totalShares | uint256 | 51 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| __gap | uint256[48] | 52 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| maxPerDeposit | uint256 | 100 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| maxTotalDeposits | uint256 | 101 | 0 | 32 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | +| __gap | uint256[48] | 102 | 0 | 1536 | src/contracts/strategies/StrategyBaseTVLLimits.sol:StrategyBaseTVLLimits | diff --git a/docs/storage-report/StrategyFactory.md b/docs/storage-report/StrategyFactory.md index c3a44b912..56b8a0cb8 100644 --- a/docs/storage-report/StrategyFactory.md +++ b/docs/storage-report/StrategyFactory.md @@ -1,14 +1,14 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|--------------------|------------------------------------------------|------|--------|-------|--------------------------------------------------------------| -| strategyBeacon | contract IBeacon | 0 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| deployedStrategies | mapping(contract IERC20 => contract IStrategy) | 1 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| isBlacklisted | mapping(contract IERC20 => bool) | 2 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| __gap | uint256[48] | 3 | 0 | 1536 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| _initialized | uint8 | 51 | 0 | 1 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| _initializing | bool | 51 | 1 | 1 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| __gap | uint256[50] | 52 | 0 | 1600 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| _owner | address | 102 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| __gap | uint256[49] | 103 | 0 | 1568 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| pauserRegistry | contract IPauserRegistry | 152 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| _paused | uint256 | 153 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | -| __gap | uint256[48] | 154 | 0 | 1536 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| Name | Type | Slot | Offset | Bytes | Contract | +|-----------------------------|------------------------------------------------|------|--------|-------|--------------------------------------------------------------| +| strategyBeacon | contract IBeacon | 0 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| deployedStrategies | mapping(contract IERC20 => contract IStrategy) | 1 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| isBlacklisted | mapping(contract IERC20 => bool) | 2 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| __gap | uint256[48] | 3 | 0 | 1536 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| _initialized | uint8 | 51 | 0 | 1 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| _initializing | bool | 51 | 1 | 1 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| __gap | uint256[50] | 52 | 0 | 1600 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| _owner | address | 102 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| __gap | uint256[49] | 103 | 0 | 1568 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| __deprecated_pauserRegistry | contract IPauserRegistry | 152 | 0 | 20 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| _paused | uint256 | 153 | 0 | 32 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | +| __gap | uint256[48] | 154 | 0 | 1536 | src/contracts/strategies/StrategyFactory.sol:StrategyFactory | diff --git a/docs/storage-report/StrategyManager.md b/docs/storage-report/StrategyManager.md index 8f7e5cb4b..06ae17544 100644 --- a/docs/storage-report/StrategyManager.md +++ b/docs/storage-report/StrategyManager.md @@ -1,24 +1,24 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|---------------------------------------------|------------------------------------------------------------|------|--------|-------|--------------------------------------------------------| -| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/StrategyManager.sol:StrategyManager | -| _initializing | bool | 0 | 1 | 1 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/StrategyManager.sol:StrategyManager | -| _owner | address | 51 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/StrategyManager.sol:StrategyManager | -| _status | uint256 | 101 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __gap | uint256[49] | 102 | 0 | 1568 | src/contracts/core/StrategyManager.sol:StrategyManager | -| pauserRegistry | contract IPauserRegistry | 151 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | -| _paused | uint256 | 152 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __gap | uint256[48] | 153 | 0 | 1536 | src/contracts/core/StrategyManager.sol:StrategyManager | -| _DOMAIN_SEPARATOR | bytes32 | 201 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| nonces | mapping(address => uint256) | 202 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| strategyWhitelister | address | 203 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __deprecated_withdrawalDelayBlocks | uint256 | 204 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| stakerStrategyShares | mapping(address => mapping(contract IStrategy => uint256)) | 205 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| stakerStrategyList | mapping(address => contract IStrategy[]) | 206 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __deprecated_withdrawalRootPending | mapping(bytes32 => bool) | 207 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __deprecated_numWithdrawalsQueued | mapping(address => uint256) | 208 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| strategyIsWhitelistedForDeposit | mapping(contract IStrategy => bool) | 209 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| beaconChainETHSharesToDecrementOnWithdrawal | mapping(address => uint256) | 210 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| thirdPartyTransfersForbidden | mapping(contract IStrategy => bool) | 211 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | -| __gap | uint256[39] | 212 | 0 | 1248 | src/contracts/core/StrategyManager.sol:StrategyManager | +| Name | Type | Slot | Offset | Bytes | Contract | +|----------------------------------------------------------|------------------------------------------------------------|------|--------|-------|--------------------------------------------------------| +| _initialized | uint8 | 0 | 0 | 1 | src/contracts/core/StrategyManager.sol:StrategyManager | +| _initializing | bool | 0 | 1 | 1 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __gap | uint256[50] | 1 | 0 | 1600 | src/contracts/core/StrategyManager.sol:StrategyManager | +| _owner | address | 51 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __gap | uint256[49] | 52 | 0 | 1568 | src/contracts/core/StrategyManager.sol:StrategyManager | +| _status | uint256 | 101 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __gap | uint256[49] | 102 | 0 | 1568 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_pauserRegistry | contract IPauserRegistry | 151 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | +| _paused | uint256 | 152 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __gap | uint256[48] | 153 | 0 | 1536 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 201 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| nonces | mapping(address => uint256) | 202 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| strategyWhitelister | address | 203 | 0 | 20 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_withdrawalDelayBlocks | uint256 | 204 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| stakerDepositShares | mapping(address => mapping(contract IStrategy => uint256)) | 205 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| stakerStrategyList | mapping(address => contract IStrategy[]) | 206 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_withdrawalRootPending | mapping(bytes32 => bool) | 207 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_numWithdrawalsQueued | mapping(address => uint256) | 208 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| strategyIsWhitelistedForDeposit | mapping(contract IStrategy => bool) | 209 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_beaconChainETHSharesToDecrementOnWithdrawal | mapping(address => uint256) | 210 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __deprecated_thirdPartyTransfersForbidden | mapping(contract IStrategy => bool) | 211 | 0 | 32 | src/contracts/core/StrategyManager.sol:StrategyManager | +| __gap | uint256[39] | 212 | 0 | 1248 | src/contracts/core/StrategyManager.sol:StrategyManager | diff --git a/docs/storage-report/StrategyManagerStorage.md b/docs/storage-report/StrategyManagerStorage.md index 701045da7..5581d10e3 100644 --- a/docs/storage-report/StrategyManagerStorage.md +++ b/docs/storage-report/StrategyManagerStorage.md @@ -1,14 +1,14 @@ -| Name | Type | Slot | Offset | Bytes | Contract | -|---------------------------------------------|------------------------------------------------------------|------|--------|-------|----------------------------------------------------------------------| -| _DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| nonces | mapping(address => uint256) | 1 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| strategyWhitelister | address | 2 | 0 | 20 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| __deprecated_withdrawalDelayBlocks | uint256 | 3 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| stakerStrategyShares | mapping(address => mapping(contract IStrategy => uint256)) | 4 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| stakerStrategyList | mapping(address => contract IStrategy[]) | 5 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| __deprecated_withdrawalRootPending | mapping(bytes32 => bool) | 6 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| __deprecated_numWithdrawalsQueued | mapping(address => uint256) | 7 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| strategyIsWhitelistedForDeposit | mapping(contract IStrategy => bool) | 8 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| beaconChainETHSharesToDecrementOnWithdrawal | mapping(address => uint256) | 9 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| thirdPartyTransfersForbidden | mapping(contract IStrategy => bool) | 10 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | -| __gap | uint256[39] | 11 | 0 | 1248 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| Name | Type | Slot | Offset | Bytes | Contract | +|----------------------------------------------------------|------------------------------------------------------------|------|--------|-------|----------------------------------------------------------------------| +| __deprecated_DOMAIN_SEPARATOR | bytes32 | 0 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| nonces | mapping(address => uint256) | 1 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| strategyWhitelister | address | 2 | 0 | 20 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __deprecated_withdrawalDelayBlocks | uint256 | 3 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| stakerDepositShares | mapping(address => mapping(contract IStrategy => uint256)) | 4 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| stakerStrategyList | mapping(address => contract IStrategy[]) | 5 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __deprecated_withdrawalRootPending | mapping(bytes32 => bool) | 6 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __deprecated_numWithdrawalsQueued | mapping(address => uint256) | 7 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| strategyIsWhitelistedForDeposit | mapping(contract IStrategy => bool) | 8 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __deprecated_beaconChainETHSharesToDecrementOnWithdrawal | mapping(address => uint256) | 9 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __deprecated_thirdPartyTransfersForbidden | mapping(contract IStrategy => bool) | 10 | 0 | 32 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | +| __gap | uint256[39] | 11 | 0 | 1248 | src/contracts/core/StrategyManagerStorage.sol:StrategyManagerStorage | diff --git a/foundry.toml b/foundry.toml index 8a79acefa..f665c7559 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,6 +6,13 @@ fs_permissions = [{ access = "read-write", path = "./"}] gas_reports = ["*"] # ignore upgrade testing in scripts by default no_match_test = "queueUpgrade" +remappings = [ + "@openzeppelin/=lib/openzeppelin-contracts-v4.9.0/", + "@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable-v4.9.0/", + "ds-test/=lib/ds-test/src/", + "forge-std/=lib/forge-std/src/" +] +sparse_mode = true # A list of ignored solc error codes @@ -16,7 +23,7 @@ optimizer_runs = 200 # Whether or not to use the Yul intermediate representation compilation pipeline via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) -solc_version = '0.8.12' +solc_version = '0.8.27' [rpc_endpoints] mainnet = "${RPC_MAINNET}" diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts deleted file mode 160000 index 3b8b4ba82..000000000 --- a/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3b8b4ba82c880c31cd3b96dd5e15741d7e26658e diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable deleted file mode 160000 index 6b9807b06..000000000 --- a/lib/openzeppelin-contracts-upgradeable +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6b9807b0639e1dd75e07fa062e9432eb3f35dd8c diff --git a/pkg/bindings/AVSDirectory/binding.go b/pkg/bindings/AVSDirectory/binding.go index e91d51eb1..65e32a4aa 100644 --- a/pkg/bindings/AVSDirectory/binding.go +++ b/pkg/bindings/AVSDirectory/binding.go @@ -38,8 +38,8 @@ type ISignatureUtilsSignatureWithSaltAndExpiry struct { // AVSDirectoryMetaData contains all meta data concerning the AVSDirectory contract. var AVSDirectoryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegation\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"avsOperatorStatus\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"cancelSalt\",\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60c06040523480156200001157600080fd5b5060405162001f7838038062001f78833981016040819052620000349162000118565b6001600160a01b0381166080526200004b62000056565b504660a0526200014a565b600054610100900460ff1615620000c35760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000116576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012b57600080fd5b81516001600160a01b03811681146200014357600080fd5b9392505050565b60805160a051611e01620001776000396000610ea801526000818161032401526109830152611e016000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638da5cb5b116100b8578063d79aceab1161007c578063d79aceab146102f8578063df5cf7231461031f578063ec76f44214610346578063f2fde38b14610359578063f698da251461036c578063fabc1cbc1461037457600080fd5b80638da5cb5b1461029b5780639926ee7d146102ac578063a1060c88146102bf578063a364f4da146102d2578063a98fb355146102e557600080fd5b806349075da31161010a57806349075da3146101fa578063595c6a67146102355780635ac86ab71461023d5780635c975abb14610260578063715018a614610268578063886f11951461027057600080fd5b806310d67a2f14610147578063136439dd1461015c5780631794bb3c1461016f57806320606b7014610182578063374823b5146101bc575b600080fd5b61015a6101553660046118ab565b610387565b005b61015a61016a3660046118cf565b610443565b61015a61017d3660046118e8565b610582565b6101a97f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b6101ea6101ca366004611929565b609960209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016101b3565b610228610208366004611955565b609860209081526000928352604080842090915290825290205460ff1681565b6040516101b391906119a4565b61015a6106ac565b6101ea61024b3660046119cc565b606654600160ff9092169190911b9081161490565b6066546101a9565b61015a610773565b606554610283906001600160a01b031681565b6040516001600160a01b0390911681526020016101b3565b6033546001600160a01b0316610283565b61015a6102ba366004611a5f565b610787565b6101a96102cd366004611b46565b610b1a565b61015a6102e03660046118ab565b610bd3565b61015a6102f3366004611b8c565b610d3c565b6101a97fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd81565b6102837f000000000000000000000000000000000000000000000000000000000000000081565b61015a6103543660046118cf565b610d83565b61015a6103673660046118ab565b610e2e565b6101a9610ea4565b61015a6103823660046118cf565b610ee2565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fe9190611bfe565b6001600160a01b0316336001600160a01b0316146104375760405162461bcd60e51b815260040161042e90611c1b565b60405180910390fd5b6104408161103e565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561048b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104af9190611c65565b6104cb5760405162461bcd60e51b815260040161042e90611c87565b606654818116146105445760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c6974790000000000000000606482015260840161042e565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600054610100900460ff16158080156105a25750600054600160ff909116105b806105bc5750303b1580156105bc575060005460ff166001145b61061f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161042e565b6000805460ff191660011790558015610642576000805461ff0019166101001790555b61064c8383611135565b61065461121f565b609755610660846112b6565b80156106a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156106f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107189190611c65565b6107345760405162461bcd60e51b815260040161042e90611c87565b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b61077b611308565b61078560006112b6565b565b606654600090600190811614156107dc5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b604482015260640161042e565b42826040015110156108445760405162461bcd60e51b815260206004820152603e6024820152600080516020611dac83398151915260448201527f56533a206f70657261746f72207369676e617475726520657870697265640000606482015260840161042e565b60013360009081526098602090815260408083206001600160a01b038816845290915290205460ff16600181111561087e5761087e61198e565b14156108e05760405162461bcd60e51b815260206004820152603f6024820152600080516020611dac83398151915260448201527f56533a206f70657261746f7220616c7265616479207265676973746572656400606482015260840161042e565b6001600160a01b038316600090815260996020908152604080832085830151845290915290205460ff16156109645760405162461bcd60e51b81526020600482015260366024820152600080516020611dac8339815191526044820152751594ce881cd85b1d08185b1c9958591e481cdc195b9d60521b606482015260840161042e565b6040516336b87bd760e11b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636d70f7ae90602401602060405180830381865afa1580156109ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ee9190611c65565b610a645760405162461bcd60e51b815260206004820152604d6024820152600080516020611dac83398151915260448201527f56533a206f70657261746f72206e6f74207265676973746572656420746f204560648201526c1a59d95b93185e595c881e595d609a1b608482015260a40161042e565b6000610a7a843385602001518660400151610b1a565b9050610a8b84828560000151611362565b3360008181526098602090815260408083206001600160a01b0389168085529083528184208054600160ff199182168117909255609985528386208a860151875290945293829020805490931684179092555190917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b4191610b0c91906119a4565b60405180910390a350505050565b604080517fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd6020808301919091526001600160a01b0387811683850152861660608301526080820185905260a08083018590528351808403909101815260c0909201909252805191012060009081610b90610ea4565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f190181529190528051602090910120979650505050505050565b60665460009060019081161415610c285760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b604482015260640161042e565b60013360009081526098602090815260408083206001600160a01b038716845290915290205460ff166001811115610c6257610c6261198e565b14610cd55760405162461bcd60e51b815260206004820152603f60248201527f4156534469726563746f72792e646572656769737465724f70657261746f724660448201527f726f6d4156533a206f70657261746f72206e6f74207265676973746572656400606482015260840161042e565b3360008181526098602090815260408083206001600160a01b0387168085529252808320805460ff191690555190917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b4191610d3091906119a4565b60405180910390a35050565b336001600160a01b03167fa89c1dc243d8908a96dd84944bcc97d6bc6ac00dd78e20621576be6a3c9437138383604051610d77929190611ccf565b60405180910390a25050565b33600090815260996020908152604080832084845290915290205460ff1615610e085760405162461bcd60e51b815260206004820152603160248201527f4156534469726563746f72792e63616e63656c53616c743a2063616e6e6f742060448201527018d85b98d95b081cdc195b9d081cd85b1d607a1b606482015260840161042e565b33600090815260996020908152604080832093835292905220805460ff19166001179055565b610e36611308565b6001600160a01b038116610e9b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161042e565b610440816112b6565b60007f0000000000000000000000000000000000000000000000000000000000000000461415610ed5575060975490565b610edd61121f565b905090565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f599190611bfe565b6001600160a01b0316336001600160a01b031614610f895760405162461bcd60e51b815260040161042e90611c1b565b6066541981196066541916146110075760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c6974790000000000000000606482015260840161042e565b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610577565b6001600160a01b0381166110cc5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a40161042e565b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b031615801561115657506001600160a01b03821615155b6111d85760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a40161042e565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a261121b8261103e565b5050565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6033546001600160a01b031633146107855760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161042e565b6001600160a01b0383163b1561148157604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e906113a29086908690600401611cfe565b602060405180830381865afa1580156113bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e39190611d5b565b6001600160e01b0319161461147c5760405162461bcd60e51b815260206004820152605360248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a2045524331323731207369676e6174757265206064820152721d995c9a599a58d85d1a5bdb8819985a5b1959606a1b608482015260a40161042e565b505050565b826001600160a01b03166114958383611521565b6001600160a01b03161461147c5760405162461bcd60e51b815260206004820152604760248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a207369676e6174757265206e6f742066726f6d6064820152661039b4b3b732b960c91b608482015260a40161042e565b60008060006115308585611545565b9150915061153d816115b5565b509392505050565b60008082516041141561157c5760208301516040840151606085015160001a61157087828585611770565b945094505050506115ae565b8251604014156115a6576020830151604084015161159b86838361185d565b9350935050506115ae565b506000905060025b9250929050565b60008160048111156115c9576115c961198e565b14156115d25750565b60018160048111156115e6576115e661198e565b14156116345760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161042e565b60028160048111156116485761164861198e565b14156116965760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161042e565b60038160048111156116aa576116aa61198e565b14156117035760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161042e565b60048160048111156117175761171761198e565b14156104405760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161042e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156117a75750600090506003611854565b8460ff16601b141580156117bf57508460ff16601c14155b156117d05750600090506004611854565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611824573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661184d57600060019250925050611854565b9150600090505b94509492505050565b6000806001600160ff1b0383168161187a60ff86901c601b611d85565b905061188887828885611770565b935093505050935093915050565b6001600160a01b038116811461044057600080fd5b6000602082840312156118bd57600080fd5b81356118c881611896565b9392505050565b6000602082840312156118e157600080fd5b5035919050565b6000806000606084860312156118fd57600080fd5b833561190881611896565b9250602084013561191881611896565b929592945050506040919091013590565b6000806040838503121561193c57600080fd5b823561194781611896565b946020939093013593505050565b6000806040838503121561196857600080fd5b823561197381611896565b9150602083013561198381611896565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600283106119c657634e487b7160e01b600052602160045260246000fd5b91905290565b6000602082840312156119de57600080fd5b813560ff811681146118c857600080fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a2857611a286119ef565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611a5757611a576119ef565b604052919050565b60008060408385031215611a7257600080fd5b8235611a7d81611896565b915060208381013567ffffffffffffffff80821115611a9b57600080fd5b9085019060608288031215611aaf57600080fd5b611ab7611a05565b823582811115611ac657600080fd5b8301601f81018913611ad757600080fd5b803583811115611ae957611ae96119ef565b611afb601f8201601f19168701611a2e565b93508084528986828401011115611b1157600080fd5b808683018786013760008682860101525050818152838301358482015260408301356040820152809450505050509250929050565b60008060008060808587031215611b5c57600080fd5b8435611b6781611896565b93506020850135611b7781611896565b93969395505050506040820135916060013590565b60008060208385031215611b9f57600080fd5b823567ffffffffffffffff80821115611bb757600080fd5b818501915085601f830112611bcb57600080fd5b813581811115611bda57600080fd5b866020828501011115611bec57600080fd5b60209290920196919550909350505050565b600060208284031215611c1057600080fd5b81516118c881611896565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611c7757600080fd5b815180151581146118c857600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b82815260006020604081840152835180604085015260005b81811015611d3257858101830151858201606001528201611d16565b81811115611d44576000606083870101525b50601f01601f191692909201606001949350505050565b600060208284031215611d6d57600080fd5b81516001600160e01b0319811681146118c857600080fd5b60008219821115611da657634e487b7160e01b600052601160045260246000fd5b50019056fe4156534469726563746f72792e72656769737465724f70657261746f72546f41a26469706673582212203078326ec29ef6e4c0629c3db8b9232b52ccd0d073d4926089bdbc0d9eef3c0f64736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegation\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"avsOperatorStatus\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"cancelSalt\",\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEIP1271\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEOA\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorAlreadyRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]}]", + Bin: "0x60c060405234801561001057600080fd5b506040516118fc3803806118fc83398101604081905261002f9161010d565b6001600160a01b03811660805261004461004e565b504660a05261013d565b600054610100900460ff16156100ba5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161461010b576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011f57600080fd5b81516001600160a01b038116811461013657600080fd5b9392505050565b60805160a0516117936101696000396000610bff015260008181610324015261085f01526117936000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638da5cb5b116100b8578063d79aceab1161007c578063d79aceab146102f8578063df5cf7231461031f578063ec76f44214610346578063f2fde38b1461037a578063f698da251461038d578063fabc1cbc1461039557600080fd5b80638da5cb5b1461029b5780639926ee7d146102ac578063a1060c88146102bf578063a364f4da146102d2578063a98fb355146102e557600080fd5b806349075da31161010a57806349075da3146101fa578063595c6a67146102355780635ac86ab71461023d5780635c975abb14610260578063715018a614610268578063886f11951461027057600080fd5b806310d67a2f14610147578063136439dd1461015c5780631794bb3c1461016f57806320606b7014610182578063374823b5146101bc575b600080fd5b61015a61015536600461130d565b6103a8565b005b61015a61016a366004611331565b61045c565b61015a61017d36600461134a565b610547565b6101a97f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b6101ea6101ca36600461138b565b609960209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016101b3565b6102286102083660046113b7565b609860209081526000928352604080842090915290825290205460ff1681565b6040516101b39190611406565b61015a610676565b6101ea61024b36600461142e565b606654600160ff9092169190911b9081161490565b6066546101a9565b61015a61073e565b606554610283906001600160a01b031681565b6040516001600160a01b0390911681526020016101b3565b6033546001600160a01b0316610283565b61015a6102ba3660046114c1565b610752565b6101a96102cd3660046115b6565b61099d565b61015a6102e036600461130d565b610a56565b61015a6102f33660046115fc565b610b3e565b6101a97fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd81565b6102837f000000000000000000000000000000000000000000000000000000000000000081565b61015a610354366004611331565b33600090815260996020908152604080832093835292905220805460ff19166001179055565b61015a61038836600461130d565b610b85565b6101a9610bfb565b61015a6103a3366004611331565b610c38565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041f9190611670565b6001600160a01b0316336001600160a01b0316146104505760405163794821ff60e01b815260040160405180910390fd5b61045981610d40565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156104a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c8919061168d565b6104e557604051631d77d47760e21b815260040160405180910390fd5b606654818116146105095760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600054610100900460ff16158080156105675750600054600160ff909116105b806105815750303b158015610581575060005460ff166001145b6105e95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561060c576000805461ff0019166101001790555b6106168383610dd0565b61061e610e55565b60975561062a84610eec565b8015610670576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156106be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e2919061168d565b6106ff57604051631d77d47760e21b815260040160405180910390fd5b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b610746610f3e565b6107506000610eec565b565b60665460009060019081160361077b5760405163840a48d560e01b815260040160405180910390fd5b42826040015110156107a057604051630819bdcd60e01b815260040160405180910390fd5b60013360009081526098602090815260408083206001600160a01b038816845290915290205460ff1660018111156107da576107da6113f0565b036107f8576040516342ee68b560e01b815260040160405180910390fd5b6001600160a01b038316600090815260996020908152604080832085830151845290915290205460ff161561084057604051639a5afeb760e01b815260040160405180910390fd5b6040516336b87bd760e11b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636d70f7ae90602401602060405180830381865afa1580156108a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ca919061168d565b6108e7576040516325878fa360e21b815260040160405180910390fd5b60006108fd84338560200151866040015161099d565b905061090e84828560000151610f98565b3360008181526098602090815260408083206001600160a01b0389168085529083528184208054600160ff199182168117909255609985528386208a860151875290945293829020805490931684179092555190917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b419161098f9190611406565b60405180910390a350505050565b604080517fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd6020808301919091526001600160a01b0387811683850152861660608301526080820185905260a08083018590528351808403909101815260c0909201909252805191012060009081610a13610bfb565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f190181529190528051602090910120979650505050505050565b606654600090600190811603610a7f5760405163840a48d560e01b815260040160405180910390fd5b60013360009081526098602090815260408083206001600160a01b038716845290915290205460ff166001811115610ab957610ab96113f0565b14610ad7576040516325ec6c1f60e01b815260040160405180910390fd5b3360008181526098602090815260408083206001600160a01b0387168085529252808320805460ff191690555190917ff0952b1c65271d819d39983d2abb044b9cace59bcc4d4dd389f586ebdcb15b4191610b329190611406565b60405180910390a35050565b336001600160a01b03167fa89c1dc243d8908a96dd84944bcc97d6bc6ac00dd78e20621576be6a3c9437138383604051610b799291906116af565b60405180910390a25050565b610b8d610f3e565b6001600160a01b038116610bf25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105e0565b61045981610eec565b60007f00000000000000000000000000000000000000000000000000000000000000004603610c2b575060975490565b610c33610e55565b905090565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf9190611670565b6001600160a01b0316336001600160a01b031614610ce05760405163794821ff60e01b815260040160405180910390fd5b606654198119606654191614610d095760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161053c565b6001600160a01b038116610d67576040516339b190bb60e11b815260040160405180910390fd5b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b0316158015610df157506001600160a01b03821615155b610e0e576040516339b190bb60e11b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610e5182610d40565b5050565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6033546001600160a01b031633146107505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105e0565b6001600160a01b0383163b1561104657604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e90610fd890869086906004016116de565b602060405180830381865afa158015610ff5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110199190611733565b6001600160e01b031916146110415760405163026aa43360e31b815260040160405180910390fd5b505050565b826001600160a01b031661105a8383611081565b6001600160a01b031614611041576040516306c653c360e31b815260040160405180910390fd5b600080600061109085856110a5565b9150915061109d816110ea565b509392505050565b60008082516041036110db5760208301516040840151606085015160001a6110cf87828585611234565b945094505050506110e3565b506000905060025b9250929050565b60008160048111156110fe576110fe6113f0565b036111065750565b600181600481111561111a5761111a6113f0565b036111675760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105e0565b600281600481111561117b5761117b6113f0565b036111c85760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105e0565b60038160048111156111dc576111dc6113f0565b036104595760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105e0565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561126b57506000905060036112ef565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156112bf573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166112e8576000600192509250506112ef565b9150600090505b94509492505050565b6001600160a01b038116811461045957600080fd5b60006020828403121561131f57600080fd5b813561132a816112f8565b9392505050565b60006020828403121561134357600080fd5b5035919050565b60008060006060848603121561135f57600080fd5b833561136a816112f8565b9250602084013561137a816112f8565b929592945050506040919091013590565b6000806040838503121561139e57600080fd5b82356113a9816112f8565b946020939093013593505050565b600080604083850312156113ca57600080fd5b82356113d5816112f8565b915060208301356113e5816112f8565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b602081016002831061142857634e487b7160e01b600052602160045260246000fd5b91905290565b60006020828403121561144057600080fd5b813560ff8116811461132a57600080fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561148a5761148a611451565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156114b9576114b9611451565b604052919050565b600080604083850312156114d457600080fd5b82356114df816112f8565b9150602083013567ffffffffffffffff8111156114fb57600080fd5b83016060818603121561150d57600080fd5b611515611467565b813567ffffffffffffffff81111561152c57600080fd5b8201601f8101871361153d57600080fd5b803567ffffffffffffffff81111561155757611557611451565b61156a601f8201601f1916602001611490565b81815288602083850101111561157f57600080fd5b8160208401602083013760006020928201830152835283810135908301525060409182013591810191909152919491935090915050565b600080600080608085870312156115cc57600080fd5b84356115d7816112f8565b935060208501356115e7816112f8565b93969395505050506040820135916060013590565b6000806020838503121561160f57600080fd5b823567ffffffffffffffff81111561162657600080fd5b8301601f8101851361163757600080fd5b803567ffffffffffffffff81111561164e57600080fd5b85602082840101111561166057600080fd5b6020919091019590945092505050565b60006020828403121561168257600080fd5b815161132a816112f8565b60006020828403121561169f57600080fd5b8151801515811461132a57600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b828152604060208201526000825180604084015260005b8181101561171257602081860181015160608684010152016116f5565b506000606082850101526060601f19601f8301168401019150509392505050565b60006020828403121561174557600080fd5b81516001600160e01b03198116811461132a57600080fdfea2646970667358221220507ace4a907882df0a7be0215e9c273cbd6fe8fae0d62c9757a7e348ef8ae0f764736f6c634300081b0033", } // AVSDirectoryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/AVSDirectoryStorage/binding.go b/pkg/bindings/AVSDirectoryStorage/binding.go index 2070a8e69..558c6dd8f 100644 --- a/pkg/bindings/AVSDirectoryStorage/binding.go +++ b/pkg/bindings/AVSDirectoryStorage/binding.go @@ -38,7 +38,7 @@ type ISignatureUtilsSignatureWithSaltAndExpiry struct { // AVSDirectoryStorageMetaData contains all meta data concerning the AVSDirectoryStorage contract. var AVSDirectoryStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"avsOperatorStatus\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"avsOperatorStatus\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"OperatorAlreadyRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]}]", } // AVSDirectoryStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/BackingEigen/binding.go b/pkg/bindings/BackingEigen/binding.go index 7adf41315..0c8b4acbd 100644 --- a/pkg/bindings/BackingEigen/binding.go +++ b/pkg/bindings/BackingEigen/binding.go @@ -38,7 +38,7 @@ type ERC20VotesUpgradeableCheckpoint struct { // BackingEigenMetaData contains all meta data concerning the BackingEigen contract. var BackingEigenMetaData = &bind.MetaData{ ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_EIGEN\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CLOCK_MODE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"DOMAIN_SEPARATOR\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"EIGEN\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowedFrom\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpoints\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"pos\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structERC20VotesUpgradeable.Checkpoint\",\"components\":[{\"name\":\"fromBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"votes\",\"type\":\"uint224\",\"internalType\":\"uint224\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"clock\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"subtractedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegate\",\"inputs\":[{\"name\":\"delegatee\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateBySig\",\"inputs\":[{\"name\":\"delegatee\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"v\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"r\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"s\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegates\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableTransferRestrictions\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eip712Domain\",\"inputs\":[],\"outputs\":[{\"name\":\"fields\",\"type\":\"bytes1\",\"internalType\":\"bytes1\"},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extensions\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPastTotalSupply\",\"inputs\":[{\"name\":\"timepoint\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPastVotes\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timepoint\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotes\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"addedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numCheckpoints\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"permit\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"v\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"r\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"s\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setAllowedFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isAllowedFrom\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setAllowedTo\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isAllowedTo\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferRestrictionsDisabledAfter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Backed\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DelegateChanged\",\"inputs\":[{\"name\":\"delegator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"fromDelegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"toDelegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DelegateVotesChanged\",\"inputs\":[{\"name\":\"delegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"previousBalance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newBalance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EIP712DomainChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetAllowedFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"isAllowedFrom\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetAllowedTo\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"isAllowedTo\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TransferRestrictionsDisabled\",\"inputs\":[],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162002b4438038062002b44833981016040819052620000349162000113565b6001600160a01b0381166080526200004b62000052565b5062000145565b600054610100900460ff1615620000bf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161462000111576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012657600080fd5b81516001600160a01b03811681146200013e57600080fd5b9392505050565b6080516129c76200017d6000396000818161056f01528181610c5b01528181610c8601528181610cb10152610cd201526129c76000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c806384b0196e11610125578063b8c25594116100ad578063dd62ed3e1161007c578063dd62ed3e146104ff578063eb415f4514610512578063f1127ed81461051a578063f2fde38b14610557578063fdc371ce1461056a57600080fd5b8063b8c25594146104b3578063c3cda520146104c6578063c4d66de8146104d9578063d505accf146104ec57600080fd5b806395d89b41116100f457806395d89b41146104685780639ab24eb0146104705780639aec4bae14610483578063a457c2d71461048d578063a9059cbb146104a057600080fd5b806384b0196e1461040a5780638da5cb5b146104255780638e539e8c1461043657806391ddadf41461044957600080fd5b80633a46b1a8116101a85780636fcfff45116101775780636fcfff451461037a57806370a08231146103a2578063715018a6146103cb57806378aa33ba146103d35780637ecebe00146103f757600080fd5b80633a46b1a8146102e65780634bf5d7e9146102f9578063587cde1e146103235780635c19a95c1461036757600080fd5b80631ffacdef116101ef5780631ffacdef1461029457806323b872dd146102a9578063313ce567146102bc5780633644e515146102cb57806339509351146102d357600080fd5b80630455e6941461022157806306fdde031461025a578063095ea7b31461026f57806318160ddd14610282575b600080fd5b61024561022f366004612548565b6101316020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b610262610591565b60405161025191906125b0565b61024561027d3660046125c3565b610623565b6067545b604051908152602001610251565b6102a76102a23660046125ed565b61063b565b005b6102456102b7366004612629565b610651565b60405160128152602001610251565b610286610675565b6102456102e13660046125c3565b610684565b6102866102f43660046125c3565b6106a6565b60408051808201909152600e81526d06d6f64653d74696d657374616d760941b6020820152610262565b61034f610331366004612548565b6001600160a01b03908116600090815260fe60205260409020541690565b6040516001600160a01b039091168152602001610251565b6102a7610375366004612548565b610730565b61038d610388366004612548565b61073d565b60405163ffffffff9091168152602001610251565b6102866103b0366004612548565b6001600160a01b031660009081526065602052604090205490565b6102a7610765565b6102456103e1366004612548565b6101326020526000908152604090205460ff1681565b610286610405366004612548565b610779565b610412610797565b6040516102519796959493929190612665565b6033546001600160a01b031661034f565b6102866104443660046126fb565b610835565b61045161089d565b60405165ffffffffffff9091168152602001610251565b6102626108a8565b61028661047e366004612548565b6108b7565b6102866101305481565b61024561049b3660046125c3565b610939565b6102456104ae3660046125c3565b6109b4565b6102a76104c13660046125ed565b6109c2565b6102a76104d4366004612725565b6109d4565b6102a76104e7366004612548565b610b0a565b6102a76104fa36600461277d565b610dc9565b61028661050d3660046127e7565b610f2d565b6102a7610f58565b61052d61052836600461281a565b611028565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610251565b6102a7610565366004612548565b6110ac565b61034f7f000000000000000000000000000000000000000000000000000000000000000081565b6060606880546105a09061284f565b80601f01602080910402602001604051908101604052809291908181526020018280546105cc9061284f565b80156106195780601f106105ee57610100808354040283529160200191610619565b820191906000526020600020905b8154815290600101906020018083116105fc57829003601f168201915b5050505050905090565b600033610631818585611122565b5060019392505050565b610643611246565b61064d82826112a0565b5050565b60003361065f858285611301565b61066a85858561137b565b506001949350505050565b600061067f611537565b905090565b6000336106318185856106978383610f2d565b6106a1919061289a565b611122565b60006106b061089d565b65ffffffffffff1682106107075760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b60448201526064015b60405180910390fd5b6001600160a01b038316600090815260ff602052604090206107299083611541565b9392505050565b61073a338261162a565b50565b6001600160a01b038116600090815260ff602052604081205461075f906116a4565b92915050565b61076d611246565b610777600061170d565b565b6001600160a01b038116600090815260cb602052604081205461075f565b6000606080600080600060606097546000801b1480156107b75750609854155b6107fb5760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016106fe565b61080361175f565b61080b61176e565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b600061083f61089d565b65ffffffffffff1682106108915760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b60448201526064016106fe565b61075f61010083611541565b600061067f4261177d565b6060606980546105a09061284f565b6001600160a01b038116600090815260ff60205260408120548015610926576001600160a01b038316600090815260ff6020526040902080546000198301908110610904576109046128b2565b60009182526020909120015464010000000090046001600160e01b0316610929565b60005b6001600160e01b03169392505050565b600033816109478286610f2d565b9050838110156109a75760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016106fe565b61066a8286868403611122565b60003361063181858561137b565b6109ca611246565b61064d82826117e4565b83421115610a245760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e6174757265206578706972656400000060448201526064016106fe565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610a9e90610a969060a0016040516020818303038152906040528051906020012061183d565b85858561186a565b9050610aa981611892565b8614610af75760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e63650000000000000060448201526064016106fe565b610b01818861162a565b50505050505050565b600054610100900460ff1615808015610b2a5750600054600160ff909116105b80610b445750303b158015610b44575060005460ff166001145b610ba75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106fe565b6000805460ff191660011790558015610bca576000805461ff0019166101001790555b610bd26118ba565b610c1f6040518060400160405280600d81526020016c2130b1b5b4b7339022b4b3b2b760991b815250604051806040016040528060068152602001653122a4a3a2a760d11b8152506118e9565b610c288261170d565b610c4f604051806040016040528060068152602001653122a4a3a2a760d11b81525061191a565b60001961013055610c817f000000000000000000000000000000000000000000000000000000000000000060016112a0565b610cac7f000000000000000000000000000000000000000000000000000000000000000060016117e4565b610d577f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5291906128c8565b611964565b6040517fb7c23c1e2e36f298e9879a88ecfcd07e28fbb439bcfa9c78ca1363ca14370d2690600090a1801561064d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b83421115610e195760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016106fe565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e488c611892565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610ea38261183d565b90506000610eb38287878761186a565b9050896001600160a01b0316816001600160a01b031614610f165760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016106fe565b610f218a8a8a611122565b50505050505050505050565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b610f60611246565b6000196101305414610ff75760405162461bcd60e51b815260206004820152605460248201527f4261636b696e67456967656e2e64697361626c655472616e736665725265737460448201527f72696374696f6e733a207472616e73666572207265737472696374696f6e7320606482015273185c9948185b1c9958591e48191a5cd8589b195960621b608482015260a4016106fe565b60006101308190556040517f2b18986d3ba809db2f13a5d7bf17f60d357b37d9cbb55dd71cbbac8dc4060f649190a1565b60408051808201909152600080825260208201526001600160a01b038316600090815260ff60205260409020805463ffffffff841690811061106c5761106c6128b2565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b6110b4611246565b6001600160a01b0381166111195760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106fe565b61073a8161170d565b6001600160a01b0383166111845760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016106fe565b6001600160a01b0382166111e55760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016106fe565b6001600160a01b0383811660008181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6033546001600160a01b031633146107775760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106fe565b6001600160a01b03821660008181526101316020908152604091829020805460ff191685151590811790915591519182527fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed284362227191015b60405180910390a25050565b600061130d8484610f2d565b9050600019811461137557818110156113685760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016106fe565b6113758484848403611122565b50505050565b6001600160a01b0383166113df5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016106fe565b6001600160a01b0382166114415760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016106fe565b61144c8383836119ef565b6001600160a01b038316600090815260656020526040902054818110156114c45760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016106fe565b6001600160a01b0380851660008181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906115249086815260200190565b60405180910390a3611375848484611acd565b600061067f611aff565b81546000908181600581111561159b57600061155c84611b73565b61156690856128e1565b600088815260209020909150869082015463ffffffff16111561158b57809150611599565b61159681600161289a565b92505b505b808210156115e85760006115af8383611c58565b600088815260209020909150869082015463ffffffff1611156115d4578091506115e2565b6115df81600161289a565b92505b5061159b565b8015611614576000868152602090208101600019015464010000000090046001600160e01b0316611617565b60005b6001600160e01b03169695505050505050565b6001600160a01b03828116600081815260fe6020818152604080842080546065845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611375828483611c73565b600063ffffffff8211156117095760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016106fe565b5090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060609980546105a09061284f565b6060609a80546105a09061284f565b600065ffffffffffff8211156117095760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b60648201526084016106fe565b6001600160a01b03821660008181526101326020908152604091829020805460ff191685151590811790915591519182527f72a561d1af7409467dae4f1e9fc52590a9335a1dda17727e2b6aa8c4db35109b91016112f5565b600061075f61184a611537565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061187b87878787611db0565b9150915061188881611e74565b5095945050505050565b6001600160a01b038116600090815260cb602052604090208054600181018255905b50919050565b600054610100900460ff166118e15760405162461bcd60e51b81526004016106fe906128f8565b610777611fc2565b600054610100900460ff166119105760405162461bcd60e51b81526004016106fe906128f8565b61064d8282611ff2565b600054610100900460ff166119415760405162461bcd60e51b81526004016106fe906128f8565b61073a81604051806040016040528060018152602001603160f81b815250612040565b61196e828261209d565b6067546001600160e01b0310156119e05760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b60648201526084016106fe565b6113756101006121728361217e565b610130544211611ac8576001600160a01b0383166000908152610131602052604090205460ff1680611a3a57506001600160a01b0382166000908152610132602052604090205460ff165b80611a4c57506001600160a01b038316155b611ac85760405162461bcd60e51b815260206004820152604160248201527f4261636b696e67456967656e2e5f6265666f7265546f6b656e5472616e73666560448201527f723a2066726f6d206f7220746f206d7573742062652077686974656c697374656064820152601960fa1b608482015260a4016106fe565b505050565b6001600160a01b03838116600090815260fe6020526040808220548584168352912054611ac892918216911683611c73565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611b2a6122f3565b611b3261234c565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600081611b8257506000919050565b60006001611b8f8461237d565b901c6001901b90506001818481611ba857611ba8612943565b048201901c90506001818481611bc057611bc0612943565b048201901c90506001818481611bd857611bd8612943565b048201901c90506001818481611bf057611bf0612943565b048201901c90506001818481611c0857611c08612943565b048201901c90506001818481611c2057611c20612943565b048201901c90506001818481611c3857611c38612943565b048201901c905061072981828581611c5257611c52612943565b04612411565b6000611c676002848418612959565b6107299084841661289a565b816001600160a01b0316836001600160a01b031614158015611c955750600081115b15611ac8576001600160a01b03831615611d23576001600160a01b038316600090815260ff602052604081208190611cd0906124278561217e565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611d18929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611ac8576001600160a01b038216600090815260ff602052604081208190611d59906121728561217e565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611da1929190918252602082015260400190565b60405180910390a25050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611de75750600090506003611e6b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611e3b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611e6457600060019250925050611e6b565b9150600090505b94509492505050565b6000816004811115611e8857611e8861297b565b1415611e915750565b6001816004811115611ea557611ea561297b565b1415611ef35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106fe565b6002816004811115611f0757611f0761297b565b1415611f555760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106fe565b6003816004811115611f6957611f6961297b565b141561073a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016106fe565b600054610100900460ff16611fe95760405162461bcd60e51b81526004016106fe906128f8565b6107773361170d565b600054610100900460ff166120195760405162461bcd60e51b81526004016106fe906128f8565b815161202c90606890602085019061249c565b508051611ac890606990602084019061249c565b600054610100900460ff166120675760405162461bcd60e51b81526004016106fe906128f8565b815161207a90609990602085019061249c565b50805161208e90609a90602084019061249c565b50506000609781905560985550565b6001600160a01b0382166120f35760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106fe565b6120ff600083836119ef565b8060676000828254612111919061289a565b90915550506001600160a01b0382166000818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361064d60008383611acd565b6000610729828461289a565b825460009081908181156121cb5760008781526020902082016000190160408051808201909152905463ffffffff8116825264010000000090046001600160e01b031660208201526121e0565b60408051808201909152600080825260208201525b905080602001516001600160e01b0316935061220084868863ffffffff16565b925060008211801561222a575061221561089d565b65ffffffffffff16816000015163ffffffff16145b1561226f5761223883612433565b60008881526020902083016000190180546001600160e01b03929092166401000000000263ffffffff9092169190911790556122e9565b86604051806040016040528061229361228661089d565b65ffffffffffff166116a4565b63ffffffff1681526020016122a786612433565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b6000806122fe61175f565b805190915015612315578051602090910120919050565b60975480156123245792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b60008061235761176e565b80519091501561236e578051602090910120919050565b60985480156123245792915050565b600080608083901c1561239257608092831c92015b604083901c156123a457604092831c92015b602083901c156123b657602092831c92015b601083901c156123c857601092831c92015b600883901c156123da57600892831c92015b600483901c156123ec57600492831c92015b600283901c156123fe57600292831c92015b600183901c1561075f5760010192915050565b60008183106124205781610729565b5090919050565b600061072982846128e1565b60006001600160e01b038211156117095760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b60648201526084016106fe565b8280546124a89061284f565b90600052602060002090601f0160209004810192826124ca5760008555612510565b82601f106124e357805160ff1916838001178555612510565b82800160010185558215612510579182015b828111156125105782518255916020019190600101906124f5565b506117099291505b808211156117095760008155600101612518565b80356001600160a01b038116811461254357600080fd5b919050565b60006020828403121561255a57600080fd5b6107298261252c565b6000815180845260005b818110156125895760208185018101518683018201520161256d565b8181111561259b576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006107296020830184612563565b600080604083850312156125d657600080fd5b6125df8361252c565b946020939093013593505050565b6000806040838503121561260057600080fd5b6126098361252c565b91506020830135801515811461261e57600080fd5b809150509250929050565b60008060006060848603121561263e57600080fd5b6126478461252c565b92506126556020850161252c565b9150604084013590509250925092565b60ff60f81b881681526000602060e08184015261268560e084018a612563565b8381036040850152612697818a612563565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156126e9578351835292840192918401916001016126cd565b50909c9b505050505050505050505050565b60006020828403121561270d57600080fd5b5035919050565b803560ff8116811461254357600080fd5b60008060008060008060c0878903121561273e57600080fd5b6127478761252c565b9550602087013594506040870135935061276360608801612714565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a03121561279857600080fd5b6127a18861252c565b96506127af6020890161252c565b955060408801359450606088013593506127cb60808901612714565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156127fa57600080fd5b6128038361252c565b91506128116020840161252c565b90509250929050565b6000806040838503121561282d57600080fd5b6128368361252c565b9150602083013563ffffffff8116811461261e57600080fd5b600181811c9082168061286357607f821691505b602082108114156118b457634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082198211156128ad576128ad612884565b500190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156128da57600080fd5b5051919050565b6000828210156128f3576128f3612884565b500390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261297657634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fdfea26469706673582212208696d7fc75edc692b65d65df10ce07940ca4f7436f6a38a536db45f6904769aa64736f6c634300080c0033", + Bin: "0x60a060405234801561001057600080fd5b50604051612b9c380380612b9c83398101604081905261002f91610109565b6001600160a01b03811660805261004461004a565b50610139565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610107576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011b57600080fd5b81516001600160a01b038116811461013257600080fd5b9392505050565b608051612a2c6101706000396000818161056f01528181610c5701528181610c8201528181610cad0152610cce0152612a2c6000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c806384b0196e11610125578063b8c25594116100ad578063dd62ed3e1161007c578063dd62ed3e146104ff578063eb415f4514610512578063f1127ed81461051a578063f2fde38b14610557578063fdc371ce1461056a57600080fd5b8063b8c25594146104b3578063c3cda520146104c6578063c4d66de8146104d9578063d505accf146104ec57600080fd5b806395d89b41116100f457806395d89b41146104685780639ab24eb0146104705780639aec4bae14610483578063a457c2d71461048d578063a9059cbb146104a057600080fd5b806384b0196e1461040a5780638da5cb5b146104255780638e539e8c1461043657806391ddadf41461044957600080fd5b80633a46b1a8116101a85780636fcfff45116101775780636fcfff451461037a57806370a08231146103a2578063715018a6146103cb57806378aa33ba146103d35780637ecebe00146103f757600080fd5b80633a46b1a8146102e65780634bf5d7e9146102f9578063587cde1e146103235780635c19a95c1461036757600080fd5b80631ffacdef116101ef5780631ffacdef1461029457806323b872dd146102a9578063313ce567146102bc5780633644e515146102cb57806339509351146102d357600080fd5b80630455e6941461022157806306fdde031461025a578063095ea7b31461026f57806318160ddd14610282575b600080fd5b61024561022f366004612497565b6101316020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b610262610591565b60405161025191906124f8565b61024561027d36600461250b565b610623565b6067545b604051908152602001610251565b6102a76102a2366004612535565b61063d565b005b6102456102b7366004612571565b610653565b60405160128152602001610251565b610286610677565b6102456102e136600461250b565b610686565b6102866102f436600461250b565b6106a8565b60408051808201909152600e81526d06d6f64653d74696d657374616d760941b6020820152610262565b61034f610331366004612497565b6001600160a01b03908116600090815260fe60205260409020541690565b6040516001600160a01b039091168152602001610251565b6102a7610375366004612497565b610732565b61038d610388366004612497565b61073f565b60405163ffffffff9091168152602001610251565b6102866103b0366004612497565b6001600160a01b031660009081526065602052604090205490565b6102a7610761565b6102456103e1366004612497565b6101326020526000908152604090205460ff1681565b610286610405366004612497565b610775565b610412610793565b60405161025197969594939291906125ae565b6033546001600160a01b031661034f565b610286610444366004612646565b610831565b610451610899565b60405165ffffffffffff9091168152602001610251565b6102626108a4565b61028661047e366004612497565b6108b3565b6102866101305481565b61024561049b36600461250b565b610935565b6102456104ae36600461250b565b6109b0565b6102a76104c1366004612535565b6109be565b6102a76104d4366004612670565b6109d0565b6102a76104e7366004612497565b610b06565b6102a76104fa3660046126c8565b610dc5565b61028661050d366004612733565b610f29565b6102a7610f54565b61052d610528366004612766565b611024565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610251565b6102a7610565366004612497565b6110a8565b61034f7f000000000000000000000000000000000000000000000000000000000000000081565b6060606880546105a09061279b565b80601f01602080910402602001604051908101604052809291908181526020018280546105cc9061279b565b80156106195780601f106105ee57610100808354040283529160200191610619565b820191906000526020600020905b8154815290600101906020018083116105fc57829003601f168201915b5050505050905090565b60003361063181858561111e565b60019150505b92915050565b610645611242565b61064f828261129c565b5050565b6000336106618582856112fd565b61066c858585611377565b506001949350505050565b6000610681611533565b905090565b6000336106318185856106998383610f29565b6106a391906127e5565b61111e565b60006106b2610899565b65ffffffffffff1682106107095760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b60448201526064015b60405180910390fd5b6001600160a01b038316600090815260ff6020526040902061072b908361153d565b9392505050565b61073c3382611626565b50565b6001600160a01b038116600090815260ff6020526040812054610637906116a0565b610769611242565b6107736000611709565b565b6001600160a01b038116600090815260cb6020526040812054610637565b6000606080600080600060606097546000801b1480156107b35750609854155b6107f75760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610700565b6107ff61175b565b61080761176a565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b600061083b610899565b65ffffffffffff16821061088d5760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b6044820152606401610700565b6106376101008361153d565b600061068142611779565b6060606980546105a09061279b565b6001600160a01b038116600090815260ff60205260408120548015610922576001600160a01b038316600090815260ff60205260409020805460001983019081106109005761090061280e565b60009182526020909120015464010000000090046001600160e01b0316610925565b60005b6001600160e01b03169392505050565b600033816109438286610f29565b9050838110156109a35760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610700565b61066c828686840361111e565b600033610631818585611377565b6109c6611242565b61064f82826117e0565b83421115610a205760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610700565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610a9a90610a929060a00160405160208183030381529060405280519060200120611839565b858585611866565b9050610aa58161188e565b8614610af35760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610700565b610afd8188611626565b50505050505050565b600054610100900460ff1615808015610b265750600054600160ff909116105b80610b405750303b158015610b40575060005460ff166001145b610ba35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610700565b6000805460ff191660011790558015610bc6576000805461ff0019166101001790555b610bce6118b6565b610c1b6040518060400160405280600d81526020016c2130b1b5b4b7339022b4b3b2b760991b815250604051806040016040528060068152602001653122a4a3a2a760d11b8152506118e5565b610c2482611709565b610c4b604051806040016040528060068152602001653122a4a3a2a760d11b815250611916565b60001961013055610c7d7f0000000000000000000000000000000000000000000000000000000000000000600161129c565b610ca87f000000000000000000000000000000000000000000000000000000000000000060016117e0565b610d537f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4e9190612824565b611960565b6040517fb7c23c1e2e36f298e9879a88ecfcd07e28fbb439bcfa9c78ca1363ca14370d2690600090a1801561064f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b83421115610e155760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610700565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e448c61188e565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e9f82611839565b90506000610eaf82878787611866565b9050896001600160a01b0316816001600160a01b031614610f125760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610700565b610f1d8a8a8a61111e565b50505050505050505050565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b610f5c611242565b6000196101305414610ff35760405162461bcd60e51b815260206004820152605460248201527f4261636b696e67456967656e2e64697361626c655472616e736665725265737460448201527f72696374696f6e733a207472616e73666572207265737472696374696f6e7320606482015273185c9948185b1c9958591e48191a5cd8589b195960621b608482015260a401610700565b60006101308190556040517f2b18986d3ba809db2f13a5d7bf17f60d357b37d9cbb55dd71cbbac8dc4060f649190a1565b60408051808201909152600080825260208201526001600160a01b038316600090815260ff60205260409020805463ffffffff84169081106110685761106861280e565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b6110b0611242565b6001600160a01b0381166111155760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610700565b61073c81611709565b6001600160a01b0383166111805760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610700565b6001600160a01b0382166111e15760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610700565b6001600160a01b0383811660008181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6033546001600160a01b031633146107735760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610700565b6001600160a01b03821660008181526101316020908152604091829020805460ff191685151590811790915591519182527fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed284362227191015b60405180910390a25050565b60006113098484610f29565b9050600019811461137157818110156113645760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610700565b611371848484840361111e565b50505050565b6001600160a01b0383166113db5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610700565b6001600160a01b03821661143d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610700565b6114488383836119eb565b6001600160a01b038316600090815260656020526040902054818110156114c05760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610700565b6001600160a01b0380851660008181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906115209086815260200190565b60405180910390a3611371848484611ac9565b6000610681611afb565b81546000908181600581111561159757600061155884611b6f565b611562908561283d565b600088815260209020909150869082015463ffffffff16111561158757809150611595565b6115928160016127e5565b92505b505b808210156115e45760006115ab8383611c57565b600088815260209020909150869082015463ffffffff1611156115d0578091506115de565b6115db8160016127e5565b92505b50611597565b8015611610576000868152602090208101600019015464010000000090046001600160e01b0316611613565b60005b6001600160e01b03169695505050505050565b6001600160a01b03828116600081815260fe6020818152604080842080546065845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611371828483611c72565b600063ffffffff8211156117055760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610700565b5090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060609980546105a09061279b565b6060609a80546105a09061279b565b600065ffffffffffff8211156117055760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610700565b6001600160a01b03821660008181526101326020908152604091829020805460ff191685151590811790915591519182527f72a561d1af7409467dae4f1e9fc52590a9335a1dda17727e2b6aa8c4db35109b91016112f1565b6000610637611846611533565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600061187787878787611daf565b9150915061188481611e73565b5095945050505050565b6001600160a01b038116600090815260cb602052604090208054600181018255905b50919050565b600054610100900460ff166118dd5760405162461bcd60e51b815260040161070090612850565b610773611fbd565b600054610100900460ff1661190c5760405162461bcd60e51b815260040161070090612850565b61064f8282611fed565b600054610100900460ff1661193d5760405162461bcd60e51b815260040161070090612850565b61073c81604051806040016040528060018152602001603160f81b81525061202d565b61196a828261207c565b6067546001600160e01b0310156119dc5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610700565b6113716101006121518361215d565b610130544211611ac4576001600160a01b0383166000908152610131602052604090205460ff1680611a3657506001600160a01b0382166000908152610132602052604090205460ff165b80611a4857506001600160a01b038316155b611ac45760405162461bcd60e51b815260206004820152604160248201527f4261636b696e67456967656e2e5f6265666f7265546f6b656e5472616e73666560448201527f723a2066726f6d206f7220746f206d7573742062652077686974656c697374656064820152601960fa1b608482015260a401610700565b505050565b6001600160a01b03838116600090815260fe6020526040808220548584168352912054611ac492918216911683611c72565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611b266122d2565b611b2e61232b565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600081600003611b8157506000919050565b60006001611b8e8461235c565b901c6001901b90506001818481611ba757611ba761289b565b048201901c90506001818481611bbf57611bbf61289b565b048201901c90506001818481611bd757611bd761289b565b048201901c90506001818481611bef57611bef61289b565b048201901c90506001818481611c0757611c0761289b565b048201901c90506001818481611c1f57611c1f61289b565b048201901c90506001818481611c3757611c3761289b565b048201901c905061072b81828581611c5157611c5161289b565b046123f0565b6000611c6660028484186128b1565b61072b908484166127e5565b816001600160a01b0316836001600160a01b031614158015611c945750600081115b15611ac4576001600160a01b03831615611d22576001600160a01b038316600090815260ff602052604081208190611ccf906124068561215d565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611d17929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611ac4576001600160a01b038216600090815260ff602052604081208190611d58906121518561215d565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611da0929190918252602082015260400190565b60405180910390a25050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611de65750600090506003611e6a565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611e3a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611e6357600060019250925050611e6a565b9150600090505b94509492505050565b6000816004811115611e8757611e876128d3565b03611e8f5750565b6001816004811115611ea357611ea36128d3565b03611ef05760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610700565b6002816004811115611f0457611f046128d3565b03611f515760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610700565b6003816004811115611f6557611f656128d3565b0361073c5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610700565b600054610100900460ff16611fe45760405162461bcd60e51b815260040161070090612850565b61077333611709565b600054610100900460ff166120145760405162461bcd60e51b815260040161070090612850565b60686120208382612937565b506069611ac48282612937565b600054610100900460ff166120545760405162461bcd60e51b815260040161070090612850565b60996120608382612937565b50609a61206d8282612937565b50506000609781905560985550565b6001600160a01b0382166120d25760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610700565b6120de600083836119eb565b80606760008282546120f091906127e5565b90915550506001600160a01b0382166000818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361064f60008383611ac9565b600061072b82846127e5565b825460009081908181156121aa5760008781526020902082016000190160408051808201909152905463ffffffff8116825264010000000090046001600160e01b031660208201526121bf565b60408051808201909152600080825260208201525b905080602001516001600160e01b031693506121df84868863ffffffff16565b925060008211801561220957506121f4610899565b65ffffffffffff16816000015163ffffffff16145b1561224e5761221783612412565b60008881526020902083016000190180546001600160e01b03929092166401000000000263ffffffff9092169190911790556122c8565b866040518060400160405280612272612265610899565b65ffffffffffff166116a0565b63ffffffff16815260200161228686612412565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b6000806122dd61175b565b8051909150156122f4578051602090910120919050565b60975480156123035792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b60008061233661176a565b80519091501561234d578051602090910120919050565b60985480156123035792915050565b600080608083901c1561237157608092831c92015b604083901c1561238357604092831c92015b602083901c1561239557602092831c92015b601083901c156123a757601092831c92015b600883901c156123b957600892831c92015b600483901c156123cb57600492831c92015b600283901c156123dd57600292831c92015b600183901c156106375760010192915050565b60008183106123ff578161072b565b5090919050565b600061072b828461283d565b60006001600160e01b038211156117055760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610700565b80356001600160a01b038116811461249257600080fd5b919050565b6000602082840312156124a957600080fd5b61072b8261247b565b6000815180845260005b818110156124d8576020818501810151868301820152016124bc565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061072b60208301846124b2565b6000806040838503121561251e57600080fd5b6125278361247b565b946020939093013593505050565b6000806040838503121561254857600080fd5b6125518361247b565b91506020830135801515811461256657600080fd5b809150509250929050565b60008060006060848603121561258657600080fd5b61258f8461247b565b925061259d6020850161247b565b929592945050506040919091013590565b60ff60f81b8816815260e0602082015260006125cd60e08301896124b2565b82810360408401526125df81896124b2565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b81811015612635578351835260209384019390920191600101612617565b50909b9a5050505050505050505050565b60006020828403121561265857600080fd5b5035919050565b803560ff8116811461249257600080fd5b60008060008060008060c0878903121561268957600080fd5b6126928761247b565b955060208701359450604087013593506126ae6060880161265f565b9598949750929560808101359460a0909101359350915050565b600080600080600080600060e0888a0312156126e357600080fd5b6126ec8861247b565b96506126fa6020890161247b565b955060408801359450606088013593506127166080890161265f565b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561274657600080fd5b61274f8361247b565b915061275d6020840161247b565b90509250929050565b6000806040838503121561277957600080fd5b6127828361247b565b9150602083013563ffffffff8116811461256657600080fd5b600181811c908216806127af57607f821691505b6020821081036118b057634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610637576106376127cf565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561283657600080fd5b5051919050565b81810381811115610637576106376127cf565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b6000826128ce57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fd5b601f821115611ac457806000526020600020601f840160051c810160208510156129105750805b601f840160051c820191505b81811015612930576000815560010161291c565b5050505050565b815167ffffffffffffffff811115612951576129516127f8565b6129658161295f845461279b565b846128e9565b6020601f82116001811461299957600083156129815750848201515b600019600385901b1c1916600184901b178455612930565b600084815260208120601f198516915b828110156129c957878501518255602094850194600190920191016129a9565b50848210156129e75786840151600019600387901b60f8161c191681555b50505050600190811b0190555056fea26469706673582212209a155b5b5dac4a5d3726abe6703c01b8653a274f50492b0f76adf91f8c97cc6764736f6c634300081b0033", } // BackingEigenABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/BeaconChainProofs/binding.go b/pkg/bindings/BeaconChainProofs/binding.go index 2fc7439ef..b620d1a3d 100644 --- a/pkg/bindings/BeaconChainProofs/binding.go +++ b/pkg/bindings/BeaconChainProofs/binding.go @@ -31,8 +31,8 @@ var ( // BeaconChainProofsMetaData contains all meta data concerning the BeaconChainProofs contract. var BeaconChainProofsMetaData = &bind.MetaData{ - ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c00cb22743991a146de10677177d34d77104039d759b6119b391bd5a11f1770f64736f6c634300080c0033", + ABI: "[{\"type\":\"error\",\"name\":\"InvalidProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProofLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidValidatorFieldsLength\",\"inputs\":[]}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122019674d3bc6da7783434d71aa3e357ce154db5299101142e28cd12eae816e978464736f6c634300081b0033", } // BeaconChainProofsABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/BytesLib/binding.go b/pkg/bindings/BytesLib/binding.go index b54665bad..00be50f24 100644 --- a/pkg/bindings/BytesLib/binding.go +++ b/pkg/bindings/BytesLib/binding.go @@ -31,8 +31,8 @@ var ( // BytesLibMetaData contains all meta data concerning the BytesLib contract. var BytesLibMetaData = &bind.MetaData{ - ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122052491940b4b732c4bc716d1afbe1eaf5e1c77ff3a35e025bac5ca61a239df65964736f6c634300080c0033", + ABI: "[{\"type\":\"error\",\"name\":\"OutOfBounds\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Overflow\",\"inputs\":[]}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212204e8c051905ae1e9738a8b3cb4829f706e7ff0e36f28a79dbfba20e364001220764736f6c634300081b0033", } // BytesLibABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/Checkpoints/binding.go b/pkg/bindings/Checkpoints/binding.go new file mode 100644 index 000000000..41a27afa8 --- /dev/null +++ b/pkg/bindings/Checkpoints/binding.go @@ -0,0 +1,203 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package Checkpoints + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// CheckpointsMetaData contains all meta data concerning the Checkpoints contract. +var CheckpointsMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122033cd598fba8494d1a6958a8af518adce5917043f9d96f1543c5e5350d9ce39b364736f6c634300080c0033", +} + +// CheckpointsABI is the input ABI used to generate the binding from. +// Deprecated: Use CheckpointsMetaData.ABI instead. +var CheckpointsABI = CheckpointsMetaData.ABI + +// CheckpointsBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use CheckpointsMetaData.Bin instead. +var CheckpointsBin = CheckpointsMetaData.Bin + +// DeployCheckpoints deploys a new Ethereum contract, binding an instance of Checkpoints to it. +func DeployCheckpoints(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Checkpoints, error) { + parsed, err := CheckpointsMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CheckpointsBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Checkpoints{CheckpointsCaller: CheckpointsCaller{contract: contract}, CheckpointsTransactor: CheckpointsTransactor{contract: contract}, CheckpointsFilterer: CheckpointsFilterer{contract: contract}}, nil +} + +// Checkpoints is an auto generated Go binding around an Ethereum contract. +type Checkpoints struct { + CheckpointsCaller // Read-only binding to the contract + CheckpointsTransactor // Write-only binding to the contract + CheckpointsFilterer // Log filterer for contract events +} + +// CheckpointsCaller is an auto generated read-only Go binding around an Ethereum contract. +type CheckpointsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CheckpointsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type CheckpointsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CheckpointsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type CheckpointsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// CheckpointsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type CheckpointsSession struct { + Contract *Checkpoints // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// CheckpointsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type CheckpointsCallerSession struct { + Contract *CheckpointsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// CheckpointsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type CheckpointsTransactorSession struct { + Contract *CheckpointsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// CheckpointsRaw is an auto generated low-level Go binding around an Ethereum contract. +type CheckpointsRaw struct { + Contract *Checkpoints // Generic contract binding to access the raw methods on +} + +// CheckpointsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type CheckpointsCallerRaw struct { + Contract *CheckpointsCaller // Generic read-only contract binding to access the raw methods on +} + +// CheckpointsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type CheckpointsTransactorRaw struct { + Contract *CheckpointsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewCheckpoints creates a new instance of Checkpoints, bound to a specific deployed contract. +func NewCheckpoints(address common.Address, backend bind.ContractBackend) (*Checkpoints, error) { + contract, err := bindCheckpoints(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Checkpoints{CheckpointsCaller: CheckpointsCaller{contract: contract}, CheckpointsTransactor: CheckpointsTransactor{contract: contract}, CheckpointsFilterer: CheckpointsFilterer{contract: contract}}, nil +} + +// NewCheckpointsCaller creates a new read-only instance of Checkpoints, bound to a specific deployed contract. +func NewCheckpointsCaller(address common.Address, caller bind.ContractCaller) (*CheckpointsCaller, error) { + contract, err := bindCheckpoints(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &CheckpointsCaller{contract: contract}, nil +} + +// NewCheckpointsTransactor creates a new write-only instance of Checkpoints, bound to a specific deployed contract. +func NewCheckpointsTransactor(address common.Address, transactor bind.ContractTransactor) (*CheckpointsTransactor, error) { + contract, err := bindCheckpoints(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &CheckpointsTransactor{contract: contract}, nil +} + +// NewCheckpointsFilterer creates a new log filterer instance of Checkpoints, bound to a specific deployed contract. +func NewCheckpointsFilterer(address common.Address, filterer bind.ContractFilterer) (*CheckpointsFilterer, error) { + contract, err := bindCheckpoints(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &CheckpointsFilterer{contract: contract}, nil +} + +// bindCheckpoints binds a generic wrapper to an already deployed contract. +func bindCheckpoints(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := CheckpointsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Checkpoints *CheckpointsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Checkpoints.Contract.CheckpointsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Checkpoints *CheckpointsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Checkpoints.Contract.CheckpointsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Checkpoints *CheckpointsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Checkpoints.Contract.CheckpointsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Checkpoints *CheckpointsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Checkpoints.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Checkpoints *CheckpointsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Checkpoints.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Checkpoints *CheckpointsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Checkpoints.Contract.contract.Transact(opts, method, params...) +} diff --git a/pkg/bindings/DelayedWithdrawalRouter/binding.go b/pkg/bindings/DelayedWithdrawalRouter/binding.go new file mode 100644 index 000000000..4943de658 --- /dev/null +++ b/pkg/bindings/DelayedWithdrawalRouter/binding.go @@ -0,0 +1,1969 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package DelayedWithdrawalRouter + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IDelayedWithdrawalRouterDelayedWithdrawal is an auto generated low-level Go binding around an user-defined struct. +type IDelayedWithdrawalRouterDelayedWithdrawal struct { + Amount *big.Int + BlockCreated uint32 +} + +// IDelayedWithdrawalRouterUserDelayedWithdrawals is an auto generated low-level Go binding around an user-defined struct. +type IDelayedWithdrawalRouterUserDelayedWithdrawals struct { + DelayedWithdrawalsCompleted *big.Int + DelayedWithdrawals []IDelayedWithdrawalRouterDelayedWithdrawal +} + +// DelayedWithdrawalRouterMetaData contains all meta data concerning the DelayedWithdrawalRouter contract. +var DelayedWithdrawalRouterMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"MAX_WITHDRAWAL_DELAY_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"canClaimDelayedWithdrawal\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimDelayedWithdrawals\",\"inputs\":[{\"name\":\"maxNumberOfDelayedWithdrawalsToClaim\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"claimDelayedWithdrawals\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"maxNumberOfDelayedWithdrawalsToClaim\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createDelayedWithdrawal\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getClaimableUserDelayedWithdrawals\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIDelayedWithdrawalRouter.DelayedWithdrawal[]\",\"components\":[{\"name\":\"amount\",\"type\":\"uint224\",\"internalType\":\"uint224\"},{\"name\":\"blockCreated\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getUserDelayedWithdrawals\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIDelayedWithdrawalRouter.DelayedWithdrawal[]\",\"components\":[{\"name\":\"amount\",\"type\":\"uint224\",\"internalType\":\"uint224\"},{\"name\":\"blockCreated\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_withdrawalDelayBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"newValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userDelayedWithdrawalByIndex\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelayedWithdrawalRouter.DelayedWithdrawal\",\"components\":[{\"name\":\"amount\",\"type\":\"uint224\",\"internalType\":\"uint224\"},{\"name\":\"blockCreated\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"userWithdrawals\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelayedWithdrawalRouter.UserDelayedWithdrawals\",\"components\":[{\"name\":\"delayedWithdrawalsCompleted\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"delayedWithdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelayedWithdrawalRouter.DelayedWithdrawal[]\",\"components\":[{\"name\":\"amount\",\"type\":\"uint224\",\"internalType\":\"uint224\"},{\"name\":\"blockCreated\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"userWithdrawalsLength\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"DelayedWithdrawalCreated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"index\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DelayedWithdrawalsClaimed\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"amountClaimed\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"delayedWithdrawalsCompleted\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001f0e38038062001f0e8339810160408190526200003491620001a8565b6001600160a01b038116620000cb5760405162461bcd60e51b815260206004820152604c60248201527f44656c617965645769746864726177616c526f757465722e636f6e737472756360448201527f746f723a205f656967656e506f644d616e616765722063616e6e6f742062652060648201526b7a65726f206164647265737360a01b608482015260a4015b60405180910390fd5b6001600160a01b038116608052620000e2620000e9565b50620001da565b600054610100900460ff1615620001535760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608401620000c2565b60005460ff9081161015620001a6576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b600060208284031215620001bb57600080fd5b81516001600160a01b0381168114620001d357600080fd5b9392505050565b608051611d11620001fd600039600081816101fa0152610c000152611d116000f3fe60806040526004361061014b5760003560e01c806385594e58116100b6578063e4f4f8871161006f578063e4f4f887146103cc578063e5db06c014610405578063eb990c5914610425578063ecb7cb1b14610445578063f2fde38b14610472578063fabc1cbc1461049257600080fd5b806385594e5814610317578063886f1195146103445780638da5cb5b14610364578063c0db354c14610382578063ca661c0414610395578063d44e1b76146103ac57600080fd5b806350f73e7c1161010857806350f73e7c14610254578063595c6a67146102785780635ac86ab71461028d5780635c975abb146102cd578063715018a6146102e257806375608896146102f757600080fd5b806310d67a2f14610150578063136439dd146101725780631f39d87f146101925780633e1de008146101c85780634665bcda146101e85780634d50f9a414610234575b600080fd5b34801561015c57600080fd5b5061017061016b36600461196d565b6104b2565b005b34801561017e57600080fd5b5061017061018d366004611991565b61056e565b34801561019e57600080fd5b506101b26101ad36600461196d565b6106ad565b6040516101bf91906119c8565b60405180910390f35b3480156101d457600080fd5b506101b26101e336600461196d565b6108a8565b3480156101f457600080fd5b5061021c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101bf565b34801561024057600080fd5b5061017061024f366004611991565b6109ee565b34801561026057600080fd5b5061026a60c95481565b6040519081526020016101bf565b34801561028457600080fd5b506101706109ff565b34801561029957600080fd5b506102bd6102a8366004611a15565b609854600160ff9092169190911b9081161490565b60405190151581526020016101bf565b3480156102d957600080fd5b5060985461026a565b3480156102ee57600080fd5b50610170610ac6565b34801561030357600080fd5b506102bd610312366004611a38565b610ada565b34801561032357600080fd5b50610337610332366004611a38565b610b5d565b6040516101bf9190611a64565b34801561035057600080fd5b5060975461021c906001600160a01b031681565b34801561037057600080fd5b506033546001600160a01b031661021c565b610170610390366004611a72565b610bdd565b3480156103a157600080fd5b5061026a62034bc081565b3480156103b857600080fd5b506101706103c7366004611991565b610e9d565b3480156103d857600080fd5b5061026a6103e736600461196d565b6001600160a01b0316600090815260ca602052604090206001015490565b34801561041157600080fd5b50610170610420366004611a38565b610f31565b34801561043157600080fd5b50610170610440366004611aab565b610fc6565b34801561045157600080fd5b5061046561046036600461196d565b6110ee565b6040516101bf9190611af1565b34801561047e57600080fd5b5061017061048d36600461196d565b6111a8565b34801561049e57600080fd5b506101706104ad366004611991565b61121e565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610505573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105299190611b47565b6001600160a01b0316336001600160a01b0316146105625760405162461bcd60e51b815260040161055990611b64565b60405180910390fd5b61056b8161137a565b50565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105da9190611bae565b6105f65760405162461bcd60e51b815260040161055990611bd0565b6098548181161461066f5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610559565b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001600160a01b038116600090815260ca6020526040812080546001909101546060926106da8383611c2e565b90508060005b82811015610786576001600160a01b038716600090815260ca6020526040812060010161070d8388611c45565b8154811061071d5761071d611c5d565b6000918252602091829020604080518082019091529101546001600160e01b0381168252600160e01b900463ffffffff1691810182905260c95490925061076391611c45565b4310156107735781925050610786565b508061077e81611c73565b9150506106e0565b508060008167ffffffffffffffff8111156107a3576107a3611c8e565b6040519080825280602002602001820160405280156107e857816020015b60408051808201909152600080825260208201528152602001906001900390816107c15790505b509050811561089d5760005b8281101561089b576001600160a01b038916600090815260ca602052604090206001016108218289611c45565b8154811061083157610831611c5d565b6000918252602091829020604080518082019091529101546001600160e01b0381168252600160e01b900463ffffffff1691810191909152825183908390811061087d5761087d611c5d565b6020026020010181905250808061089390611c73565b9150506107f4565b505b979650505050505050565b6001600160a01b038116600090815260ca6020526040812080546001909101546060926108d58383611c2e565b905060008167ffffffffffffffff8111156108f2576108f2611c8e565b60405190808252806020026020018201604052801561093757816020015b60408051808201909152600080825260208201528152602001906001900390816109105790505b50905060005b828110156109e4576001600160a01b038716600090815260ca6020526040902060010161096a8287611c45565b8154811061097a5761097a611c5d565b6000918252602091829020604080518082019091529101546001600160e01b0381168252600160e01b900463ffffffff169181019190915282518390839081106109c6576109c6611c5d565b602002602001018190525080806109dc90611c73565b91505061093d565b5095945050505050565b6109f6611471565b61056b816114cb565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610a47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6b9190611bae565b610a875760405162461bcd60e51b815260040161055990611bd0565b600019609881905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b610ace611471565b610ad86000611593565b565b6001600160a01b038216600090815260ca60205260408120548210801590610b54575060c9546001600160a01b038416600090815260ca60205260409020600101805484908110610b2d57610b2d611c5d565b600091825260209091200154610b509190600160e01b900463ffffffff16611c45565b4310155b90505b92915050565b60408051808201909152600080825260208201526001600160a01b038316600090815260ca60205260409020600101805483908110610b9e57610b9e611c5d565b6000918252602091829020604080518082019091529101546001600160e01b0381168252600160e01b900463ffffffff16918101919091529392505050565b60405163a38406a360e01b81526001600160a01b038084166004830152839133917f0000000000000000000000000000000000000000000000000000000000000000169063a38406a390602401602060405180830381865afa158015610c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6b9190611b47565b6001600160a01b031614610ce75760405162461bcd60e51b815260206004820152603d60248201527f44656c617965645769746864726177616c526f757465722e6f6e6c794569676560448201527f6e506f643a206e6f7420706f644f776e6572277320456967656e506f640000006064820152608401610559565b60985460009060019081161415610d105760405162461bcd60e51b815260040161055990611ca4565b6001600160a01b038316610da65760405162461bcd60e51b815260206004820152605160248201527f44656c617965645769746864726177616c526f757465722e637265617465446560448201527f6c617965645769746864726177616c3a20726563697069656e742063616e6e6f60648201527074206265207a65726f206164647265737360781b608482015260a401610559565b346001600160e01b03811615610e96576040805180820182526001600160e01b03808416825263ffffffff43811660208085019182526001600160a01b038a16600081815260ca8352968720600190810180548083018255818a5293892088519551909616600160e01b029490961693909317939091019290925593525490917fb8f1b14c7caf74150801dcc9bc18d575cbeaf5b421943497e409df92c92e0f5991889188918691610e5791611c2e565b604080516001600160a01b0395861681529490931660208501526001600160e01b039091169183019190915260608201526080015b60405180910390a1505b5050505050565b60026065541415610ef05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610559565b600260655560985460009060019081161415610f1e5760405162461bcd60e51b815260040161055990611ca4565b610f2833836115e5565b50506001606555565b60026065541415610f845760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610559565b600260655560985460009060019081161415610fb25760405162461bcd60e51b815260040161055990611ca4565b610fbc83836115e5565b5050600160655550565b600054610100900460ff1615808015610fe65750600054600160ff909116105b806110005750303b158015611000575060005460ff166001145b6110635760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610559565b6000805460ff191660011790558015611086576000805461ff0019166101001790555b61108f85611593565b6110998484611750565b6110a2826114cb565b8015610e96576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b6040805180820190915260008152606060208201526001600160a01b038216600090815260ca6020908152604080832081518083018352815481526001820180548451818702810187019095528085529195929486810194939192919084015b8282101561119a57600084815260209081902060408051808201909152908401546001600160e01b0381168252600160e01b900463ffffffff168183015282526001909201910161114e565b505050915250909392505050565b6111b0611471565b6001600160a01b0381166112155760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610559565b61056b81611593565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112959190611b47565b6001600160a01b0316336001600160a01b0316146112c55760405162461bcd60e51b815260040161055990611b64565b6098541981196098541916146113435760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610559565b609881905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016106a2565b6001600160a01b0381166114085760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610559565b609754604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1609780546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b03163314610ad85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610559565b62034bc08111156115525760405162461bcd60e51b815260206004820152604560248201527f44656c617965645769746864726177616c526f757465722e5f7365745769746860448201527f64726177616c44656c6179426c6f636b733a206e657756616c756520746f6f206064820152646c6172676560d81b608482015260a401610559565b60c95460408051918252602082018390527f4ffb00400574147429ee377a5633386321e66d45d8b14676014b5fa393e61e9e910160405180910390a160c955565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216600090815260ca602052604081208054600190910154825b848110801561161e57508161161c8285611c45565b105b156116cb576001600160a01b038616600090815260ca602052604081206001016116488386611c45565b8154811061165857611658611c5d565b6000918252602091829020604080518082019091529101546001600160e01b0381168252600160e01b900463ffffffff1691810182905260c95490925061169e91611c45565b4310156116ab57506116cb565b80516116c0906001600160e01b031686611c45565b945050600101611607565b6116d58184611c45565b6001600160a01b038716600090815260ca602052604090205583156116fe576116fe868561183a565b7f6b7151500bd0b5cc211bcc47b3029831b769004df4549e8e1c9a69da05bb0943868561172b8487611c45565b604080516001600160a01b039094168452602084019290925290820152606001610e8c565b6097546001600160a01b031615801561177157506001600160a01b03821615155b6117f35760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610559565b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26118368261137a565b5050565b8047101561188a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610559565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146118d7576040519150601f19603f3d011682016040523d82523d6000602084013e6118dc565b606091505b50509050806119535760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610559565b505050565b6001600160a01b038116811461056b57600080fd5b60006020828403121561197f57600080fd5b813561198a81611958565b9392505050565b6000602082840312156119a357600080fd5b5035919050565b80516001600160e01b0316825260209081015163ffffffff16910152565b602080825282518282018190526000919060409081850190868401855b82811015611a08576119f88483516119aa565b92840192908501906001016119e5565b5091979650505050505050565b600060208284031215611a2757600080fd5b813560ff8116811461198a57600080fd5b60008060408385031215611a4b57600080fd5b8235611a5681611958565b946020939093013593505050565b60408101610b5782846119aa565b60008060408385031215611a8557600080fd5b8235611a9081611958565b91506020830135611aa081611958565b809150509250929050565b60008060008060808587031215611ac157600080fd5b8435611acc81611958565b93506020850135611adc81611958565b93969395505050506040820135916060013590565b602080825282518282015282810151604080840181905281516060850181905260009392830191849160808701905b8084101561089b57611b338286516119aa565b938501936001939093019290820190611b20565b600060208284031215611b5957600080fd5b815161198a81611958565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611bc057600080fd5b8151801515811461198a57600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b600082821015611c4057611c40611c18565b500390565b60008219821115611c5857611c58611c18565b500190565b634e487b7160e01b600052603260045260246000fd5b6000600019821415611c8757611c87611c18565b5060010190565b634e487b7160e01b600052604160045260246000fd5b60208082526019908201527f5061757361626c653a20696e646578206973207061757365640000000000000060408201526060019056fea264697066735822122005b0ecc66b0468e43c0d5b0ff9c7b1e449b7556e61ae26d108ff696ed83f730364736f6c634300080c0033", +} + +// DelayedWithdrawalRouterABI is the input ABI used to generate the binding from. +// Deprecated: Use DelayedWithdrawalRouterMetaData.ABI instead. +var DelayedWithdrawalRouterABI = DelayedWithdrawalRouterMetaData.ABI + +// DelayedWithdrawalRouterBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use DelayedWithdrawalRouterMetaData.Bin instead. +var DelayedWithdrawalRouterBin = DelayedWithdrawalRouterMetaData.Bin + +// DeployDelayedWithdrawalRouter deploys a new Ethereum contract, binding an instance of DelayedWithdrawalRouter to it. +func DeployDelayedWithdrawalRouter(auth *bind.TransactOpts, backend bind.ContractBackend, _eigenPodManager common.Address) (common.Address, *types.Transaction, *DelayedWithdrawalRouter, error) { + parsed, err := DelayedWithdrawalRouterMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DelayedWithdrawalRouterBin), backend, _eigenPodManager) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &DelayedWithdrawalRouter{DelayedWithdrawalRouterCaller: DelayedWithdrawalRouterCaller{contract: contract}, DelayedWithdrawalRouterTransactor: DelayedWithdrawalRouterTransactor{contract: contract}, DelayedWithdrawalRouterFilterer: DelayedWithdrawalRouterFilterer{contract: contract}}, nil +} + +// DelayedWithdrawalRouter is an auto generated Go binding around an Ethereum contract. +type DelayedWithdrawalRouter struct { + DelayedWithdrawalRouterCaller // Read-only binding to the contract + DelayedWithdrawalRouterTransactor // Write-only binding to the contract + DelayedWithdrawalRouterFilterer // Log filterer for contract events +} + +// DelayedWithdrawalRouterCaller is an auto generated read-only Go binding around an Ethereum contract. +type DelayedWithdrawalRouterCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelayedWithdrawalRouterTransactor is an auto generated write-only Go binding around an Ethereum contract. +type DelayedWithdrawalRouterTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelayedWithdrawalRouterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type DelayedWithdrawalRouterFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelayedWithdrawalRouterSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type DelayedWithdrawalRouterSession struct { + Contract *DelayedWithdrawalRouter // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DelayedWithdrawalRouterCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type DelayedWithdrawalRouterCallerSession struct { + Contract *DelayedWithdrawalRouterCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// DelayedWithdrawalRouterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type DelayedWithdrawalRouterTransactorSession struct { + Contract *DelayedWithdrawalRouterTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DelayedWithdrawalRouterRaw is an auto generated low-level Go binding around an Ethereum contract. +type DelayedWithdrawalRouterRaw struct { + Contract *DelayedWithdrawalRouter // Generic contract binding to access the raw methods on +} + +// DelayedWithdrawalRouterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type DelayedWithdrawalRouterCallerRaw struct { + Contract *DelayedWithdrawalRouterCaller // Generic read-only contract binding to access the raw methods on +} + +// DelayedWithdrawalRouterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type DelayedWithdrawalRouterTransactorRaw struct { + Contract *DelayedWithdrawalRouterTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewDelayedWithdrawalRouter creates a new instance of DelayedWithdrawalRouter, bound to a specific deployed contract. +func NewDelayedWithdrawalRouter(address common.Address, backend bind.ContractBackend) (*DelayedWithdrawalRouter, error) { + contract, err := bindDelayedWithdrawalRouter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouter{DelayedWithdrawalRouterCaller: DelayedWithdrawalRouterCaller{contract: contract}, DelayedWithdrawalRouterTransactor: DelayedWithdrawalRouterTransactor{contract: contract}, DelayedWithdrawalRouterFilterer: DelayedWithdrawalRouterFilterer{contract: contract}}, nil +} + +// NewDelayedWithdrawalRouterCaller creates a new read-only instance of DelayedWithdrawalRouter, bound to a specific deployed contract. +func NewDelayedWithdrawalRouterCaller(address common.Address, caller bind.ContractCaller) (*DelayedWithdrawalRouterCaller, error) { + contract, err := bindDelayedWithdrawalRouter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterCaller{contract: contract}, nil +} + +// NewDelayedWithdrawalRouterTransactor creates a new write-only instance of DelayedWithdrawalRouter, bound to a specific deployed contract. +func NewDelayedWithdrawalRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*DelayedWithdrawalRouterTransactor, error) { + contract, err := bindDelayedWithdrawalRouter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterTransactor{contract: contract}, nil +} + +// NewDelayedWithdrawalRouterFilterer creates a new log filterer instance of DelayedWithdrawalRouter, bound to a specific deployed contract. +func NewDelayedWithdrawalRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*DelayedWithdrawalRouterFilterer, error) { + contract, err := bindDelayedWithdrawalRouter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterFilterer{contract: contract}, nil +} + +// bindDelayedWithdrawalRouter binds a generic wrapper to an already deployed contract. +func bindDelayedWithdrawalRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := DelayedWithdrawalRouterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DelayedWithdrawalRouter.Contract.DelayedWithdrawalRouterCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.DelayedWithdrawalRouterTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.DelayedWithdrawalRouterTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DelayedWithdrawalRouter.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.contract.Transact(opts, method, params...) +} + +// MAXWITHDRAWALDELAYBLOCKS is a free data retrieval call binding the contract method 0xca661c04. +// +// Solidity: function MAX_WITHDRAWAL_DELAY_BLOCKS() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) MAXWITHDRAWALDELAYBLOCKS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "MAX_WITHDRAWAL_DELAY_BLOCKS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MAXWITHDRAWALDELAYBLOCKS is a free data retrieval call binding the contract method 0xca661c04. +// +// Solidity: function MAX_WITHDRAWAL_DELAY_BLOCKS() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) MAXWITHDRAWALDELAYBLOCKS() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.MAXWITHDRAWALDELAYBLOCKS(&_DelayedWithdrawalRouter.CallOpts) +} + +// MAXWITHDRAWALDELAYBLOCKS is a free data retrieval call binding the contract method 0xca661c04. +// +// Solidity: function MAX_WITHDRAWAL_DELAY_BLOCKS() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) MAXWITHDRAWALDELAYBLOCKS() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.MAXWITHDRAWALDELAYBLOCKS(&_DelayedWithdrawalRouter.CallOpts) +} + +// CanClaimDelayedWithdrawal is a free data retrieval call binding the contract method 0x75608896. +// +// Solidity: function canClaimDelayedWithdrawal(address user, uint256 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) CanClaimDelayedWithdrawal(opts *bind.CallOpts, user common.Address, index *big.Int) (bool, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "canClaimDelayedWithdrawal", user, index) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaimDelayedWithdrawal is a free data retrieval call binding the contract method 0x75608896. +// +// Solidity: function canClaimDelayedWithdrawal(address user, uint256 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) CanClaimDelayedWithdrawal(user common.Address, index *big.Int) (bool, error) { + return _DelayedWithdrawalRouter.Contract.CanClaimDelayedWithdrawal(&_DelayedWithdrawalRouter.CallOpts, user, index) +} + +// CanClaimDelayedWithdrawal is a free data retrieval call binding the contract method 0x75608896. +// +// Solidity: function canClaimDelayedWithdrawal(address user, uint256 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) CanClaimDelayedWithdrawal(user common.Address, index *big.Int) (bool, error) { + return _DelayedWithdrawalRouter.Contract.CanClaimDelayedWithdrawal(&_DelayedWithdrawalRouter.CallOpts, user, index) +} + +// EigenPodManager is a free data retrieval call binding the contract method 0x4665bcda. +// +// Solidity: function eigenPodManager() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) EigenPodManager(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "eigenPodManager") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// EigenPodManager is a free data retrieval call binding the contract method 0x4665bcda. +// +// Solidity: function eigenPodManager() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) EigenPodManager() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.EigenPodManager(&_DelayedWithdrawalRouter.CallOpts) +} + +// EigenPodManager is a free data retrieval call binding the contract method 0x4665bcda. +// +// Solidity: function eigenPodManager() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) EigenPodManager() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.EigenPodManager(&_DelayedWithdrawalRouter.CallOpts) +} + +// GetClaimableUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x1f39d87f. +// +// Solidity: function getClaimableUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) GetClaimableUserDelayedWithdrawals(opts *bind.CallOpts, user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "getClaimableUserDelayedWithdrawals", user) + + if err != nil { + return *new([]IDelayedWithdrawalRouterDelayedWithdrawal), err + } + + out0 := *abi.ConvertType(out[0], new([]IDelayedWithdrawalRouterDelayedWithdrawal)).(*[]IDelayedWithdrawalRouterDelayedWithdrawal) + + return out0, err + +} + +// GetClaimableUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x1f39d87f. +// +// Solidity: function getClaimableUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) GetClaimableUserDelayedWithdrawals(user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.GetClaimableUserDelayedWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// GetClaimableUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x1f39d87f. +// +// Solidity: function getClaimableUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) GetClaimableUserDelayedWithdrawals(user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.GetClaimableUserDelayedWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// GetUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x3e1de008. +// +// Solidity: function getUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) GetUserDelayedWithdrawals(opts *bind.CallOpts, user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "getUserDelayedWithdrawals", user) + + if err != nil { + return *new([]IDelayedWithdrawalRouterDelayedWithdrawal), err + } + + out0 := *abi.ConvertType(out[0], new([]IDelayedWithdrawalRouterDelayedWithdrawal)).(*[]IDelayedWithdrawalRouterDelayedWithdrawal) + + return out0, err + +} + +// GetUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x3e1de008. +// +// Solidity: function getUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) GetUserDelayedWithdrawals(user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.GetUserDelayedWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// GetUserDelayedWithdrawals is a free data retrieval call binding the contract method 0x3e1de008. +// +// Solidity: function getUserDelayedWithdrawals(address user) view returns((uint224,uint32)[]) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) GetUserDelayedWithdrawals(user common.Address) ([]IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.GetUserDelayedWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Owner() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.Owner(&_DelayedWithdrawalRouter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) Owner() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.Owner(&_DelayedWithdrawalRouter.CallOpts) +} + +// Paused is a free data retrieval call binding the contract method 0x5ac86ab7. +// +// Solidity: function paused(uint8 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) Paused(opts *bind.CallOpts, index uint8) (bool, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "paused", index) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Paused is a free data retrieval call binding the contract method 0x5ac86ab7. +// +// Solidity: function paused(uint8 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Paused(index uint8) (bool, error) { + return _DelayedWithdrawalRouter.Contract.Paused(&_DelayedWithdrawalRouter.CallOpts, index) +} + +// Paused is a free data retrieval call binding the contract method 0x5ac86ab7. +// +// Solidity: function paused(uint8 index) view returns(bool) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) Paused(index uint8) (bool, error) { + return _DelayedWithdrawalRouter.Contract.Paused(&_DelayedWithdrawalRouter.CallOpts, index) +} + +// Paused0 is a free data retrieval call binding the contract method 0x5c975abb. +// +// Solidity: function paused() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) Paused0(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "paused0") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Paused0 is a free data retrieval call binding the contract method 0x5c975abb. +// +// Solidity: function paused() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Paused0() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.Paused0(&_DelayedWithdrawalRouter.CallOpts) +} + +// Paused0 is a free data retrieval call binding the contract method 0x5c975abb. +// +// Solidity: function paused() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) Paused0() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.Paused0(&_DelayedWithdrawalRouter.CallOpts) +} + +// PauserRegistry is a free data retrieval call binding the contract method 0x886f1195. +// +// Solidity: function pauserRegistry() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) PauserRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "pauserRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// PauserRegistry is a free data retrieval call binding the contract method 0x886f1195. +// +// Solidity: function pauserRegistry() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) PauserRegistry() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.PauserRegistry(&_DelayedWithdrawalRouter.CallOpts) +} + +// PauserRegistry is a free data retrieval call binding the contract method 0x886f1195. +// +// Solidity: function pauserRegistry() view returns(address) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) PauserRegistry() (common.Address, error) { + return _DelayedWithdrawalRouter.Contract.PauserRegistry(&_DelayedWithdrawalRouter.CallOpts) +} + +// UserDelayedWithdrawalByIndex is a free data retrieval call binding the contract method 0x85594e58. +// +// Solidity: function userDelayedWithdrawalByIndex(address user, uint256 index) view returns((uint224,uint32)) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) UserDelayedWithdrawalByIndex(opts *bind.CallOpts, user common.Address, index *big.Int) (IDelayedWithdrawalRouterDelayedWithdrawal, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "userDelayedWithdrawalByIndex", user, index) + + if err != nil { + return *new(IDelayedWithdrawalRouterDelayedWithdrawal), err + } + + out0 := *abi.ConvertType(out[0], new(IDelayedWithdrawalRouterDelayedWithdrawal)).(*IDelayedWithdrawalRouterDelayedWithdrawal) + + return out0, err + +} + +// UserDelayedWithdrawalByIndex is a free data retrieval call binding the contract method 0x85594e58. +// +// Solidity: function userDelayedWithdrawalByIndex(address user, uint256 index) view returns((uint224,uint32)) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) UserDelayedWithdrawalByIndex(user common.Address, index *big.Int) (IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.UserDelayedWithdrawalByIndex(&_DelayedWithdrawalRouter.CallOpts, user, index) +} + +// UserDelayedWithdrawalByIndex is a free data retrieval call binding the contract method 0x85594e58. +// +// Solidity: function userDelayedWithdrawalByIndex(address user, uint256 index) view returns((uint224,uint32)) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) UserDelayedWithdrawalByIndex(user common.Address, index *big.Int) (IDelayedWithdrawalRouterDelayedWithdrawal, error) { + return _DelayedWithdrawalRouter.Contract.UserDelayedWithdrawalByIndex(&_DelayedWithdrawalRouter.CallOpts, user, index) +} + +// UserWithdrawals is a free data retrieval call binding the contract method 0xecb7cb1b. +// +// Solidity: function userWithdrawals(address user) view returns((uint256,(uint224,uint32)[])) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) UserWithdrawals(opts *bind.CallOpts, user common.Address) (IDelayedWithdrawalRouterUserDelayedWithdrawals, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "userWithdrawals", user) + + if err != nil { + return *new(IDelayedWithdrawalRouterUserDelayedWithdrawals), err + } + + out0 := *abi.ConvertType(out[0], new(IDelayedWithdrawalRouterUserDelayedWithdrawals)).(*IDelayedWithdrawalRouterUserDelayedWithdrawals) + + return out0, err + +} + +// UserWithdrawals is a free data retrieval call binding the contract method 0xecb7cb1b. +// +// Solidity: function userWithdrawals(address user) view returns((uint256,(uint224,uint32)[])) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) UserWithdrawals(user common.Address) (IDelayedWithdrawalRouterUserDelayedWithdrawals, error) { + return _DelayedWithdrawalRouter.Contract.UserWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// UserWithdrawals is a free data retrieval call binding the contract method 0xecb7cb1b. +// +// Solidity: function userWithdrawals(address user) view returns((uint256,(uint224,uint32)[])) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) UserWithdrawals(user common.Address) (IDelayedWithdrawalRouterUserDelayedWithdrawals, error) { + return _DelayedWithdrawalRouter.Contract.UserWithdrawals(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// UserWithdrawalsLength is a free data retrieval call binding the contract method 0xe4f4f887. +// +// Solidity: function userWithdrawalsLength(address user) view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) UserWithdrawalsLength(opts *bind.CallOpts, user common.Address) (*big.Int, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "userWithdrawalsLength", user) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// UserWithdrawalsLength is a free data retrieval call binding the contract method 0xe4f4f887. +// +// Solidity: function userWithdrawalsLength(address user) view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) UserWithdrawalsLength(user common.Address) (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.UserWithdrawalsLength(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// UserWithdrawalsLength is a free data retrieval call binding the contract method 0xe4f4f887. +// +// Solidity: function userWithdrawalsLength(address user) view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) UserWithdrawalsLength(user common.Address) (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.UserWithdrawalsLength(&_DelayedWithdrawalRouter.CallOpts, user) +} + +// WithdrawalDelayBlocks is a free data retrieval call binding the contract method 0x50f73e7c. +// +// Solidity: function withdrawalDelayBlocks() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCaller) WithdrawalDelayBlocks(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _DelayedWithdrawalRouter.contract.Call(opts, &out, "withdrawalDelayBlocks") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// WithdrawalDelayBlocks is a free data retrieval call binding the contract method 0x50f73e7c. +// +// Solidity: function withdrawalDelayBlocks() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) WithdrawalDelayBlocks() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.WithdrawalDelayBlocks(&_DelayedWithdrawalRouter.CallOpts) +} + +// WithdrawalDelayBlocks is a free data retrieval call binding the contract method 0x50f73e7c. +// +// Solidity: function withdrawalDelayBlocks() view returns(uint256) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterCallerSession) WithdrawalDelayBlocks() (*big.Int, error) { + return _DelayedWithdrawalRouter.Contract.WithdrawalDelayBlocks(&_DelayedWithdrawalRouter.CallOpts) +} + +// ClaimDelayedWithdrawals is a paid mutator transaction binding the contract method 0xd44e1b76. +// +// Solidity: function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) ClaimDelayedWithdrawals(opts *bind.TransactOpts, maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "claimDelayedWithdrawals", maxNumberOfDelayedWithdrawalsToClaim) +} + +// ClaimDelayedWithdrawals is a paid mutator transaction binding the contract method 0xd44e1b76. +// +// Solidity: function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) ClaimDelayedWithdrawals(maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.ClaimDelayedWithdrawals(&_DelayedWithdrawalRouter.TransactOpts, maxNumberOfDelayedWithdrawalsToClaim) +} + +// ClaimDelayedWithdrawals is a paid mutator transaction binding the contract method 0xd44e1b76. +// +// Solidity: function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) ClaimDelayedWithdrawals(maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.ClaimDelayedWithdrawals(&_DelayedWithdrawalRouter.TransactOpts, maxNumberOfDelayedWithdrawalsToClaim) +} + +// ClaimDelayedWithdrawals0 is a paid mutator transaction binding the contract method 0xe5db06c0. +// +// Solidity: function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) ClaimDelayedWithdrawals0(opts *bind.TransactOpts, recipient common.Address, maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "claimDelayedWithdrawals0", recipient, maxNumberOfDelayedWithdrawalsToClaim) +} + +// ClaimDelayedWithdrawals0 is a paid mutator transaction binding the contract method 0xe5db06c0. +// +// Solidity: function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) ClaimDelayedWithdrawals0(recipient common.Address, maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.ClaimDelayedWithdrawals0(&_DelayedWithdrawalRouter.TransactOpts, recipient, maxNumberOfDelayedWithdrawalsToClaim) +} + +// ClaimDelayedWithdrawals0 is a paid mutator transaction binding the contract method 0xe5db06c0. +// +// Solidity: function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfDelayedWithdrawalsToClaim) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) ClaimDelayedWithdrawals0(recipient common.Address, maxNumberOfDelayedWithdrawalsToClaim *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.ClaimDelayedWithdrawals0(&_DelayedWithdrawalRouter.TransactOpts, recipient, maxNumberOfDelayedWithdrawalsToClaim) +} + +// CreateDelayedWithdrawal is a paid mutator transaction binding the contract method 0xc0db354c. +// +// Solidity: function createDelayedWithdrawal(address podOwner, address recipient) payable returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) CreateDelayedWithdrawal(opts *bind.TransactOpts, podOwner common.Address, recipient common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "createDelayedWithdrawal", podOwner, recipient) +} + +// CreateDelayedWithdrawal is a paid mutator transaction binding the contract method 0xc0db354c. +// +// Solidity: function createDelayedWithdrawal(address podOwner, address recipient) payable returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) CreateDelayedWithdrawal(podOwner common.Address, recipient common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.CreateDelayedWithdrawal(&_DelayedWithdrawalRouter.TransactOpts, podOwner, recipient) +} + +// CreateDelayedWithdrawal is a paid mutator transaction binding the contract method 0xc0db354c. +// +// Solidity: function createDelayedWithdrawal(address podOwner, address recipient) payable returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) CreateDelayedWithdrawal(podOwner common.Address, recipient common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.CreateDelayedWithdrawal(&_DelayedWithdrawalRouter.TransactOpts, podOwner, recipient) +} + +// Initialize is a paid mutator transaction binding the contract method 0xeb990c59. +// +// Solidity: function initialize(address initOwner, address _pauserRegistry, uint256 initPausedStatus, uint256 _withdrawalDelayBlocks) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) Initialize(opts *bind.TransactOpts, initOwner common.Address, _pauserRegistry common.Address, initPausedStatus *big.Int, _withdrawalDelayBlocks *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "initialize", initOwner, _pauserRegistry, initPausedStatus, _withdrawalDelayBlocks) +} + +// Initialize is a paid mutator transaction binding the contract method 0xeb990c59. +// +// Solidity: function initialize(address initOwner, address _pauserRegistry, uint256 initPausedStatus, uint256 _withdrawalDelayBlocks) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Initialize(initOwner common.Address, _pauserRegistry common.Address, initPausedStatus *big.Int, _withdrawalDelayBlocks *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Initialize(&_DelayedWithdrawalRouter.TransactOpts, initOwner, _pauserRegistry, initPausedStatus, _withdrawalDelayBlocks) +} + +// Initialize is a paid mutator transaction binding the contract method 0xeb990c59. +// +// Solidity: function initialize(address initOwner, address _pauserRegistry, uint256 initPausedStatus, uint256 _withdrawalDelayBlocks) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) Initialize(initOwner common.Address, _pauserRegistry common.Address, initPausedStatus *big.Int, _withdrawalDelayBlocks *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Initialize(&_DelayedWithdrawalRouter.TransactOpts, initOwner, _pauserRegistry, initPausedStatus, _withdrawalDelayBlocks) +} + +// Pause is a paid mutator transaction binding the contract method 0x136439dd. +// +// Solidity: function pause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) Pause(opts *bind.TransactOpts, newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "pause", newPausedStatus) +} + +// Pause is a paid mutator transaction binding the contract method 0x136439dd. +// +// Solidity: function pause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Pause(newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Pause(&_DelayedWithdrawalRouter.TransactOpts, newPausedStatus) +} + +// Pause is a paid mutator transaction binding the contract method 0x136439dd. +// +// Solidity: function pause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) Pause(newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Pause(&_DelayedWithdrawalRouter.TransactOpts, newPausedStatus) +} + +// PauseAll is a paid mutator transaction binding the contract method 0x595c6a67. +// +// Solidity: function pauseAll() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) PauseAll(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "pauseAll") +} + +// PauseAll is a paid mutator transaction binding the contract method 0x595c6a67. +// +// Solidity: function pauseAll() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) PauseAll() (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.PauseAll(&_DelayedWithdrawalRouter.TransactOpts) +} + +// PauseAll is a paid mutator transaction binding the contract method 0x595c6a67. +// +// Solidity: function pauseAll() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) PauseAll() (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.PauseAll(&_DelayedWithdrawalRouter.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "renounceOwnership") +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) RenounceOwnership() (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.RenounceOwnership(&_DelayedWithdrawalRouter.TransactOpts) +} + +// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. +// +// Solidity: function renounceOwnership() returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.RenounceOwnership(&_DelayedWithdrawalRouter.TransactOpts) +} + +// SetPauserRegistry is a paid mutator transaction binding the contract method 0x10d67a2f. +// +// Solidity: function setPauserRegistry(address newPauserRegistry) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) SetPauserRegistry(opts *bind.TransactOpts, newPauserRegistry common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "setPauserRegistry", newPauserRegistry) +} + +// SetPauserRegistry is a paid mutator transaction binding the contract method 0x10d67a2f. +// +// Solidity: function setPauserRegistry(address newPauserRegistry) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) SetPauserRegistry(newPauserRegistry common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.SetPauserRegistry(&_DelayedWithdrawalRouter.TransactOpts, newPauserRegistry) +} + +// SetPauserRegistry is a paid mutator transaction binding the contract method 0x10d67a2f. +// +// Solidity: function setPauserRegistry(address newPauserRegistry) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) SetPauserRegistry(newPauserRegistry common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.SetPauserRegistry(&_DelayedWithdrawalRouter.TransactOpts, newPauserRegistry) +} + +// SetWithdrawalDelayBlocks is a paid mutator transaction binding the contract method 0x4d50f9a4. +// +// Solidity: function setWithdrawalDelayBlocks(uint256 newValue) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) SetWithdrawalDelayBlocks(opts *bind.TransactOpts, newValue *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "setWithdrawalDelayBlocks", newValue) +} + +// SetWithdrawalDelayBlocks is a paid mutator transaction binding the contract method 0x4d50f9a4. +// +// Solidity: function setWithdrawalDelayBlocks(uint256 newValue) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) SetWithdrawalDelayBlocks(newValue *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.SetWithdrawalDelayBlocks(&_DelayedWithdrawalRouter.TransactOpts, newValue) +} + +// SetWithdrawalDelayBlocks is a paid mutator transaction binding the contract method 0x4d50f9a4. +// +// Solidity: function setWithdrawalDelayBlocks(uint256 newValue) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) SetWithdrawalDelayBlocks(newValue *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.SetWithdrawalDelayBlocks(&_DelayedWithdrawalRouter.TransactOpts, newValue) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "transferOwnership", newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.TransferOwnership(&_DelayedWithdrawalRouter.TransactOpts, newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address newOwner) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.TransferOwnership(&_DelayedWithdrawalRouter.TransactOpts, newOwner) +} + +// Unpause is a paid mutator transaction binding the contract method 0xfabc1cbc. +// +// Solidity: function unpause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactor) Unpause(opts *bind.TransactOpts, newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.contract.Transact(opts, "unpause", newPausedStatus) +} + +// Unpause is a paid mutator transaction binding the contract method 0xfabc1cbc. +// +// Solidity: function unpause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterSession) Unpause(newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Unpause(&_DelayedWithdrawalRouter.TransactOpts, newPausedStatus) +} + +// Unpause is a paid mutator transaction binding the contract method 0xfabc1cbc. +// +// Solidity: function unpause(uint256 newPausedStatus) returns() +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterTransactorSession) Unpause(newPausedStatus *big.Int) (*types.Transaction, error) { + return _DelayedWithdrawalRouter.Contract.Unpause(&_DelayedWithdrawalRouter.TransactOpts, newPausedStatus) +} + +// DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator is returned from FilterDelayedWithdrawalCreated and is used to iterate over the raw logs and unpacked data for DelayedWithdrawalCreated events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator struct { + Event *DelayedWithdrawalRouterDelayedWithdrawalCreated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterDelayedWithdrawalCreated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterDelayedWithdrawalCreated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterDelayedWithdrawalCreated represents a DelayedWithdrawalCreated event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterDelayedWithdrawalCreated struct { + PodOwner common.Address + Recipient common.Address + Amount *big.Int + Index *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDelayedWithdrawalCreated is a free log retrieval operation binding the contract event 0xb8f1b14c7caf74150801dcc9bc18d575cbeaf5b421943497e409df92c92e0f59. +// +// Solidity: event DelayedWithdrawalCreated(address podOwner, address recipient, uint256 amount, uint256 index) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterDelayedWithdrawalCreated(opts *bind.FilterOpts) (*DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "DelayedWithdrawalCreated") + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterDelayedWithdrawalCreatedIterator{contract: _DelayedWithdrawalRouter.contract, event: "DelayedWithdrawalCreated", logs: logs, sub: sub}, nil +} + +// WatchDelayedWithdrawalCreated is a free log subscription operation binding the contract event 0xb8f1b14c7caf74150801dcc9bc18d575cbeaf5b421943497e409df92c92e0f59. +// +// Solidity: event DelayedWithdrawalCreated(address podOwner, address recipient, uint256 amount, uint256 index) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchDelayedWithdrawalCreated(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterDelayedWithdrawalCreated) (event.Subscription, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "DelayedWithdrawalCreated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterDelayedWithdrawalCreated) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "DelayedWithdrawalCreated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDelayedWithdrawalCreated is a log parse operation binding the contract event 0xb8f1b14c7caf74150801dcc9bc18d575cbeaf5b421943497e409df92c92e0f59. +// +// Solidity: event DelayedWithdrawalCreated(address podOwner, address recipient, uint256 amount, uint256 index) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseDelayedWithdrawalCreated(log types.Log) (*DelayedWithdrawalRouterDelayedWithdrawalCreated, error) { + event := new(DelayedWithdrawalRouterDelayedWithdrawalCreated) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "DelayedWithdrawalCreated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator is returned from FilterDelayedWithdrawalsClaimed and is used to iterate over the raw logs and unpacked data for DelayedWithdrawalsClaimed events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator struct { + Event *DelayedWithdrawalRouterDelayedWithdrawalsClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterDelayedWithdrawalsClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterDelayedWithdrawalsClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterDelayedWithdrawalsClaimed represents a DelayedWithdrawalsClaimed event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterDelayedWithdrawalsClaimed struct { + Recipient common.Address + AmountClaimed *big.Int + DelayedWithdrawalsCompleted *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDelayedWithdrawalsClaimed is a free log retrieval operation binding the contract event 0x6b7151500bd0b5cc211bcc47b3029831b769004df4549e8e1c9a69da05bb0943. +// +// Solidity: event DelayedWithdrawalsClaimed(address recipient, uint256 amountClaimed, uint256 delayedWithdrawalsCompleted) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterDelayedWithdrawalsClaimed(opts *bind.FilterOpts) (*DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "DelayedWithdrawalsClaimed") + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterDelayedWithdrawalsClaimedIterator{contract: _DelayedWithdrawalRouter.contract, event: "DelayedWithdrawalsClaimed", logs: logs, sub: sub}, nil +} + +// WatchDelayedWithdrawalsClaimed is a free log subscription operation binding the contract event 0x6b7151500bd0b5cc211bcc47b3029831b769004df4549e8e1c9a69da05bb0943. +// +// Solidity: event DelayedWithdrawalsClaimed(address recipient, uint256 amountClaimed, uint256 delayedWithdrawalsCompleted) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchDelayedWithdrawalsClaimed(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterDelayedWithdrawalsClaimed) (event.Subscription, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "DelayedWithdrawalsClaimed") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterDelayedWithdrawalsClaimed) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "DelayedWithdrawalsClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDelayedWithdrawalsClaimed is a log parse operation binding the contract event 0x6b7151500bd0b5cc211bcc47b3029831b769004df4549e8e1c9a69da05bb0943. +// +// Solidity: event DelayedWithdrawalsClaimed(address recipient, uint256 amountClaimed, uint256 delayedWithdrawalsCompleted) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseDelayedWithdrawalsClaimed(log types.Log) (*DelayedWithdrawalRouterDelayedWithdrawalsClaimed, error) { + event := new(DelayedWithdrawalRouterDelayedWithdrawalsClaimed) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "DelayedWithdrawalsClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterInitializedIterator struct { + Event *DelayedWithdrawalRouterInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterInitialized represents a Initialized event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterInitialized struct { + Version uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterInitialized(opts *bind.FilterOpts) (*DelayedWithdrawalRouterInitializedIterator, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterInitializedIterator{contract: _DelayedWithdrawalRouter.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterInitialized) (event.Subscription, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterInitialized) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. +// +// Solidity: event Initialized(uint8 version) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseInitialized(log types.Log) (*DelayedWithdrawalRouterInitialized, error) { + event := new(DelayedWithdrawalRouterInitialized) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterOwnershipTransferredIterator struct { + Event *DelayedWithdrawalRouterOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterOwnershipTransferred represents a OwnershipTransferred event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*DelayedWithdrawalRouterOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterOwnershipTransferredIterator{contract: _DelayedWithdrawalRouter.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterOwnershipTransferred) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseOwnershipTransferred(log types.Log) (*DelayedWithdrawalRouterOwnershipTransferred, error) { + event := new(DelayedWithdrawalRouterOwnershipTransferred) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterPausedIterator is returned from FilterPaused and is used to iterate over the raw logs and unpacked data for Paused events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterPausedIterator struct { + Event *DelayedWithdrawalRouterPaused // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterPausedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterPaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterPaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterPausedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterPaused represents a Paused event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterPaused struct { + Account common.Address + NewPausedStatus *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPaused is a free log retrieval operation binding the contract event 0xab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d. +// +// Solidity: event Paused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterPaused(opts *bind.FilterOpts, account []common.Address) (*DelayedWithdrawalRouterPausedIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "Paused", accountRule) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterPausedIterator{contract: _DelayedWithdrawalRouter.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +// WatchPaused is a free log subscription operation binding the contract event 0xab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d. +// +// Solidity: event Paused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterPaused, account []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "Paused", accountRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterPaused) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Paused", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParsePaused is a log parse operation binding the contract event 0xab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d. +// +// Solidity: event Paused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParsePaused(log types.Log) (*DelayedWithdrawalRouterPaused, error) { + event := new(DelayedWithdrawalRouterPaused) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterPauserRegistrySetIterator is returned from FilterPauserRegistrySet and is used to iterate over the raw logs and unpacked data for PauserRegistrySet events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterPauserRegistrySetIterator struct { + Event *DelayedWithdrawalRouterPauserRegistrySet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterPauserRegistrySetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterPauserRegistrySet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterPauserRegistrySet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterPauserRegistrySetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterPauserRegistrySetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterPauserRegistrySet represents a PauserRegistrySet event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterPauserRegistrySet struct { + PauserRegistry common.Address + NewPauserRegistry common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPauserRegistrySet is a free log retrieval operation binding the contract event 0x6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6. +// +// Solidity: event PauserRegistrySet(address pauserRegistry, address newPauserRegistry) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterPauserRegistrySet(opts *bind.FilterOpts) (*DelayedWithdrawalRouterPauserRegistrySetIterator, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "PauserRegistrySet") + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterPauserRegistrySetIterator{contract: _DelayedWithdrawalRouter.contract, event: "PauserRegistrySet", logs: logs, sub: sub}, nil +} + +// WatchPauserRegistrySet is a free log subscription operation binding the contract event 0x6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6. +// +// Solidity: event PauserRegistrySet(address pauserRegistry, address newPauserRegistry) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchPauserRegistrySet(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterPauserRegistrySet) (event.Subscription, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "PauserRegistrySet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterPauserRegistrySet) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "PauserRegistrySet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParsePauserRegistrySet is a log parse operation binding the contract event 0x6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6. +// +// Solidity: event PauserRegistrySet(address pauserRegistry, address newPauserRegistry) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParsePauserRegistrySet(log types.Log) (*DelayedWithdrawalRouterPauserRegistrySet, error) { + event := new(DelayedWithdrawalRouterPauserRegistrySet) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "PauserRegistrySet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterUnpausedIterator is returned from FilterUnpaused and is used to iterate over the raw logs and unpacked data for Unpaused events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterUnpausedIterator struct { + Event *DelayedWithdrawalRouterUnpaused // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterUnpausedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterUnpaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterUnpaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterUnpausedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterUnpaused represents a Unpaused event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterUnpaused struct { + Account common.Address + NewPausedStatus *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUnpaused is a free log retrieval operation binding the contract event 0x3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c. +// +// Solidity: event Unpaused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterUnpaused(opts *bind.FilterOpts, account []common.Address) (*DelayedWithdrawalRouterUnpausedIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "Unpaused", accountRule) + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterUnpausedIterator{contract: _DelayedWithdrawalRouter.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +// WatchUnpaused is a free log subscription operation binding the contract event 0x3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c. +// +// Solidity: event Unpaused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterUnpaused, account []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "Unpaused", accountRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterUnpaused) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Unpaused", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUnpaused is a log parse operation binding the contract event 0x3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c. +// +// Solidity: event Unpaused(address indexed account, uint256 newPausedStatus) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseUnpaused(log types.Log) (*DelayedWithdrawalRouterUnpaused, error) { + event := new(DelayedWithdrawalRouterUnpaused) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator is returned from FilterWithdrawalDelayBlocksSet and is used to iterate over the raw logs and unpacked data for WithdrawalDelayBlocksSet events raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator struct { + Event *DelayedWithdrawalRouterWithdrawalDelayBlocksSet // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterWithdrawalDelayBlocksSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelayedWithdrawalRouterWithdrawalDelayBlocksSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelayedWithdrawalRouterWithdrawalDelayBlocksSet represents a WithdrawalDelayBlocksSet event raised by the DelayedWithdrawalRouter contract. +type DelayedWithdrawalRouterWithdrawalDelayBlocksSet struct { + PreviousValue *big.Int + NewValue *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterWithdrawalDelayBlocksSet is a free log retrieval operation binding the contract event 0x4ffb00400574147429ee377a5633386321e66d45d8b14676014b5fa393e61e9e. +// +// Solidity: event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) FilterWithdrawalDelayBlocksSet(opts *bind.FilterOpts) (*DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.FilterLogs(opts, "WithdrawalDelayBlocksSet") + if err != nil { + return nil, err + } + return &DelayedWithdrawalRouterWithdrawalDelayBlocksSetIterator{contract: _DelayedWithdrawalRouter.contract, event: "WithdrawalDelayBlocksSet", logs: logs, sub: sub}, nil +} + +// WatchWithdrawalDelayBlocksSet is a free log subscription operation binding the contract event 0x4ffb00400574147429ee377a5633386321e66d45d8b14676014b5fa393e61e9e. +// +// Solidity: event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) WatchWithdrawalDelayBlocksSet(opts *bind.WatchOpts, sink chan<- *DelayedWithdrawalRouterWithdrawalDelayBlocksSet) (event.Subscription, error) { + + logs, sub, err := _DelayedWithdrawalRouter.contract.WatchLogs(opts, "WithdrawalDelayBlocksSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelayedWithdrawalRouterWithdrawalDelayBlocksSet) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "WithdrawalDelayBlocksSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseWithdrawalDelayBlocksSet is a log parse operation binding the contract event 0x4ffb00400574147429ee377a5633386321e66d45d8b14676014b5fa393e61e9e. +// +// Solidity: event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue) +func (_DelayedWithdrawalRouter *DelayedWithdrawalRouterFilterer) ParseWithdrawalDelayBlocksSet(log types.Log) (*DelayedWithdrawalRouterWithdrawalDelayBlocksSet, error) { + event := new(DelayedWithdrawalRouterWithdrawalDelayBlocksSet) + if err := _DelayedWithdrawalRouter.contract.UnpackLog(event, "WithdrawalDelayBlocksSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/pkg/bindings/DelegationManager/binding.go b/pkg/bindings/DelegationManager/binding.go index cf241371c..346fffd9f 100644 --- a/pkg/bindings/DelegationManager/binding.go +++ b/pkg/bindings/DelegationManager/binding.go @@ -62,8 +62,8 @@ type ISignatureUtilsSignatureWithExpiry struct { // DelegationManagerMetaData contains all meta data concerning the DelegationManager contract. var DelegationManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_STAKER_OPT_OUT_WINDOW_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_WITHDRAWAL_DELAY_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDelegatableShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_minWithdrawalDelayBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"_withdrawalDelayBlocks\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"newMinWithdrawalDelayBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setStrategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"withdrawalDelayBlocks\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoots\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false}]", - Bin: "0x6101006040523480156200001257600080fd5b5060405162005c4638038062005c46833981016040819052620000359162000140565b6001600160a01b0380841660805280821660c052821660a0526200005862000065565b50504660e0525062000194565b600054610100900460ff1615620000d25760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000125576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146200013d57600080fd5b50565b6000806000606084860312156200015657600080fd5b8351620001638162000127565b6020850151909350620001768162000127565b6040850151909250620001898162000127565b809150509250925092565b60805160a05160c05160e051615a1d6200022960003960006126a00152600081816105b10152818161102e015281816113aa01528181611c23015281816129f901528181613eac0152614398015260006107620152600081816104f901528181610ffc0152818161137801528181611cb701528181612ac601528181612c4901528181613fd2015261443e0152615a1d6000f3fe608060405234801561001057600080fd5b50600436106103425760003560e01c8063635bbd10116101b8578063b7f06ebe11610104578063cf80873e116100a2578063f16172b01161007c578063f16172b014610908578063f2fde38b1461091b578063f698da251461092e578063fabc1cbc1461093657600080fd5b8063cf80873e146108c1578063da8be864146108e2578063eea9064b146108f557600080fd5b8063c488375a116100de578063c488375a146107de578063c5e480db146107fe578063c94b5111146108a4578063ca661c04146108b757600080fd5b8063b7f06ebe14610784578063bb45fef2146107a7578063c448feb8146107d557600080fd5b8063886f1195116101715780639104c3191161014b5780639104c3191461070f57806399be81c81461072a578063a17884841461073d578063b13442711461075d57600080fd5b8063886f1195146106cb5780638da5cb5b146106de57806390041347146106ef57600080fd5b8063635bbd101461063657806365da1264146106495780636d70f7ae14610672578063715018a614610685578063778e55f31461068d5780637f548071146106b857600080fd5b806328a573ae116102925780634665bcda11610230578063597b36da1161020a578063597b36da146105e55780635ac86ab7146105f85780635c975abb1461061b57806360d7faed1461062357600080fd5b80634665bcda146105ac5780634fc40b61146105d3578063595c6a67146105dd57600080fd5b806339b70e381161026c57806339b70e38146104f45780633cdeb5e0146105335780633e28391d14610562578063433773821461058557600080fd5b806328a573ae146104ae57806329c77d4f146104c157806333404396146104e157600080fd5b8063132d4967116102ff57806316928365116102d957806316928365146104285780631bbce0911461046157806320606b701461047457806322bf40e41461049b57600080fd5b8063132d4967146103ef578063136439dd146104025780631522bf021461041557600080fd5b80630449ca391461034757806304a4f9791461036d5780630b9f487a146103945780630dd8dd02146103a75780630f589e59146103c757806310d67a2f146103dc575b600080fd5b61035a61035536600461484e565b610949565b6040519081526020015b60405180910390f35b61035a7f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad81565b61035a6103a23660046148b4565b6109ce565b6103ba6103b536600461484e565b610a90565b604051610364919061490f565b6103da6103d53660046149ac565b610df9565b005b6103da6103ea3660046149ff565b610f3e565b6103da6103fd366004614a23565b610ff1565b6103da610410366004614a64565b6110a8565b6103da610423366004614a7d565b6111e7565b61035a6104363660046149ff565b6001600160a01b0316600090815260996020526040902060010154600160a01b900463ffffffff1690565b61035a61046f366004614a23565b6111fb565b61035a7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6103da6104a9366004614ae8565b611229565b6103da6104bc366004614a23565b61136d565b61035a6104cf3660046149ff565b609b6020526000908152604090205481565b6103da6104ef366004614b8f565b61141d565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610364565b61051b6105413660046149ff565b6001600160a01b039081166000908152609960205260409020600101541690565b6105756105703660046149ff565b61155a565b6040519015158152602001610364565b61035a7f39111bc4a4d688e1f685123d7497d4615370152a8ee4a0593e647bd06ad8bb0b81565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b61035a6213c68081565b6103da61157a565b61035a6105f3366004614e8c565b611641565b610575610606366004614ec8565b606654600160ff9092169190911b9081161490565b60665461035a565b6103da610631366004614ef9565b611671565b6103da610644366004614a64565b61170c565b61051b6106573660046149ff565b609a602052600090815260409020546001600160a01b031681565b6105756106803660046149ff565b61171d565b6103da611757565b61035a61069b366004614f88565b609860209081526000928352604080842090915290825290205481565b6103da6106c6366004615069565b61176b565b60655461051b906001600160a01b031681565b6033546001600160a01b031661051b565b6107026106fd3660046150f9565b611997565b6040516103649190615183565b61051b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b6103da610738366004615196565b611a71565b61035a61074b3660046149ff565b609f6020526000908152604090205481565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b610575610792366004614a64565b609e6020526000908152604090205460ff1681565b6105756107b53660046151cb565b609c60209081526000928352604080842090915290825290205460ff1681565b61035a609d5481565b61035a6107ec3660046149ff565b60a16020526000908152604090205481565b61086e61080c3660046149ff565b6040805160608082018352600080835260208084018290529284018190526001600160a01b03948516815260998352839020835191820184528054851682526001015493841691810191909152600160a01b90920463ffffffff169082015290565b6040805182516001600160a01b039081168252602080850151909116908201529181015163ffffffff1690820152606001610364565b61035a6108b23660046151f7565b611b43565b61035a62034bc081565b6108d46108cf3660046149ff565b611bfc565b604051610364929190615278565b6103ba6108f03660046149ff565b611fb4565b6103da61090336600461529d565b612478565b6103da6109163660046152f5565b612595565b6103da6109293660046149ff565b612626565b61035a61269c565b6103da610944366004614a64565b6126da565b609d54600090815b838110156109c657600060a1600087878581811061097157610971615311565b905060200201602081019061098691906149ff565b6001600160a01b03166001600160a01b03168152602001908152602001600020549050828111156109b5578092505b506109bf8161533d565b9050610951565b509392505050565b604080517f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad6020808301919091526001600160a01b038681168385015288811660608401528716608083015260a0820185905260c08083018590528351808403909101815260e0909201909252805191012060009081610a4c61269c565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f19018152919052805160209091012098975050505050505050565b60665460609060019060029081161415610ac55760405162461bcd60e51b8152600401610abc90615358565b60405180910390fd5b6000836001600160401b03811115610adf57610adf614c31565b604051908082528060200260200182016040528015610b08578160200160208202803683370190505b50336000908152609a60205260408120549192506001600160a01b03909116905b85811015610dee57868682818110610b4357610b43615311565b9050602002810190610b55919061538f565b610b639060208101906153af565b9050878783818110610b7757610b77615311565b9050602002810190610b89919061538f565b610b9390806153af565b905014610c085760405162461bcd60e51b815260206004820152603860248201527f44656c65676174696f6e4d616e616765722e717565756557697468647261776160448201527f6c3a20696e707574206c656e677468206d69736d6174636800000000000000006064820152608401610abc565b33878783818110610c1b57610c1b615311565b9050602002810190610c2d919061538f565b610c3e9060608101906040016149ff565b6001600160a01b031614610cba5760405162461bcd60e51b815260206004820152603c60248201527f44656c65676174696f6e4d616e616765722e717565756557697468647261776160448201527f6c3a2077697468647261776572206d757374206265207374616b6572000000006064820152608401610abc565b610dbf3383898985818110610cd157610cd1615311565b9050602002810190610ce3919061538f565b610cf49060608101906040016149ff565b8a8a86818110610d0657610d06615311565b9050602002810190610d18919061538f565b610d2290806153af565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508e92508d9150889050818110610d6857610d68615311565b9050602002810190610d7a919061538f565b610d889060208101906153af565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061283692505050565b838281518110610dd157610dd1615311565b602090810291909101015280610de68161533d565b915050610b29565b509095945050505050565b610e023361155a565b15610e885760405162461bcd60e51b815260206004820152604a60248201527f44656c65676174696f6e4d616e616765722e726567697374657241734f70657260448201527f61746f723a2063616c6c657220697320616c7265616479206163746976656c796064820152690819195b1959d85d195960b21b608482015260a401610abc565b610e923384612df6565b604080518082019091526060815260006020820152610eb43380836000612fe9565b336001600160a01b03167f8e8485583a2310d41f7c82b9427d0bd49bad74bb9cff9d3402a29d8f9b28a0e285604051610eed91906153f8565b60405180910390a2336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908484604051610f3092919061544a565b60405180910390a250505050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb59190615479565b6001600160a01b0316336001600160a01b031614610fe55760405162461bcd60e51b8152600401610abc90615496565b610fee8161327f565b50565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806110505750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61106c5760405162461bcd60e51b8152600401610abc906154e0565b6110758361155a565b156110a3576001600160a01b038084166000908152609a6020526040902054166110a181858585613376565b505b505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611114919061553d565b6111305760405162461bcd60e51b8152600401610abc9061555a565b606654818116146111a95760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610abc565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6111ef6133f1565b6110a18484848461344b565b6001600160a01b0383166000908152609b602052604081205461122085828686611b43565b95945050505050565b600054610100900460ff16158080156112495750600054600160ff909116105b806112635750303b158015611263575060005460ff166001145b6112c65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610abc565b6000805460ff1916600117905580156112e9576000805461ff0019166101001790555b6112f38888613671565b6112fb61375b565b609755611307896137f2565b61131086613844565b61131c8585858561344b565b8015611362576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806113cc5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6113e85760405162461bcd60e51b8152600401610abc906154e0565b6113f18361155a565b156110a3576001600160a01b038084166000908152609a6020526040902054166110a18185858561393e565b606654600290600490811614156114465760405162461bcd60e51b8152600401610abc90615358565b600260c95414156114995760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610abc565b600260c95560005b88811015611549576115398a8a838181106114be576114be615311565b90506020028101906114d091906155a2565b8989848181106114e2576114e2615311565b90506020028101906114f491906153af565b89898681811061150657611506615311565b9050602002013588888781811061151f5761151f615311565b905060200201602081019061153491906155b8565b6139b9565b6115428161533d565b90506114a1565b5050600160c9555050505050505050565b6001600160a01b039081166000908152609a602052604090205416151590565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156115c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e6919061553d565b6116025760405162461bcd60e51b8152600401610abc9061555a565b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000816040516020016116549190615649565b604051602081830303815290604052805190602001209050919050565b6066546002906004908116141561169a5760405162461bcd60e51b8152600401610abc90615358565b600260c95414156116ed5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610abc565b600260c9556116ff86868686866139b9565b5050600160c95550505050565b6117146133f1565b610fee81613844565b60006001600160a01b0382161580159061175157506001600160a01b038083166000818152609a6020526040902054909116145b92915050565b61175f6133f1565b61176960006137f2565b565b42836020015110156117ef5760405162461bcd60e51b815260206004820152604160248201527f44656c65676174696f6e4d616e616765722e64656c6567617465546f4279536960448201527f676e61747572653a207374616b6572207369676e6174757265206578706972656064820152601960fa1b608482015260a401610abc565b6117f88561155a565b156118815760405162461bcd60e51b815260206004820152604d60248201527f44656c65676174696f6e4d616e616765722e64656c6567617465546f4279536960448201527f676e61747572653a207374616b657220697320616c726561647920616374697660648201526c195b1e4819195b1959d85d1959609a1b608482015260a401610abc565b61188a8461171d565b6119165760405162461bcd60e51b815260206004820152605160248201527f44656c65676174696f6e4d616e616765722e64656c6567617465546f4279536960448201527f676e61747572653a206f70657261746f72206973206e6f7420726567697374656064820152703932b21034b71022b4b3b2b72630bcb2b960791b608482015260a401610abc565b6000609b6000876001600160a01b03166001600160a01b0316815260200190815260200160002054905060006119528783888860200151611b43565b6001600160a01b0388166000908152609b60205260409020600184019055855190915061198290889083906141a3565b61198e87878686612fe9565b50505050505050565b6060600082516001600160401b038111156119b4576119b4614c31565b6040519080825280602002602001820160405280156119dd578160200160208202803683370190505b50905060005b83518110156109c6576001600160a01b03851660009081526098602052604081208551909190869084908110611a1b57611a1b615311565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054828281518110611a5657611a56615311565b6020908102919091010152611a6a8161533d565b90506119e3565b611a7a3361171d565b611afc5760405162461bcd60e51b815260206004820152604760248201527f44656c65676174696f6e4d616e616765722e7570646174654f70657261746f7260448201527f4d657461646174615552493a2063616c6c6572206d75737420626520616e206f6064820152663832b930ba37b960c91b608482015260a401610abc565b336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908383604051611b3792919061544a565b60405180910390a25050565b604080517f39111bc4a4d688e1f685123d7497d4615370152a8ee4a0593e647bd06ad8bb0b6020808301919091526001600160a01b0387811683850152851660608301526080820186905260a08083018590528351808403909101815260c0909201909252805191012060009081611bb961269c565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f190181529190528051602090910120979650505050505050565b6040516360f4062b60e01b81526001600160a01b03828116600483015260609182916000917f0000000000000000000000000000000000000000000000000000000000000000909116906360f4062b90602401602060405180830381865afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c90919061565c565b6040516394f649dd60e01b81526001600160a01b03868116600483015291925060009182917f0000000000000000000000000000000000000000000000000000000000000000909116906394f649dd90602401600060405180830381865afa158015611d00573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d2891908101906156d0565b9150915060008313611d3f57909590945092505050565b606080835160001415611df9576040805160018082528183019092529060208083019080368337505060408051600180825281830190925292945090506020808301908036833701905050905073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac082600081518110611db457611db4615311565b60200260200101906001600160a01b031690816001600160a01b0316815250508481600081518110611de857611de8615311565b602002602001018181525050611fa7565b8351611e0690600161578a565b6001600160401b03811115611e1d57611e1d614c31565b604051908082528060200260200182016040528015611e46578160200160208202803683370190505b50915081516001600160401b03811115611e6257611e62614c31565b604051908082528060200260200182016040528015611e8b578160200160208202803683370190505b50905060005b8451811015611f2557848181518110611eac57611eac615311565b6020026020010151838281518110611ec657611ec6615311565b60200260200101906001600160a01b031690816001600160a01b031681525050838181518110611ef857611ef8615311565b6020026020010151828281518110611f1257611f12615311565b6020908102919091010152600101611e91565b5073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac08260018451611f4a91906157a2565b81518110611f5a57611f5a615311565b60200260200101906001600160a01b031690816001600160a01b031681525050848160018451611f8a91906157a2565b81518110611f9a57611f9a615311565b6020026020010181815250505b9097909650945050505050565b60665460609060019060029081161415611fe05760405162461bcd60e51b8152600401610abc90615358565b611fe98361155a565b6120695760405162461bcd60e51b8152602060048201526044602482018190527f44656c65676174696f6e4d616e616765722e756e64656c65676174653a207374908201527f616b6572206d7573742062652064656c65676174656420746f20756e64656c656064820152636761746560e01b608482015260a401610abc565b6120728361171d565b156120e55760405162461bcd60e51b815260206004820152603d60248201527f44656c65676174696f6e4d616e616765722e756e64656c65676174653a206f7060448201527f657261746f72732063616e6e6f7420626520756e64656c6567617465640000006064820152608401610abc565b6001600160a01b0383166121615760405162461bcd60e51b815260206004820152603c60248201527f44656c65676174696f6e4d616e616765722e756e64656c65676174653a20636160448201527f6e6e6f7420756e64656c6567617465207a65726f2061646472657373000000006064820152608401610abc565b6001600160a01b038084166000818152609a6020526040902054909116903314806121945750336001600160a01b038216145b806121bb57506001600160a01b038181166000908152609960205260409020600101541633145b61222d5760405162461bcd60e51b815260206004820152603d60248201527f44656c65676174696f6e4d616e616765722e756e64656c65676174653a20636160448201527f6c6c65722063616e6e6f7420756e64656c6567617465207374616b65720000006064820152608401610abc565b60008061223986611bfc565b9092509050336001600160a01b0387161461228f57826001600160a01b0316866001600160a01b03167ff0eddf07e6ea14f388b47e1e94a0f464ecbd9eed4171130e0fc0e99fb4030a8a60405160405180910390a35b826001600160a01b0316866001600160a01b03167ffee30966a256b71e14bc0ebfc94315e28ef4a97a7131a9e2b7a310a73af4467660405160405180910390a36001600160a01b0386166000908152609a6020526040902080546001600160a01b0319169055815161231157604080516000815260208101909152945061246f565b81516001600160401b0381111561232a5761232a614c31565b604051908082528060200260200182016040528015612353578160200160208202803683370190505b50945060005b825181101561246d576040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090508483815181106123b9576123b9615311565b6020026020010151826000815181106123d4576123d4615311565b60200260200101906001600160a01b031690816001600160a01b03168152505083838151811061240657612406615311565b60200260200101518160008151811061242157612421615311565b60200260200101818152505061243a89878b8585612836565b88848151811061244c5761244c615311565b602002602001018181525050505080806124659061533d565b915050612359565b505b50505050919050565b6124813361155a565b156124ff5760405162461bcd60e51b815260206004820152604260248201527f44656c65676174696f6e4d616e616765722e64656c6567617465546f3a20737460448201527f616b657220697320616c7265616479206163746976656c792064656c65676174606482015261195960f21b608482015260a401610abc565b6125088361171d565b6125895760405162461bcd60e51b815260206004820152604660248201527f44656c65676174696f6e4d616e616765722e64656c6567617465546f3a206f7060448201527f657261746f72206973206e6f74207265676973746572656420696e2045696765606482015265372630bcb2b960d11b608482015260a401610abc565b6110a333848484612fe9565b61259e3361171d565b61261c5760405162461bcd60e51b815260206004820152604360248201527f44656c65676174696f6e4d616e616765722e6d6f646966794f70657261746f7260448201527f44657461696c733a2063616c6c6572206d75737420626520616e206f706572616064820152623a37b960e91b608482015260a401610abc565b610fee3382612df6565b61262e6133f1565b6001600160a01b0381166126935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610abc565b610fee816137f2565b60007f00000000000000000000000000000000000000000000000000000000000000004614156126cd575060975490565b6126d561375b565b905090565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561272d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127519190615479565b6001600160a01b0316336001600160a01b0316146127815760405162461bcd60e51b8152600401610abc90615496565b6066541981196066541916146127ff5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610abc565b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016111dc565b60006001600160a01b0386166128cd5760405162461bcd60e51b815260206004820152605060248201527f44656c65676174696f6e4d616e616765722e5f72656d6f76655368617265734160448201527f6e6451756575655769746864726177616c3a207374616b65722063616e6e6f7460648201526f206265207a65726f206164647265737360801b608482015260a401610abc565b82516129575760405162461bcd60e51b815260206004820152604d60248201527f44656c65676174696f6e4d616e616765722e5f72656d6f76655368617265734160448201527f6e6451756575655769746864726177616c3a207374726174656769657320636160648201526c6e6e6f7420626520656d70747960981b608482015260a401610abc565b60005b8351811015612d04576001600160a01b038616156129b0576129b0868886848151811061298957612989615311565b60200260200101518685815181106129a3576129a3615311565b6020026020010151613376565b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06001600160a01b03168482815181106129e0576129e0615311565b60200260200101516001600160a01b03161415612aa9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663beffbb8988858481518110612a3957612a39615311565b60200260200101516040518363ffffffff1660e01b8152600401612a729291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015612a8c57600080fd5b505af1158015612aa0573d6000803e3d6000fd5b50505050612cfc565b846001600160a01b0316876001600160a01b03161480612b7b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639b4da03d858381518110612b0557612b05615311565b60200260200101516040518263ffffffff1660e01b8152600401612b3891906001600160a01b0391909116815260200190565b602060405180830381865afa158015612b55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b79919061553d565b155b612c475760405162461bcd60e51b8152602060048201526084602482018190527f44656c65676174696f6e4d616e616765722e5f72656d6f76655368617265734160448301527f6e6451756575655769746864726177616c3a2077697468647261776572206d7560648301527f73742062652073616d652061646472657373206173207374616b657220696620908201527f746869726450617274795472616e7366657273466f7262696464656e2061726560a482015263081cd95d60e21b60c482015260e401610abc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638c80d4e588868481518110612c8957612c89615311565b6020026020010151868581518110612ca357612ca3615311565b60200260200101516040518463ffffffff1660e01b8152600401612cc9939291906157b9565b600060405180830381600087803b158015612ce357600080fd5b505af1158015612cf7573d6000803e3d6000fd5b505050505b60010161295a565b506001600160a01b0386166000908152609f60205260408120805491829190612d2c8361533d565b919050555060006040518060e00160405280896001600160a01b03168152602001886001600160a01b03168152602001876001600160a01b031681526020018381526020014363ffffffff1681526020018681526020018581525090506000612d9482611641565b6000818152609e602052604090819020805460ff19166001179055519091507f9009ab153e8014fbfb02f2217f5cde7aa7f9ad734ae85ca3ee3f4ca2fdd499f990612de290839085906157dd565b60405180910390a198975050505050505050565b6213c680612e0a60608301604084016157f6565b63ffffffff161115612ebf5760405162461bcd60e51b815260206004820152606c60248201527f44656c65676174696f6e4d616e616765722e5f7365744f70657261746f72446560448201527f7461696c733a207374616b65724f70744f757457696e646f77426c6f636b732060648201527f63616e6e6f74206265203e204d41585f5354414b45525f4f50545f4f55545f5760848201526b494e444f575f424c4f434b5360a01b60a482015260c401610abc565b6001600160a01b0382166000908152609960205260409081902060010154600160a01b900463ffffffff1690612efb90606084019084016157f6565b63ffffffff161015612f915760405162461bcd60e51b815260206004820152605360248201527f44656c65676174696f6e4d616e616765722e5f7365744f70657261746f72446560448201527f7461696c733a207374616b65724f70744f757457696e646f77426c6f636b732060648201527218d85b9b9bdd08189948191958dc99585cd959606a1b608482015260a401610abc565b6001600160a01b03821660009081526099602052604090208190612fb58282615833565b505060405133907ffebe5cd24b2cbc7b065b9d0fdeb904461e4afcff57dd57acda1e7832031ba7ac90611b379084906153f8565b606654600090600190811614156130125760405162461bcd60e51b8152600401610abc90615358565b6001600160a01b038085166000908152609960205260409020600101541680158015906130485750336001600160a01b03821614155b801561305d5750336001600160a01b03861614155b156131ca5742846020015110156130dc5760405162461bcd60e51b815260206004820152603760248201527f44656c65676174696f6e4d616e616765722e5f64656c65676174653a2061707060448201527f726f766572207369676e617475726520657870697265640000000000000000006064820152608401610abc565b6001600160a01b0381166000908152609c6020908152604080832086845290915290205460ff16156131765760405162461bcd60e51b815260206004820152603760248201527f44656c65676174696f6e4d616e616765722e5f64656c65676174653a2061707060448201527f726f76657253616c7420616c7265616479207370656e740000000000000000006064820152608401610abc565b6001600160a01b0381166000908152609c6020908152604080832086845282528220805460ff191660011790558501516131b79088908890859088906109ce565b90506131c8828287600001516141a3565b505b6001600160a01b038681166000818152609a602052604080822080546001600160a01b031916948a169485179055517fc3ee9f2e5fda98e8066a1f745b2df9285f416fe98cf2559cd21484b3d87433049190a360008061322988611bfc565b9150915060005b825181101561136257613277888a85848151811061325057613250615311565b602002602001015185858151811061326a5761326a615311565b602002602001015161393e565b600101613230565b6001600160a01b03811661330d5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610abc565b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038085166000908152609860209081526040808320938616835292905290812080548392906133ad9084906157a2565b92505081905550836001600160a01b03167f6909600037b75d7b4733aedd815442b5ec018a827751c832aaff64eba5d6d2dd848484604051610f30939291906157b9565b6033546001600160a01b031633146117695760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610abc565b8281146134d35760405162461bcd60e51b815260206004820152604a60248201527f44656c65676174696f6e4d616e616765722e5f7365745374726174656779576960448201527f746864726177616c44656c6179426c6f636b733a20696e707574206c656e67746064820152690d040dad2e6dac2e8c6d60b31b608482015260a401610abc565b8260005b818110156136695760008686838181106134f3576134f3615311565b905060200201602081019061350891906149ff565b6001600160a01b038116600090815260a1602052604081205491925086868581811061353657613536615311565b90506020020135905062034bc08111156135fa5760405162461bcd60e51b815260206004820152607360248201527f44656c65676174696f6e4d616e616765722e5f7365745374726174656779576960448201527f746864726177616c44656c6179426c6f636b733a205f7769746864726177616c60648201527f44656c6179426c6f636b732063616e6e6f74206265203e204d41585f5749544860848201527244524157414c5f44454c41595f424c4f434b5360681b60a482015260c401610abc565b6001600160a01b038316600081815260a160209081526040918290208490558151928352820184905281018290527f0e7efa738e8b0ce6376a0c1af471655540d2e9a81647d7b09ed823018426576d9060600160405180910390a1505050806136629061533d565b90506134d7565b505050505050565b6065546001600160a01b031615801561369257506001600160a01b03821615155b6137145760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610abc565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26137578261327f565b5050565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b62034bc08111156138fd5760405162461bcd60e51b815260206004820152607160248201527f44656c65676174696f6e4d616e616765722e5f7365744d696e5769746864726160448201527f77616c44656c6179426c6f636b733a205f6d696e5769746864726177616c446560648201527f6c6179426c6f636b732063616e6e6f74206265203e204d41585f5749544844526084820152704157414c5f44454c41595f424c4f434b5360781b60a482015260c401610abc565b609d5460408051918252602082018390527fafa003cd76f87ff9d62b35beea889920f33c0c42b8d45b74954d61d50f4b6b69910160405180910390a1609d55565b6001600160a01b0380851660009081526098602090815260408083209386168352929052908120805483929061397590849061578a565b92505081905550836001600160a01b03167f1ec042c965e2edd7107b51188ee0f383e22e76179041ab3a9d18ff151405166c848484604051610f30939291906157b9565b60006139c76105f387615896565b6000818152609e602052604090205490915060ff16613a485760405162461bcd60e51b815260206004820152604360248201526000805160206159c883398151915260448201527f645769746864726177616c3a20616374696f6e206973206e6f7420696e20717560648201526265756560e81b608482015260a401610abc565b609d544390613a5d60a0890160808a016157f6565b63ffffffff16613a6d919061578a565b1115613af55760405162461bcd60e51b815260206004820152605f60248201526000805160206159c883398151915260448201527f645769746864726177616c3a206d696e5769746864726177616c44656c61794260648201527f6c6f636b7320706572696f6420686173206e6f74207965742070617373656400608482015260a401610abc565b613b0560608701604088016149ff565b6001600160a01b0316336001600160a01b031614613b925760405162461bcd60e51b815260206004820152605060248201526000805160206159c883398151915260448201527f645769746864726177616c3a206f6e6c7920776974686472617765722063616e60648201526f1031b7b6b83632ba329030b1ba34b7b760811b608482015260a401610abc565b8115613c1457613ba560a08701876153af565b85149050613c145760405162461bcd60e51b815260206004820152604260248201526000805160206159c883398151915260448201527f645769746864726177616c3a20696e707574206c656e677468206d69736d61746064820152610c6d60f31b608482015260a401610abc565b6000818152609e60205260409020805460ff191690558115613d795760005b613c4060a08801886153af565b9050811015613d73574360a16000613c5b60a08b018b6153af565b85818110613c6b57613c6b615311565b9050602002016020810190613c8091906149ff565b6001600160a01b03168152602081019190915260400160002054613caa60a08a0160808b016157f6565b63ffffffff16613cba919061578a565b1115613cd85760405162461bcd60e51b8152600401610abc906158a2565b613d6b613ce860208901896149ff565b33613cf660a08b018b6153af565b85818110613d0657613d06615311565b9050602002016020810190613d1b91906149ff565b613d2860c08c018c6153af565b86818110613d3857613d38615311565b905060200201358a8a87818110613d5157613d51615311565b9050602002016020810190613d6691906149ff565b61435d565b600101613c33565b50614168565b336000908152609a60205260408120546001600160a01b0316905b613da160a08901896153af565b9050811015614165574360a16000613dbc60a08c018c6153af565b85818110613dcc57613dcc615311565b9050602002016020810190613de191906149ff565b6001600160a01b03168152602081019190915260400160002054613e0b60a08b0160808c016157f6565b63ffffffff16613e1b919061578a565b1115613e395760405162461bcd60e51b8152600401610abc906158a2565b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0613e5b60a08a018a6153af565b83818110613e6b57613e6b615311565b9050602002016020810190613e8091906149ff565b6001600160a01b03161415613fd0576000613e9e60208a018a6149ff565b905060006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630e81073c83613edf60c08e018e6153af565b87818110613eef57613eef615311565b6040516001600160e01b031960e087901b1681526001600160a01b03909416600485015260200291909101356024830152506044016020604051808303816000875af1158015613f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f67919061565c565b6001600160a01b038084166000908152609a6020526040902054919250168015613fc857613fc88184613f9d60a08f018f6153af565b88818110613fad57613fad615311565b9050602002016020810190613fc291906149ff565b8561393e565b50505061415d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4623ea13389898581811061401257614012615311565b905060200201602081019061402791906149ff565b61403460a08d018d6153af565b8681811061404457614044615311565b905060200201602081019061405991906149ff565b61406660c08e018e6153af565b8781811061407657614076615311565b60405160e088901b6001600160e01b03191681526001600160a01b03968716600482015294861660248601529290941660448401526020909102013560648201526084019050600060405180830381600087803b1580156140d657600080fd5b505af11580156140ea573d6000803e3d6000fd5b505050506001600160a01b0382161561415d5761415d823361410f60a08c018c6153af565b8581811061411f5761411f615311565b905060200201602081019061413491906149ff565b61414160c08d018d6153af565b8681811061415157614151615311565b9050602002013561393e565b600101613d94565b50505b6040518181527fc97098c2f658800b4df29001527f7324bcdffcf6e8751a699ab920a1eced5b1d9060200160405180910390a1505050505050565b6001600160a01b0383163b156142bd57604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e906141e3908690869060040161592a565b602060405180830381865afa158015614200573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142249190615987565b6001600160e01b031916146110a35760405162461bcd60e51b815260206004820152605360248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a2045524331323731207369676e6174757265206064820152721d995c9a599a58d85d1a5bdb8819985a5b1959606a1b608482015260a401610abc565b826001600160a01b03166142d1838361449d565b6001600160a01b0316146110a35760405162461bcd60e51b815260206004820152604760248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a207369676e6174757265206e6f742066726f6d6064820152661039b4b3b732b960c91b608482015260a401610abc565b6001600160a01b03831673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac014156144085760405162387b1360e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063387b1300906143d1908890889087906004016157b9565b600060405180830381600087803b1580156143eb57600080fd5b505af11580156143ff573d6000803e3d6000fd5b50505050614496565b60405163c608c7f360e01b81526001600160a01b03858116600483015284811660248301526044820184905282811660648301527f0000000000000000000000000000000000000000000000000000000000000000169063c608c7f390608401600060405180830381600087803b15801561448257600080fd5b505af1158015611362573d6000803e3d6000fd5b5050505050565b60008060006144ac85856144b9565b915091506109c681614529565b6000808251604114156144f05760208301516040840151606085015160001a6144e4878285856146e4565b94509450505050614522565b82516040141561451a576020830151604084015161450f8683836147d1565b935093505050614522565b506000905060025b9250929050565b600081600481111561453d5761453d6159b1565b14156145465750565b600181600481111561455a5761455a6159b1565b14156145a85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610abc565b60028160048111156145bc576145bc6159b1565b141561460a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610abc565b600381600481111561461e5761461e6159b1565b14156146775760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610abc565b600481600481111561468b5761468b6159b1565b1415610fee5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610abc565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561471b57506000905060036147c8565b8460ff16601b1415801561473357508460ff16601c14155b1561474457506000905060046147c8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614798573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166147c1576000600192509250506147c8565b9150600090505b94509492505050565b6000806001600160ff1b038316816147ee60ff86901c601b61578a565b90506147fc878288856146e4565b935093505050935093915050565b60008083601f84011261481c57600080fd5b5081356001600160401b0381111561483357600080fd5b6020830191508360208260051b850101111561452257600080fd5b6000806020838503121561486157600080fd5b82356001600160401b0381111561487757600080fd5b6148838582860161480a565b90969095509350505050565b6001600160a01b0381168114610fee57600080fd5b80356148af8161488f565b919050565b600080600080600060a086880312156148cc57600080fd5b85356148d78161488f565b945060208601356148e78161488f565b935060408601356148f78161488f565b94979396509394606081013594506080013592915050565b6020808252825182820181905260009190848201906040850190845b818110156149475783518352928401929184019160010161492b565b50909695505050505050565b60006060828403121561496557600080fd5b50919050565b60008083601f84011261497d57600080fd5b5081356001600160401b0381111561499457600080fd5b60208301915083602082850101111561452257600080fd5b6000806000608084860312156149c157600080fd5b6149cb8585614953565b925060608401356001600160401b038111156149e657600080fd5b6149f28682870161496b565b9497909650939450505050565b600060208284031215614a1157600080fd5b8135614a1c8161488f565b9392505050565b600080600060608486031215614a3857600080fd5b8335614a438161488f565b92506020840135614a538161488f565b929592945050506040919091013590565b600060208284031215614a7657600080fd5b5035919050565b60008060008060408587031215614a9357600080fd5b84356001600160401b0380821115614aaa57600080fd5b614ab68883890161480a565b90965094506020870135915080821115614acf57600080fd5b50614adc8782880161480a565b95989497509550505050565b60008060008060008060008060c0898b031215614b0457600080fd5b8835614b0f8161488f565b97506020890135614b1f8161488f565b9650604089013595506060890135945060808901356001600160401b0380821115614b4957600080fd5b614b558c838d0161480a565b909650945060a08b0135915080821115614b6e57600080fd5b50614b7b8b828c0161480a565b999c989b5096995094979396929594505050565b6000806000806000806000806080898b031215614bab57600080fd5b88356001600160401b0380821115614bc257600080fd5b614bce8c838d0161480a565b909a50985060208b0135915080821115614be757600080fd5b614bf38c838d0161480a565b909850965060408b0135915080821115614c0c57600080fd5b614c188c838d0161480a565b909650945060608b0135915080821115614b6e57600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715614c6957614c69614c31565b60405290565b604080519081016001600160401b0381118282101715614c6957614c69614c31565b604051601f8201601f191681016001600160401b0381118282101715614cb957614cb9614c31565b604052919050565b63ffffffff81168114610fee57600080fd5b80356148af81614cc1565b60006001600160401b03821115614cf757614cf7614c31565b5060051b60200190565b600082601f830112614d1257600080fd5b81356020614d27614d2283614cde565b614c91565b82815260059290921b84018101918181019086841115614d4657600080fd5b8286015b84811015614d6a578035614d5d8161488f565b8352918301918301614d4a565b509695505050505050565b600082601f830112614d8657600080fd5b81356020614d96614d2283614cde565b82815260059290921b84018101918181019086841115614db557600080fd5b8286015b84811015614d6a5780358352918301918301614db9565b600060e08284031215614de257600080fd5b614dea614c47565b9050614df5826148a4565b8152614e03602083016148a4565b6020820152614e14604083016148a4565b604082015260608201356060820152614e2f60808301614cd3565b608082015260a08201356001600160401b0380821115614e4e57600080fd5b614e5a85838601614d01565b60a084015260c0840135915080821115614e7357600080fd5b50614e8084828501614d75565b60c08301525092915050565b600060208284031215614e9e57600080fd5b81356001600160401b03811115614eb457600080fd5b614ec084828501614dd0565b949350505050565b600060208284031215614eda57600080fd5b813560ff81168114614a1c57600080fd5b8015158114610fee57600080fd5b600080600080600060808688031215614f1157600080fd5b85356001600160401b0380821115614f2857600080fd5b9087019060e0828a031215614f3c57600080fd5b90955060208701359080821115614f5257600080fd5b50614f5f8882890161480a565b909550935050604086013591506060860135614f7a81614eeb565b809150509295509295909350565b60008060408385031215614f9b57600080fd5b8235614fa68161488f565b91506020830135614fb68161488f565b809150509250929050565b600060408284031215614fd357600080fd5b614fdb614c6f565b905081356001600160401b0380821115614ff457600080fd5b818401915084601f83011261500857600080fd5b813560208282111561501c5761501c614c31565b61502e601f8301601f19168201614c91565b9250818352868183860101111561504457600080fd5b8181850182850137600081838501015282855280860135818601525050505092915050565b600080600080600060a0868803121561508157600080fd5b853561508c8161488f565b9450602086013561509c8161488f565b935060408601356001600160401b03808211156150b857600080fd5b6150c489838a01614fc1565b945060608801359150808211156150da57600080fd5b506150e788828901614fc1565b95989497509295608001359392505050565b6000806040838503121561510c57600080fd5b82356151178161488f565b915060208301356001600160401b0381111561513257600080fd5b61513e85828601614d01565b9150509250929050565b600081518084526020808501945080840160005b838110156151785781518752958201959082019060010161515c565b509495945050505050565b602081526000614a1c6020830184615148565b600080602083850312156151a957600080fd5b82356001600160401b038111156151bf57600080fd5b6148838582860161496b565b600080604083850312156151de57600080fd5b82356151e98161488f565b946020939093013593505050565b6000806000806080858703121561520d57600080fd5b84356152188161488f565b935060208501359250604085013561522f8161488f565b9396929550929360600135925050565b600081518084526020808501945080840160005b838110156151785781516001600160a01b031687529582019590820190600101615253565b60408152600061528b604083018561523f565b82810360208401526112208185615148565b6000806000606084860312156152b257600080fd5b83356152bd8161488f565b925060208401356001600160401b038111156152d857600080fd5b6152e486828701614fc1565b925050604084013590509250925092565b60006060828403121561530757600080fd5b614a1c8383614953565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060001982141561535157615351615327565b5060010190565b60208082526019908201527f5061757361626c653a20696e6465782069732070617573656400000000000000604082015260600190565b60008235605e198336030181126153a557600080fd5b9190910192915050565b6000808335601e198436030181126153c657600080fd5b8301803591506001600160401b038211156153e057600080fd5b6020019150600581901b360382131561452257600080fd5b6060810182356154078161488f565b6001600160a01b0390811683526020840135906154238261488f565b166020830152604083013561543781614cc1565b63ffffffff811660408401525092915050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60006020828403121561548b57600080fd5b8151614a1c8161488f565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b60208082526037908201527f44656c65676174696f6e4d616e616765723a206f6e6c7953747261746567794d60408201527f616e616765724f72456967656e506f644d616e61676572000000000000000000606082015260800190565b60006020828403121561554f57600080fd5b8151614a1c81614eeb565b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b6000823560de198336030181126153a557600080fd5b6000602082840312156155ca57600080fd5b8135614a1c81614eeb565b600060018060a01b03808351168452806020840151166020850152806040840151166040850152506060820151606084015263ffffffff608083015116608084015260a082015160e060a085015261563060e085018261523f565b905060c083015184820360c08601526112208282615148565b602081526000614a1c60208301846155d5565b60006020828403121561566e57600080fd5b5051919050565b600082601f83011261568657600080fd5b81516020615696614d2283614cde565b82815260059290921b840181019181810190868411156156b557600080fd5b8286015b84811015614d6a57805183529183019183016156b9565b600080604083850312156156e357600080fd5b82516001600160401b03808211156156fa57600080fd5b818501915085601f83011261570e57600080fd5b8151602061571e614d2283614cde565b82815260059290921b8401810191818101908984111561573d57600080fd5b948201945b838610156157645785516157558161488f565b82529482019490820190615742565b9188015191965090935050508082111561577d57600080fd5b5061513e85828601615675565b6000821982111561579d5761579d615327565b500190565b6000828210156157b4576157b4615327565b500390565b6001600160a01b039384168152919092166020820152604081019190915260600190565b828152604060208201526000614ec060408301846155d5565b60006020828403121561580857600080fd5b8135614a1c81614cc1565b80546001600160a01b0319166001600160a01b0392909216919091179055565b813561583e8161488f565b6158488183615813565b5060018101602083013561585b8161488f565b6158658183615813565b50604083013561587481614cc1565b815463ffffffff60a01b191660a09190911b63ffffffff60a01b161790555050565b60006117513683614dd0565b6020808252606e908201526000805160206159c883398151915260408201527f645769746864726177616c3a207769746864726177616c44656c6179426c6f6360608201527f6b7320706572696f6420686173206e6f74207965742070617373656420666f7260808201526d207468697320737472617465677960901b60a082015260c00190565b82815260006020604081840152835180604085015260005b8181101561595e57858101830151858201606001528201615942565b81811115615970576000606083870101525b50601f01601f191692909201606001949350505050565b60006020828403121561599957600080fd5b81516001600160e01b031981168114614a1c57600080fd5b634e487b7160e01b600052602160045260246000fdfe44656c65676174696f6e4d616e616765722e5f636f6d706c6574655175657565a264697066735822122046f59d0774fea296e76e107662bfe5a0f076e0013aabe21beb6ded4a9b0f61a864736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_STAKER_OPT_OUT_WINDOW_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_WITHDRAWAL_DELAY_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDelegatableShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_minWithdrawalDelayBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"_withdrawalDelayBlocks\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"newMinWithdrawalDelayBlocks\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setStrategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"withdrawalDelayBlocks\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoots\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEIP1271\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEOA\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotCurrentlyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorsCannotUndelegate\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksCannotDecrease\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawerNotStaker\",\"inputs\":[]}]", + Bin: "0x61010060405234801561001157600080fd5b50604051614b63380380614b6383398101604081905261003091610134565b6001600160a01b0380841660805280821660c052821660a05261005161005d565b50504660e05250610181565b600054610100900460ff16156100c95760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161461011a576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811461013157600080fd5b50565b60008060006060848603121561014957600080fd5b83516101548161011c565b60208501519093506101658161011c565b60408501519092506101768161011c565b809150509250925092565b60805160a05160c05160e05161494e61021560003960006120460152600081816105b101528181610f04015281816112320152818161185b0152818161227301528181613156015261356c015260006107620152600081816104f901528181610ed201528181611200015281816118ef01528181612340015281816124140152818161327c0152613612015261494e6000f3fe608060405234801561001057600080fd5b50600436106103425760003560e01c8063635bbd10116101b8578063b7f06ebe11610104578063cf80873e116100a2578063f16172b01161007c578063f16172b014610908578063f2fde38b1461091b578063f698da251461092e578063fabc1cbc1461093657600080fd5b8063cf80873e146108c1578063da8be864146108e2578063eea9064b146108f557600080fd5b8063c488375a116100de578063c488375a146107de578063c5e480db146107fe578063c94b5111146108a4578063ca661c04146108b757600080fd5b8063b7f06ebe14610784578063bb45fef2146107a7578063c448feb8146107d557600080fd5b8063886f1195116101715780639104c3191161014b5780639104c3191461070f57806399be81c81461072a578063a17884841461073d578063b13442711461075d57600080fd5b8063886f1195146106cb5780638da5cb5b146106de57806390041347146106ef57600080fd5b8063635bbd101461063657806365da1264146106495780636d70f7ae14610672578063715018a614610685578063778e55f31461068d5780637f548071146106b857600080fd5b806328a573ae116102925780634665bcda11610230578063597b36da1161020a578063597b36da146105e55780635ac86ab7146105f85780635c975abb1461061b57806360d7faed1461062357600080fd5b80634665bcda146105ac5780634fc40b61146105d3578063595c6a67146105dd57600080fd5b806339b70e381161026c57806339b70e38146104f45780633cdeb5e0146105335780633e28391d14610562578063433773821461058557600080fd5b806328a573ae146104ae57806329c77d4f146104c157806333404396146104e157600080fd5b8063132d4967116102ff57806316928365116102d957806316928365146104285780631bbce0911461046157806320606b701461047457806322bf40e41461049b57600080fd5b8063132d4967146103ef578063136439dd146104025780631522bf021461041557600080fd5b80630449ca391461034757806304a4f9791461036d5780630b9f487a146103945780630dd8dd02146103a75780630f589e59146103c757806310d67a2f146103dc575b600080fd5b61035a610355366004613924565b610949565b6040519081526020015b60405180910390f35b61035a7f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad81565b61035a6103a236600461398a565b6109c8565b6103ba6103b5366004613924565b610a8a565b60405161036491906139e5565b6103da6103d5366004613a76565b610d36565b005b6103da6103ea366004613ac9565b610e13565b6103da6103fd366004613aed565b610ec7565b6103da610410366004613b2e565b610f7f565b6103da610423366004613b47565b61106a565b61035a610436366004613ac9565b6001600160a01b0316600090815260996020526040902060010154600160a01b900463ffffffff1690565b61035a61046f366004613aed565b61107e565b61035a7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6103da6104a9366004613bb6565b6110ac565b6103da6104bc366004613aed565b6111f5565b61035a6104cf366004613ac9565b609b6020526000908152604090205481565b6103da6104ef366004613c61565b6112a6565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610364565b61051b610541366004613ac9565b6001600160a01b039081166000908152609960205260409020600101541690565b610575610570366004613ac9565b611385565b6040519015158152602001610364565b61035a7f39111bc4a4d688e1f685123d7497d4615370152a8ee4a0593e647bd06ad8bb0b81565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b61035a6213c68081565b6103da6113a5565b61035a6105f3366004613f78565b61146d565b610575610606366004613fb4565b606654600160ff9092169190911b9081161490565b60665461035a565b6103da610631366004613fe5565b61149d565b6103da610644366004613b2e565b6114ed565b61051b610657366004613ac9565b609a602052600090815260409020546001600160a01b031681565b610575610680366004613ac9565b6114fe565b6103da611535565b61035a61069b366004614075565b609860209081526000928352604080842090915290825290205481565b6103da6106c6366004614159565b611549565b60655461051b906001600160a01b031681565b6033546001600160a01b031661051b565b6107026106fd3660046141ed565b61163c565b6040516103649190614278565b61051b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b6103da61073836600461428b565b61170e565b61035a61074b366004613ac9565b609f6020526000908152604090205481565b61051b7f000000000000000000000000000000000000000000000000000000000000000081565b610575610792366004613b2e565b609e6020526000908152604090205460ff1681565b6105756107b53660046142c0565b609c60209081526000928352604080842090915290825290205460ff1681565b61035a609d5481565b61035a6107ec366004613ac9565b60a16020526000908152604090205481565b61086e61080c366004613ac9565b6040805160608082018352600080835260208084018290529284018190526001600160a01b03948516815260998352839020835191820184528054851682526001015493841691810191909152600160a01b90920463ffffffff169082015290565b6040805182516001600160a01b039081168252602080850151909116908201529181015163ffffffff1690820152606001610364565b61035a6108b23660046142ec565b61177b565b61035a62034bc081565b6108d46108cf366004613ac9565b611834565b60405161036492919061436f565b6103ba6108f0366004613ac9565b611beb565b6103da610903366004614394565b611f43565b6103da6109163660046143ed565b611f9c565b6103da610929366004613ac9565b611fcc565b61035a612042565b6103da610944366004613b2e565b61207f565b609d54600090815b838110156109be57600060a1600087878581811061097157610971614409565b90506020020160208101906109869190613ac9565b6001600160a01b03166001600160a01b03168152602001908152602001600020549050828111156109b5578092505b50600101610951565b5090505b92915050565b604080517f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad6020808301919091526001600160a01b038681168385015288811660608401528716608083015260a0820185905260c08083018590528351808403909101815260e0909201909252805191012060009081610a46612042565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f19018152919052805160209091012098975050505050505050565b606654606090600190600290811603610ab65760405163840a48d560e01b815260040160405180910390fd5b6000836001600160401b03811115610ad057610ad0613d14565b604051908082528060200260200182016040528015610af9578160200160208202803683370190505b50336000908152609a60205260408120549192506001600160a01b03909116905b85811015610d2b57868682818110610b3457610b34614409565b9050602002810190610b46919061441f565b610b5490602081019061443f565b9050878783818110610b6857610b68614409565b9050602002810190610b7a919061441f565b610b84908061443f565b905014610ba4576040516343714afd60e01b815260040160405180910390fd5b33878783818110610bb757610bb7614409565b9050602002810190610bc9919061441f565b610bda906060810190604001613ac9565b6001600160a01b031614610c01576040516330c4716960e21b815260040160405180910390fd5b610d063383898985818110610c1857610c18614409565b9050602002810190610c2a919061441f565b610c3b906060810190604001613ac9565b8a8a86818110610c4d57610c4d614409565b9050602002810190610c5f919061441f565b610c69908061443f565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508e92508d9150889050818110610caf57610caf614409565b9050602002810190610cc1919061441f565b610ccf90602081019061443f565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061218792505050565b838281518110610d1857610d18614409565b6020908102919091010152600101610b1a565b509095945050505050565b610d3f33611385565b15610d5d57604051631a30c08d60e31b815260040160405180910390fd5b610d6733846125c1565b604080518082019091526060815260006020820152610d8933808360006126b3565b336001600160a01b03167f8e8485583a2310d41f7c82b9427d0bd49bad74bb9cff9d3402a29d8f9b28a0e285604051610dc29190614488565b60405180910390a2336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908484604051610e059291906144df565b60405180910390a250505050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8a919061450e565b6001600160a01b0316336001600160a01b031614610ebb5760405163794821ff60e01b815260040160405180910390fd5b610ec48161289f565b50565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f265750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b610f4357604051635c427cd960e01b815260040160405180910390fd5b610f4c83611385565b15610f7a576001600160a01b038084166000908152609a602052604090205416610f788185858561292f565b505b505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610feb919061452b565b61100857604051631d77d47760e21b815260040160405180910390fd5b6066548181161461102c5760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6110726129aa565b610f7884848484612a04565b6001600160a01b0383166000908152609b60205260408120546110a38582868661177b565b95945050505050565b600054610100900460ff16158080156110cc5750600054600160ff909116105b806110e65750303b1580156110e6575060005460ff166001145b61114e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015611171576000805461ff0019166101001790555b61117b8888612b1d565b611183612ba2565b60975561118f89612c39565b61119886612c8b565b6111a485858585612a04565b80156111ea576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806112545750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61127157604051635c427cd960e01b815260040160405180910390fd5b61127a83611385565b15610f7a576001600160a01b038084166000908152609a602052604090205416610f7881858585612cf0565b6066546002906004908116036112cf5760405163840a48d560e01b815260040160405180910390fd5b6112d7612d6b565b60005b8881101561137a576113728a8a838181106112f7576112f7614409565b90506020028101906113099190614548565b89898481811061131b5761131b614409565b905060200281019061132d919061443f565b89898681811061133f5761133f614409565b9050602002013588888781811061135857611358614409565b905060200201602081019061136d919061455e565b612dc4565b6001016112da565b506111ea600160c955565b6001600160a01b039081166000908152609a602052604090205416151590565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156113ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611411919061452b565b61142e57604051631d77d47760e21b815260040160405180910390fd5b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b60008160405160200161148091906145fa565b604051602081830303815290604052805190602001209050919050565b6066546002906004908116036114c65760405163840a48d560e01b815260040160405180910390fd5b6114ce612d6b565b6114db8686868686612dc4565b6114e5600160c955565b505050505050565b6114f56129aa565b610ec481612c8b565b60006001600160a01b038216158015906109c25750506001600160a01b039081166000818152609a60205260409020549091161490565b61153d6129aa565b6115476000612c39565b565b428360200151101561156e57604051630819bdcd60e01b815260040160405180910390fd5b61157785611385565b1561159557604051631a30c08d60e31b815260040160405180910390fd5b61159e846114fe565b6115bb576040516325878fa360e21b815260040160405180910390fd5b6000609b6000876001600160a01b03166001600160a01b0316815260200190815260200160002054905060006115f7878388886020015161177b565b6001600160a01b0388166000908152609b602052604090206001840190558551909150611627908890839061344d565b611633878786866126b3565b50505050505050565b6060600082516001600160401b0381111561165957611659613d14565b604051908082528060200260200182016040528015611682578160200160208202803683370190505b50905060005b83518110156109be576001600160a01b038516600090815260986020526040812085519091908690849081106116c0576116c0614409565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020548282815181106116fb576116fb614409565b6020908102919091010152600101611688565b611717336114fe565b611734576040516325878fa360e21b815260040160405180910390fd5b336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b6708090838360405161176f9291906144df565b60405180910390a25050565b604080517f39111bc4a4d688e1f685123d7497d4615370152a8ee4a0593e647bd06ad8bb0b6020808301919091526001600160a01b0387811683850152851660608301526080820186905260a08083018590528351808403909101815260c09092019092528051910120600090816117f1612042565b60405161190160f01b602082015260228101919091526042810183905260620160408051808303601f190181529190528051602090910120979650505050505050565b6040516360f4062b60e01b81526001600160a01b03828116600483015260609182916000917f0000000000000000000000000000000000000000000000000000000000000000909116906360f4062b90602401602060405180830381865afa1580156118a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c8919061460d565b6040516394f649dd60e01b81526001600160a01b03868116600483015291925060009182917f0000000000000000000000000000000000000000000000000000000000000000909116906394f649dd90602401600060405180830381865afa158015611938573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119609190810190614684565b915091506000831361197757909590945092505050565b6060808351600003611a30576040805160018082528183019092529060208083019080368337505060408051600180825281830190925292945090506020808301908036833701905050905073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0826000815181106119eb576119eb614409565b60200260200101906001600160a01b031690816001600160a01b0316815250508481600081518110611a1f57611a1f614409565b602002602001018181525050611bde565b8351611a3d90600161475b565b6001600160401b03811115611a5457611a54613d14565b604051908082528060200260200182016040528015611a7d578160200160208202803683370190505b50915081516001600160401b03811115611a9957611a99613d14565b604051908082528060200260200182016040528015611ac2578160200160208202803683370190505b50905060005b8451811015611b5c57848181518110611ae357611ae3614409565b6020026020010151838281518110611afd57611afd614409565b60200260200101906001600160a01b031690816001600160a01b031681525050838181518110611b2f57611b2f614409565b6020026020010151828281518110611b4957611b49614409565b6020908102919091010152600101611ac8565b5073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac08260018451611b81919061476e565b81518110611b9157611b91614409565b60200260200101906001600160a01b031690816001600160a01b031681525050848160018451611bc1919061476e565b81518110611bd157611bd1614409565b6020026020010181815250505b9097909650945050505050565b606654606090600190600290811603611c175760405163840a48d560e01b815260040160405180910390fd5b611c2083611385565b611c3d57604051630b3d63f960e11b815260040160405180910390fd5b611c46836114fe565b15611c64576040516311ca333560e31b815260040160405180910390fd5b6001600160a01b038316611c8b576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b038084166000818152609a602052604090205490911690331480611cbe5750336001600160a01b038216145b80611ce557506001600160a01b038181166000908152609960205260409020600101541633145b611d0257604051635c427cd960e01b815260040160405180910390fd5b600080611d0e86611834565b9092509050336001600160a01b03871614611d6457826001600160a01b0316866001600160a01b03167ff0eddf07e6ea14f388b47e1e94a0f464ecbd9eed4171130e0fc0e99fb4030a8a60405160405180910390a35b826001600160a01b0316866001600160a01b03167ffee30966a256b71e14bc0ebfc94315e28ef4a97a7131a9e2b7a310a73af4467660405160405180910390a36001600160a01b0386166000908152609a6020526040812080546001600160a01b031916905582519003611de8576040805160008152602081019091529450611f3a565b81516001600160401b03811115611e0157611e01613d14565b604051908082528060200260200182016040528015611e2a578160200160208202803683370190505b50945060005b8251811015611f3857604080516001808252818301909252600091602080830190803683375050604080516001808252818301909252929350600092915060208083019080368337019050509050848381518110611e9057611e90614409565b602002602001015182600081518110611eab57611eab614409565b60200260200101906001600160a01b031690816001600160a01b031681525050838381518110611edd57611edd614409565b602002602001015181600081518110611ef857611ef8614409565b602002602001018181525050611f1189878b8585612187565b888481518110611f2357611f23614409565b60209081029190910101525050600101611e30565b505b50505050919050565b611f4c33611385565b15611f6a57604051631a30c08d60e31b815260040160405180910390fd5b611f73836114fe565b611f90576040516325878fa360e21b815260040160405180910390fd5b610f7a338484846126b3565b611fa5336114fe565b611fc2576040516325878fa360e21b815260040160405180910390fd5b610ec433826125c1565b611fd46129aa565b6001600160a01b0381166120395760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611145565b610ec481612c39565b60007f00000000000000000000000000000000000000000000000000000000000000004603612072575060975490565b61207a612ba2565b905090565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f6919061450e565b6001600160a01b0316336001600160a01b0316146121275760405163794821ff60e01b815260040160405180910390fd5b6066541981196066541916146121505760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161105f565b60006001600160a01b0386166121b0576040516339b190bb60e11b815260040160405180910390fd5b82516000036121d25760405163796cc52560e01b815260040160405180910390fd5b60005b83518110156124cf576001600160a01b0386161561222b5761222b868886848151811061220457612204614409565b602002602001015186858151811061221e5761221e614409565b602002602001015161292f565b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06001600160a01b031684828151811061225b5761225b614409565b60200260200101516001600160a01b031603612323577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663beffbb89888584815181106122b3576122b3614409565b60200260200101516040518363ffffffff1660e01b81526004016122ec9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b15801561230657600080fd5b505af115801561231a573d6000803e3d6000fd5b505050506124c7565b846001600160a01b0316876001600160a01b031614806123f557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639b4da03d85838151811061237f5761237f614409565b60200260200101516040518263ffffffff1660e01b81526004016123b291906001600160a01b0391909116815260200190565b602060405180830381865afa1580156123cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f3919061452b565b155b612412576040516330c4716960e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638c80d4e58886848151811061245457612454614409565b602002602001015186858151811061246e5761246e614409565b60200260200101516040518463ffffffff1660e01b815260040161249493929190614781565b600060405180830381600087803b1580156124ae57600080fd5b505af11580156124c2573d6000803e3d6000fd5b505050505b6001016121d5565b506001600160a01b0386166000908152609f602052604081208054918291906124f7836147a5565b919050555060006040518060e00160405280896001600160a01b03168152602001886001600160a01b03168152602001876001600160a01b031681526020018381526020014363ffffffff168152602001868152602001858152509050600061255f8261146d565b6000818152609e602052604090819020805460ff19166001179055519091507f9009ab153e8014fbfb02f2217f5cde7aa7f9ad734ae85ca3ee3f4ca2fdd499f9906125ad90839085906147be565b60405180910390a198975050505050505050565b6213c6806125d560608301604084016147d7565b63ffffffff1611156125fa57604051638b11ba2f60e01b815260040160405180910390fd5b6001600160a01b0382166000908152609960205260409081902060010154600160a01b900463ffffffff169061263690606084019084016147d7565b63ffffffff16101561265b5760405163102b92a760e01b815260040160405180910390fd5b6001600160a01b0382166000908152609960205260409020819061267f8282614814565b505060405133907ffebe5cd24b2cbc7b065b9d0fdeb904461e4afcff57dd57acda1e7832031ba7ac9061176f908490614488565b6066546000906001908116036126dc5760405163840a48d560e01b815260040160405180910390fd5b6001600160a01b038085166000908152609960205260409020600101541680158015906127125750336001600160a01b03821614155b80156127275750336001600160a01b03861614155b156127ea57428460200151101561275157604051630819bdcd60e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832086845290915290205460ff161561279657604051639a5afeb760e01b815260040160405180910390fd5b6001600160a01b0381166000908152609c6020908152604080832086845282528220805460ff191660011790558501516127d79088908890859088906109c8565b90506127e88282876000015161344d565b505b6001600160a01b038681166000818152609a602052604080822080546001600160a01b031916948a169485179055517fc3ee9f2e5fda98e8066a1f745b2df9285f416fe98cf2559cd21484b3d87433049190a360008061284988611834565b9150915060005b82518110156111ea57612897888a85848151811061287057612870614409565b602002602001015185858151811061288a5761288a614409565b6020026020010151612cf0565b600101612850565b6001600160a01b0381166128c6576040516339b190bb60e11b815260040160405180910390fd5b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0380851660009081526098602090815260408083209386168352929052908120805483929061296690849061476e565b92505081905550836001600160a01b03167f6909600037b75d7b4733aedd815442b5ec018a827751c832aaff64eba5d6d2dd848484604051610e0593929190614781565b6033546001600160a01b031633146115475760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611145565b828114612a24576040516343714afd60e01b815260040160405180910390fd5b8260005b818110156114e5576000868683818110612a4457612a44614409565b9050602002016020810190612a599190613ac9565b6001600160a01b038116600090815260a16020526040812054919250868685818110612a8757612a87614409565b90506020020135905062034bc0811115612ab457604051639373e7cf60e01b815260040160405180910390fd5b6001600160a01b038316600081815260a160209081526040918290208490558151928352820184905281018290527f0e7efa738e8b0ce6376a0c1af471655540d2e9a81647d7b09ed823018426576d9060600160405180910390a1505050806001019050612a28565b6065546001600160a01b0316158015612b3e57506001600160a01b03821615155b612b5b576040516339b190bb60e11b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2612b9e8261289f565b5050565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b62034bc0811115612caf57604051639373e7cf60e01b815260040160405180910390fd5b609d5460408051918252602082018390527fafa003cd76f87ff9d62b35beea889920f33c0c42b8d45b74954d61d50f4b6b69910160405180910390a1609d55565b6001600160a01b03808516600090815260986020908152604080832093861683529290529081208054839290612d2790849061475b565b92505081905550836001600160a01b03167f1ec042c965e2edd7107b51188ee0f383e22e76179041ab3a9d18ff151405166c848484604051610e0593929190614781565b600260c95403612dbd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611145565b600260c955565b6000612dd26105f387614877565b6000818152609e602052604090205490915060ff16612e045760405163295a66e160e11b815260040160405180910390fd5b609d544390612e1960a0890160808a016147d7565b63ffffffff16612e29919061475b565b1115612e48576040516378f67ae160e11b815260040160405180910390fd5b612e586060870160408801613ac9565b6001600160a01b0316336001600160a01b031614612e8957604051635c427cd960e01b815260040160405180910390fd5b8115612ebd57612e9c60a087018761443f565b85149050612ebd576040516343714afd60e01b815260040160405180910390fd5b6000818152609e60205260409020805460ff1916905581156130235760005b612ee960a088018861443f565b905081101561301d574360a16000612f0460a08b018b61443f565b85818110612f1457612f14614409565b9050602002016020810190612f299190613ac9565b6001600160a01b03168152602081019190915260400160002054612f5360a08a0160808b016147d7565b63ffffffff16612f63919061475b565b1115612f82576040516378f67ae160e11b815260040160405180910390fd5b613015612f926020890189613ac9565b33612fa060a08b018b61443f565b85818110612fb057612fb0614409565b9050602002016020810190612fc59190613ac9565b612fd260c08c018c61443f565b86818110612fe257612fe2614409565b905060200201358a8a87818110612ffb57612ffb614409565b90506020020160208101906130109190613ac9565b613531565b600101612edc565b50613412565b336000908152609a60205260408120546001600160a01b0316905b61304b60a089018961443f565b905081101561340f574360a1600061306660a08c018c61443f565b8581811061307657613076614409565b905060200201602081019061308b9190613ac9565b6001600160a01b031681526020810191909152604001600020546130b560a08b0160808c016147d7565b63ffffffff166130c5919061475b565b11156130e4576040516378f67ae160e11b815260040160405180910390fd5b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac061310660a08a018a61443f565b8381811061311657613116614409565b905060200201602081019061312b9190613ac9565b6001600160a01b03160361327a57600061314860208a018a613ac9565b905060006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630e81073c8361318960c08e018e61443f565b8781811061319957613199614409565b6040516001600160e01b031960e087901b1681526001600160a01b03909416600485015260200291909101356024830152506044016020604051808303816000875af11580156131ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613211919061460d565b6001600160a01b038084166000908152609a602052604090205491925016801561327257613272818461324760a08f018f61443f565b8881811061325757613257614409565b905060200201602081019061326c9190613ac9565b85612cf0565b505050613407565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c4623ea1338989858181106132bc576132bc614409565b90506020020160208101906132d19190613ac9565b6132de60a08d018d61443f565b868181106132ee576132ee614409565b90506020020160208101906133039190613ac9565b61331060c08e018e61443f565b8781811061332057613320614409565b60405160e088901b6001600160e01b03191681526001600160a01b03968716600482015294861660248601529290941660448401526020909102013560648201526084019050600060405180830381600087803b15801561338057600080fd5b505af1158015613394573d6000803e3d6000fd5b505050506001600160a01b038216156134075761340782336133b960a08c018c61443f565b858181106133c9576133c9614409565b90506020020160208101906133de9190613ac9565b6133eb60c08d018d61443f565b868181106133fb576133fb614409565b90506020020135612cf0565b60010161303e565b50505b6040518181527fc97098c2f658800b4df29001527f7324bcdffcf6e8751a699ab920a1eced5b1d9060200160405180910390a1505050505050565b6001600160a01b0383163b156134f657604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e9061348d9086908690600401614883565b602060405180830381865afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce91906148d8565b6001600160e01b03191614610f7a5760405163026aa43360e31b815260040160405180910390fd5b826001600160a01b031661350a8383613671565b6001600160a01b031614610f7a576040516306c653c360e31b815260040160405180910390fd5b73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeabf196001600160a01b038416016135dc5760405162387b1360e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063387b1300906135a590889088908790600401614781565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b5050505061366a565b60405163c608c7f360e01b81526001600160a01b03858116600483015284811660248301526044820184905282811660648301527f0000000000000000000000000000000000000000000000000000000000000000169063c608c7f390608401600060405180830381600087803b15801561365657600080fd5b505af11580156111ea573d6000803e3d6000fd5b5050505050565b6000806000613680858561368d565b915091506109be816136d2565b60008082516041036136c35760208301516040840151606085015160001a6136b78782858561381c565b945094505050506136cb565b506000905060025b9250929050565b60008160048111156136e6576136e6614902565b036136ee5750565b600181600481111561370257613702614902565b0361374f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401611145565b600281600481111561376357613763614902565b036137b05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611145565b60038160048111156137c4576137c4614902565b03610ec45760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401611145565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561385357506000905060036138d7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156138a7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166138d0576000600192509250506138d7565b9150600090505b94509492505050565b60008083601f8401126138f257600080fd5b5081356001600160401b0381111561390957600080fd5b6020830191508360208260051b85010111156136cb57600080fd5b6000806020838503121561393757600080fd5b82356001600160401b0381111561394d57600080fd5b613959858286016138e0565b90969095509350505050565b6001600160a01b0381168114610ec457600080fd5b803561398581613965565b919050565b600080600080600060a086880312156139a257600080fd5b85356139ad81613965565b945060208601356139bd81613965565b935060408601356139cd81613965565b94979396509394606081013594506080013592915050565b602080825282518282018190526000918401906040840190835b81811015610d2b5783518352602093840193909201916001016139ff565b600060608284031215613a2f57600080fd5b50919050565b60008083601f840112613a4757600080fd5b5081356001600160401b03811115613a5e57600080fd5b6020830191508360208285010111156136cb57600080fd5b600080600060808486031215613a8b57600080fd5b613a958585613a1d565b925060608401356001600160401b03811115613ab057600080fd5b613abc86828701613a35565b9497909650939450505050565b600060208284031215613adb57600080fd5b8135613ae681613965565b9392505050565b600080600060608486031215613b0257600080fd5b8335613b0d81613965565b92506020840135613b1d81613965565b929592945050506040919091013590565b600060208284031215613b4057600080fd5b5035919050565b60008060008060408587031215613b5d57600080fd5b84356001600160401b03811115613b7357600080fd5b613b7f878288016138e0565b90955093505060208501356001600160401b03811115613b9e57600080fd5b613baa878288016138e0565b95989497509550505050565b60008060008060008060008060c0898b031215613bd257600080fd5b8835613bdd81613965565b97506020890135613bed81613965565b9650604089013595506060890135945060808901356001600160401b03811115613c1657600080fd5b613c228b828c016138e0565b90955093505060a08901356001600160401b03811115613c4157600080fd5b613c4d8b828c016138e0565b999c989b5096995094979396929594505050565b6000806000806000806000806080898b031215613c7d57600080fd5b88356001600160401b03811115613c9357600080fd5b613c9f8b828c016138e0565b90995097505060208901356001600160401b03811115613cbe57600080fd5b613cca8b828c016138e0565b90975095505060408901356001600160401b03811115613ce957600080fd5b613cf58b828c016138e0565b90955093505060608901356001600160401b03811115613c4157600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613d4c57613d4c613d14565b60405290565b604080519081016001600160401b0381118282101715613d4c57613d4c613d14565b604051601f8201601f191681016001600160401b0381118282101715613d9c57613d9c613d14565b604052919050565b63ffffffff81168114610ec457600080fd5b803561398581613da4565b60006001600160401b03821115613dda57613dda613d14565b5060051b60200190565b600082601f830112613df557600080fd5b8135613e08613e0382613dc1565b613d74565b8082825260208201915060208360051b860101925085831115613e2a57600080fd5b602085015b83811015613e50578035613e4281613965565b835260209283019201613e2f565b5095945050505050565b600082601f830112613e6b57600080fd5b8135613e79613e0382613dc1565b8082825260208201915060208360051b860101925085831115613e9b57600080fd5b602085015b83811015613e50578035835260209283019201613ea0565b600060e08284031215613eca57600080fd5b613ed2613d2a565b9050613edd8261397a565b8152613eeb6020830161397a565b6020820152613efc6040830161397a565b604082015260608281013590820152613f1760808301613db6565b608082015260a08201356001600160401b03811115613f3557600080fd5b613f4184828501613de4565b60a08301525060c08201356001600160401b03811115613f6057600080fd5b613f6c84828501613e5a565b60c08301525092915050565b600060208284031215613f8a57600080fd5b81356001600160401b03811115613fa057600080fd5b613fac84828501613eb8565b949350505050565b600060208284031215613fc657600080fd5b813560ff81168114613ae657600080fd5b8015158114610ec457600080fd5b600080600080600060808688031215613ffd57600080fd5b85356001600160401b0381111561401357600080fd5b860160e0818903121561402557600080fd5b945060208601356001600160401b0381111561404057600080fd5b61404c888289016138e0565b90955093505060408601359150606086013561406781613fd7565b809150509295509295909350565b6000806040838503121561408857600080fd5b823561409381613965565b915060208301356140a381613965565b809150509250929050565b6000604082840312156140c057600080fd5b6140c8613d52565b905081356001600160401b038111156140e057600080fd5b8201601f810184136140f157600080fd5b80356001600160401b0381111561410a5761410a613d14565b61411d601f8201601f1916602001613d74565b81815285602083850101111561413257600080fd5b81602084016020830137600060209282018301528352928301359282019290925292915050565b600080600080600060a0868803121561417157600080fd5b853561417c81613965565b9450602086013561418c81613965565b935060408601356001600160401b038111156141a757600080fd5b6141b3888289016140ae565b93505060608601356001600160401b038111156141cf57600080fd5b6141db888289016140ae565b95989497509295608001359392505050565b6000806040838503121561420057600080fd5b823561420b81613965565b915060208301356001600160401b0381111561422657600080fd5b61423285828601613de4565b9150509250929050565b600081518084526020840193506020830160005b8281101561426e578151865260209586019590910190600101614250565b5093949350505050565b602081526000613ae6602083018461423c565b6000806020838503121561429e57600080fd5b82356001600160401b038111156142b457600080fd5b61395985828601613a35565b600080604083850312156142d357600080fd5b82356142de81613965565b946020939093013593505050565b6000806000806080858703121561430257600080fd5b843561430d81613965565b935060208501359250604085013561432481613965565b9396929550929360600135925050565b600081518084526020840193506020830160005b8281101561426e5781516001600160a01b0316865260209586019590910190600101614348565b6040815260006143826040830185614334565b82810360208401526110a3818561423c565b6000806000606084860312156143a957600080fd5b83356143b481613965565b925060208401356001600160401b038111156143cf57600080fd5b6143db868287016140ae565b93969395505050506040919091013590565b6000606082840312156143ff57600080fd5b613ae68383613a1d565b634e487b7160e01b600052603260045260246000fd5b60008235605e1983360301811261443557600080fd5b9190910192915050565b6000808335601e1984360301811261445657600080fd5b8301803591506001600160401b0382111561447057600080fd5b6020019150600581901b36038213156136cb57600080fd5b60608101823561449781613965565b6001600160a01b0316825260208301356144b081613965565b6001600160a01b0316602083015260408301356144cc81613da4565b63ffffffff811660408401525092915050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60006020828403121561452057600080fd5b8151613ae681613965565b60006020828403121561453d57600080fd5b8151613ae681613fd7565b6000823560de1983360301811261443557600080fd5b60006020828403121561457057600080fd5b8135613ae681613fd7565b80516001600160a01b03908116835260208083015182169084015260408083015190911690830152606080820151908301526080808201516000916145c79085018263ffffffff169052565b5060a082015160e060a08501526145e160e0850182614334565b905060c083015184820360c08601526110a3828261423c565b602081526000613ae6602083018461457b565b60006020828403121561461f57600080fd5b5051919050565b600082601f83011261463757600080fd5b8151614645613e0382613dc1565b8082825260208201915060208360051b86010192508583111561466757600080fd5b602085015b83811015613e5057805183526020928301920161466c565b6000806040838503121561469757600080fd5b82516001600160401b038111156146ad57600080fd5b8301601f810185136146be57600080fd5b80516146cc613e0382613dc1565b8082825260208201915060208360051b8501019250878311156146ee57600080fd5b6020840193505b8284101561471957835161470881613965565b8252602093840193909101906146f5565b8095505050505060208301516001600160401b0381111561473957600080fd5b61423285828601614626565b634e487b7160e01b600052601160045260246000fd5b808201808211156109c2576109c2614745565b818103818111156109c2576109c2614745565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000600182016147b7576147b7614745565b5060010190565b828152604060208201526000613fac604083018461457b565b6000602082840312156147e957600080fd5b8135613ae681613da4565b80546001600160a01b0319166001600160a01b0392909216919091179055565b813561481f81613965565b61482981836147f4565b5060018101602083013561483c81613965565b61484681836147f4565b50604083013561485581613da4565b815463ffffffff60a01b191660a09190911b63ffffffff60a01b161790555050565b60006109c23683613eb8565b828152604060208201526000825180604084015260005b818110156148b7576020818601810151606086840101520161489a565b506000606082850101526060601f19601f8301168401019150509392505050565b6000602082840312156148ea57600080fd5b81516001600160e01b031981168114613ae657600080fd5b634e487b7160e01b600052602160045260246000fdfea26469706673582212207eff95b58bd0423a50ea943d372bfc0aa51f5a496e204874795e3046ea0b53ee64736f6c634300081b0033", } // DelegationManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/DelegationManagerStorage/binding.go b/pkg/bindings/DelegationManagerStorage/binding.go index 3930e4310..4b84442e1 100644 --- a/pkg/bindings/DelegationManagerStorage/binding.go +++ b/pkg/bindings/DelegationManagerStorage/binding.go @@ -62,7 +62,7 @@ type ISignatureUtilsSignatureWithExpiry struct { // DelegationManagerStorageMetaData contains all meta data concerning the DelegationManagerStorage contract. var DelegationManagerStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_WITHDRAWAL_DELAY_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_WITHDRAWAL_DELAY_BLOCKS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotCurrentlyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorsCannotUndelegate\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksCannotDecrease\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawerNotStaker\",\"inputs\":[]}]", } // DelegationManagerStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EIP1271SignatureUtils/binding.go b/pkg/bindings/EIP1271SignatureUtils/binding.go index d5903bc37..63ec28665 100644 --- a/pkg/bindings/EIP1271SignatureUtils/binding.go +++ b/pkg/bindings/EIP1271SignatureUtils/binding.go @@ -31,8 +31,8 @@ var ( // EIP1271SignatureUtilsMetaData contains all meta data concerning the EIP1271SignatureUtils contract. var EIP1271SignatureUtilsMetaData = &bind.MetaData{ - ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209832fdd04d36d0bbe78b7b9457ca6759978d3e81a33602cb69f518c735ee384664736f6c634300080c0033", + ABI: "[{\"type\":\"error\",\"name\":\"InvalidSignatureEIP1271\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEOA\",\"inputs\":[]}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209c5fdbaf7c0f38f6979f9c98f90e58d8a565b39580e2f87466ca63aa80f59b6764736f6c634300081b0033", } // EIP1271SignatureUtilsABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/Eigen/binding.go b/pkg/bindings/Eigen/binding.go index 419305571..4af9d8c6c 100644 --- a/pkg/bindings/Eigen/binding.go +++ b/pkg/bindings/Eigen/binding.go @@ -38,7 +38,7 @@ type ERC20VotesUpgradeableCheckpoint struct { // EigenMetaData contains all meta data concerning the Eigen contract. var EigenMetaData = &bind.MetaData{ ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_bEIGEN\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CLOCK_MODE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"DOMAIN_SEPARATOR\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowedFrom\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"allowedTo\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"bEIGEN\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpoints\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"pos\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structERC20VotesUpgradeable.Checkpoint\",\"components\":[{\"name\":\"fromBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"votes\",\"type\":\"uint224\",\"internalType\":\"uint224\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"clock\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"subtractedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegate\",\"inputs\":[{\"name\":\"delegatee\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateBySig\",\"inputs\":[{\"name\":\"delegatee\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"v\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"r\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"s\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegates\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableTransferRestrictions\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eip712Domain\",\"inputs\":[],\"outputs\":[{\"name\":\"fields\",\"type\":\"bytes1\",\"internalType\":\"bytes1\"},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extensions\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPastTotalSupply\",\"inputs\":[{\"name\":\"timepoint\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPastVotes\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timepoint\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotes\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"addedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"minters\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"mintingAllowances\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"mintAllowedAfters\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"mint\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"mintAllowedAfter\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"mintingAllowance\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"multisend\",\"inputs\":[{\"name\":\"receivers\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"amounts\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numCheckpoints\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"permit\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"v\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"r\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"s\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setAllowedFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isAllowedFrom\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setAllowedTo\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isAllowedTo\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferRestrictionsDisabledAfter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unwrap\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"wrap\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DelegateChanged\",\"inputs\":[{\"name\":\"delegator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"fromDelegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"toDelegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DelegateVotesChanged\",\"inputs\":[{\"name\":\"delegate\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"previousBalance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newBalance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EIP712DomainChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Mint\",\"inputs\":[{\"name\":\"minter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetAllowedFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"isAllowedFrom\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetAllowedTo\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"isAllowedTo\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TransferRestrictionsDisabled\",\"inputs\":[],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200342538038062003425833981016040819052620000349162000113565b6001600160a01b0381166080526200004b62000052565b5062000145565b600054610100900460ff1615620000bf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161462000111576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012657600080fd5b81516001600160a01b03811681146200013e57600080fd5b9392505050565b6080516132b66200016f6000396000818161034801528181611475015261156401526132b66000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806381b9716111610146578063a9059cbb116100c3578063dd62ed3e11610087578063dd62ed3e146105c5578063de0e9a3e146105d8578063ea598cb0146105eb578063eb415f45146105fe578063f1127ed814610606578063f2fde38b1461064357600080fd5b8063a9059cbb14610566578063aad41a4114610579578063b8c255941461058c578063c3cda5201461059f578063d505accf146105b257600080fd5b806395d89b411161010a57806395d89b411461051b5780639ab24eb0146105235780639aec4bae14610536578063a457c2d714610540578063a7d1195d1461055357600080fd5b806381b971611461049c57806384b0196e146104bd5780638da5cb5b146104d85780638e539e8c146104e957806391ddadf4146104fc57600080fd5b80633a46b1a8116101df5780635c19a95c116101a35780635c19a95c146103f95780636fcfff451461040c57806370a0823114610434578063715018a61461045d57806378aa33ba146104655780637ecebe001461048957600080fd5b80633a46b1a8146103305780633f4da4c6146103435780634bf5d7e91461038257806353957125146103ac578063587cde1e146103cd57600080fd5b80631ffacdef116102265780631ffacdef146102e057806323b872dd146102f3578063313ce567146103065780633644e51514610315578063395093511461031d57600080fd5b80630455e6941461026357806306fdde031461029c578063095ea7b3146102b15780631249c58b146102c457806318160ddd146102ce575b600080fd5b610287610271366004612b8a565b6101336020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102a4610656565b6040516102939190612bf2565b6102876102bf366004612c05565b6106e8565b6102cc610700565b005b6067545b604051908152602001610293565b6102cc6102ee366004612c3d565b61084b565b610287610301366004612c74565b6108b4565b60405160128152602001610293565b6102d26108d8565b61028761032b366004612c05565b6108e7565b6102d261033e366004612c05565b610909565b61036a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610293565b60408051808201909152600e81526d06d6f64653d74696d657374616d760941b60208201526102a4565b6102d26103ba366004612b8a565b6101306020526000908152604090205481565b61036a6103db366004612b8a565b6001600160a01b03908116600090815260fe60205260409020541690565b6102cc610407366004612b8a565b61098e565b61041f61041a366004612b8a565b61099b565b60405163ffffffff9091168152602001610293565b6102d2610442366004612b8a565b6001600160a01b031660009081526065602052604090205490565b6102cc6109c3565b610287610473366004612b8a565b6101346020526000908152604090205460ff1681565b6102d2610497366004612b8a565b6109d7565b6102d26104aa366004612b8a565b6101316020526000908152604090205481565b6104c56109f5565b6040516102939796959493929190612cb0565b6033546001600160a01b031661036a565b6102d26104f7366004612d46565b610a93565b610504610afb565b60405165ffffffffffff9091168152602001610293565b6102a4610b06565b6102d2610531366004612b8a565b610b15565b6102d26101325481565b61028761054e366004612c05565b610b97565b6102cc610561366004612e35565b610c12565b610287610574366004612c05565b61103f565b6102cc610587366004612f78565b61104d565b6102cc61059a366004612c3d565b611128565b6102cc6105ad366004612ff5565b611189565b6102cc6105c036600461304d565b6112bf565b6102d26105d33660046130b7565b611423565b6102cc6105e6366004612d46565b61144e565b6102cc6105f9366004612d46565b611542565b6102cc61163b565b6106196106143660046130ea565b611704565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610293565b6102cc610651366004612b8a565b611788565b6060606880546106659061311f565b80601f01602080910402602001604051908101604052809291908181526020018280546106919061311f565b80156106de5780601f106106b3576101008083540402835291602001916106de565b820191906000526020600020905b8154815290600101906020018083116106c157829003601f168201915b5050505050905090565b6000336106f68185856117fe565b5060019392505050565b336000908152610131602052604090205461077a5760405162461bcd60e51b815260206004820152602f60248201527f456967656e2e6d696e743a206d73672e73656e64657220686173206e6f206d6960448201526e6e74696e6720616c6c6f77616e636560881b60648201526084015b60405180910390fd5b336000908152610130602052604090205442116107f35760405162461bcd60e51b815260206004820152603160248201527f456967656e2e6d696e743a206d73672e73656e646572206973206e6f7420616c6044820152701b1bddd959081d1bc81b5a5b9d081e595d607a1b6064820152608401610771565b336000818152610131602052604081208054919055906108139082611922565b60405181815233907f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968859060200160405180910390a250565b6108536119b3565b6001600160a01b03821660008181526101336020908152604091829020805460ff191685151590811790915591519182527fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed284362227191015b60405180910390a25050565b6000336108c2858285611a0d565b6108cd858585611a81565b506001949350505050565b60006108e2611c3d565b905090565b6000336106f68185856108fa8383611423565b610904919061316a565b6117fe565b6000610913610afb565b65ffffffffffff1682106109655760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b6044820152606401610771565b6001600160a01b038316600090815260ff602052604090206109879083611c47565b9392505050565b6109983382611d30565b50565b6001600160a01b038116600090815260ff60205260408120546109bd90611daa565b92915050565b6109cb6119b3565b6109d56000611e13565b565b6001600160a01b038116600090815260cb60205260408120546109bd565b6000606080600080600060606097546000801b148015610a155750609854155b610a595760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610771565b610a61611e65565b610a69611e74565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000610a9d610afb565b65ffffffffffff168210610aef5760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b6044820152606401610771565b6109bd61010083611c47565b60006108e242611e83565b6060606980546106659061311f565b6001600160a01b038116600090815260ff60205260408120548015610b84576001600160a01b038316600090815260ff6020526040902080546000198301908110610b6257610b62613182565b60009182526020909120015464010000000090046001600160e01b0316610b87565b60005b6001600160e01b03169392505050565b60003381610ba58286611423565b905083811015610c055760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610771565b6108cd82868684036117fe565b600054610100900460ff1615808015610c325750600054600160ff909116105b80610c4c5750303b158015610c4c575060005460ff166001145b610caf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610771565b6000805460ff191660011790558015610cd2576000805461ff0019166101001790555b610cda611eea565b610d1e6040518060400160405280600581526020016422b4b3b2b760d91b8152506040518060400160405280600581526020016422a4a3a2a760d91b815250611f19565b610d2785611e13565b610d4d6040518060400160405280600581526020016422a4a3a2a760d91b815250611f4e565b8251845114610dd45760405162461bcd60e51b815260206004820152604760248201527f456967656e2e696e697469616c697a653a206d696e7465727320616e64206d6960448201527f6e74696e67416c6c6f77616e636573206d757374206265207468652073616d65606482015266040d8cadccee8d60cb1b608482015260a401610771565b8151845114610e5b5760405162461bcd60e51b815260206004820152604760248201527f456967656e2e696e697469616c697a653a206d696e7465727320616e64206d6960448201527f6e74416c6c6f776564416674657273206d757374206265207468652073616d65606482015266040d8cadccee8d60cb1b608482015260a401610771565b60005b8451811015610fea57838181518110610e7957610e79613182565b60200260200101516101316000878481518110610e9857610e98613182565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002081905550828181518110610ed657610ed6613182565b60200260200101516101306000878481518110610ef557610ef5613182565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555060016101336000878481518110610f3a57610f3a613182565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550848181518110610f8b57610f8b613182565b60200260200101516001600160a01b03167fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed28436222716001604051610fd0911515815260200190565b60405180910390a280610fe281613198565b915050610e5e565b50600019610132558015611038576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000336106f6818585611a81565b8281146110c25760405162461bcd60e51b815260206004820152603e60248201527f456967656e2e6d756c746973656e643a2072656365697665727320616e64206160448201527f6d6f756e7473206d757374206265207468652073616d65206c656e67746800006064820152608401610771565b60005b8381101561103857611116338686848181106110e3576110e3613182565b90506020020160208101906110f89190612b8a565b85858581811061110a5761110a613182565b90506020020135611a81565b8061112081613198565b9150506110c5565b6111306119b3565b6001600160a01b03821660008181526101346020908152604091829020805460ff191685151590811790915591519182527f72a561d1af7409467dae4f1e9fc52590a9335a1dda17727e2b6aa8c4db35109b91016108a8565b834211156111d95760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610771565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b0388169181019190915260608101869052608081018590526000906112539061124b9060a00160405160208183030381529060405280519060200120611f98565b858585611fc5565b905061125e81611fed565b86146112ac5760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610771565b6112b68188611d30565b50505050505050565b8342111561130f5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610771565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861133e8c611fed565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061139982611f98565b905060006113a982878787611fc5565b9050896001600160a01b0316816001600160a01b03161461140c5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610771565b6114178a8a8a6117fe565b50505050505050505050565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b611459333083611a81565b60405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156114c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ea91906131b3565b6109985760405162461bcd60e51b8152602060048201526024808201527f456967656e2e756e777261703a2062454947454e207472616e736665722066616044820152631a5b195960e21b6064820152608401610771565b6040516323b872dd60e01b8152336004820152306024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af11580156115b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d991906131b3565b6116305760405162461bcd60e51b815260206004820152602260248201527f456967656e2e777261703a2062454947454e207472616e73666572206661696c604482015261195960f21b6064820152608401610771565b610998303383611a81565b6116436119b3565b60001961013254146116d35760405162461bcd60e51b815260206004820152604d60248201527f456967656e2e64697361626c655472616e736665725265737472696374696f6e60448201527f733a207472616e73666572207265737472696374696f6e732061726520616c7260648201526c1958591e48191a5cd8589b1959609a1b608482015260a401610771565b60006101328190556040517f2b18986d3ba809db2f13a5d7bf17f60d357b37d9cbb55dd71cbbac8dc4060f649190a1565b60408051808201909152600080825260208201526001600160a01b038316600090815260ff60205260409020805463ffffffff841690811061174857611748613182565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b6117906119b3565b6001600160a01b0381166117f55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610771565b61099881611e13565b6001600160a01b0383166118605760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610771565b6001600160a01b0382166118c15760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610771565b6001600160a01b0383811660008181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b61192c8282612015565b6067546001600160e01b03101561199e5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610771565b6119ad6101006120ea836120f6565b50505050565b6033546001600160a01b031633146109d55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610771565b6000611a198484611423565b905060001981146119ad5781811015611a745760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610771565b6119ad84848484036117fe565b6001600160a01b038316611ae55760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610771565b6001600160a01b038216611b475760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610771565b611b5283838361226b565b6001600160a01b03831660009081526065602052604090205481811015611bca5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610771565b6001600160a01b0380851660008181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c2a9086815260200190565b60405180910390a36119ad848484612365565b60006108e2612397565b815460009081816005811115611ca1576000611c628461240b565b611c6c90856131d0565b600088815260209020909150869082015463ffffffff161115611c9157809150611c9f565b611c9c81600161316a565b92505b505b80821015611cee576000611cb583836124f0565b600088815260209020909150869082015463ffffffff161115611cda57809150611ce8565b611ce581600161316a565b92505b50611ca1565b8015611d1a576000868152602090208101600019015464010000000090046001600160e01b0316611d1d565b60005b6001600160e01b03169695505050505050565b6001600160a01b03828116600081815260fe6020818152604080842080546065845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46119ad82848361250b565b600063ffffffff821115611e0f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610771565b5090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060609980546106659061311f565b6060609a80546106659061311f565b600065ffffffffffff821115611e0f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610771565b600054610100900460ff16611f115760405162461bcd60e51b8152600401610771906131e7565b6109d5612648565b600054610100900460ff16611f405760405162461bcd60e51b8152600401610771906131e7565b611f4a8282612678565b5050565b600054610100900460ff16611f755760405162461bcd60e51b8152600401610771906131e7565b61099881604051806040016040528060018152602001603160f81b8152506126c6565b60006109bd611fa5611c3d565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000611fd687878787612723565b91509150611fe3816127e7565b5095945050505050565b6001600160a01b038116600090815260cb602052604090208054600181018255905b50919050565b6001600160a01b03821661206b5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610771565b6120776000838361226b565b8060676000828254612089919061316a565b90915550506001600160a01b0382166000818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611f4a60008383612365565b6000610987828461316a565b825460009081908181156121435760008781526020902082016000190160408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152612158565b60408051808201909152600080825260208201525b905080602001516001600160e01b0316935061217884868863ffffffff16565b92506000821180156121a2575061218d610afb565b65ffffffffffff16816000015163ffffffff16145b156121e7576121b083612935565b60008881526020902083016000190180546001600160e01b03929092166401000000000263ffffffff909216919091179055612261565b86604051806040016040528061220b6121fe610afb565b65ffffffffffff16611daa565b63ffffffff16815260200161221f86612935565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b610132544211612360576001600160a01b038316158061229357506001600160a01b03831630145b806122a657506001600160a01b03821630145b806122ca57506001600160a01b0383166000908152610133602052604090205460ff165b806122ee57506001600160a01b0382166000908152610134602052604090205460ff165b6123605760405162461bcd60e51b815260206004820152603a60248201527f456967656e2e5f6265666f7265546f6b656e5472616e736665723a2066726f6d60448201527f206f7220746f206d7573742062652077686974656c69737465640000000000006064820152608401610771565b505050565b6001600160a01b03838116600090815260fe60205260408082205485841683529120546123609291821691168361250b565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6123c261299e565b6123ca6129f7565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008161241a57506000919050565b6000600161242784612a28565b901c6001901b9050600181848161244057612440613232565b048201901c9050600181848161245857612458613232565b048201901c9050600181848161247057612470613232565b048201901c9050600181848161248857612488613232565b048201901c905060018184816124a0576124a0613232565b048201901c905060018184816124b8576124b8613232565b048201901c905060018184816124d0576124d0613232565b048201901c9050610987818285816124ea576124ea613232565b04612abc565b60006124ff6002848418613248565b6109879084841661316a565b816001600160a01b0316836001600160a01b03161415801561252d5750600081115b15612360576001600160a01b038316156125bb576001600160a01b038316600090815260ff60205260408120819061256890612ad2856120f6565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516125b0929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615612360576001600160a01b038216600090815260ff6020526040812081906125f1906120ea856120f6565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612639929190918252602082015260400190565b60405180910390a25050505050565b600054610100900460ff1661266f5760405162461bcd60e51b8152600401610771906131e7565b6109d533611e13565b600054610100900460ff1661269f5760405162461bcd60e51b8152600401610771906131e7565b81516126b2906068906020850190612ade565b508051612360906069906020840190612ade565b600054610100900460ff166126ed5760405162461bcd60e51b8152600401610771906131e7565b8151612700906099906020850190612ade565b50805161271490609a906020840190612ade565b50506000609781905560985550565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561275a57506000905060036127de565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156127ae573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166127d7576000600192509250506127de565b9150600090505b94509492505050565b60008160048111156127fb576127fb61326a565b14156128045750565b60018160048111156128185761281861326a565b14156128665760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610771565b600281600481111561287a5761287a61326a565b14156128c85760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610771565b60038160048111156128dc576128dc61326a565b14156109985760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610771565b60006001600160e01b03821115611e0f5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610771565b6000806129a9611e65565b8051909150156129c0578051602090910120919050565b60975480156129cf5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080612a02611e74565b805190915015612a19578051602090910120919050565b60985480156129cf5792915050565b600080608083901c15612a3d57608092831c92015b604083901c15612a4f57604092831c92015b602083901c15612a6157602092831c92015b601083901c15612a7357601092831c92015b600883901c15612a8557600892831c92015b600483901c15612a9757600492831c92015b600283901c15612aa957600292831c92015b600183901c156109bd5760010192915050565b6000818310612acb5781610987565b5090919050565b600061098782846131d0565b828054612aea9061311f565b90600052602060002090601f016020900481019282612b0c5760008555612b52565b82601f10612b2557805160ff1916838001178555612b52565b82800160010185558215612b52579182015b82811115612b52578251825591602001919060010190612b37565b50611e0f9291505b80821115611e0f5760008155600101612b5a565b80356001600160a01b0381168114612b8557600080fd5b919050565b600060208284031215612b9c57600080fd5b61098782612b6e565b6000815180845260005b81811015612bcb57602081850181015186830182015201612baf565b81811115612bdd576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006109876020830184612ba5565b60008060408385031215612c1857600080fd5b612c2183612b6e565b946020939093013593505050565b801515811461099857600080fd5b60008060408385031215612c5057600080fd5b612c5983612b6e565b91506020830135612c6981612c2f565b809150509250929050565b600080600060608486031215612c8957600080fd5b612c9284612b6e565b9250612ca060208501612b6e565b9150604084013590509250925092565b60ff60f81b881681526000602060e081840152612cd060e084018a612ba5565b8381036040850152612ce2818a612ba5565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015612d3457835183529284019291840191600101612d18565b50909c9b505050505050505050505050565b600060208284031215612d5857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612d9e57612d9e612d5f565b604052919050565b600067ffffffffffffffff821115612dc057612dc0612d5f565b5060051b60200190565b600082601f830112612ddb57600080fd5b81356020612df0612deb83612da6565b612d75565b82815260059290921b84018101918181019086841115612e0f57600080fd5b8286015b84811015612e2a5780358352918301918301612e13565b509695505050505050565b60008060008060808587031215612e4b57600080fd5b612e5485612b6e565b935060208086013567ffffffffffffffff80821115612e7257600080fd5b818801915088601f830112612e8657600080fd5b8135612e94612deb82612da6565b81815260059190911b8301840190848101908b831115612eb357600080fd5b938501935b82851015612ed857612ec985612b6e565b82529385019390850190612eb8565b975050506040880135925080831115612ef057600080fd5b612efc89848a01612dca565b94506060880135925080831115612f1257600080fd5b5050612f2087828801612dca565b91505092959194509250565b60008083601f840112612f3e57600080fd5b50813567ffffffffffffffff811115612f5657600080fd5b6020830191508360208260051b8501011115612f7157600080fd5b9250929050565b60008060008060408587031215612f8e57600080fd5b843567ffffffffffffffff80821115612fa657600080fd5b612fb288838901612f2c565b90965094506020870135915080821115612fcb57600080fd5b50612fd887828801612f2c565b95989497509550505050565b803560ff81168114612b8557600080fd5b60008060008060008060c0878903121561300e57600080fd5b61301787612b6e565b9550602087013594506040870135935061303360608801612fe4565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a03121561306857600080fd5b61307188612b6e565b965061307f60208901612b6e565b9550604088013594506060880135935061309b60808901612fe4565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156130ca57600080fd5b6130d383612b6e565b91506130e160208401612b6e565b90509250929050565b600080604083850312156130fd57600080fd5b61310683612b6e565b9150602083013563ffffffff81168114612c6957600080fd5b600181811c9082168061313357607f821691505b6020821081141561200f57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561317d5761317d613154565b500190565b634e487b7160e01b600052603260045260246000fd5b60006000198214156131ac576131ac613154565b5060010190565b6000602082840312156131c557600080fd5b815161098781612c2f565b6000828210156131e2576131e2613154565b500390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261326557634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220e4ee2d6f1ea92311c558c0a9f0569a6bf43ef4fd4d69cf13ea69ec8c5e2bf86a64736f6c634300080c0033", + Bin: "0x60a060405234801561001057600080fd5b5060405161343c38038061343c83398101604081905261002f91610109565b6001600160a01b03811660805261004461004a565b50610139565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610107576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011b57600080fd5b81516001600160a01b038116811461013257600080fd5b9392505050565b6080516132da610162600039600081816103480152818161145d015261154c01526132da6000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806381b9716111610146578063a9059cbb116100c3578063dd62ed3e11610087578063dd62ed3e146105c5578063de0e9a3e146105d8578063ea598cb0146105eb578063eb415f45146105fe578063f1127ed814610606578063f2fde38b1461064357600080fd5b8063a9059cbb14610566578063aad41a4114610579578063b8c255941461058c578063c3cda5201461059f578063d505accf146105b257600080fd5b806395d89b411161010a57806395d89b411461051b5780639ab24eb0146105235780639aec4bae14610536578063a457c2d714610540578063a7d1195d1461055357600080fd5b806381b971611461049c57806384b0196e146104bd5780638da5cb5b146104d85780638e539e8c146104e957806391ddadf4146104fc57600080fd5b80633a46b1a8116101df5780635c19a95c116101a35780635c19a95c146103f95780636fcfff451461040c57806370a0823114610434578063715018a61461045d57806378aa33ba146104655780637ecebe001461048957600080fd5b80633a46b1a8146103305780633f4da4c6146103435780634bf5d7e91461038257806353957125146103ac578063587cde1e146103cd57600080fd5b80631ffacdef116102265780631ffacdef146102e057806323b872dd146102f3578063313ce567146103065780633644e51514610315578063395093511461031d57600080fd5b80630455e6941461026357806306fdde031461029c578063095ea7b3146102b15780631249c58b146102c457806318160ddd146102ce575b600080fd5b610287610271366004612ac5565b6101336020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6102a4610656565b6040516102939190612b26565b6102876102bf366004612b39565b6106e8565b6102cc610702565b005b6067545b604051908152602001610293565b6102cc6102ee366004612b71565b61084d565b610287610301366004612ba8565b6108b6565b60405160128152602001610293565b6102d26108da565b61028761032b366004612b39565b6108e9565b6102d261033e366004612b39565b61090b565b61036a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610293565b60408051808201909152600e81526d06d6f64653d74696d657374616d760941b60208201526102a4565b6102d26103ba366004612ac5565b6101306020526000908152604090205481565b61036a6103db366004612ac5565b6001600160a01b03908116600090815260fe60205260409020541690565b6102cc610407366004612ac5565b610990565b61041f61041a366004612ac5565b61099d565b60405163ffffffff9091168152602001610293565b6102d2610442366004612ac5565b6001600160a01b031660009081526065602052604090205490565b6102cc6109bf565b610287610473366004612ac5565b6101346020526000908152604090205460ff1681565b6102d2610497366004612ac5565b6109d3565b6102d26104aa366004612ac5565b6101316020526000908152604090205481565b6104c56109f1565b6040516102939796959493929190612be5565b6033546001600160a01b031661036a565b6102d26104f7366004612c7d565b610a8f565b610504610af7565b60405165ffffffffffff9091168152602001610293565b6102a4610b02565b6102d2610531366004612ac5565b610b11565b6102d26101325481565b61028761054e366004612b39565b610b93565b6102cc610561366004612d64565b610c0e565b610287610574366004612b39565b611031565b6102cc610587366004612eb5565b61103f565b6102cc61059a366004612b71565b611110565b6102cc6105ad366004612f37565b611171565b6102cc6105c0366004612f8f565b6112a7565b6102d26105d3366004612ffa565b61140b565b6102cc6105e6366004612c7d565b611436565b6102cc6105f9366004612c7d565b61152a565b6102cc611623565b61061961061436600461302d565b6116ec565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610293565b6102cc610651366004612ac5565b611770565b60606068805461066590613062565b80601f016020809104026020016040519081016040528092919081815260200182805461069190613062565b80156106de5780601f106106b3576101008083540402835291602001916106de565b820191906000526020600020905b8154815290600101906020018083116106c157829003601f168201915b5050505050905090565b6000336106f68185856117e6565b60019150505b92915050565b336000908152610131602052604090205461077c5760405162461bcd60e51b815260206004820152602f60248201527f456967656e2e6d696e743a206d73672e73656e64657220686173206e6f206d6960448201526e6e74696e6720616c6c6f77616e636560881b60648201526084015b60405180910390fd5b336000908152610130602052604090205442116107f55760405162461bcd60e51b815260206004820152603160248201527f456967656e2e6d696e743a206d73672e73656e646572206973206e6f7420616c6044820152701b1bddd959081d1bc81b5a5b9d081e595d607a1b6064820152608401610773565b33600081815261013160205260408120805491905590610815908261190a565b60405181815233907f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968859060200160405180910390a250565b61085561199b565b6001600160a01b03821660008181526101336020908152604091829020805460ff191685151590811790915591519182527fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed284362227191015b60405180910390a25050565b6000336108c48582856119f5565b6108cf858585611a69565b506001949350505050565b60006108e4611c25565b905090565b6000336106f68185856108fc838361140b565b61090691906130ac565b6117e6565b6000610915610af7565b65ffffffffffff1682106109675760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b6044820152606401610773565b6001600160a01b038316600090815260ff602052604090206109899083611c2f565b9392505050565b61099a3382611d18565b50565b6001600160a01b038116600090815260ff60205260408120546106fc90611d92565b6109c761199b565b6109d16000611dfb565b565b6001600160a01b038116600090815260cb60205260408120546106fc565b6000606080600080600060606097546000801b148015610a115750609854155b610a555760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610773565b610a5d611e4d565b610a65611e5c565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000610a99610af7565b65ffffffffffff168210610aeb5760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b6044820152606401610773565b6106fc61010083611c2f565b60006108e442611e6b565b60606069805461066590613062565b6001600160a01b038116600090815260ff60205260408120548015610b80576001600160a01b038316600090815260ff6020526040902080546000198301908110610b5e57610b5e6130bf565b60009182526020909120015464010000000090046001600160e01b0316610b83565b60005b6001600160e01b03169392505050565b60003381610ba1828661140b565b905083811015610c015760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610773565b6108cf82868684036117e6565b600054610100900460ff1615808015610c2e5750600054600160ff909116105b80610c485750303b158015610c48575060005460ff166001145b610cab5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610773565b6000805460ff191660011790558015610cce576000805461ff0019166101001790555b610cd6611ed2565b610d1a6040518060400160405280600581526020016422b4b3b2b760d91b8152506040518060400160405280600581526020016422a4a3a2a760d91b815250611f01565b610d2385611dfb565b610d496040518060400160405280600581526020016422a4a3a2a760d91b815250611f36565b8251845114610dd05760405162461bcd60e51b815260206004820152604760248201527f456967656e2e696e697469616c697a653a206d696e7465727320616e64206d6960448201527f6e74696e67416c6c6f77616e636573206d757374206265207468652073616d65606482015266040d8cadccee8d60cb1b608482015260a401610773565b8151845114610e575760405162461bcd60e51b815260206004820152604760248201527f456967656e2e696e697469616c697a653a206d696e7465727320616e64206d6960448201527f6e74416c6c6f776564416674657273206d757374206265207468652073616d65606482015266040d8cadccee8d60cb1b608482015260a401610773565b60005b8451811015610fdc57838181518110610e7557610e756130bf565b60200260200101516101316000878481518110610e9457610e946130bf565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002081905550828181518110610ed257610ed26130bf565b60200260200101516101306000878481518110610ef157610ef16130bf565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555060016101336000878481518110610f3657610f366130bf565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550848181518110610f8757610f876130bf565b60200260200101516001600160a01b03167fcf20b1ecb604b0e8888d579c64e8a3b10e590d45c1c2dddb393bed28436222716001604051610fcc911515815260200190565b60405180910390a2600101610e5a565b5060001961013255801561102a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000336106f6818585611a69565b8281146110b45760405162461bcd60e51b815260206004820152603e60248201527f456967656e2e6d756c746973656e643a2072656365697665727320616e64206160448201527f6d6f756e7473206d757374206265207468652073616d65206c656e67746800006064820152608401610773565b60005b8381101561102a57611108338686848181106110d5576110d56130bf565b90506020020160208101906110ea9190612ac5565b8585858181106110fc576110fc6130bf565b90506020020135611a69565b6001016110b7565b61111861199b565b6001600160a01b03821660008181526101346020908152604091829020805460ff191685151590811790915591519182527f72a561d1af7409467dae4f1e9fc52590a9335a1dda17727e2b6aa8c4db35109b91016108aa565b834211156111c15760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610773565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b03881691810191909152606081018690526080810185905260009061123b906112339060a00160405160208183030381529060405280519060200120611f80565b858585611fad565b905061124681611fd5565b86146112945760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610773565b61129e8188611d18565b50505050505050565b834211156112f75760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610773565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886113268c611fd5565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061138182611f80565b9050600061139182878787611fad565b9050896001600160a01b0316816001600160a01b0316146113f45760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610773565b6113ff8a8a8a6117e6565b50505050505050505050565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b611441333083611a69565b60405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156114ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d291906130d5565b61099a5760405162461bcd60e51b8152602060048201526024808201527f456967656e2e756e777261703a2062454947454e207472616e736665722066616044820152631a5b195960e21b6064820152608401610773565b6040516323b872dd60e01b8152336004820152306024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af115801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c191906130d5565b6116185760405162461bcd60e51b815260206004820152602260248201527f456967656e2e777261703a2062454947454e207472616e73666572206661696c604482015261195960f21b6064820152608401610773565b61099a303383611a69565b61162b61199b565b60001961013254146116bb5760405162461bcd60e51b815260206004820152604d60248201527f456967656e2e64697361626c655472616e736665725265737472696374696f6e60448201527f733a207472616e73666572207265737472696374696f6e732061726520616c7260648201526c1958591e48191a5cd8589b1959609a1b608482015260a401610773565b60006101328190556040517f2b18986d3ba809db2f13a5d7bf17f60d357b37d9cbb55dd71cbbac8dc4060f649190a1565b60408051808201909152600080825260208201526001600160a01b038316600090815260ff60205260409020805463ffffffff8416908110611730576117306130bf565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b61177861199b565b6001600160a01b0381166117dd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610773565b61099a81611dfb565b6001600160a01b0383166118485760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610773565b6001600160a01b0382166118a95760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610773565b6001600160a01b0383811660008181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6119148282611ffd565b6067546001600160e01b0310156119865760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610773565b6119956101006120d2836120de565b50505050565b6033546001600160a01b031633146109d15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610773565b6000611a01848461140b565b905060001981146119955781811015611a5c5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610773565b61199584848484036117e6565b6001600160a01b038316611acd5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610773565b6001600160a01b038216611b2f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610773565b611b3a838383612253565b6001600160a01b03831660009081526065602052604090205481811015611bb25760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610773565b6001600160a01b0380851660008181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c129086815260200190565b60405180910390a361199584848461234d565b60006108e461237f565b815460009081816005811115611c89576000611c4a846123f3565b611c5490856130f2565b600088815260209020909150869082015463ffffffff161115611c7957809150611c87565b611c848160016130ac565b92505b505b80821015611cd6576000611c9d83836124db565b600088815260209020909150869082015463ffffffff161115611cc257809150611cd0565b611ccd8160016130ac565b92505b50611c89565b8015611d02576000868152602090208101600019015464010000000090046001600160e01b0316611d05565b60005b6001600160e01b03169695505050505050565b6001600160a01b03828116600081815260fe6020818152604080842080546065845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46119958284836124f6565b600063ffffffff821115611df75760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610773565b5090565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606099805461066590613062565b6060609a805461066590613062565b600065ffffffffffff821115611df75760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610773565b600054610100900460ff16611ef95760405162461bcd60e51b815260040161077390613105565b6109d1612633565b600054610100900460ff16611f285760405162461bcd60e51b815260040161077390613105565b611f328282612663565b5050565b600054610100900460ff16611f5d5760405162461bcd60e51b815260040161077390613105565b61099a81604051806040016040528060018152602001603160f81b8152506126a3565b60006106fc611f8d611c25565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000611fbe878787876126f2565b91509150611fcb816127b6565b5095945050505050565b6001600160a01b038116600090815260cb602052604090208054600181018255905b50919050565b6001600160a01b0382166120535760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610773565b61205f60008383612253565b806067600082825461207191906130ac565b90915550506001600160a01b0382166000818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611f326000838361234d565b600061098982846130ac565b8254600090819081811561212b5760008781526020902082016000190160408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152612140565b60408051808201909152600080825260208201525b905080602001516001600160e01b0316935061216084868863ffffffff16565b925060008211801561218a5750612175610af7565b65ffffffffffff16816000015163ffffffff16145b156121cf5761219883612900565b60008881526020902083016000190180546001600160e01b03929092166401000000000263ffffffff909216919091179055612249565b8660405180604001604052806121f36121e6610af7565b65ffffffffffff16611d92565b63ffffffff16815260200161220786612900565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b610132544211612348576001600160a01b038316158061227b57506001600160a01b03831630145b8061228e57506001600160a01b03821630145b806122b257506001600160a01b0383166000908152610133602052604090205460ff165b806122d657506001600160a01b0382166000908152610134602052604090205460ff165b6123485760405162461bcd60e51b815260206004820152603a60248201527f456967656e2e5f6265666f7265546f6b656e5472616e736665723a2066726f6d60448201527f206f7220746f206d7573742062652077686974656c69737465640000000000006064820152608401610773565b505050565b6001600160a01b03838116600090815260fe6020526040808220548584168352912054612348929182169116836124f6565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6123aa612969565b6123b26129c2565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008160000361240557506000919050565b60006001612412846129f3565b901c6001901b9050600181848161242b5761242b613150565b048201901c9050600181848161244357612443613150565b048201901c9050600181848161245b5761245b613150565b048201901c9050600181848161247357612473613150565b048201901c9050600181848161248b5761248b613150565b048201901c905060018184816124a3576124a3613150565b048201901c905060018184816124bb576124bb613150565b048201901c9050610989818285816124d5576124d5613150565b04612a87565b60006124ea6002848418613166565b610989908484166130ac565b816001600160a01b0316836001600160a01b0316141580156125185750600081115b15612348576001600160a01b038316156125a6576001600160a01b038316600090815260ff60205260408120819061255390612a9d856120de565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724838360405161259b929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615612348576001600160a01b038216600090815260ff6020526040812081906125dc906120d2856120de565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612624929190918252602082015260400190565b60405180910390a25050505050565b600054610100900460ff1661265a5760405162461bcd60e51b815260040161077390613105565b6109d133611dfb565b600054610100900460ff1661268a5760405162461bcd60e51b815260040161077390613105565b606861269683826131cf565b50606961234882826131cf565b600054610100900460ff166126ca5760405162461bcd60e51b815260040161077390613105565b60996126d683826131cf565b50609a6126e382826131cf565b50506000609781905560985550565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561272957506000905060036127ad565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561277d573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166127a6576000600192509250506127ad565b9150600090505b94509492505050565b60008160048111156127ca576127ca61328e565b036127d25750565b60018160048111156127e6576127e661328e565b036128335760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610773565b60028160048111156128475761284761328e565b036128945760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610773565b60038160048111156128a8576128a861328e565b0361099a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610773565b60006001600160e01b03821115611df75760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610773565b600080612974611e4d565b80519091501561298b578051602090910120919050565b609754801561299a5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b6000806129cd611e5c565b8051909150156129e4578051602090910120919050565b609854801561299a5792915050565b600080608083901c15612a0857608092831c92015b604083901c15612a1a57604092831c92015b602083901c15612a2c57602092831c92015b601083901c15612a3e57601092831c92015b600883901c15612a5057600892831c92015b600483901c15612a6257600492831c92015b600283901c15612a7457600292831c92015b600183901c156106fc5760010192915050565b6000818310612a965781610989565b5090919050565b600061098982846130f2565b80356001600160a01b0381168114612ac057600080fd5b919050565b600060208284031215612ad757600080fd5b61098982612aa9565b6000815180845260005b81811015612b0657602081850181015186830182015201612aea565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006109896020830184612ae0565b60008060408385031215612b4c57600080fd5b612b5583612aa9565b946020939093013593505050565b801515811461099a57600080fd5b60008060408385031215612b8457600080fd5b612b8d83612aa9565b91506020830135612b9d81612b63565b809150509250929050565b600080600060608486031215612bbd57600080fd5b612bc684612aa9565b9250612bd460208501612aa9565b929592945050506040919091013590565b60ff60f81b8816815260e060208201526000612c0460e0830189612ae0565b8281036040840152612c168189612ae0565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501528451808252602080870193509091019060005b81811015612c6c578351835260209384019390920191600101612c4e565b50909b9a5050505050505050505050565b600060208284031215612c8f57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612cd557612cd5612c96565b604052919050565b600067ffffffffffffffff821115612cf757612cf7612c96565b5060051b60200190565b600082601f830112612d1257600080fd5b8135612d25612d2082612cdd565b612cac565b8082825260208201915060208360051b860101925085831115612d4757600080fd5b602085015b83811015611fcb578035835260209283019201612d4c565b60008060008060808587031215612d7a57600080fd5b612d8385612aa9565b9350602085013567ffffffffffffffff811115612d9f57600080fd5b8501601f81018713612db057600080fd5b8035612dbe612d2082612cdd565b8082825260208201915060208360051b850101925089831115612de057600080fd5b6020840193505b82841015612e0957612df884612aa9565b825260209384019390910190612de7565b9550505050604085013567ffffffffffffffff811115612e2857600080fd5b612e3487828801612d01565b925050606085013567ffffffffffffffff811115612e5157600080fd5b612e5d87828801612d01565b91505092959194509250565b60008083601f840112612e7b57600080fd5b50813567ffffffffffffffff811115612e9357600080fd5b6020830191508360208260051b8501011115612eae57600080fd5b9250929050565b60008060008060408587031215612ecb57600080fd5b843567ffffffffffffffff811115612ee257600080fd5b612eee87828801612e69565b909550935050602085013567ffffffffffffffff811115612f0e57600080fd5b612f1a87828801612e69565b95989497509550505050565b803560ff81168114612ac057600080fd5b60008060008060008060c08789031215612f5057600080fd5b612f5987612aa9565b95506020870135945060408701359350612f7560608801612f26565b9598949750929560808101359460a0909101359350915050565b600080600080600080600060e0888a031215612faa57600080fd5b612fb388612aa9565b9650612fc160208901612aa9565b95506040880135945060608801359350612fdd60808901612f26565b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561300d57600080fd5b61301683612aa9565b915061302460208401612aa9565b90509250929050565b6000806040838503121561304057600080fd5b61304983612aa9565b9150602083013563ffffffff81168114612b9d57600080fd5b600181811c9082168061307657607f821691505b602082108103611ff757634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156106fc576106fc613096565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156130e757600080fd5b815161098981612b63565b818103818111156106fc576106fc613096565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261318357634e487b7160e01b600052601260045260246000fd5b500490565b601f82111561234857806000526020600020601f840160051c810160208510156131af5750805b601f840160051c820191505b8181101561102a57600081556001016131bb565b815167ffffffffffffffff8111156131e9576131e9612c96565b6131fd816131f78454613062565b84613188565b6020601f82116001811461323157600083156132195750848201515b600019600385901b1c1916600184901b17845561102a565b600084815260208120601f198516915b828110156132615787850151825560209485019460019092019101613241565b508482101561327f5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220c953bf88fe4f0052b179072da96a2ae4af941e269ad20a9f42a59b0afeca835864736f6c634300081b0033", } // EigenABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EigenPod/binding.go b/pkg/bindings/EigenPod/binding.go index 7016ff63f..a4c9d6a32 100644 --- a/pkg/bindings/EigenPod/binding.go +++ b/pkg/bindings/EigenPod/binding.go @@ -72,8 +72,8 @@ type IEigenPodValidatorInfo struct { // EigenPodMetaData contains all meta data concerning the EigenPod contract. var EigenPodMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_ethPOS\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"},{\"name\":\"_GENESIS_TIME\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"GENESIS_TIME\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amountWei\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false}]", - Bin: "0x60e06040523480156200001157600080fd5b5060405162004ad038038062004ad0833981016040819052620000349162000142565b6001600160a01b03808416608052821660a0526001600160401b03811660c0526200005e62000067565b505050620001a1565b600054610100900460ff1615620000d45760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000127576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146200013f57600080fd5b50565b6000806000606084860312156200015857600080fd5b8351620001658162000129565b6020850151909350620001788162000129565b60408501519092506001600160401b03811681146200019657600080fd5b809150509250925092565b60805160a05160c0516148b26200021e60003960006105ff0152600081816102bd0152818161063a015281816106ec01528181610abf01528181610d6c015281816110f40152818161119c0152818161143c015281816118db01528181611a8401526131250152600081816104b8015261126701526148b26000f3fe60806040526004361061016a5760003560e01c80636fcd0e53116100d1578063c49074421161008a578063dda3346c11610064578063dda3346c1461058d578063ee94d67c146105ad578063f074ba62146105cd578063f2882461146105ed57600080fd5b8063c49074421461052d578063c4d66de81461054d578063d06d55871461056d57600080fd5b80636fcd0e53146104425780637439841f1461046f57806374cdd798146104a657806388676cad146104da5780639b4e4634146104fa578063b522538a1461050d57600080fd5b80634665bcda116101235780634665bcda146102ab57806347d28372146102df57806352396a591461039f57806358753357146103d557806358eaee79146103f55780636c0d2d5a1461042257600080fd5b8063039157d2146101a95780630b18ff66146101cb5780632340e8d3146102085780633474aa161461022c5780633f65cf191461026457806342ecff2a1461028457600080fd5b366101a4576040513481527f6fdd3dbdb173299608c0aa9f368735857c8842b581f8389238bf05bd04b3bf499060200160405180910390a1005b600080fd5b3480156101b557600080fd5b506101c96101c4366004613b66565b610621565b005b3480156101d757600080fd5b506033546101eb906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561021457600080fd5b5061021e60395481565b6040519081526020016101ff565b34801561023857600080fd5b5060345461024c906001600160401b031681565b6040516001600160401b0390911681526020016101ff565b34801561027057600080fd5b506101c961027f366004613c24565b610a67565b34801561029057600080fd5b50603a5461024c90600160401b90046001600160401b031681565b3480156102b757600080fd5b506101eb7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102eb57600080fd5b5061035b6040805160808101825260008082526020820181905291810182905260608101919091525060408051608081018252603c548152603d5462ffffff811660208301526001600160401b03630100000082041692820192909252600160581b909104600f0b606082015290565b6040516101ff91908151815260208083015162ffffff16908201526040808301516001600160401b031690820152606091820151600f0b9181019190915260800190565b3480156103ab57600080fd5b5061024c6103ba366004613cf2565b603b602052600090815260409020546001600160401b031681565b3480156103e157600080fd5b50603e546101eb906001600160a01b031681565b34801561040157600080fd5b50610415610410366004613d4e565b610dd6565b6040516101ff9190613dc7565b34801561042e57600080fd5b5061021e61043d366004613cf2565b610e3b565b34801561044e57600080fd5b5061046261045d366004613dd5565b610fef565b6040516101ff9190613dee565b34801561047b57600080fd5b5061041561048a366004613dd5565b600090815260366020526040902054600160c01b900460ff1690565b3480156104b257600080fd5b506101eb7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e657600080fd5b506101c96104f5366004613e44565b61109c565b6101c9610508366004613e61565b611191565b34801561051957600080fd5b50610462610528366004613d4e565b61133e565b34801561053957600080fd5b506101c9610548366004613ef4565b611431565b34801561055957600080fd5b506101c9610568366004613f20565b61166e565b34801561057957600080fd5b506101c9610588366004613f20565b611805565b34801561059957600080fd5b506101c96105a8366004614011565b611898565b3480156105b957600080fd5b50603a5461024c906001600160401b031681565b3480156105d957600080fd5b506101c96105e83660046140e2565b611a6b565b3480156105f957600080fd5b5061024c7f000000000000000000000000000000000000000000000000000000000000000081565b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad919061414a565b156106d35760405162461bcd60e51b81526004016106ca90614167565b60405180910390fd5b604051635ac86ab760e01b8152600860048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa15801561073b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075f919061414a565b1561077c5760405162461bcd60e51b81526004016106ca90614167565b60006107c261078b85806141c4565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611ebe92505050565b6000818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff16600281111561083157610831613d8f565b600281111561084257610842613d8f565b81525050905080604001516001600160401b0316876001600160401b0316116108d5576040805162461bcd60e51b81526020600482015260248101919091527f456967656e506f642e7665726966795374616c6542616c616e63653a2070726f60448201527f6f66206973206f6c646572207468616e206c61737420636865636b706f696e7460648201526084016106ca565b6001816060015160028111156108ed576108ed613d8f565b146109575760405162461bcd60e51b815260206004820152603460248201527f456967656e506f642e7665726966795374616c6542616c616e63653a2076616c604482015273696461746f72206973206e6f742061637469766560601b60648201526084016106ca565b61099b61096486806141c4565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611ee292505050565b610a1f5760405162461bcd60e51b815260206004820152604960248201527f456967656e506f642e7665726966795374616c6542616c616e63653a2076616c60448201527f696461746f72206d75737420626520736c617368656420746f206265206d61726064820152686b6564207374616c6560b81b608482015260a4016106ca565b610a31610a2b88610e3b565b87611f0c565b610a548635610a4087806141c4565b610a4d60208a018a61420d565b8651612067565b610a5e600061227e565b50505050505050565b6033546001600160a01b0316331480610a8a5750603e546001600160a01b031633145b610aa65760405162461bcd60e51b81526004016106ca90614253565b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b32919061414a565b15610b4f5760405162461bcd60e51b81526004016106ca90614167565b8584148015610b5d57508382145b610bed5760405162461bcd60e51b815260206004820152605560248201527f456967656e506f642e7665726966795769746864726177616c43726564656e7460448201527f69616c733a2076616c696461746f72496e646963657320616e642070726f6f666064820152740e640daeae6e840c4ca40e6c2daca40d8cadccee8d605b1b608482015260a4016106ca565b603a546001600160401b03600160401b9091048116908a1611610c8d5760405162461bcd60e51b815260206004820152604c60248201527f456967656e506f642e7665726966795769746864726177616c43726564656e7460448201527f69616c733a207370656369666965642074696d657374616d7020697320746f6f60648201526b0819985c881a5b881c185cdd60a21b608482015260a4016106ca565b610c9f610c998a610e3b565b89611f0c565b6000805b87811015610d4257610d248a358a8a84818110610cc257610cc26142c7565b9050602002016020810190610cd791906142dd565b898985818110610ce957610ce96142c7565b9050602002810190610cfb919061420d565b898987818110610d0d57610d0d6142c7565b9050602002810190610d1f91906141c4565b612514565b610d2e908361431a565b915080610d3a81614332565b915050610ca3565b5060335460405163030b147160e61b81526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063c2c51c4090604401600060405180830381600087803b158015610db257600080fd5b505af1158015610dc6573d6000803e3d6000fd5b5050505050505050505050505050565b600080610e1884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612afa92505050565b600090815260366020526040902054600160c01b900460ff169150505b92915050565b6000610e4a611fff600c61434d565b610e5d6001600160401b0384164261436c565b10610ec65760405162461bcd60e51b815260206004820152603360248201527f456967656e506f642e676574506172656e74426c6f636b526f6f743a2074696d604482015272657374616d70206f7574206f662072616e676560681b60648201526084016106ca565b604080516001600160401b03841660208201526000918291720f3df6d732807ef1319fb7b8bb8522d0beac02910160408051601f1981840301815290829052610f0e916143b3565b600060405180830381855afa9150503d8060008114610f49576040519150601f19603f3d011682016040523d82523d6000602084013e610f4e565b606091505b5091509150818015610f61575060008151115b610fd35760405162461bcd60e51b815260206004820152603860248201527f456967656e506f642e676574506172656e74426c6f636b526f6f743a20696e7660448201527f616c696420626c6f636b20726f6f742072657475726e6564000000000000000060648201526084016106ca565b80806020019051810190610fe791906143cf565b949350505050565b6110176040805160808101825260008082526020820181905291810182905290606082015290565b600082815260366020908152604091829020825160808101845281546001600160401b038082168352600160401b8204811694830194909452600160801b810490931693810193909352906060830190600160c01b900460ff16600281111561108257611082613d8f565b600281111561109357611093613d8f565b90525092915050565b6033546001600160a01b03163314806110bf5750603e546001600160a01b031633145b6110db5760405162461bcd60e51b81526004016106ca90614253565b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611143573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611167919061414a565b156111845760405162461bcd60e51b81526004016106ca90614167565b61118d8261227e565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111d95760405162461bcd60e51b81526004016106ca906143e8565b346801bc16d674ec800000146112655760405162461bcd60e51b8152602060048201526044602482018190527f456967656e506f642e7374616b653a206d75737420696e697469616c6c792073908201527f74616b6520666f7220616e792076616c696461746f72207769746820333220656064820152633a3432b960e11b608482015260a4016106ca565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec80000087876112a8612bf4565b8888886040518863ffffffff1660e01b81526004016112cc9695949392919061448e565b6000604051808303818588803b1580156112e557600080fd5b505af11580156112f9573d6000803e3d6000fd5b50505050507f606865b7934a25d4aed43f6cdb426403353fa4b3009c4d228407474581b01e23858560405161132f9291906144dd565b60405180910390a15050505050565b6113666040805160808101825260008082526020820181905291810182905290606082015290565b603660006113a985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612afa92505050565b81526020808201929092526040908101600020815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b81049094169281019290925290916060830190600160c01b900460ff16600281111561141657611416613d8f565b600281111561142757611427613d8f565b9052509392505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114795760405162461bcd60e51b81526004016106ca906143e8565b611487633b9aca0082614507565b156115115760405162461bcd60e51b815260206004820152604e60248201527f456967656e506f642e776974686472617752657374616b6564426561636f6e4360448201527f6861696e4554483a20616d6f756e74576569206d75737420626520612077686f60648201526d1b194811ddd95a48185b5bdd5b9d60921b608482015260a4016106ca565b6000611521633b9aca008361451b565b6034549091506001600160401b0390811690821611156115da5760405162461bcd60e51b815260206004820152606260248201527f456967656e506f642e776974686472617752657374616b6564426561636f6e4360448201527f6861696e4554483a20616d6f756e74477765692065786365656473207769746860648201527f6472617761626c6552657374616b6564457865637574696f6e4c617965724777608482015261656960f01b60a482015260c4016106ca565b603480548291906000906115f89084906001600160401b031661452f565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e8360405161165791815260200190565b60405180910390a26116698383612c39565b505050565b600054610100900460ff161580801561168e5750600054600160ff909116105b806116a85750303b1580156116a8575060005460ff166001145b61170b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106ca565b6000805460ff19166001179055801561172e576000805461ff0019166101001790555b6001600160a01b0382166117a15760405162461bcd60e51b815260206004820152603460248201527f456967656e506f642e696e697469616c697a653a20706f644f776e65722063616044820152736e6e6f74206265207a65726f206164647265737360601b60648201526084016106ca565b603380546001600160a01b0319166001600160a01b038416179055801561118d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6033546001600160a01b0316331461182f5760405162461bcd60e51b81526004016106ca90614557565b603e54604080516001600160a01b03928316815291831660208301527ffb8129080a19d34dceac04ba253fc50304dc86c729bd63cdca4a969ad19a5eac910160405180910390a1603e80546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b031633146118c25760405162461bcd60e51b81526004016106ca90614557565b604051635ac86ab760e01b8152600560048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa15801561192a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194e919061414a565b1561196b5760405162461bcd60e51b81526004016106ca90614167565b82518451146119f65760405162461bcd60e51b815260206004820152604b60248201527f456967656e506f642e7265636f766572546f6b656e733a20746f6b656e4c697360448201527f7420616e6420616d6f756e7473546f5769746864726177206d7573742062652060648201526a0e6c2daca40d8cadccee8d60ab1b608482015260a4016106ca565b60005b8451811015611a6457611a5283858381518110611a1857611a186142c7565b6020026020010151878481518110611a3257611a326142c7565b60200260200101516001600160a01b0316612d529092919063ffffffff16565b80611a5c81614332565b9150506119f9565b5050505050565b604051635ac86ab760e01b8152600760048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611ad3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af7919061414a565b15611b145760405162461bcd60e51b81526004016106ca90614167565b603a54600160401b90046001600160401b031680611bc05760405162461bcd60e51b815260206004820152605860248201527f456967656e506f642e766572696679436865636b706f696e7450726f6f66733a60448201527f206d75737420686176652061637469766520636865636b706f696e7420746f2060648201527f706572666f726d20636865636b706f696e742070726f6f660000000000000000608482015260a4016106ca565b60408051608081018252603c54808252603d5462ffffff811660208401526001600160401b03630100000082041693830193909352600160581b909204600f0b606082015290611c109087612da4565b6000805b85811015611e645736878783818110611c2f57611c2f6142c7565b9050602002810190611c41919061459f565b80356000908152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff166002811115611cb257611cb2613d8f565b6002811115611cc357611cc3613d8f565b9052509050600181606001516002811115611ce057611ce0613d8f565b14611cec575050611e52565b856001600160401b031681604001516001600160401b031610611d10575050611e52565b600080611d2083898e3587612f20565b602089018051929450909250611d35826145b5565b62ffffff16905250606087018051839190611d519083906145d4565b600f0b905250611d618187614623565b84356000908152603660209081526040918290208651815492880151938801516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b0319909516919092161792909217928316821781556060870151939950869390929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b836002811115611e0657611e06613d8f565b021790555050835160405164ffffffffff90911691506001600160401b038a16907fa91c59033c3423e18b54d0acecebb4972f9ea95aedf5f4cae3b677b02eaf3a3f90600090a3505050505b80611e5c81614332565b915050611c14565b506001600160401b038084166000908152603b6020526040812080548493919291611e9191859116614623565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550610a5e82613042565b600081600081518110611ed357611ed36142c7565b60200260200101519050919050565b600081600381518110611ef757611ef76142c7565b60200260200101516000801b14159050919050565b611f186003602061434d565b611f25602083018361420d565b905014611f9a5760405162461bcd60e51b815260206004820152603d60248201527f426561636f6e436861696e50726f6f66732e7665726966795374617465526f6f60448201527f743a2050726f6f662068617320696e636f7272656374206c656e67746800000060648201526084016106ca565b611fea611faa602083018361420d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525086925050843590506003613249565b61118d5760405162461bcd60e51b815260206004820152604260248201527f426561636f6e436861696e50726f6f66732e7665726966795374617465526f6f60448201527f743a20496e76616c696420737461746520726f6f74206d65726b6c652070726f60648201526137b360f11b608482015260a4016106ca565b600884146120e25760405162461bcd60e51b815260206004820152604e602482015260008051602061485d83398151915260448201527f724669656c64733a2056616c696461746f72206669656c64732068617320696e60648201526d0c6dee4e4cac6e840d8cadccee8d60931b608482015260a4016106ca565b60056120f06028600161431a565b6120fa919061431a565b61210590602061434d565b82146121735760405162461bcd60e51b8152602060048201526043602482015260008051602061485d83398151915260448201527f724669656c64733a2050726f6f662068617320696e636f7272656374206c656e6064820152620cee8d60eb1b608482015260a4016106ca565b60006121b186868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061326192505050565b9050600064ffffffffff83166121c96028600161431a565b600b901b17905061221485858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c9250869150859050613249565b6122745760405162461bcd60e51b815260206004820152603d602482015260008051602061485d83398151915260448201527f724669656c64733a20496e76616c6964206d65726b6c652070726f6f6600000060648201526084016106ca565b5050505050505050565b603a54600160401b90046001600160401b03161561231f5760405162461bcd60e51b815260206004820152605260248201527f456967656e506f642e5f7374617274436865636b706f696e743a206d7573742060448201527f66696e6973682070726576696f757320636865636b706f696e74206265666f72606482015271329039ba30b93a34b7339030b737ba3432b960711b608482015260a4016106ca565b603a54426001600160401b03908116911614156123a45760405162461bcd60e51b815260206004820152603f60248201527f456967656e506f642e5f7374617274436865636b706f696e743a2063616e6e6f60448201527f7420636865636b706f696e7420747769636520696e206f6e6520626c6f636b0060648201526084016106ca565b6034546000906001600160401b03166123c1633b9aca004761451b565b6123cb919061452f565b90508180156123e157506001600160401b038116155b156124545760405162461bcd60e51b815260206004820152603d60248201527f456967656e506f642e5f7374617274436865636b706f696e743a206e6f20626160448201527f6c616e636520617661696c61626c6520746f20636865636b706f696e7400000060648201526084016106ca565b6000604051806080016040528061246a42610e3b565b815260200160395462ffffff168152602001836001600160401b031681526020016000600f0b815250905042603a60086101000a8154816001600160401b0302191690836001600160401b031602179055506124c581613042565b805160208083015160405162ffffff90911681526001600160401b034216917f575796133bbed337e5b39aa49a30dc2556a91e0c6c2af4b7b886ae77ebef1076910160405180910390a3505050565b600080612553848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611ebe92505050565b6000818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff1660028111156125c2576125c2613d8f565b60028111156125d3576125d3613d8f565b90525090506000816060015160028111156125f0576125f0613d8f565b146126815760405162461bcd60e51b8152602060048201526061602482015260008051602061483d83398151915260448201527f7469616c733a2076616c696461746f72206d75737420626520696e616374697660648201527f6520746f2070726f7665207769746864726177616c2063726564656e7469616c6084820152607360f81b60a482015260c4016106ca565b6001600160401b0380166126c786868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061350e92505050565b6001600160401b031614156127505760405162461bcd60e51b8152602060048201526055602482015260008051602061483d83398151915260448201527f7469616c733a2076616c696461746f72206d75737420626520696e207468652060648201527470726f63657373206f662061637469766174696e6760581b608482015260a4016106ca565b6001600160401b03801661279686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061353392505050565b6001600160401b03161461280e5760405162461bcd60e51b81526020600482015260446024820181905260008051602061483d833981519152908201527f7469616c733a2076616c696461746f72206d757374206e6f742062652065786960648201526374696e6760e01b608482015260a4016106ca565b612816612bf4565b61281f9061464e565b61285b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061354b92505050565b146128ca5760405162461bcd60e51b8152602060048201526045602482015260008051602061483d83398151915260448201527f7469616c733a2070726f6f66206973206e6f7420666f72207468697320456967606482015264195b941bd960da1b608482015260a4016106ca565b600061290886868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061356092505050565b90506129188a87878b8b8e612067565b6039805490600061292883614332565b9091555050603a54600090600160401b90046001600160401b03161561296057603a54600160401b90046001600160401b031661296d565b603a546001600160401b03165b6040805160808101825264ffffffffff8d1681526001600160401b03858116602083015283169181019190915290915060608101600190526000858152603660209081526040918290208351815492850151938501516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b031990951691909216179290921792831682178155606084015190929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b836002811115612a4357612a43613d8f565b02179055505060405164ffffffffff8c1681527f2d0800bbc377ea54a08c5db6a87aafff5e3e9c8fead0eda110e40e0c10441449915060200160405180910390a16040805164ffffffffff8c1681526001600160401b03838116602083015284168183015290517f0e5fac175b83177cc047381e030d8fb3b42b37bd1c025e22c280facad62c32df9181900360600190a1612aeb633b9aca006001600160401b03841661434d565b9b9a5050505050505050505050565b60008151603014612b835760405162461bcd60e51b815260206004820152604760248201527f456967656e506f642e5f63616c63756c61746556616c696461746f725075626b60448201527f657948617368206d75737420626520612034382d6279746520424c53207075626064820152666c6963206b657960c81b608482015260a4016106ca565b604051600290612b9a908490600090602001614672565b60408051601f1981840301815290829052612bb4916143b3565b602060405180830381855afa158015612bd1573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e3591906143cf565b60408051600160f81b60208201526000602182015230606090811b6bffffffffffffffffffffffff1916602c8301529101604051602081830303815290604052905090565b80471015612c895760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016106ca565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612cd6576040519150601f19603f3d011682016040523d82523d6000602084013e612cdb565b606091505b50509050806116695760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016106ca565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611669908490613578565b612db06005600361431a565b612dbb90602061434d565b612dc8602083018361420d565b905014612e4b5760405162461bcd60e51b8152602060048201526044602482018190527f426561636f6e436861696e50726f6f66732e76657269667942616c616e636543908201527f6f6e7461696e65723a2050726f6f662068617320696e636f7272656374206c656064820152630dccee8d60e31b608482015260a4016106ca565b606c612e9c612e5d602084018461420d565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250508535905084613249565b6116695760405162461bcd60e51b815260206004820152604960248201527f426561636f6e436861696e50726f6f66732e76657269667942616c616e63654360448201527f6f6e7461696e65723a20696e76616c69642062616c616e636520636f6e7461696064820152683732b910383937b7b360b91b608482015260a4016106ca565b83516020850151600091829182612f3887848861364a565b9050816001600160401b0316816001600160401b031614612fb257612f5d81836137c1565b6040805164ffffffffff861681526001600160401b038b8116602083015284168183015290519196507f0e5fac175b83177cc047381e030d8fb3b42b37bd1c025e22c280facad62c32df919081900360600190a15b6001600160401b0380821660208b0181905290891660408b01526130365760398054906000612fe0836146a1565b9091555050600260608a0152612ff5856146b8565b93508264ffffffffff16886001600160401b03167f2a02361ffa66cf2c2da4682c2355a6adcaa9f6c227b6e6563e68480f9587626a60405160405180910390a35b50505094509492505050565b602081015162ffffff166131c9576000633b9aca00826060015183604001516001600160401b031661307491906145d4565b600f0b61308191906146df565b60408301516034805492935090916000906130a69084906001600160401b0316614623565b82546101009290920a6001600160401b03818102199093169183160217909155603a8054600160401b81049092166001600160801b0319909216919091179055506000603c55603d80546001600160d81b031916905560335460405163030b147160e61b81526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063c2c51c4090604401600060405180830381600087803b15801561316b57600080fd5b505af115801561317f573d6000803e3d6000fd5b5050603a546040518481526001600160401b0390911692507f525408c201bc1576eb44116f6478f1c2a54775b19a043bcfdc708364f74f8e44915060200160405180910390a25050565b8051603c556020810151603d8054604084015160608501516fffffffffffffffffffffffffffffffff16600160581b026fffffffffffffffffffffffffffffffff60581b196001600160401b039092166301000000026affffffffffffffffffffff1990931662ffffff9095169490941791909117169190911790555b50565b6000836132578685856137d9565b1495945050505050565b60008060028351613272919061451b565b90506000816001600160401b0381111561328e5761328e613f3d565b6040519080825280602002602001820160405280156132b7578160200160208202803683370190505b50905060005b828110156133be576002856132d2838361434d565b815181106132e2576132e26142c7565b6020026020010151868360026132f8919061434d565b61330390600161431a565b81518110613313576133136142c7565b6020026020010151604051602001613335929190918252602082015260400190565b60408051601f198184030181529082905261334f916143b3565b602060405180830381855afa15801561336c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061338f91906143cf565b8282815181106133a1576133a16142c7565b6020908102919091010152806133b681614332565b9150506132bd565b506133ca60028361451b565b91505b81156134ea5760005b828110156134d7576002826133eb838361434d565b815181106133fb576133fb6142c7565b602002602001015183836002613411919061434d565b61341c90600161431a565b8151811061342c5761342c6142c7565b602002602001015160405160200161344e929190918252602082015260400190565b60408051601f1981840301815290829052613468916143b3565b602060405180830381855afa158015613485573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906134a891906143cf565b8282815181106134ba576134ba6142c7565b6020908102919091010152806134cf81614332565b9150506133d6565b506134e360028361451b565b91506133cd565b806000815181106134fd576134fd6142c7565b602002602001015192505050919050565b6000610e3582600581518110613526576135266142c7565b6020026020010151613925565b6000610e3582600681518110613526576135266142c7565b600081600181518110611ed357611ed36142c7565b6000610e3582600281518110613526576135266142c7565b60006135cd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661398c9092919063ffffffff16565b80519091501561166957808060200190518101906135eb919061414a565b6116695760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106ca565b60006136586026600161431a565b61366390602061434d565b613670604084018461420d565b9050146136e15760405162461bcd60e51b81526020600482015260446024820181905260008051602061485d833981519152908201527f7242616c616e63653a2050726f6f662068617320696e636f7272656374206c656064820152630dccee8d60e31b608482015260a4016106ca565b60006136ee600485614764565b64ffffffffff169050613748613707604085018561420d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508992505050602086013584613249565b6137a85760405162461bcd60e51b815260206004820152603e602482015260008051602061485d83398151915260448201527f7242616c616e63653a20496e76616c6964206d65726b6c652070726f6f66000060648201526084016106ca565b6137b683602001358561399b565b9150505b9392505050565b60006137ba6001600160401b03808416908516614788565b600083516000141580156137f85750602084516137f69190614507565b155b6138875760405162461bcd60e51b815260206004820152605460248201527f4d65726b6c652e70726f63657373496e636c7573696f6e50726f6f665368613260448201527f35363a2070726f6f66206c656e6774682073686f756c642062652061206e6f6e60648201527316bd32b9379036bab63a34b836329037b310199960611b608482015260a4016106ca565b604080516020808201909252848152905b8551811161391b576138ab600285614507565b6138de578151600052808601516020526020826040600060026107d05a03fa6138d357600080fd5b600284049350613909565b8086015160005281516020526020826040600060026107d05a03fa61390257600080fd5b6002840493505b61391460208261431a565b9050613898565b5051949350505050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b6060610fe784846000856139c8565b6000806139a96004846147d8565b6139b49060406147fc565b64ffffffffff169050610fe784821b613925565b606082471015613a295760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106ca565b6001600160a01b0385163b613a805760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106ca565b600080866001600160a01b03168587604051613a9c91906143b3565b60006040518083038185875af1925050503d8060008114613ad9576040519150601f19603f3d011682016040523d82523d6000602084013e613ade565b606091505b5091509150613aee828286613af9565b979650505050505050565b60608315613b085750816137ba565b825115613b185782518084602001fd5b8160405162461bcd60e51b81526004016106ca9190614829565b80356001600160401b0381168114613b4957600080fd5b919050565b600060408284031215613b6057600080fd5b50919050565b600080600060608486031215613b7b57600080fd5b613b8484613b32565b925060208401356001600160401b0380821115613ba057600080fd5b613bac87838801613b4e565b93506040860135915080821115613bc257600080fd5b50613bcf86828701613b4e565b9150509250925092565b60008083601f840112613beb57600080fd5b5081356001600160401b03811115613c0257600080fd5b6020830191508360208260051b8501011115613c1d57600080fd5b9250929050565b60008060008060008060008060a0898b031215613c4057600080fd5b613c4989613b32565b975060208901356001600160401b0380821115613c6557600080fd5b613c718c838d01613b4e565b985060408b0135915080821115613c8757600080fd5b613c938c838d01613bd9565b909850965060608b0135915080821115613cac57600080fd5b613cb88c838d01613bd9565b909650945060808b0135915080821115613cd157600080fd5b50613cde8b828c01613bd9565b999c989b5096995094979396929594505050565b600060208284031215613d0457600080fd5b6137ba82613b32565b60008083601f840112613d1f57600080fd5b5081356001600160401b03811115613d3657600080fd5b602083019150836020828501011115613c1d57600080fd5b60008060208385031215613d6157600080fd5b82356001600160401b03811115613d7757600080fd5b613d8385828601613d0d565b90969095509350505050565b634e487b7160e01b600052602160045260246000fd5b60038110613dc357634e487b7160e01b600052602160045260246000fd5b9052565b60208101610e358284613da5565b600060208284031215613de757600080fd5b5035919050565b60006080820190506001600160401b03808451168352806020850151166020840152806040850151166040840152506060830151613e2f6060840182613da5565b5092915050565b801515811461324657600080fd5b600060208284031215613e5657600080fd5b81356137ba81613e36565b600080600080600060608688031215613e7957600080fd5b85356001600160401b0380821115613e9057600080fd5b613e9c89838a01613d0d565b90975095506020880135915080821115613eb557600080fd5b50613ec288828901613d0d565b96999598509660400135949350505050565b6001600160a01b038116811461324657600080fd5b8035613b4981613ed4565b60008060408385031215613f0757600080fd5b8235613f1281613ed4565b946020939093013593505050565b600060208284031215613f3257600080fd5b81356137ba81613ed4565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613f7b57613f7b613f3d565b604052919050565b60006001600160401b03821115613f9c57613f9c613f3d565b5060051b60200190565b600082601f830112613fb757600080fd5b81356020613fcc613fc783613f83565b613f53565b82815260059290921b84018101918181019086841115613feb57600080fd5b8286015b848110156140065780358352918301918301613fef565b509695505050505050565b60008060006060848603121561402657600080fd5b83356001600160401b038082111561403d57600080fd5b818601915086601f83011261405157600080fd5b81356020614061613fc783613f83565b82815260059290921b8401810191818101908a84111561408057600080fd5b948201945b838610156140a757853561409881613ed4565b82529482019490820190614085565b975050870135925050808211156140bd57600080fd5b506140ca86828701613fa6565b9250506140d960408501613ee9565b90509250925092565b6000806000604084860312156140f757600080fd5b83356001600160401b038082111561410e57600080fd5b61411a87838801613b4e565b9450602086013591508082111561413057600080fd5b5061413d86828701613bd9565b9497909650939450505050565b60006020828403121561415c57600080fd5b81516137ba81613e36565b6020808252603e908201527f456967656e506f642e6f6e6c795768656e4e6f745061757365643a20696e646560408201527f782069732070617573656420696e20456967656e506f644d616e616765720000606082015260800190565b6000808335601e198436030181126141db57600080fd5b8301803591506001600160401b038211156141f557600080fd5b6020019150600581901b3603821315613c1d57600080fd5b6000808335601e1984360301811261422457600080fd5b8301803591506001600160401b0382111561423e57600080fd5b602001915036819003821315613c1d57600080fd5b6020808252604e908201527f456967656e506f642e6f6e6c794f776e65724f7250726f6f665375626d69747460408201527f65723a2063616c6c6572206973206e6f7420706f64206f776e6572206f72207060608201526d3937b7b31039bab136b4ba3a32b960911b608082015260a00190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156142ef57600080fd5b813564ffffffffff811681146137ba57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561432d5761432d614304565b500190565b600060001982141561434657614346614304565b5060010190565b600081600019048311821515161561436757614367614304565b500290565b60008282101561437e5761437e614304565b500390565b60005b8381101561439e578181015183820152602001614386565b838111156143ad576000848401525b50505050565b600082516143c5818460208701614383565b9190910192915050565b6000602082840312156143e157600080fd5b5051919050565b60208082526031908201527f456967656e506f642e6f6e6c79456967656e506f644d616e616765723a206e6f6040820152703a1032b4b3b2b72837b226b0b730b3b2b960791b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261447a816020860160208601614383565b601f01601f19169290920160200192915050565b6080815260006144a260808301888a614439565b82810360208401526144b48188614462565b905082810360408401526144c9818688614439565b915050826060830152979650505050505050565b602081526000610fe7602083018486614439565b634e487b7160e01b600052601260045260246000fd5b600082614516576145166144f1565b500690565b60008261452a5761452a6144f1565b500490565b60006001600160401b038381169083168181101561454f5761454f614304565b039392505050565b60208082526028908201527f456967656e506f642e6f6e6c79456967656e506f644f776e65723a206e6f74206040820152673837b227bbb732b960c11b606082015260800190565b60008235605e198336030181126143c557600080fd5b600062ffffff8216806145ca576145ca614304565b6000190192915050565b600081600f0b83600f0b600082128260016001607f1b03038213811516156145fe576145fe614304565b8260016001607f1b031903821281161561461a5761461a614304565b50019392505050565b60006001600160401b0380831681851680830382111561464557614645614304565b01949350505050565b80516020808301519190811015613b605760001960209190910360031b1b16919050565b60008351614684818460208801614383565b6001600160801b0319939093169190920190815260100192915050565b6000816146b0576146b0614304565b506000190190565b600081600f0b60016001607f1b03198114156146d6576146d6614304565b60000392915050565b60006001600160ff1b038184138284138082168684048611161561470557614705614304565b600160ff1b600087128281168783058912161561472457614724614304565b6000871292508782058712848416161561474057614740614304565b8785058712818416161561475657614756614304565b505050929093029392505050565b600064ffffffffff8084168061477c5761477c6144f1565b92169190910492915050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156147b3576147b3614304565b8160016001607f1b030183138116156147ce576147ce614304565b5090039392505050565b600064ffffffffff808416806147f0576147f06144f1565b92169190910692915050565b600064ffffffffff8083168185168183048111821515161561482057614820614304565b02949350505050565b6020815260006137ba602083018461446256fe456967656e506f642e5f7665726966795769746864726177616c43726564656e426561636f6e436861696e50726f6f66732e76657269667956616c696461746fa2646970667358221220721ae261e7ea8172633ca39b5c47509345abd9d23c9a1d07374863ca537d102264736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_ethPOS\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"},{\"name\":\"_GENESIS_TIME\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"GENESIS_TIME\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amountWei\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountMustBeMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BeaconTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CannotCheckpointTwiceInSingleBlock\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CheckpointAlreadyActive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CredentialsAlreadyVerified\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientWithdrawableBalance\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEIP4788Response\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProofLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProofLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPubKeyLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidValidatorFieldsLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MsgValueNot32ETH\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoActiveCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoBalanceToCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TimestampOutOfRange\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorInactiveOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorIsExitingBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotActiveInPod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotSlashedOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawCredentialsNotForEigenPod\",\"inputs\":[]}]", + Bin: "0x60e060405234801561001057600080fd5b50604051613cf9380380613cf983398101604081905261002f91610136565b6001600160a01b03808416608052821660a0526001600160401b03811660c05261005761005f565b50505061018f565b600054610100900460ff16156100cb5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161461011c576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811461013357600080fd5b50565b60008060006060848603121561014b57600080fd5b83516101568161011e565b60208501519093506101678161011e565b60408501519092506001600160401b038116811461018457600080fd5b809150509250925092565b60805160a05160c051613aee61020b60003960006105ff0152600081816102bd0152818161063a015281816106e4015281816109af01528181610b7601528181610e5f01528181610f0801528181611146015281816114af015281816115e601526126a90152600081816104b80152610f710152613aee6000f3fe60806040526004361061016a5760003560e01c80636fcd0e53116100d1578063c49074421161008a578063dda3346c11610064578063dda3346c1461058d578063ee94d67c146105ad578063f074ba62146105cd578063f2882461146105ed57600080fd5b8063c49074421461052d578063c4d66de81461054d578063d06d55871461056d57600080fd5b80636fcd0e53146104425780637439841f1461046f57806374cdd798146104a657806388676cad146104da5780639b4e4634146104fa578063b522538a1461050d57600080fd5b80634665bcda116101235780634665bcda146102ab57806347d28372146102df57806352396a591461039f57806358753357146103d557806358eaee79146103f55780636c0d2d5a1461042257600080fd5b8063039157d2146101a95780630b18ff66146101cb5780632340e8d3146102085780633474aa161461022c5780633f65cf191461026457806342ecff2a1461028457600080fd5b366101a4576040513481527f6fdd3dbdb173299608c0aa9f368735857c8842b581f8389238bf05bd04b3bf499060200160405180910390a1005b600080fd5b3480156101b557600080fd5b506101c96101c4366004612fea565b610621565b005b3480156101d757600080fd5b506033546101eb906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561021457600080fd5b5061021e60395481565b6040519081526020016101ff565b34801561023857600080fd5b5060345461024c906001600160401b031681565b6040516001600160401b0390911681526020016101ff565b34801561027057600080fd5b506101c961027f3660046130ac565b610956565b34801561029057600080fd5b50603a5461024c90600160401b90046001600160401b031681565b3480156102b757600080fd5b506101eb7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102eb57600080fd5b5061035b6040805160808101825260008082526020820181905291810182905260608101919091525060408051608081018252603c548152603d5462ffffff811660208301526001600160401b03630100000082041692820192909252600160581b909104600f0b606082015290565b6040516101ff91908151815260208083015162ffffff16908201526040808301516001600160401b031690820152606091820151600f0b9181019190915260800190565b3480156103ab57600080fd5b5061024c6103ba36600461318a565b603b602052600090815260409020546001600160401b031681565b3480156103e157600080fd5b50603e546101eb906001600160a01b031681565b34801561040157600080fd5b506104156104103660046131e6565b610be0565b6040516101ff919061325f565b34801561042e57600080fd5b5061021e61043d36600461318a565b610c45565b34801561044e57600080fd5b5061046261045d36600461326d565b610d59565b6040516101ff9190613286565b34801561047b57600080fd5b5061041561048a36600461326d565b600090815260366020526040902054600160c01b900460ff1690565b3480156104b257600080fd5b506101eb7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e657600080fd5b506101c96104f53660046132e8565b610e06565b6101c9610508366004613305565b610efd565b34801561051957600080fd5b506104626105283660046131e6565b611048565b34801561053957600080fd5b506101c961054836600461339c565b61113b565b34801561055957600080fd5b506101c96105683660046133c8565b611287565b34801561057957600080fd5b506101c96105883660046133c8565b6113d7565b34801561059957600080fd5b506101c96105a83660046134bb565b61146b565b3480156105b957600080fd5b50603a5461024c906001600160401b031681565b3480156105d957600080fd5b506101c96105e8366004613594565b6115cd565b3480156105f957600080fd5b5061024c7f000000000000000000000000000000000000000000000000000000000000000081565b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad9190613600565b156106cb5760405163840a48d560e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600860048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610733573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107579190613600565b156107755760405163840a48d560e01b815260040160405180910390fd5b60006107bb610784858061361d565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506119a092505050565b6000818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff16600281111561082a5761082a613227565b600281111561083b5761083b613227565b81525050905080604001516001600160401b0316876001600160401b031611610877576040516337e07ffd60e01b815260040160405180910390fd5b60018160600151600281111561088f5761088f613227565b146108ad5760405163d49e19a760e01b815260040160405180910390fd5b6108f16108ba868061361d565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506119c492505050565b61090e5760405163161ce5ed60e31b815260040160405180910390fd5b61092061091a88610c45565b876119ee565b610943863561092f878061361d565b61093c60208a018a613666565b8651611a94565b61094d6000611bbf565b50505050505050565b6033546001600160a01b03163314806109795750603e546001600160a01b031633145b61099657604051635c427cd960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a229190613600565b15610a405760405163840a48d560e01b815260040160405180910390fd5b8584148015610a4e57508382145b610a6b576040516343714afd60e01b815260040160405180910390fd5b603a546001600160401b03600160401b9091048116908a1611610aa1576040516337e07ffd60e01b815260040160405180910390fd5b610ab3610aad8a610c45565b896119ee565b6000805b87811015610b4c57610b388a358a8a84818110610ad657610ad66136ac565b9050602002016020810190610aeb91906136c2565b898985818110610afd57610afd6136ac565b9050602002810190610b0f9190613666565b898987818110610b2157610b216136ac565b9050602002810190610b33919061361d565b611d38565b610b4290836136ff565b9150600101610ab7565b5060335460405163030b147160e61b81526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063c2c51c4090604401600060405180830381600087803b158015610bbc57600080fd5b505af1158015610bd0573d6000803e3d6000fd5b5050505050505050505050505050565b600080610c2284848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506121a792505050565b600090815260366020526040902054600160c01b900460ff169150505b92915050565b6000610c54611fff600c613712565b610c676001600160401b03841642613729565b10610c8557604051637944e66d60e11b815260040160405180910390fd5b604080516001600160401b03841660208201526000918291720f3df6d732807ef1319fb7b8bb8522d0beac02910160408051601f1981840301815290829052610ccd91613760565b600060405180830381855afa9150503d8060008114610d08576040519150601f19603f3d011682016040523d82523d6000602084013e610d0d565b606091505b5091509150818015610d20575060008151115b610d3d5760405163558ad0a360e01b815260040160405180910390fd5b80806020019051810190610d51919061377c565b949350505050565b610d816040805160808101825260008082526020820181905291810182905290606082015290565b600082815260366020908152604091829020825160808101845281546001600160401b038082168352600160401b8204811694830194909452600160801b810490931693810193909352906060830190600160c01b900460ff166002811115610dec57610dec613227565b6002811115610dfd57610dfd613227565b90525092915050565b6033546001600160a01b0316331480610e295750603e546001600160a01b031633145b610e4657604051635c427cd960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610eae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed29190613600565b15610ef05760405163840a48d560e01b815260040160405180910390fd5b610ef982611bbf565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f4657604051635c427cd960e01b815260040160405180910390fd5b346801bc16d674ec80000014610f6f5760405163049696b360e31b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008787610fb261223c565b8888886040518863ffffffff1660e01b8152600401610fd6969594939291906137ea565b6000604051808303818588803b158015610fef57600080fd5b505af1158015611003573d6000803e3d6000fd5b50505050507f606865b7934a25d4aed43f6cdb426403353fa4b3009c4d228407474581b01e238585604051611039929190613839565b60405180910390a15050505050565b6110706040805160808101825260008082526020820181905291810182905290606082015290565b603660006110b385858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506121a792505050565b81526020808201929092526040908101600020815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b81049094169281019290925290916060830190600160c01b900460ff16600281111561112057611120613227565b600281111561113157611131613227565b9052509392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461118457604051635c427cd960e01b815260040160405180910390fd5b611192633b9aca0082613863565b156111b0576040516321ddeb1760e21b815260040160405180910390fd5b60006111c0633b9aca0083613877565b6034549091506001600160401b0390811690821611156111f3576040516302c6f54760e21b815260040160405180910390fd5b603480548291906000906112119084906001600160401b031661388b565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e8360405161127091815260200190565b60405180910390a26112828383612281565b505050565b600054610100900460ff16158080156112a75750600054600160ff909116105b806112c15750303b1580156112c1575060005460ff166001145b6113295760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561134c576000805461ff0019166101001790555b6001600160a01b038216611373576040516339b190bb60e11b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0384161790558015610ef9576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6033546001600160a01b0316331461140257604051635c427cd960e01b815260040160405180910390fd5b603e54604080516001600160a01b03928316815291831660208301527ffb8129080a19d34dceac04ba253fc50304dc86c729bd63cdca4a969ad19a5eac910160405180910390a1603e80546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b0316331461149657604051635c427cd960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600560048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa1580156114fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115229190613600565b156115405760405163840a48d560e01b815260040160405180910390fd5b8251845114611562576040516343714afd60e01b815260040160405180910390fd5b60005b84518110156115c6576115be83858381518110611584576115846136ac565b602002602001015187848151811061159e5761159e6136ac565b60200260200101516001600160a01b031661239a9092919063ffffffff16565b600101611565565b5050505050565b604051635ac86ab760e01b8152600760048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611635573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116599190613600565b156116775760405163840a48d560e01b815260040160405180910390fd5b603a54600160401b90046001600160401b031660008190036116ac57604051631a544f4960e01b815260040160405180910390fd5b60408051608081018252603c54808252603d5462ffffff811660208401526001600160401b03630100000082041693830193909352600160581b909204600f0b6060820152906116fc90876123ec565b6000805b85811015611946573687878381811061171b5761171b6136ac565b905060200281019061172d91906138aa565b80356000908152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff16600281111561179e5761179e613227565b60028111156117af576117af613227565b90525090506001816060015160028111156117cc576117cc613227565b146117d857505061193e565b856001600160401b031681604001516001600160401b0316106117fc57505061193e565b60008061180c83898e358761249e565b602089018051929450909250611821826138c0565b62ffffff1690525060608701805183919061183d9083906138df565b600f0b90525061184d818761390c565b84356000908152603660209081526040918290208651815492880151938801516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b0319909516919092161792909217928316821781556060870151939950869390929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b8360028111156118f2576118f2613227565b021790555050835160405164ffffffffff90911691506001600160401b038a16907fa91c59033c3423e18b54d0acecebb4972f9ea95aedf5f4cae3b677b02eaf3a3f90600090a3505050505b600101611700565b506001600160401b038084166000908152603b60205260408120805484939192916119739185911661390c565b92506101000a8154816001600160401b0302191690836001600160401b0316021790555061094d826125c3565b6000816000815181106119b5576119b56136ac565b60200260200101519050919050565b6000816003815181106119d9576119d96136ac565b60200260200101516000801b14159050919050565b6119fa60036020613712565b611a076020830183613666565b905014611a27576040516313717da960e21b815260040160405180910390fd5b611a77611a376020830183613666565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250508435905060036127cd565b610ef9576040516309bde33960e01b815260040160405180910390fd5b60088414611ab55760405163200591bd60e01b815260040160405180910390fd5b6005611ac3602860016136ff565b611acd91906136ff565b611ad8906020613712565b8214611af7576040516313717da960e21b815260040160405180910390fd5b6000611b358686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506127e592505050565b9050600064ffffffffff8316611b4d602860016136ff565b600b901b179050611b9885858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508691508590506127cd565b611bb5576040516309bde33960e01b815260040160405180910390fd5b5050505050505050565b603a54600160401b90046001600160401b031615611bef5760405162be9bc360e81b815260040160405180910390fd5b603a546001600160401b03428116911603611c1d576040516367db5b8b60e01b815260040160405180910390fd5b6034546000906001600160401b0316611c3a633b9aca0047613877565b611c44919061388b565b9050818015611c5a57506001600160401b038116155b15611c78576040516332dea95960e21b815260040160405180910390fd5b60006040518060800160405280611c8e42610c45565b815260200160395462ffffff168152602001836001600160401b031681526020016000600f0b815250905042603a60086101000a8154816001600160401b0302191690836001600160401b03160217905550611ce9816125c3565b805160208083015160405162ffffff90911681526001600160401b034216917f575796133bbed337e5b39aa49a30dc2556a91e0c6c2af4b7b886ae77ebef1076910160405180910390a3505050565b600080611d778484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506119a092505050565b6000818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff166002811115611de657611de6613227565b6002811115611df757611df7613227565b9052509050600081606001516002811115611e1457611e14613227565b14611e32576040516335e09e9d60e01b815260040160405180910390fd5b6001600160401b038016611e78868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a7e92505050565b6001600160401b031603611e9f57604051631958236d60e21b815260040160405180910390fd5b6001600160401b038016611ee5868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612aa392505050565b6001600160401b031614611f0c57604051632eade63760e01b815260040160405180910390fd5b611f1461223c565b611f1d9061392b565b611f59868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612abb92505050565b14611f7757604051632230566760e11b815260040160405180910390fd5b6000611fb5868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612ad092505050565b9050611fc58a87878b8b8e611a94565b60398054906000611fd58361394f565b9091555050603a54600090600160401b90046001600160401b03161561200d57603a54600160401b90046001600160401b031661201a565b603a546001600160401b03165b6040805160808101825264ffffffffff8d1681526001600160401b03858116602083015283169181019190915290915060608101600190526000858152603660209081526040918290208351815492850151938501516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b031990951691909216179290921792831682178155606084015190929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b8360028111156120f0576120f0613227565b02179055505060405164ffffffffff8c1681527f2d0800bbc377ea54a08c5db6a87aafff5e3e9c8fead0eda110e40e0c10441449915060200160405180910390a16040805164ffffffffff8c1681526001600160401b03838116602083015284168183015290517f0e5fac175b83177cc047381e030d8fb3b42b37bd1c025e22c280facad62c32df9181900360600190a1612198633b9aca006001600160401b038416613712565b9b9a5050505050505050505050565b600081516030146121cb57604051634f88323960e11b815260040160405180910390fd5b6040516002906121e2908490600090602001613968565b60408051601f19818403018152908290526121fc91613760565b602060405180830381855afa158015612219573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610c3f919061377c565b60408051600160f81b60208201526000602182015230606090811b6bffffffffffffffffffffffff1916602c8301529101604051602081830303815290604052905090565b804710156122d15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611320565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461231e576040519150601f19603f3d011682016040523d82523d6000602084013e612323565b606091505b50509050806112825760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611320565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611282908490612ae8565b6123f8600560036136ff565b612403906020613712565b6124106020830183613666565b905014612430576040516313717da960e21b815260040160405180910390fd5b606c6124816124426020840184613666565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792505085359050846127cd565b611282576040516309bde33960e01b815260040160405180910390fd5b835160208501516000918291826124b6878488612bbd565b9050816001600160401b0316816001600160401b031614612530576124db8183612c9e565b6040805164ffffffffff861681526001600160401b038b8116602083015284168183015290519196507f0e5fac175b83177cc047381e030d8fb3b42b37bd1c025e22c280facad62c32df919081900360600190a15b6001600160401b0380821660208b0181905290891660408b01526000036125b7576039805490600061256183613997565b9091555050600260608a0152612576856139ae565b93508264ffffffffff16886001600160401b03167f2a02361ffa66cf2c2da4682c2355a6adcaa9f6c227b6e6563e68480f9587626a60405160405180910390a35b50505094509492505050565b806020015162ffffff1660000361274d576000633b9aca00826060015183604001516001600160401b03166125f891906138df565b600f0b61260591906139d4565b604083015160348054929350909160009061262a9084906001600160401b031661390c565b82546101009290920a6001600160401b03818102199093169183160217909155603a8054600160401b81049092166001600160801b0319909216919091179055506000603c55603d80546001600160d81b031916905560335460405163030b147160e61b81526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063c2c51c4090604401600060405180830381600087803b1580156126ef57600080fd5b505af1158015612703573d6000803e3d6000fd5b5050603a546040518481526001600160401b0390911692507f525408c201bc1576eb44116f6478f1c2a54775b19a043bcfdc708364f74f8e44915060200160405180910390a25050565b8051603c556020810151603d8054604084015160608501516fffffffffffffffffffffffffffffffff16600160581b026fffffffffffffffffffffffffffffffff60581b196001600160401b039092166301000000026affffffffffffffffffffff1990931662ffffff9095169490941791909117169190911790555b50565b6000836127db868585612cbd565b1495945050505050565b600080600283516127f69190613877565b90506000816001600160401b03811115612812576128126133e5565b60405190808252806020026020018201604052801561283b578160200160208202803683370190505b50905060005b82811015612938576002856128568383613712565b81518110612866576128666136ac565b60200260200101518683600261287c9190613712565b6128879060016136ff565b81518110612897576128976136ac565b60200260200101516040516020016128b9929190918252602082015260400190565b60408051601f19818403018152908290526128d391613760565b602060405180830381855afa1580156128f0573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612913919061377c565b828281518110612925576129256136ac565b6020908102919091010152600101612841565b50612944600283613877565b91505b8115612a5a5760005b82811015612a47576002826129658383613712565b81518110612975576129756136ac565b60200260200101518383600261298b9190613712565b6129969060016136ff565b815181106129a6576129a66136ac565b60200260200101516040516020016129c8929190918252602082015260400190565b60408051601f19818403018152908290526129e291613760565b602060405180830381855afa1580156129ff573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612a22919061377c565b828281518110612a3457612a346136ac565b6020908102919091010152600101612950565b50612a53600283613877565b9150612947565b80600081518110612a6d57612a6d6136ac565b602002602001015192505050919050565b6000610c3f82600581518110612a9657612a966136ac565b6020026020010151612d9a565b6000610c3f82600681518110612a9657612a966136ac565b6000816001815181106119b5576119b56136ac565b6000610c3f82600281518110612a9657612a966136ac565b6000612b3d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e019092919063ffffffff16565b9050805160001480612b5e575080806020019051810190612b5e9190613600565b6112825760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611320565b6000612bcb602660016136ff565b612bd6906020613712565b612be36040840184613666565b905014612c03576040516313717da960e21b815260040160405180910390fd5b6000612c10600485613a04565b64ffffffffff169050612c6a612c296040850185613666565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525089925050506020860135846127cd565b612c87576040516309bde33960e01b815260040160405180910390fd5b612c95836020013585612e10565b95945050505050565b6000612cb66001600160401b03808416908516613a2e565b9392505050565b60008351600014158015612cdc575060208451612cda9190613863565b155b612cf9576040516313717da960e21b815260040160405180910390fd5b604080516020808201909252848152905b85518111612d9057612d1d600285613863565b600003612d53578151600052808601516020526020826040600060026107d05a03fa612d4857600080fd5b600284049350612d7e565b8086015160005281516020526020826040600060026107d05a03fa612d7757600080fd5b6002840493505b612d896020826136ff565b9050612d0a565b5051949350505050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b6060610d518484600085612e3d565b600080612e1e600484613a5b565b612e29906040613a85565b64ffffffffff169050610d5184821b612d9a565b606082471015612e9e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611320565b600080866001600160a01b03168587604051612eba9190613760565b60006040518083038185875af1925050503d8060008114612ef7576040519150601f19603f3d011682016040523d82523d6000602084013e612efc565b606091505b5091509150612f0d87838387612f18565b979650505050505050565b60608315612f87578251600003612f80576001600160a01b0385163b612f805760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611320565b5081610d51565b610d518383815115612f9c5781518083602001fd5b8060405162461bcd60e51b81526004016113209190613aa5565b80356001600160401b0381168114612fcd57600080fd5b919050565b600060408284031215612fe457600080fd5b50919050565b600080600060608486031215612fff57600080fd5b61300884612fb6565b925060208401356001600160401b0381111561302357600080fd5b61302f86828701612fd2565b92505060408401356001600160401b0381111561304b57600080fd5b61305786828701612fd2565b9150509250925092565b60008083601f84011261307357600080fd5b5081356001600160401b0381111561308a57600080fd5b6020830191508360208260051b85010111156130a557600080fd5b9250929050565b60008060008060008060008060a0898b0312156130c857600080fd5b6130d189612fb6565b975060208901356001600160401b038111156130ec57600080fd5b6130f88b828c01612fd2565b97505060408901356001600160401b0381111561311457600080fd5b6131208b828c01613061565b90975095505060608901356001600160401b0381111561313f57600080fd5b61314b8b828c01613061565b90955093505060808901356001600160401b0381111561316a57600080fd5b6131768b828c01613061565b999c989b5096995094979396929594505050565b60006020828403121561319c57600080fd5b612cb682612fb6565b60008083601f8401126131b757600080fd5b5081356001600160401b038111156131ce57600080fd5b6020830191508360208285010111156130a557600080fd5b600080602083850312156131f957600080fd5b82356001600160401b0381111561320f57600080fd5b61321b858286016131a5565b90969095509350505050565b634e487b7160e01b600052602160045260246000fd5b6003811061325b57634e487b7160e01b600052602160045260246000fd5b9052565b60208101610c3f828461323d565b60006020828403121561327f57600080fd5b5035919050565b60006080820190506001600160401b0383511682526001600160401b0360208401511660208301526001600160401b03604084015116604083015260608301516132d3606084018261323d565b5092915050565b80151581146127ca57600080fd5b6000602082840312156132fa57600080fd5b8135612cb6816132da565b60008060008060006060868803121561331d57600080fd5b85356001600160401b0381111561333357600080fd5b61333f888289016131a5565b90965094505060208601356001600160401b0381111561335e57600080fd5b61336a888289016131a5565b96999598509660400135949350505050565b6001600160a01b03811681146127ca57600080fd5b8035612fcd8161337c565b600080604083850312156133af57600080fd5b82356133ba8161337c565b946020939093013593505050565b6000602082840312156133da57600080fd5b8135612cb68161337c565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613423576134236133e5565b604052919050565b60006001600160401b03821115613444576134446133e5565b5060051b60200190565b600082601f83011261345f57600080fd5b813561347261346d8261342b565b6133fb565b8082825260208201915060208360051b86010192508583111561349457600080fd5b602085015b838110156134b1578035835260209283019201613499565b5095945050505050565b6000806000606084860312156134d057600080fd5b83356001600160401b038111156134e657600080fd5b8401601f810186136134f757600080fd5b803561350561346d8261342b565b8082825260208201915060208360051b85010192508883111561352757600080fd5b6020840193505b828410156135525783356135418161337c565b82526020938401939091019061352e565b955050505060208401356001600160401b0381111561357057600080fd5b61357c8682870161344e565b92505061358b60408501613391565b90509250925092565b6000806000604084860312156135a957600080fd5b83356001600160401b038111156135bf57600080fd5b6135cb86828701612fd2565b93505060208401356001600160401b038111156135e757600080fd5b6135f386828701613061565b9497909650939450505050565b60006020828403121561361257600080fd5b8151612cb6816132da565b6000808335601e1984360301811261363457600080fd5b8301803591506001600160401b0382111561364e57600080fd5b6020019150600581901b36038213156130a557600080fd5b6000808335601e1984360301811261367d57600080fd5b8301803591506001600160401b0382111561369757600080fd5b6020019150368190038213156130a557600080fd5b634e487b7160e01b600052603260045260246000fd5b6000602082840312156136d457600080fd5b813564ffffffffff81168114612cb657600080fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610c3f57610c3f6136e9565b8082028115828204841417610c3f57610c3f6136e9565b81810381811115610c3f57610c3f6136e9565b60005b8381101561375757818101518382015260200161373f565b50506000910152565b6000825161377281846020870161373c565b9190910192915050565b60006020828403121561378e57600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526137d681602086016020860161373c565b601f01601f19169290920160200192915050565b6080815260006137fe60808301888a613795565b828103602084015261381081886137be565b90508281036040840152613825818688613795565b915050826060830152979650505050505050565b602081526000610d51602083018486613795565b634e487b7160e01b600052601260045260246000fd5b6000826138725761387261384d565b500690565b6000826138865761388661384d565b500490565b6001600160401b038281168282160390811115610c3f57610c3f6136e9565b60008235605e1983360301811261377257600080fd5b600062ffffff8216806138d5576138d56136e9565b6000190192915050565b600f81810b9083900b0160016001607f1b03811360016001607f1b031982121715610c3f57610c3f6136e9565b6001600160401b038181168382160190811115610c3f57610c3f6136e9565b80516020808301519190811015612fe45760001960209190910360031b1b16919050565b600060018201613961576139616136e9565b5060010190565b6000835161397a81846020880161373c565b6001600160801b0319939093169190920190815260100192915050565b6000816139a6576139a66136e9565b506000190190565b600081600f0b60016001607f1b031981036139cb576139cb6136e9565b60000392915050565b80820260008212600160ff1b841416156139f0576139f06136e9565b8181058314821517610c3f57610c3f6136e9565b600064ffffffffff831680613a1b57613a1b61384d565b8064ffffffffff84160491505092915050565b600f82810b9082900b0360016001607f1b0319811260016001607f1b0382131715610c3f57610c3f6136e9565b600064ffffffffff831680613a7257613a7261384d565b8064ffffffffff84160691505092915050565b64ffffffffff81811683821602908116908181146132d3576132d36136e9565b602081526000612cb660208301846137be56fea2646970667358221220664a186ca2293474f5b888bb43cec0d11c533e4c5ee98ff34e78c2530565217264736f6c634300081b0033", } // EigenPodABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EigenPodManager/binding.go b/pkg/bindings/EigenPodManager/binding.go index 9b44ba82d..87ec33e00 100644 --- a/pkg/bindings/EigenPodManager/binding.go +++ b/pkg/bindings/EigenPodManager/binding.go @@ -31,8 +31,8 @@ var ( // EigenPodManagerMetaData contains all meta data concerning the EigenPodManager contract. var EigenPodManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_ethPOS\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"},{\"name\":\"_eigenPodBeacon\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"},{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"},{\"name\":\"_delegationManager\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"_initPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x6101206040523480156200001257600080fd5b50604051620031693803806200316983398101604081905262000035916200014b565b6001600160a01b0380861660805280851660a05280841660c05280831660e0528116610100526200006562000070565b5050505050620001cb565b600054610100900460ff1615620000dd5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000130576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146200014857600080fd5b50565b600080600080600060a086880312156200016457600080fd5b8551620001718162000132565b6020870151909550620001848162000132565b6040870151909450620001978162000132565b6060870151909350620001aa8162000132565b6080870151909250620001bd8162000132565b809150509295509295909350565b60805160a05160c05160e05161010051612f286200024160003960008181610551015281816105fb01528181610b7901528181611313015281816117bf01526118af015260006104dd015260006102cf015260008181610263015281816112920152611e64015260006103af0152612f286000f3fe6080604052600436106101b75760003560e01c8063886f1195116100ec578063b13442711161008a578063ea4d3c9b11610064578063ea4d3c9b1461053f578063f2fde38b14610573578063f6848d2414610593578063fabc1cbc146105ce57600080fd5b8063b1344271146104cb578063beffbb89146104ff578063c2c51c401461051f57600080fd5b80639b4e4634116100c65780639b4e46341461044c5780639ba062751461045f578063a38406a314610495578063a6a509be146104b557600080fd5b8063886f1195146103e65780638da5cb5b146104065780639104c3191461042457600080fd5b8063595c6a671161015957806360f4062b1161013357806360f4062b1461035b578063715018a61461038857806374cdd7981461039d57806384d81062146103d157600080fd5b8063595c6a67146102f15780635ac86ab7146103065780635c975abb1461034657600080fd5b80631794bb3c116101955780631794bb3c14610231578063292b7b2b14610251578063387b13001461029d57806339b70e38146102bd57600080fd5b80630e81073c146101bc57806310d67a2f146101ef578063136439dd14610211575b600080fd5b3480156101c857600080fd5b506101dc6101d73660046120fc565b6105ee565b6040519081526020015b60405180910390f35b3480156101fb57600080fd5b5061020f61020a366004612128565b61085d565b005b34801561021d57600080fd5b5061020f61022c366004612145565b610910565b34801561023d57600080fd5b5061020f61024c36600461215e565b610a4f565b34801561025d57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101e6565b3480156102a957600080fd5b5061020f6102b836600461215e565b610b6e565b3480156102c957600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156102fd57600080fd5b5061020f610f82565b34801561031257600080fd5b5061033661032136600461219f565b606654600160ff9092169190911b9081161490565b60405190151581526020016101e6565b34801561035257600080fd5b506066546101dc565b34801561036757600080fd5b506101dc610376366004612128565b609b6020526000908152604090205481565b34801561039457600080fd5b5061020f611049565b3480156103a957600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156103dd57600080fd5b5061028561105d565b3480156103f257600080fd5b50606554610285906001600160a01b031681565b34801561041257600080fd5b506033546001600160a01b0316610285565b34801561043057600080fd5b5061028573beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b61020f61045a36600461220b565b611147565b34801561046b57600080fd5b5061028561047a366004612128565b6098602052600090815260409020546001600160a01b031681565b3480156104a157600080fd5b506102856104b0366004612128565b611236565b3480156104c157600080fd5b506101dc60995481565b3480156104d757600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561050b57600080fd5b5061020f61051a3660046120fc565b611308565b34801561052b57600080fd5b5061020f61053a3660046120fc565b611547565b34801561054b57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561057f57600080fd5b5061020f61058e366004612128565b61197b565b34801561059f57600080fd5b506103366105ae366004612128565b6001600160a01b0390811660009081526098602052604090205416151590565b3480156105da57600080fd5b5061020f6105e9366004612145565b6119f1565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106415760405162461bcd60e51b81526004016106389061227f565b60405180910390fd5b6001600160a01b0383166106bd5760405162461bcd60e51b815260206004820152603a60248201527f456967656e506f644d616e616765722e6164645368617265733a20706f644f7760448201527f6e65722063616e6e6f74206265207a65726f20616464726573730000000000006064820152608401610638565b600082121561072b5760405162461bcd60e51b815260206004820152603460248201527f456967656e506f644d616e616765722e6164645368617265733a207368617265604482015273732063616e6e6f74206265206e6567617469766560601b6064820152608401610638565b610739633b9aca00836122f3565b156107ac5760405162461bcd60e51b815260206004820152603d60248201527f456967656e506f644d616e616765722e6164645368617265733a20736861726560448201527f73206d75737420626520612077686f6c65204777656920616d6f756e740000006064820152608401610638565b6001600160a01b0383166000908152609b6020526040812054906107d0848361231d565b6001600160a01b0386166000818152609b6020526040908190208390555191925090600080516020612eb38339815191529061080f9087815260200190565b60405180910390a2846001600160a01b03166000805160206125858339815191528260405161084091815260200190565b60405180910390a26108528282611b4d565b925050505b92915050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d4919061235e565b6001600160a01b0316336001600160a01b0316146109045760405162461bcd60e51b81526004016106389061237b565b61090d81611b8f565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097c91906123c5565b6109985760405162461bcd60e51b8152600401610638906123e7565b60665481811614610a115760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610638565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600054610100900460ff1615808015610a6f5750600054600160ff909116105b80610a895750303b158015610a89575060005460ff166001145b610aec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610638565b6000805460ff191660011790558015610b0f576000805461ff0019166101001790555b610b1884611c86565b610b228383611cd8565b8015610b68576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610bb65760405162461bcd60e51b81526004016106389061227f565b6001600160a01b038316610c305760405162461bcd60e51b81526020600482015260476024820152600080516020612ed383398151915260448201527f546f6b656e733a20706f644f776e65722063616e6e6f74206265207a65726f206064820152666164647265737360c81b608482015260a401610638565b6001600160a01b038216610cad5760405162461bcd60e51b815260206004820152604a6024820152600080516020612ed383398151915260448201527f546f6b656e733a2064657374696e6174696f6e2063616e6e6f74206265207a65606482015269726f206164647265737360b01b608482015260a401610638565b6000811215610d1c5760405162461bcd60e51b81526020600482015260416024820152600080516020612ed383398151915260448201527f546f6b656e733a207368617265732063616e6e6f74206265206e6567617469766064820152606560f81b608482015260a401610638565b610d2a633b9aca00826122f3565b15610d9e5760405162461bcd60e51b815260206004820152604a6024820152600080516020612ed383398151915260448201527f546f6b656e733a20736861726573206d75737420626520612077686f6c6520476064820152691dd95a48185b5bdd5b9d60b21b608482015260a401610638565b6001600160a01b0383166000908152609b602052604081205490811215610f07576000610dca8261242f565b905080831115610e61576001600160a01b0385166000908152609b6020526040812055610df7818461244c565b9250846001600160a01b0316600080516020612eb383398151915282604051610e2291815260200190565b60405180910390a2846001600160a01b03166000805160206125858339815191526000604051610e5491815260200190565b60405180910390a2610f05565b6001600160a01b0385166000908152609b6020526040812054610e8590859061231d565b6001600160a01b0387166000818152609b6020526040908190208390555191925090600080516020612eb383398151915290610ec49087815260200190565b60405180910390a2856001600160a01b031660008051602061258583398151915282604051610ef591815260200190565b60405180910390a2505050505050565b505b6001600160a01b03848116600090815260986020526040908190205490516362483a2160e11b815285831660048201526024810185905291169063c490744290604401600060405180830381600087803b158015610f6457600080fd5b505af1158015610f78573d6000803e3d6000fd5b5050505050505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee91906123c5565b61100a5760405162461bcd60e51b8152600401610638906123e7565b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b611051611dc2565b61105b6000611c86565b565b6066546000908190600190811614156110b45760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610638565b336000908152609860205260409020546001600160a01b0316156111365760405162461bcd60e51b815260206004820152603360248201527f456967656e506f644d616e616765722e637265617465506f643a2053656e64656044820152721c88185b1c9958591e481a185cc818481c1bd9606a1b6064820152608401610638565b6000611140611e1c565b9250505090565b6066546000906001908116141561119c5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610638565b336000908152609860205260409020546001600160a01b0316806111c5576111c2611e1c565b90505b6040516326d3918d60e21b81526001600160a01b03821690639b4e46349034906111fb908b908b908b908b908b9060040161248c565b6000604051808303818588803b15801561121457600080fd5b505af1158015611228573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b038082166000908152609860205260408120549091168061085757611301836001600160a01b031660001b60405180610940016040528061090e81526020016125a561090e9139604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166020820152808201919091526000606082015260800160408051601f19818403018152908290526112e69291602001612501565b60405160208183030381529060405280519060200120611f81565b9392505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113505760405162461bcd60e51b81526004016106389061227f565b60008112156113c75760405162461bcd60e51b815260206004820152603760248201527f456967656e506f644d616e616765722e72656d6f76655368617265733a20736860448201527f617265732063616e6e6f74206265206e656761746976650000000000000000006064820152608401610638565b6113d5633b9aca00826122f3565b1561144a576040805162461bcd60e51b81526020600482015260248101919091527f456967656e506f644d616e616765722e72656d6f76655368617265733a20736860448201527f61726573206d75737420626520612077686f6c65204777656920616d6f756e746064820152608401610638565b6001600160a01b0382166000908152609b602052604081205461146e908390612516565b905060008112156114ff5760405162461bcd60e51b815260206004820152604f60248201527f456967656e506f644d616e616765722e72656d6f76655368617265733a20636160448201527f6e6e6f7420726573756c7420696e20706f64206f776e657220686176696e672060648201526e6e656761746976652073686172657360881b608482015260a401610638565b6001600160a01b0383166000818152609b602052604090819020839055516000805160206125858339815191529061153a9084815260200190565b60405180910390a2505050565b6001600160a01b0380831660009081526098602052604090205483911633146115c25760405162461bcd60e51b815260206004820152602760248201527f456967656e506f644d616e616765722e6f6e6c79456967656e506f643a206e6f6044820152661d0818481c1bd960ca1b6064820152608401610638565b600260c95414156116155760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610638565b600260c9556001600160a01b0383166116b15760405162461bcd60e51b815260206004820152605260248201527f456967656e506f644d616e616765722e7265636f7264426561636f6e4368616960448201527f6e45544842616c616e63655570646174653a20706f644f776e65722063616e6e6064820152716f74206265207a65726f206164647265737360701b608482015260a401610638565b6116bf633b9aca0083612555565b156117585760405162461bcd60e51b815260206004820152605a60248201527f456967656e506f644d616e616765722e7265636f7264426561636f6e4368616960448201527f6e45544842616c616e63655570646174653a2073686172657344656c7461206d60648201527f75737420626520612077686f6c65204777656920616d6f756e74000000000000608482015260a401610638565b6001600160a01b0383166000908152609b60205260408120549061177c848361231d565b6001600160a01b0386166000908152609b602052604081208290559091506117a48383611b4d565b9050801561190c57600081121561186f576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663132d49678773beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06118038561242f565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b15801561185257600080fd5b505af1158015611866573d6000803e3d6000fd5b5050505061190c565b604051631452b9d760e11b81526001600160a01b03878116600483015273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906328a573ae90606401600060405180830381600087803b1580156118f357600080fd5b505af1158015611907573d6000803e3d6000fd5b505050505b856001600160a01b0316600080516020612eb38339815191528660405161193591815260200190565b60405180910390a2856001600160a01b03166000805160206125858339815191528360405161196691815260200190565b60405180910390a25050600160c95550505050565b611983611dc2565b6001600160a01b0381166119e85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610638565b61090d81611c86565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a68919061235e565b6001600160a01b0316336001600160a01b031614611a985760405162461bcd60e51b81526004016106389061237b565b606654198119606654191614611b165760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610638565b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610a44565b6000808313611b6d5760008213611b6657506000610857565b5080610857565b60008213611b8557611b7e8361242f565b9050610857565b611b7e8383612516565b6001600160a01b038116611c1d5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610638565b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6065546001600160a01b0316158015611cf957506001600160a01b03821615155b611d7b5760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610638565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2611dbe82611b8f565b5050565b6033546001600160a01b0316331461105b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610638565b6000609960008154611e2d90612569565b9091555060408051610940810190915261090e808252600091611ecc91839133916125a56020830139604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166020820152808201919091526000606082015260800160408051601f1981840301815290829052611eb89291602001612501565b604051602081830303815290604052611fdd565b60405163189acdbd60e31b81523360048201529091506001600160a01b0382169063c4d66de890602401600060405180830381600087803b158015611f1057600080fd5b505af1158015611f24573d6000803e3d6000fd5b50503360008181526098602052604080822080546001600160a01b0319166001600160a01b038816908117909155905192945092507f21c99d0db02213c32fff5b05cf0a718ab5f858802b91498f80d82270289d856a91a3919050565b604080516001600160f81b03196020808301919091526bffffffffffffffffffffffff193060601b1660218301526035820185905260558083018590528351808403909101815260759092019092528051910120600090611301565b600080844710156120305760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610638565b825161207e5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610638565b8383516020850187f590506001600160a01b0381166120df5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610638565b949350505050565b6001600160a01b038116811461090d57600080fd5b6000806040838503121561210f57600080fd5b823561211a816120e7565b946020939093013593505050565b60006020828403121561213a57600080fd5b8135611301816120e7565b60006020828403121561215757600080fd5b5035919050565b60008060006060848603121561217357600080fd5b833561217e816120e7565b9250602084013561218e816120e7565b929592945050506040919091013590565b6000602082840312156121b157600080fd5b813560ff8116811461130157600080fd5b60008083601f8401126121d457600080fd5b50813567ffffffffffffffff8111156121ec57600080fd5b60208301915083602082850101111561220457600080fd5b9250929050565b60008060008060006060868803121561222357600080fd5b853567ffffffffffffffff8082111561223b57600080fd5b61224789838a016121c2565b9097509550602088013591508082111561226057600080fd5b5061226d888289016121c2565b96999598509660400135949350505050565b602080825260409082018190527f456967656e506f644d616e616765722e6f6e6c7944656c65676174696f6e4d61908201527f6e616765723a206e6f74207468652044656c65676174696f6e4d616e61676572606082015260800190565b634e487b7160e01b600052601260045260246000fd5b600082612302576123026122dd565b500690565b634e487b7160e01b600052601160045260246000fd5b600080821280156001600160ff1b038490038513161561233f5761233f612307565b600160ff1b839003841281161561235857612358612307565b50500190565b60006020828403121561237057600080fd5b8151611301816120e7565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b6000602082840312156123d757600080fd5b8151801515811461130157600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b6000600160ff1b82141561244557612445612307565b5060000390565b60008282101561245e5761245e612307565b500390565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6060815260006124a0606083018789612463565b82810360208401526124b3818688612463565b9150508260408301529695505050505050565b6000815160005b818110156124e757602081850181015186830152016124cd565b818111156124f6576000828601525b509290920192915050565b60006120df61251083866124c6565b846124c6565b60008083128015600160ff1b85018412161561253457612534612307565b6001600160ff1b038401831381161561254f5761254f612307565b50500390565b600082612564576125646122dd565b500790565b600060001982141561257d5761257d612307565b506001019056fed4def76d6d2bed6f14d5cd9af73cc2913d618d00edde42432e81c09bfe077098608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e2b791dedccd9fb30141b088cabf5c14a8912b52f59375c95c010700b8c6193456967656e506f644d616e616765722e77697468647261775368617265734173a264697066735822122069d3a03119733341cd267e296785e37b1c350fc350d796fc97aa45c1e8213da664736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_ethPOS\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"},{\"name\":\"_eigenPodBeacon\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"},{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"},{\"name\":\"_delegationManager\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"_initPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EigenPodAlreadyExists\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNegative\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNotMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", + Bin: "0x61012060405234801561001157600080fd5b5060405161294f38038061294f8339810160408190526100309161013f565b6001600160a01b0380861660805280851660a05280841660c05280831660e05281166101005261005e610068565b50505050506101b4565b600054610100900460ff16156100d45760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610125576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811461013c57600080fd5b50565b600080600080600060a0868803121561015757600080fd5b855161016281610127565b602087015190955061017381610127565b604087015190945061018481610127565b606087015190935061019581610127565b60808701519092506101a681610127565b809150509295509295909350565b60805160a05160c05160e0516101005161272661022960003960008181610551015281816105fb01528181610a2d01528181610fdb015281816111f501526112e5015260006104dd015260006102cf01526000818161026301528181610f5a015261177a015260006103af01526127266000f3fe6080604052600436106101b75760003560e01c8063886f1195116100ec578063b13442711161008a578063ea4d3c9b11610064578063ea4d3c9b1461053f578063f2fde38b14610573578063f6848d2414610593578063fabc1cbc146105ce57600080fd5b8063b1344271146104cb578063beffbb89146104ff578063c2c51c401461051f57600080fd5b80639b4e4634116100c65780639b4e46341461044c5780639ba062751461045f578063a38406a314610495578063a6a509be146104b557600080fd5b8063886f1195146103e65780638da5cb5b146104065780639104c3191461042457600080fd5b8063595c6a671161015957806360f4062b1161013357806360f4062b1461035b578063715018a61461038857806374cdd7981461039d57806384d81062146103d157600080fd5b8063595c6a67146102f15780635ac86ab7146103065780635c975abb1461034657600080fd5b80631794bb3c116101955780631794bb3c14610231578063292b7b2b14610251578063387b13001461029d57806339b70e38146102bd57600080fd5b80630e81073c146101bc57806310d67a2f146101ef578063136439dd14610211575b600080fd5b3480156101c857600080fd5b506101dc6101d7366004611a40565b6105ee565b6040519081526020015b60405180910390f35b3480156101fb57600080fd5b5061020f61020a366004611a6c565b61075f565b005b34801561021d57600080fd5b5061020f61022c366004611a89565b610813565b34801561023d57600080fd5b5061020f61024c366004611aa2565b6108fe565b34801561025d57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101e6565b3480156102a957600080fd5b5061020f6102b8366004611aa2565b610a22565b3480156102c957600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156102fd57600080fd5b5061020f610cec565b34801561031257600080fd5b50610336610321366004611ae3565b606654600160ff9092169190911b9081161490565b60405190151581526020016101e6565b34801561035257600080fd5b506066546101dc565b34801561036757600080fd5b506101dc610376366004611a6c565b609b6020526000908152604090205481565b34801561039457600080fd5b5061020f610db4565b3480156103a957600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156103dd57600080fd5b50610285610dc8565b3480156103f257600080fd5b50606554610285906001600160a01b031681565b34801561041257600080fd5b506033546001600160a01b0316610285565b34801561043057600080fd5b5061028573beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b61020f61045a366004611b4f565b610e3b565b34801561046b57600080fd5b5061028561047a366004611a6c565b6098602052600090815260409020546001600160a01b031681565b3480156104a157600080fd5b506102856104b0366004611a6c565b610efe565b3480156104c157600080fd5b506101dc60995481565b3480156104d757600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561050b57600080fd5b5061020f61051a366004611a40565b610fd0565b34801561052b57600080fd5b5061020f61053a366004611a40565b6110f7565b34801561054b57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561057f57600080fd5b5061020f61058e366004611a6c565b6113b1565b34801561059f57600080fd5b506103366105ae366004611a6c565b6001600160a01b0390811660009081526098602052604090205416151590565b3480156105da57600080fd5b5061020f6105e9366004611a89565b611427565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461063957604051635c427cd960e01b815260040160405180910390fd5b6001600160a01b038316610660576040516339b190bb60e11b815260040160405180910390fd5b60008212156106825760405163ef147de160e01b815260040160405180910390fd5b610690633b9aca0083611bde565b156106ae576040516347d072bb60e11b815260040160405180910390fd5b6001600160a01b0383166000908152609b6020526040812054906106d28483611c08565b6001600160a01b0386166000818152609b60205260409081902083905551919250906000805160206126d1833981519152906107119087815260200190565b60405180910390a2846001600160a01b0316600080516020611da38339815191528260405161074291815260200190565b60405180910390a2610754828261152f565b925050505b92915050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d69190611c30565b6001600160a01b0316336001600160a01b0316146108075760405163794821ff60e01b815260040160405180910390fd5b61081081611571565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f9190611c4d565b61089c57604051631d77d47760e21b815260040160405180910390fd5b606654818116146108c05760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600054610100900460ff161580801561091e5750600054600160ff909116105b806109385750303b158015610938575060005460ff166001145b6109a05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156109c3576000805461ff0019166101001790555b6109cc84611601565b6109d68383611653565b8015610a1c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a6b57604051635c427cd960e01b815260040160405180910390fd5b6001600160a01b038316610a92576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b038216610ab9576040516339b190bb60e11b815260040160405180910390fd5b6000811215610adb5760405163ef147de160e01b815260040160405180910390fd5b610ae9633b9aca0082611bde565b15610b07576040516347d072bb60e11b815260040160405180910390fd5b6001600160a01b0383166000908152609b602052604081205490811215610c70576000610b3382611c6f565b905080831115610bca576001600160a01b0385166000908152609b6020526040812055610b608184611c8b565b9250846001600160a01b03166000805160206126d183398151915282604051610b8b91815260200190565b60405180910390a2846001600160a01b0316600080516020611da38339815191526000604051610bbd91815260200190565b60405180910390a2610c6e565b6001600160a01b0385166000908152609b6020526040812054610bee908590611c08565b6001600160a01b0387166000818152609b60205260409081902083905551919250906000805160206126d183398151915290610c2d9087815260200190565b60405180910390a2856001600160a01b0316600080516020611da383398151915282604051610c5e91815260200190565b60405180910390a2505050505050565b505b6001600160a01b03848116600090815260986020526040908190205490516362483a2160e11b815285831660048201526024810185905291169063c490744290604401600060405180830381600087803b158015610ccd57600080fd5b505af1158015610ce1573d6000803e3d6000fd5b50505050505b505050565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610d34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d589190611c4d565b610d7557604051631d77d47760e21b815260040160405180910390fd5b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b610dbc6116d8565b610dc66000611601565b565b6066546000908190600190811603610df35760405163840a48d560e01b815260040160405180910390fd5b336000908152609860205260409020546001600160a01b031615610e2a5760405163031a852160e21b815260040160405180910390fd5b6000610e34611732565b9250505090565b606654600090600190811603610e645760405163840a48d560e01b815260040160405180910390fd5b336000908152609860205260409020546001600160a01b031680610e8d57610e8a611732565b90505b6040516326d3918d60e21b81526001600160a01b03821690639b4e4634903490610ec3908b908b908b908b908b90600401611cc7565b6000604051808303818588803b158015610edc57600080fd5b505af1158015610ef0573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b038082166000908152609860205260408120549091168061075957610fc9836001600160a01b031660001b60405180610940016040528061090e8152602001611dc361090e9139604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166020820152808201919091526000606082015260800160408051601f1981840301815290829052610fae9291602001611d31565b60405160208183030381529060405280519060200120611897565b9392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461101957604051635c427cd960e01b815260040160405180910390fd5b600081121561103b5760405163ef147de160e01b815260040160405180910390fd5b611049633b9aca0082611bde565b15611067576040516347d072bb60e11b815260040160405180910390fd5b6001600160a01b0382166000908152609b602052604081205461108b908390611d4e565b905060008112156110af5760405163ef147de160e01b815260040160405180910390fd5b6001600160a01b0383166000818152609b60205260409081902083905551600080516020611da3833981519152906110ea9084815260200190565b60405180910390a2505050565b6001600160a01b03808316600090815260986020526040902054839116331461113357604051635c427cd960e01b815260040160405180910390fd5b61113b6118a4565b6001600160a01b038316611162576040516339b190bb60e11b815260040160405180910390fd5b611170633b9aca0083611d75565b1561118e576040516347d072bb60e11b815260040160405180910390fd5b6001600160a01b0383166000908152609b6020526040812054906111b28483611c08565b6001600160a01b0386166000908152609b602052604081208290559091506111da838361152f565b905080156113425760008112156112a5576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663132d49678773beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac061123985611c6f565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b15801561128857600080fd5b505af115801561129c573d6000803e3d6000fd5b50505050611342565b604051631452b9d760e11b81526001600160a01b03878116600483015273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906328a573ae90606401600060405180830381600087803b15801561132957600080fd5b505af115801561133d573d6000803e3d6000fd5b505050505b856001600160a01b03166000805160206126d18339815191528660405161136b91815260200190565b60405180910390a2856001600160a01b0316600080516020611da38339815191528360405161139c91815260200190565b60405180910390a2505050610ce7600160c955565b6113b96116d8565b6001600160a01b03811661141e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610997565b61081081611601565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561147a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149e9190611c30565b6001600160a01b0316336001600160a01b0316146114cf5760405163794821ff60e01b815260040160405180910390fd5b6066541981196066541916146114f85760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016108f3565b600080831361154f576000821361154857506000610759565b5080610759565b600082136115675761156083611c6f565b9050610759565b6115608383611d4e565b6001600160a01b038116611598576040516339b190bb60e11b815260040160405180910390fd5b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6065546001600160a01b031615801561167457506001600160a01b03821615155b611691576040516339b190bb60e11b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26116d482611571565b5050565b6033546001600160a01b03163314610dc65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610997565b600060996000815461174390611d89565b9091555060408051610940810190915261090e8082526000916117e29183913391611dc36020830139604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166020820152808201919091526000606082015260800160408051601f19818403018152908290526117ce9291602001611d31565b6040516020818303038152906040526118fd565b60405163189acdbd60e31b81523360048201529091506001600160a01b0382169063c4d66de890602401600060405180830381600087803b15801561182657600080fd5b505af115801561183a573d6000803e3d6000fd5b50503360008181526098602052604080822080546001600160a01b0319166001600160a01b038816908117909155905192945092507f21c99d0db02213c32fff5b05cf0a718ab5f858802b91498f80d82270289d856a91a3919050565b6000610fc9838330611a01565b600260c954036118f65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610997565b600260c955565b60008347101561194f5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610997565b81516000036119a05760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610997565b8282516020840186f590506001600160a01b038116610fc95760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610997565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b6001600160a01b038116811461081057600080fd5b60008060408385031215611a5357600080fd5b8235611a5e81611a2b565b946020939093013593505050565b600060208284031215611a7e57600080fd5b8135610fc981611a2b565b600060208284031215611a9b57600080fd5b5035919050565b600080600060608486031215611ab757600080fd5b8335611ac281611a2b565b92506020840135611ad281611a2b565b929592945050506040919091013590565b600060208284031215611af557600080fd5b813560ff81168114610fc957600080fd5b60008083601f840112611b1857600080fd5b50813567ffffffffffffffff811115611b3057600080fd5b602083019150836020828501011115611b4857600080fd5b9250929050565b600080600080600060608688031215611b6757600080fd5b853567ffffffffffffffff811115611b7e57600080fd5b611b8a88828901611b06565b909650945050602086013567ffffffffffffffff811115611baa57600080fd5b611bb688828901611b06565b96999598509660400135949350505050565b634e487b7160e01b600052601260045260246000fd5b600082611bed57611bed611bc8565b500690565b634e487b7160e01b600052601160045260246000fd5b8082018281126000831280158216821582161715611c2857611c28611bf2565b505092915050565b600060208284031215611c4257600080fd5b8151610fc981611a2b565b600060208284031215611c5f57600080fd5b81518015158114610fc957600080fd5b6000600160ff1b8201611c8457611c84611bf2565b5060000390565b8181038181111561075957610759611bf2565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000611cdb606083018789611c9e565b8281036020840152611cee818688611c9e565b9150508260408301529695505050505050565b6000815160005b81811015611d225760208185018101518683015201611d08565b50600093019283525090919050565b6000611d46611d408386611d01565b84611d01565b949350505050565b8181036000831280158383131683831282161715611d6e57611d6e611bf2565b5092915050565b600082611d8457611d84611bc8565b500790565b600060018201611d9b57611d9b611bf2565b506001019056fed4def76d6d2bed6f14d5cd9af73cc2913d618d00edde42432e81c09bfe077098608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e2b791dedccd9fb30141b088cabf5c14a8912b52f59375c95c010700b8c6193a264697066735822122070074fb6728b07578949f85faece04d9f0732f0b02b5ddb0a886e8b31a7358f764736f6c634300081b0033", } // EigenPodManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EigenPodManagerStorage/binding.go b/pkg/bindings/EigenPodManagerStorage/binding.go index 446bf1a74..6b3ba1371 100644 --- a/pkg/bindings/EigenPodManagerStorage/binding.go +++ b/pkg/bindings/EigenPodManagerStorage/binding.go @@ -31,7 +31,7 @@ var ( // EigenPodManagerStorageMetaData contains all meta data concerning the EigenPodManagerStorage contract. var EigenPodManagerStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EigenPodAlreadyExists\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNegative\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNotMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // EigenPodManagerStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EigenPodStorage/binding.go b/pkg/bindings/EigenPodStorage/binding.go index 70640763e..4fad640ec 100644 --- a/pkg/bindings/EigenPodStorage/binding.go +++ b/pkg/bindings/EigenPodStorage/binding.go @@ -72,7 +72,7 @@ type IEigenPodValidatorInfo struct { // EigenPodStorageMetaData contains all meta data concerning the EigenPodStorage contract. var EigenPodStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountMustBeMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BeaconTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CannotCheckpointTwiceInSingleBlock\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CheckpointAlreadyActive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CredentialsAlreadyVerified\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientWithdrawableBalance\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEIP4788Response\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPubKeyLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MsgValueNot32ETH\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoActiveCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoBalanceToCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TimestampOutOfRange\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorInactiveOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorIsExitingBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotActiveInPod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotSlashedOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawCredentialsNotForEigenPod\",\"inputs\":[]}]", } // EigenPodStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/EigenStrategy/binding.go b/pkg/bindings/EigenStrategy/binding.go index 2070a2d17..1d3a62c10 100644 --- a/pkg/bindings/EigenStrategy/binding.go +++ b/pkg/bindings/EigenStrategy/binding.go @@ -31,8 +31,8 @@ var ( // EigenStrategyMetaData contains all meta data concerning the EigenStrategy contract. var EigenStrategyMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"EIGEN\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigen\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_EIGEN\",\"type\":\"address\",\"internalType\":\"contractIEigen\"},{\"name\":\"_bEIGEN\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001dc338038062001dc3833981016040819052620000349162000116565b6001600160a01b038116608052806200004c62000054565b505062000148565b600054610100900460ff1615620000c15760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000114576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012957600080fd5b81516001600160a01b03811681146200014157600080fd5b9392505050565b608051611c4a62000179600039600081816101af015281816105ac01528181610ad40152610b9f0152611c4a6000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80637a8b2637116100c3578063ce7c2ac21161007c578063ce7c2ac2146102da578063d9caed12146102ed578063e3dae51c14610300578063f3e7387514610313578063fabc1cbc14610326578063fdc371ce1461033957600080fd5b80637a8b263714610260578063886f1195146102735780638c8710191461028c5780638f6a62401461029f578063ab5921e1146102b2578063c0c53b8b146102c757600080fd5b806347e7ef241161011557806347e7ef24146101e8578063485cc955146101fb578063553ca5f81461020e578063595c6a67146102215780635ac86ab7146102295780635c975abb1461025857600080fd5b806310d67a2f14610152578063136439dd146101675780632495a5991461017a57806339b70e38146101aa5780633a98ef39146101d1575b600080fd5b61016561016036600461181e565b61034c565b005b61016561017536600461183b565b610408565b60325461018d906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b6101da60335481565b6040519081526020016101a1565b6101da6101f6366004611854565b61054c565b610165610209366004611880565b610790565b6101da61021c36600461181e565b61085e565b610165610872565b6102486102373660046118c8565b6001805460ff9092161b9081161490565b60405190151581526020016101a1565b6001546101da565b6101da61026e36600461183b565b61093e565b60005461018d906201000090046001600160a01b031681565b6101da61029a36600461183b565b610989565b6101da6102ad36600461181e565b610994565b6102ba6109a2565b6040516101a19190611911565b6101656102d5366004611944565b6109c2565b6101da6102e836600461181e565b610aac565b6101656102fb36600461198f565b610b41565b6101da61030e36600461183b565b610d27565b6101da61032136600461183b565b610d60565b61016561033436600461183b565b610d6b565b60645461018d906001600160a01b031681565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c391906119d0565b6001600160a01b0316336001600160a01b0316146103fc5760405162461bcd60e51b81526004016103f3906119ed565b60405180910390fd5b61040581610ec7565b50565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104799190611a37565b6104955760405162461bcd60e51b81526004016103f390611a59565b6001548181161461050e5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c697479000000000000000060648201526084016103f3565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600180546000918291811614156105a15760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b60448201526064016103f3565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106195760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e6167657260448201526064016103f3565b6106238484610fcc565b60335460006106346103e883611ab7565b905060006103e86106436110e0565b61064d9190611ab7565b9050600061065b8783611acf565b9050806106688489611ae6565b6106729190611b05565b9550856106d85760405162461bcd60e51b815260206004820152602e60248201527f5374726174656779426173652e6465706f7369743a206e65775368617265732060448201526d63616e6e6f74206265207a65726f60901b60648201526084016103f3565b6106e28685611ab7565b60338190556f4b3b4ca85a86c47a098a223fffffffff101561076c5760405162461bcd60e51b815260206004820152603c60248201527f5374726174656779426173652e6465706f7369743a20746f74616c536861726560448201527f73206578636565647320604d41585f544f54414c5f534841524553600000000060648201526084016103f3565b610785826103e86033546107809190611ab7565b611152565b505050505092915050565b600054610100900460ff16158080156107b05750600054600160ff909116105b806107ca5750303b1580156107ca575060005460ff166001145b6107e65760405162461bcd60e51b81526004016103f390611b27565b6000805460ff191660011790558015610809576000805461ff0019166101001790555b61081383836111a6565b8015610859576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600061086c61026e83610aac565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa1580156108bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e39190611a37565b6108ff5760405162461bcd60e51b81526004016103f390611a59565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e86033546109519190611ab7565b905060006103e86109606110e0565b61096a9190611ab7565b9050816109778583611ae6565b6109819190611b05565b949350505050565b600061086c82610d27565b600061086c61032183610aac565b60606040518060800160405280604d8152602001611bc8604d9139905090565b600054610100900460ff16158080156109e25750600054600160ff909116105b806109fc5750303b1580156109fc575060005460ff166001145b610a185760405162461bcd60e51b81526004016103f390611b27565b6000805460ff191660011790558015610a3b576000805461ff0019166101001790555b606480546001600160a01b0319166001600160a01b038616179055610a6083836111a6565b8015610aa6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086c9190611b75565b6001805460029081161415610b945760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b60448201526064016103f3565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c0c5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e6167657260448201526064016103f3565b610c178484846112f1565b60335480831115610ca65760405162461bcd60e51b815260206004820152604d60248201527f5374726174656779426173652e77697468647261773a20616d6f756e7453686160448201527f726573206d757374206265206c657373207468616e206f7220657175616c207460648201526c6f20746f74616c53686172657360981b608482015260a4016103f3565b6000610cb46103e883611ab7565b905060006103e8610cc36110e0565b610ccd9190611ab7565b9050600082610cdc8784611ae6565b610ce69190611b05565b9050610cf28685611acf565b603355610d12610d028284611acf565b6103e86033546107809190611ab7565b610d1d88888361138c565b5050505050505050565b6000806103e8603354610d3a9190611ab7565b905060006103e8610d496110e0565b610d539190611ab7565b9050806109778386611ae6565b600061086c8261093e565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de291906119d0565b6001600160a01b0316336001600160a01b031614610e125760405162461bcd60e51b81526004016103f3906119ed565b600154198119600154191614610e905760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c697479000000000000000060648201526084016103f3565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610541565b6001600160a01b038116610f555760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a4016103f3565b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6032546001600160a01b0383811691161480610ff557506064546001600160a01b038381169116145b6110675760405162461bcd60e51b815260206004820152603760248201527f456967656e53747261746567792e6465706f7369743a2043616e206f6e6c792060448201527f6465706f7369742062454947454e206f7220454947454e00000000000000000060648201526084016103f3565b6064546001600160a01b03838116911614156110dc57606454604051636f074d1f60e11b8152600481018390526001600160a01b039091169063de0e9a3e90602401600060405180830381600087803b1580156110c357600080fd5b505af11580156110d7573d6000803e3d6000fd5b505050505b5050565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611129573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114d9190611b75565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be88161118684670de0b6b3a7640000611ae6565b6111909190611b05565b6040519081526020015b60405180910390a15050565b600054610100900460ff166112115760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016103f3565b603280546001600160a01b0319166001600160a01b03841617905561123781600061148d565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d09190611b8e565b604080516001600160a01b03909316835260ff90911660208301520161119a565b6032546001600160a01b038381169116148061131a57506064546001600160a01b038381169116145b6108595760405162461bcd60e51b815260206004820152603960248201527f456967656e53747261746567792e77697468647261773a2043616e206f6e6c7960448201527f2077697468647261772062454947454e206f7220454947454e0000000000000060648201526084016103f3565b6064546001600160a01b03838116911614156114795760325460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044016020604051808303816000875af11580156113f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114199190611a37565b50606454604051630ea598cb60e41b8152600481018390526001600160a01b039091169063ea598cb090602401600060405180830381600087803b15801561146057600080fd5b505af1158015611474573d6000803e3d6000fd5b505050505b6108596001600160a01b0383168483611579565b6000546201000090046001600160a01b03161580156114b457506001600160a01b03821615155b6115365760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a4016103f3565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26110dc82610ec7565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649084015261085992869291600091611609918516908490611686565b80519091501561085957808060200190518101906116279190611a37565b6108595760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103f3565b6060611695848460008561169f565b90505b9392505050565b6060824710156117005760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103f3565b6001600160a01b0385163b6117575760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103f3565b600080866001600160a01b031685876040516117739190611bab565b60006040518083038185875af1925050503d80600081146117b0576040519150601f19603f3d011682016040523d82523d6000602084013e6117b5565b606091505b50915091506117c58282866117d0565b979650505050505050565b606083156117df575081611698565b8251156117ef5782518084602001fd5b8160405162461bcd60e51b81526004016103f39190611911565b6001600160a01b038116811461040557600080fd5b60006020828403121561183057600080fd5b813561169881611809565b60006020828403121561184d57600080fd5b5035919050565b6000806040838503121561186757600080fd5b823561187281611809565b946020939093013593505050565b6000806040838503121561189357600080fd5b823561189e81611809565b915060208301356118ae81611809565b809150509250929050565b60ff8116811461040557600080fd5b6000602082840312156118da57600080fd5b8135611698816118b9565b60005b838110156119005781810151838201526020016118e8565b83811115610aa65750506000910152565b60208152600082518060208401526119308160408501602087016118e5565b601f01601f19169190910160400192915050565b60008060006060848603121561195957600080fd5b833561196481611809565b9250602084013561197481611809565b9150604084013561198481611809565b809150509250925092565b6000806000606084860312156119a457600080fd5b83356119af81611809565b925060208401356119bf81611809565b929592945050506040919091013590565b6000602082840312156119e257600080fd5b815161169881611809565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611a4957600080fd5b8151801515811461169857600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611aca57611aca611aa1565b500190565b600082821015611ae157611ae1611aa1565b500390565b6000816000190483118215151615611b0057611b00611aa1565b500290565b600082611b2257634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600060208284031215611b8757600080fd5b5051919050565b600060208284031215611ba057600080fd5b8151611698816118b9565b60008251611bbd8184602087016118e5565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a26469706673582212209f0a5f3b361d82437f0c321794900a7aead1b85f77f12d7038cbafbf9ebeb3f164736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"EIGEN\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigen\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_EIGEN\",\"type\":\"address\",\"internalType\":\"contractIEigen\"},{\"name\":\"_bEIGEN\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"BalanceExceedsMaxTotalDeposits\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxPerDepositExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewSharesZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnderlyingToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TotalSharesExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalAmountExceedsTotalDeposits\",\"inputs\":[]}]", + Bin: "0x60a060405234801561001057600080fd5b506040516118df3803806118df83398101604081905261002f9161010b565b6001600160a01b0381166080528061004561004c565b505061013b565b600054610100900460ff16156100b85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610109576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011d57600080fd5b81516001600160a01b038116811461013457600080fd5b9392505050565b60805161177461016b600039600081816101af015281816105240152818161098f0152610a2e01526117746000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80637a8b2637116100c3578063ce7c2ac21161007c578063ce7c2ac2146102da578063d9caed12146102ed578063e3dae51c14610300578063f3e7387514610313578063fabc1cbc14610326578063fdc371ce1461033957600080fd5b80637a8b263714610260578063886f1195146102735780638c8710191461028c5780638f6a62401461029f578063ab5921e1146102b2578063c0c53b8b146102c757600080fd5b806347e7ef241161011557806347e7ef24146101e8578063485cc955146101fb578063553ca5f81461020e578063595c6a67146102215780635ac86ab7146102295780635c975abb1461025857600080fd5b806310d67a2f14610152578063136439dd146101675780632495a5991461017a57806339b70e38146101aa5780633a98ef39146101d1575b600080fd5b6101656101603660046113ec565b61034c565b005b610165610175366004611410565b610400565b60325461018d906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61018d7f000000000000000000000000000000000000000000000000000000000000000081565b6101da60335481565b6040519081526020016101a1565b6101da6101f6366004611429565b6104f0565b610165610209366004611455565b610641565b6101da61021c3660046113ec565b610718565b61016561072c565b61024861023736600461149d565b6001805460ff9092161b9081161490565b60405190151581526020016101a1565b6001546101da565b6101da61026e366004611410565b6107f9565b60005461018d906201000090046001600160a01b031681565b6101da61029a366004611410565b610844565b6101da6102ad3660046113ec565b61084f565b6102ba61085d565b6040516101a191906114de565b6101656102d5366004611511565b61087d565b6101da6102e83660046113ec565b610967565b6101656102fb36600461155c565b6109fc565b6101da61030e366004611410565b610b1c565b6101da610321366004611410565b610b55565b610165610334366004611410565b610b60565b60645461018d906001600160a01b031681565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561039f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c3919061159d565b6001600160a01b0316336001600160a01b0316146103f45760405163794821ff60e01b815260040160405180910390fd5b6103fd81610c68565b50565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa15801561044d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047191906115ba565b61048e57604051631d77d47760e21b815260040160405180910390fd5b600154818116146104b25760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116036105195760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461056257604051635c427cd960e01b815260040160405180910390fd5b61056c8484610d06565b603354600061057d6103e8836115f2565b905060006103e861058c610dc5565b61059691906115f2565b905060006105a48783611605565b9050806105b18489611618565b6105bb919061162f565b9550856000036105de57604051630c392ed360e11b815260040160405180910390fd5b6105e886856115f2565b60338190556f4b3b4ca85a86c47a098a223fffffffff101561061d57604051632f14e8a360e11b815260040160405180910390fd5b610636826103e860335461063191906115f2565b610e37565b505050505092915050565b600054610100900460ff16158080156106615750600054600160ff909116105b8061067b5750303b15801561067b575060005460ff166001145b6106a05760405162461bcd60e51b815260040161069790611651565b60405180910390fd5b6000805460ff1916600117905580156106c3576000805461ff0019166101001790555b6106cd8383610e8b565b8015610713576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600061072661026e83610967565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610779573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079d91906115ba565b6107ba57604051631d77d47760e21b815260040160405180910390fd5b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e860335461080c91906115f2565b905060006103e861081b610dc5565b61082591906115f2565b9050816108328583611618565b61083c919061162f565b949350505050565b600061072682610b1c565b600061072661032183610967565b60606040518060800160405280604d81526020016116f2604d9139905090565b600054610100900460ff161580801561089d5750600054600160ff909116105b806108b75750303b1580156108b7575060005460ff166001145b6108d35760405162461bcd60e51b815260040161069790611651565b6000805460ff1916600117905580156108f6576000805461ff0019166101001790555b606480546001600160a01b0319166001600160a01b03861617905561091b8383610e8b565b8015610961576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa1580156109d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610726919061169f565b60018054600290811603610a235760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a6c57604051635c427cd960e01b815260040160405180910390fd5b610a77848484610fd6565b60335480831115610a9b57604051630b469df360e41b815260040160405180910390fd5b6000610aa96103e8836115f2565b905060006103e8610ab8610dc5565b610ac291906115f2565b9050600082610ad18784611618565b610adb919061162f565b9050610ae78685611605565b603355610b07610af78284611605565b6103e860335461063191906115f2565b610b1288888361101c565b5050505050505050565b6000806103e8603354610b2f91906115f2565b905060006103e8610b3e610dc5565b610b4891906115f2565b9050806108328386611618565b6000610726826107f9565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd7919061159d565b6001600160a01b0316336001600160a01b031614610c085760405163794821ff60e01b815260040160405180910390fd5b600154198119600154191614610c315760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016104e5565b6001600160a01b038116610c8f576040516339b190bb60e11b815260040160405180910390fd5b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6032546001600160a01b0383811691161480610d2f57506064546001600160a01b038381169116145b610d4c57604051630312abdd60e61b815260040160405180910390fd5b6064546001600160a01b0390811690831603610dc157606454604051636f074d1f60e11b8152600481018390526001600160a01b039091169063de0e9a3e90602401600060405180830381600087803b158015610da857600080fd5b505af1158015610dbc573d6000803e3d6000fd5b505050505b5050565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610e0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e32919061169f565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be881610e6b84670de0b6b3a7640000611618565b610e75919061162f565b6040519081526020015b60405180910390a15050565b600054610100900460ff16610ef65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610697565b603280546001600160a01b0319166001600160a01b038416179055610f1c81600061111d565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb591906116b8565b604080516001600160a01b03909316835260ff909116602083015201610e7f565b6032546001600160a01b0383811691161480610fff57506064546001600160a01b038381169116145b61071357604051630312abdd60e61b815260040160405180910390fd5b6064546001600160a01b03908116908316036111095760325460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044016020604051808303816000875af1158015611085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a991906115ba565b50606454604051630ea598cb60e41b8152600481018390526001600160a01b039091169063ea598cb090602401600060405180830381600087803b1580156110f057600080fd5b505af1158015611104573d6000803e3d6000fd5b505050505b6107136001600160a01b03831684836111a4565b6000546201000090046001600160a01b031615801561114457506001600160a01b03821615155b611161576040516339b190bb60e11b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610dc182610c68565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490840152610713928692916000916112349185169084906112b4565b905080516000148061125557508080602001905181019061125591906115ba565b6107135760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610697565b606061083c848460008585600080866001600160a01b031685876040516112db91906116d5565b60006040518083038185875af1925050503d8060008114611318576040519150601f19603f3d011682016040523d82523d6000602084013e61131d565b606091505b509150915061132e87838387611339565b979650505050505050565b606083156113a85782516000036113a1576001600160a01b0385163b6113a15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610697565b508161083c565b61083c83838151156113bd5781518083602001fd5b8060405162461bcd60e51b815260040161069791906114de565b6001600160a01b03811681146103fd57600080fd5b6000602082840312156113fe57600080fd5b8135611409816113d7565b9392505050565b60006020828403121561142257600080fd5b5035919050565b6000806040838503121561143c57600080fd5b8235611447816113d7565b946020939093013593505050565b6000806040838503121561146857600080fd5b8235611473816113d7565b91506020830135611483816113d7565b809150509250929050565b60ff811681146103fd57600080fd5b6000602082840312156114af57600080fd5b81356114098161148e565b60005b838110156114d55781810151838201526020016114bd565b50506000910152565b60208152600082518060208401526114fd8160408501602087016114ba565b601f01601f19169190910160400192915050565b60008060006060848603121561152657600080fd5b8335611531816113d7565b92506020840135611541816113d7565b91506040840135611551816113d7565b809150509250925092565b60008060006060848603121561157157600080fd5b833561157c816113d7565b9250602084013561158c816113d7565b929592945050506040919091013590565b6000602082840312156115af57600080fd5b8151611409816113d7565b6000602082840312156115cc57600080fd5b8151801515811461140957600080fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610726576107266115dc565b81810381811115610726576107266115dc565b8082028115828204841417610726576107266115dc565b60008261164c57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6000602082840312156116b157600080fd5b5051919050565b6000602082840312156116ca57600080fd5b81516114098161148e565b600082516116e78184602087016114ba565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a26469706673582212206982b114e140ae69a3ee1e71453119b2cca547aff53e109050078bca0e473a5b64736f6c634300081b0033", } // EigenStrategyABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/Endian/binding.go b/pkg/bindings/Endian/binding.go index b9f7ef348..a9f01f06b 100644 --- a/pkg/bindings/Endian/binding.go +++ b/pkg/bindings/Endian/binding.go @@ -32,7 +32,7 @@ var ( // EndianMetaData contains all meta data concerning the Endian contract. var EndianMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220731750cc39c1118f2ee5b7230bba50321789b805b1844817687dc7c3931262f964736f6c634300080c0033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200e8c171a49a88c008c51fbc758d7e647b957281590468bff199dd9b70928e79964736f6c634300081b0033", } // EndianABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IAVSDirectory/binding.go b/pkg/bindings/IAVSDirectory/binding.go index 6ee8f3ce0..20c44ca22 100644 --- a/pkg/bindings/IAVSDirectory/binding.go +++ b/pkg/bindings/IAVSDirectory/binding.go @@ -38,7 +38,7 @@ type ISignatureUtilsSignatureWithSaltAndExpiry struct { // IAVSDirectoryMetaData contains all meta data concerning the IAVSDirectory contract. var IAVSDirectoryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deregisterOperatorFromAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorSaltIsSpent\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperatorToAVS\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatorSignature\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithSaltAndExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateAVSMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSMetadataURIUpdated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorAVSRegistrationStatusUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumIAVSDirectory.OperatorAVSRegistrationStatus\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"OperatorAlreadyRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]}]", } // IAVSDirectoryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IDelegationManager/binding.go b/pkg/bindings/IDelegationManager/binding.go index 3d9a84301..2f5320df7 100644 --- a/pkg/bindings/IDelegationManager/binding.go +++ b/pkg/bindings/IDelegationManager/binding.go @@ -62,7 +62,7 @@ type ISignatureUtilsSignatureWithExpiry struct { // IDelegationManagerMetaData contains all meta data concerning the IDelegationManager contract. var IDelegationManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"DELEGATION_APPROVAL_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"STAKER_DELEGATION_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateCurrentStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateDelegationApprovalDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateStakerDelegationDigestHash\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_stakerNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateWithdrawalRoot\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawal\",\"inputs\":[{\"name\":\"withdrawal\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"middlewareTimesIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"completeQueuedWithdrawals\",\"inputs\":[{\"name\":\"withdrawals\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.Withdrawal[]\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]},{\"name\":\"tokens\",\"type\":\"address[][]\",\"internalType\":\"contractIERC20[][]\"},{\"name\":\"middlewareTimesIndexes\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"receiveAsTokens\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeWithdrawalsQueued\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateTo\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegateToBySignature\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSignatureAndExpiry\",\"type\":\"tuple\",\"internalType\":\"structISignatureUtils.SignatureWithExpiry\",\"components\":[{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"approverSalt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegatedTo\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApprover\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationApproverSaltIsSpent\",\"inputs\":[{\"name\":\"_delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getWithdrawalDelay\",\"inputs\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseDelegatedShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minWithdrawalDelayBlocks\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"modifyOperatorDetails\",\"inputs\":[{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"operatorDetails\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorShares\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queueWithdrawals\",\"inputs\":[{\"name\":\"queuedWithdrawalParams\",\"type\":\"tuple[]\",\"internalType\":\"structIDelegationManager.QueuedWithdrawalParams[]\",\"components\":[{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerAsOperator\",\"inputs\":[{\"name\":\"registeringOperatorDetails\",\"type\":\"tuple\",\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stakerNonce\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerOptOutWindowBlocks\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWithdrawalDelayBlocks\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"undelegate\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateOperatorMetadataURI\",\"inputs\":[{\"name\":\"metadataURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"MinWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorDetailsModified\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOperatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorMetadataURIUpdated\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"metadataURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operatorDetails\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.OperatorDetails\",\"components\":[{\"name\":\"__deprecated_earningsReceiver\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegationApprover\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stakerOptOutWindowBlocks\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesDecreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorSharesIncreased\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerDelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerForceUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StakerUndelegated\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWithdrawalDelayBlocksSet\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalCompleted\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalQueued\",\"inputs\":[{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawal\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIDelegationManager.Withdrawal\",\"components\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delegatedTo\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startBlock\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"strategies\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"shares\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}]}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotCurrentlyDelegated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorsCannotUndelegate\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureSaltSpent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksCannotDecrease\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerOptOutWindowBlocksExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDelayNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawerNotStaker\",\"inputs\":[]}]", } // IDelegationManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IEigenPod/binding.go b/pkg/bindings/IEigenPod/binding.go index a07b03980..67461da0d 100644 --- a/pkg/bindings/IEigenPod/binding.go +++ b/pkg/bindings/IEigenPod/binding.go @@ -72,7 +72,7 @@ type IEigenPodValidatorInfo struct { // IEigenPodMetaData contains all meta data concerning the IEigenPod contract. var IEigenPodMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"activeValidatorCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"checkpointBalanceExitedGwei\",\"inputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpoint\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.Checkpoint\",\"components\":[{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proofsRemaining\",\"type\":\"uint24\",\"internalType\":\"uint24\"},{\"name\":\"podBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"balanceDeltasGwei\",\"type\":\"int128\",\"internalType\":\"int128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRoot\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"lastCheckpointTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proofSubmitter\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recoverTokens\",\"inputs\":[{\"name\":\"tokenList\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"},{\"name\":\"amountsToWithdraw\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setProofSubmitter\",\"inputs\":[{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"startCheckpoint\",\"inputs\":[{\"name\":\"revertIfNoBalance\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validatorPubkeyHashToInfo\",\"inputs\":[{\"name\":\"validatorPubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorPubkeyToInfo\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIEigenPod.ValidatorInfo\",\"components\":[{\"name\":\"validatorIndex\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"restakedBalanceGwei\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"lastCheckpointedAt\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"status\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"validatorPubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validatorStatus\",\"inputs\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumIEigenPod.VALIDATOR_STATUS\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyCheckpointProofs\",\"inputs\":[{\"name\":\"balanceContainerProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.BalanceContainerProof\",\"components\":[{\"name\":\"balanceContainerRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proofs\",\"type\":\"tuple[]\",\"internalType\":\"structBeaconChainProofs.BalanceProof[]\",\"components\":[{\"name\":\"pubkeyHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"balanceRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyStaleBalance\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"proof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.ValidatorProof\",\"components\":[{\"name\":\"validatorFields\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyWithdrawalCredentials\",\"inputs\":[{\"name\":\"beaconTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"stateRootProof\",\"type\":\"tuple\",\"internalType\":\"structBeaconChainProofs.StateRootProof\",\"components\":[{\"name\":\"beaconStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"validatorIndices\",\"type\":\"uint40[]\",\"internalType\":\"uint40[]\"},{\"name\":\"validatorFieldsProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"validatorFields\",\"type\":\"bytes32[][]\",\"internalType\":\"bytes32[][]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawRestakedBeaconChainETH\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawableRestakedExecutionLayerGwei\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CheckpointCreated\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"beaconBlockRoot\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"validatorCount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CheckpointFinalized\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"totalShareDeltaWei\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EigenPodStaked\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NonBeaconChainETHReceived\",\"inputs\":[{\"name\":\"amountReceived\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ProofSubmitterUpdated\",\"inputs\":[{\"name\":\"prevProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newProofSubmitter\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RestakedBeaconChainETHWithdrawn\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorBalanceUpdated\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"},{\"name\":\"balanceTimestamp\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"newValidatorBalanceGwei\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorCheckpointed\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorRestaked\",\"inputs\":[{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":false,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ValidatorWithdrawn\",\"inputs\":[{\"name\":\"checkpointTimestamp\",\"type\":\"uint64\",\"indexed\":true,\"internalType\":\"uint64\"},{\"name\":\"validatorIndex\",\"type\":\"uint40\",\"indexed\":true,\"internalType\":\"uint40\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountMustBeMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BeaconTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CannotCheckpointTwiceInSingleBlock\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CheckpointAlreadyActive\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CredentialsAlreadyVerified\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientWithdrawableBalance\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEIP4788Response\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPubKeyLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MsgValueNot32ETH\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoActiveCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoBalanceToCheckpoint\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TimestampOutOfRange\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorInactiveOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorIsExitingBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotActiveInPod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidatorNotSlashedOnBeaconChain\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawCredentialsNotForEigenPod\",\"inputs\":[]}]", } // IEigenPodABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IEigenPodManager/binding.go b/pkg/bindings/IEigenPodManager/binding.go index 8574aafa1..b4094e029 100644 --- a/pkg/bindings/IEigenPodManager/binding.go +++ b/pkg/bindings/IEigenPodManager/binding.go @@ -31,7 +31,7 @@ var ( // IEigenPodManagerMetaData contains all meta data concerning the IEigenPodManager contract. var IEigenPodManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createPod\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ethPOS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIETHPOSDeposit\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hasPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"numPods\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerToPod\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPod\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"podOwnerShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recordBeaconChainETHBalanceUpdate\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stake\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"depositDataRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destination\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BeaconChainETHDeposited\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BeaconChainETHWithdrawalCompleted\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"},{\"name\":\"delegatedAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"withdrawalRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NewTotalShares\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newTotalShares\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodDeployed\",\"inputs\":[{\"name\":\"eigenPod\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PodSharesUpdated\",\"inputs\":[{\"name\":\"podOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sharesDelta\",\"type\":\"int256\",\"indexed\":false,\"internalType\":\"int256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EigenPodAlreadyExists\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNegative\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesNotMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // IEigenPodManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IPausable/binding.go b/pkg/bindings/IPausable/binding.go index 4cef4b112..0cf64ce35 100644 --- a/pkg/bindings/IPausable/binding.go +++ b/pkg/bindings/IPausable/binding.go @@ -31,7 +31,7 @@ var ( // IPausableMetaData contains all meta data concerning the IPausable contract. var IPausableMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]}]", } // IPausableABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IPauserRegistry/binding.go b/pkg/bindings/IPauserRegistry/binding.go index 59678ea9e..aaa464fef 100644 --- a/pkg/bindings/IPauserRegistry/binding.go +++ b/pkg/bindings/IPauserRegistry/binding.go @@ -31,7 +31,7 @@ var ( // IPauserRegistryMetaData contains all meta data concerning the IPauserRegistry contract. var IPauserRegistryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"isPauser\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpauser\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"PauserStatusChanged\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnpauserChanged\",\"inputs\":[{\"name\":\"previousUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"isPauser\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpauser\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"PauserStatusChanged\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnpauserChanged\",\"inputs\":[{\"name\":\"previousUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]}]", } // IPauserRegistryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IRewardsCoordinator/binding.go b/pkg/bindings/IRewardsCoordinator/binding.go index caacc527a..5314b039e 100644 --- a/pkg/bindings/IRewardsCoordinator/binding.go +++ b/pkg/bindings/IRewardsCoordinator/binding.go @@ -77,7 +77,7 @@ type IRewardsCoordinatorTokenTreeMerkleLeaf struct { // IRewardsCoordinatorMetaData contains all meta data concerning the IRewardsCoordinator contract. var IRewardsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmission\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmission\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AmountIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DurationExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EarningsNotGreaterThanClaimed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidClaimProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDurationRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEarnerLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRoot\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRootIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidStartTimestampRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidTokenLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewRootMustBeForNewCalculatedPeriod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RewardsEndTimestampNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootAlreadyActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootNotActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInFuture\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategiesNotInAscendingOrder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // IRewardsCoordinatorABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IStrategy/binding.go b/pkg/bindings/IStrategy/binding.go index 4d3e0fcae..c08a0da6e 100644 --- a/pkg/bindings/IStrategy/binding.go +++ b/pkg/bindings/IStrategy/binding.go @@ -31,7 +31,7 @@ var ( // IStrategyMetaData contains all meta data concerning the IStrategy contract. var IStrategyMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"BalanceExceedsMaxTotalDeposits\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxPerDepositExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewSharesZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnderlyingToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TotalSharesExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalAmountExceedsTotalDeposits\",\"inputs\":[]}]", } // IStrategyABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IStrategyFactory/binding.go b/pkg/bindings/IStrategyFactory/binding.go index 70f95fe3e..29cda340c 100644 --- a/pkg/bindings/IStrategyFactory/binding.go +++ b/pkg/bindings/IStrategyFactory/binding.go @@ -31,7 +31,7 @@ var ( // IStrategyFactoryMetaData contains all meta data concerning the IStrategyFactory contract. var IStrategyFactoryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyBlacklisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BlacklistedToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyAlreadyExists\",\"inputs\":[]}]", } // IStrategyFactoryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/IStrategyManager/binding.go b/pkg/bindings/IStrategyManager/binding.go index 5dc38621c..0a989a611 100644 --- a/pkg/bindings/IStrategyManager/binding.go +++ b/pkg/bindings/IStrategyManager/binding.go @@ -31,7 +31,7 @@ var ( // IStrategyManagerMetaData contains all meta data concerning the IStrategyManager contract. var IStrategyManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientShares\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxStrategiesExceeded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesAmountZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ThirdPartyTransfersDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // IStrategyManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/MagnitudeCheckpoints/binding.go b/pkg/bindings/MagnitudeCheckpoints/binding.go new file mode 100644 index 000000000..9a5a2ef52 --- /dev/null +++ b/pkg/bindings/MagnitudeCheckpoints/binding.go @@ -0,0 +1,203 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package MagnitudeCheckpoints + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// MagnitudeCheckpointsMetaData contains all meta data concerning the MagnitudeCheckpoints contract. +var MagnitudeCheckpointsMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d403c7152d652d1a100c83daf55d72392c025180800bf29f79d386c0af19a05d64736f6c634300080c0033", +} + +// MagnitudeCheckpointsABI is the input ABI used to generate the binding from. +// Deprecated: Use MagnitudeCheckpointsMetaData.ABI instead. +var MagnitudeCheckpointsABI = MagnitudeCheckpointsMetaData.ABI + +// MagnitudeCheckpointsBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use MagnitudeCheckpointsMetaData.Bin instead. +var MagnitudeCheckpointsBin = MagnitudeCheckpointsMetaData.Bin + +// DeployMagnitudeCheckpoints deploys a new Ethereum contract, binding an instance of MagnitudeCheckpoints to it. +func DeployMagnitudeCheckpoints(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MagnitudeCheckpoints, error) { + parsed, err := MagnitudeCheckpointsMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MagnitudeCheckpointsBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &MagnitudeCheckpoints{MagnitudeCheckpointsCaller: MagnitudeCheckpointsCaller{contract: contract}, MagnitudeCheckpointsTransactor: MagnitudeCheckpointsTransactor{contract: contract}, MagnitudeCheckpointsFilterer: MagnitudeCheckpointsFilterer{contract: contract}}, nil +} + +// MagnitudeCheckpoints is an auto generated Go binding around an Ethereum contract. +type MagnitudeCheckpoints struct { + MagnitudeCheckpointsCaller // Read-only binding to the contract + MagnitudeCheckpointsTransactor // Write-only binding to the contract + MagnitudeCheckpointsFilterer // Log filterer for contract events +} + +// MagnitudeCheckpointsCaller is an auto generated read-only Go binding around an Ethereum contract. +type MagnitudeCheckpointsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MagnitudeCheckpointsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MagnitudeCheckpointsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MagnitudeCheckpointsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MagnitudeCheckpointsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MagnitudeCheckpointsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MagnitudeCheckpointsSession struct { + Contract *MagnitudeCheckpoints // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MagnitudeCheckpointsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MagnitudeCheckpointsCallerSession struct { + Contract *MagnitudeCheckpointsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MagnitudeCheckpointsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MagnitudeCheckpointsTransactorSession struct { + Contract *MagnitudeCheckpointsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MagnitudeCheckpointsRaw is an auto generated low-level Go binding around an Ethereum contract. +type MagnitudeCheckpointsRaw struct { + Contract *MagnitudeCheckpoints // Generic contract binding to access the raw methods on +} + +// MagnitudeCheckpointsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MagnitudeCheckpointsCallerRaw struct { + Contract *MagnitudeCheckpointsCaller // Generic read-only contract binding to access the raw methods on +} + +// MagnitudeCheckpointsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MagnitudeCheckpointsTransactorRaw struct { + Contract *MagnitudeCheckpointsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMagnitudeCheckpoints creates a new instance of MagnitudeCheckpoints, bound to a specific deployed contract. +func NewMagnitudeCheckpoints(address common.Address, backend bind.ContractBackend) (*MagnitudeCheckpoints, error) { + contract, err := bindMagnitudeCheckpoints(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MagnitudeCheckpoints{MagnitudeCheckpointsCaller: MagnitudeCheckpointsCaller{contract: contract}, MagnitudeCheckpointsTransactor: MagnitudeCheckpointsTransactor{contract: contract}, MagnitudeCheckpointsFilterer: MagnitudeCheckpointsFilterer{contract: contract}}, nil +} + +// NewMagnitudeCheckpointsCaller creates a new read-only instance of MagnitudeCheckpoints, bound to a specific deployed contract. +func NewMagnitudeCheckpointsCaller(address common.Address, caller bind.ContractCaller) (*MagnitudeCheckpointsCaller, error) { + contract, err := bindMagnitudeCheckpoints(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MagnitudeCheckpointsCaller{contract: contract}, nil +} + +// NewMagnitudeCheckpointsTransactor creates a new write-only instance of MagnitudeCheckpoints, bound to a specific deployed contract. +func NewMagnitudeCheckpointsTransactor(address common.Address, transactor bind.ContractTransactor) (*MagnitudeCheckpointsTransactor, error) { + contract, err := bindMagnitudeCheckpoints(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MagnitudeCheckpointsTransactor{contract: contract}, nil +} + +// NewMagnitudeCheckpointsFilterer creates a new log filterer instance of MagnitudeCheckpoints, bound to a specific deployed contract. +func NewMagnitudeCheckpointsFilterer(address common.Address, filterer bind.ContractFilterer) (*MagnitudeCheckpointsFilterer, error) { + contract, err := bindMagnitudeCheckpoints(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MagnitudeCheckpointsFilterer{contract: contract}, nil +} + +// bindMagnitudeCheckpoints binds a generic wrapper to an already deployed contract. +func bindMagnitudeCheckpoints(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := MagnitudeCheckpointsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MagnitudeCheckpoints.Contract.MagnitudeCheckpointsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MagnitudeCheckpoints.Contract.MagnitudeCheckpointsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MagnitudeCheckpoints.Contract.MagnitudeCheckpointsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MagnitudeCheckpoints.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MagnitudeCheckpoints.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MagnitudeCheckpoints *MagnitudeCheckpointsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MagnitudeCheckpoints.Contract.contract.Transact(opts, method, params...) +} diff --git a/pkg/bindings/Merkle/binding.go b/pkg/bindings/Merkle/binding.go index 93e82af72..9198802ac 100644 --- a/pkg/bindings/Merkle/binding.go +++ b/pkg/bindings/Merkle/binding.go @@ -31,8 +31,8 @@ var ( // MerkleMetaData contains all meta data concerning the Merkle contract. var MerkleMetaData = &bind.MetaData{ - ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220de4dce1b90fa553d4573afc57ce3ea0458378cac0669dc216b6be8ae471c99ea64736f6c634300080c0033", + ABI: "[{\"type\":\"error\",\"name\":\"InvalidProofLength\",\"inputs\":[]}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202841cbb10255cdbe21308cc631e9a3b7beea1ef700f2a2f614c153729de94ef764736f6c634300081b0033", } // MerkleABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/Pausable/binding.go b/pkg/bindings/Pausable/binding.go index 744b7e84b..38604eb8a 100644 --- a/pkg/bindings/Pausable/binding.go +++ b/pkg/bindings/Pausable/binding.go @@ -31,8 +31,8 @@ var ( // PausableMetaData contains all meta data concerning the Pausable contract. var PausableMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x608060405234801561001057600080fd5b506107c2806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80635ac86ab71161005b5780635ac86ab7146100b25780635c975abb146100e6578063886f1195146100f7578063fabc1cbc1461012257600080fd5b806310d67a2f14610082578063136439dd14610097578063595c6a67146100aa575b600080fd5b61009561009036600461065b565b610135565b005b6100956100a536600461067f565b6101ef565b61009561032e565b6100d16100c0366004610698565b6001805460ff9092161b9081161490565b60405190151581526020015b60405180910390f35b6001546040519081526020016100dd565b60005461010a906001600160a01b031681565b6040516001600160a01b0390911681526020016100dd565b61009561013036600461067f565b6103f5565b60008054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101aa91906106bb565b6001600160a01b0316336001600160a01b0316146101e35760405162461bcd60e51b81526004016101da906106d8565b60405180910390fd5b6101ec8161054f565b50565b60005460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025b9190610722565b6102775760405162461bcd60e51b81526004016101da90610744565b600154818116146102f05760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c697479000000000000000060648201526084016101da565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b60005460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610376573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039a9190610722565b6103b65760405162461bcd60e51b81526004016101da90610744565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b60008054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046a91906106bb565b6001600160a01b0316336001600160a01b03161461049a5760405162461bcd60e51b81526004016101da906106d8565b6001541981196001541916146105185760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c697479000000000000000060648201526084016101da565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610323565b6001600160a01b0381166105dd5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a4016101da565b600054604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811681146101ec57600080fd5b60006020828403121561066d57600080fd5b813561067881610646565b9392505050565b60006020828403121561069157600080fd5b5035919050565b6000602082840312156106aa57600080fd5b813560ff8116811461067857600080fd5b6000602082840312156106cd57600080fd5b815161067881610646565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b60006020828403121561073457600080fd5b8151801515811461067857600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b60608201526080019056fea26469706673582212202c2653223ee00d36dc739f8691b398adc60ad925c3636f4c4c9e100e9732974164736f6c634300080c0033", + ABI: "[{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]}]", + Bin: "0x6080604052348015600f57600080fd5b5061061a8061001f6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80635ac86ab71161005b5780635ac86ab7146100b25780635c975abb146100e6578063886f1195146100f7578063fabc1cbc1461012257600080fd5b806310d67a2f14610082578063136439dd14610097578063595c6a67146100aa575b600080fd5b610095610090366004610545565b610135565b005b6100956100a5366004610569565b6101e7565b6100956102d2565b6100d16100c0366004610582565b6001805460ff9092161b9081161490565b60405190151581526020015b60405180910390f35b6001546040519081526020016100dd565b60005461010a906001600160a01b031681565b6040516001600160a01b0390911681526020016100dd565b610095610130366004610569565b61039a565b60008054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101aa91906105a5565b6001600160a01b0316336001600160a01b0316146101db5760405163794821ff60e01b815260040160405180910390fd5b6101e4816104a0565b50565b60005460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561022f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025391906105c2565b61027057604051631d77d47760e21b815260040160405180910390fd5b600154818116146102945760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b60005460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033e91906105c2565b61035b57604051631d77d47760e21b815260040160405180910390fd5b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b60008054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040f91906105a5565b6001600160a01b0316336001600160a01b0316146104405760405163794821ff60e01b815260040160405180910390fd5b6001541981196001541916146104695760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016102c7565b6001600160a01b0381166104c7576040516339b190bb60e11b815260040160405180910390fd5b600054604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811681146101e457600080fd5b60006020828403121561055757600080fd5b813561056281610530565b9392505050565b60006020828403121561057b57600080fd5b5035919050565b60006020828403121561059457600080fd5b813560ff8116811461056257600080fd5b6000602082840312156105b757600080fd5b815161056281610530565b6000602082840312156105d457600080fd5b8151801515811461056257600080fdfea2646970667358221220799851216425bf2b36c9861b7179a838031cf8d71d5a1c8fb437485c8cce31d364736f6c634300081b0033", } // PausableABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/PauserRegistry/binding.go b/pkg/bindings/PauserRegistry/binding.go index bcfe873b2..d7d9fc219 100644 --- a/pkg/bindings/PauserRegistry/binding.go +++ b/pkg/bindings/PauserRegistry/binding.go @@ -31,8 +31,8 @@ var ( // PauserRegistryMetaData contains all meta data concerning the PauserRegistry contract. var PauserRegistryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_pausers\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"_unpauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isPauser\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setIsPauser\",\"inputs\":[{\"name\":\"newPauser\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setUnpauser\",\"inputs\":[{\"name\":\"newUnpauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpauser\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"PauserStatusChanged\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnpauserChanged\",\"inputs\":[{\"name\":\"previousUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false}]", - Bin: "0x608060405234801561001057600080fd5b5060405161077838038061077883398101604081905261002f91610263565b60005b82518110156100775761006583828151811061005057610050610339565b6020026020010151600161008860201b60201c565b8061006f8161034f565b915050610032565b506100818161015a565b5050610378565b6001600160a01b0382166100f95760405162461bcd60e51b815260206004820152602d60248201527f50617573657252656769737472792e5f7365745061757365723a207a65726f2060448201526c1859191c995cdcc81a5b9c1d5d609a1b60648201526084015b60405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f65d3a1fd4c13f05cba164f80d03ce90fb4b5e21946bfc3ab7dbd434c2d0b9152910160405180910390a15050565b6001600160a01b0381166101c85760405162461bcd60e51b815260206004820152602f60248201527f50617573657252656769737472792e5f736574556e7061757365723a207a657260448201526e1bc81859191c995cdcc81a5b9c1d5d608a1b60648201526084016100f0565b600154604080516001600160a01b03928316815291831660208301527f06b4167a2528887a1e97a366eefe8549bfbf1ea3e6ac81cb2564a934d20e8892910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b038116811461025e57600080fd5b919050565b6000806040838503121561027657600080fd5b82516001600160401b038082111561028d57600080fd5b818501915085601f8301126102a157600080fd5b81516020828211156102b5576102b5610231565b8160051b604051601f19603f830116810181811086821117156102da576102da610231565b6040529283528183019350848101820192898411156102f857600080fd5b948201945b8386101561031d5761030e86610247565b855294820194938201936102fd565b965061032c9050878201610247565b9450505050509250929050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561037157634e487b7160e01b600052601160045260246000fd5b5060010190565b6103f1806103876000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806346fbf68e146100515780638568520614610089578063ce5484281461009e578063eab66d7a146100b1575b600080fd5b61007461005f366004610313565b60006020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b61009c610097366004610335565b6100dc565b005b61009c6100ac366004610313565b61011d565b6001546100c4906001600160a01b031681565b6040516001600160a01b039091168152602001610080565b6001546001600160a01b0316331461010f5760405162461bcd60e51b815260040161010690610371565b60405180910390fd5b6101198282610153565b5050565b6001546001600160a01b031633146101475760405162461bcd60e51b815260040161010690610371565b61015081610220565b50565b6001600160a01b0382166101bf5760405162461bcd60e51b815260206004820152602d60248201527f50617573657252656769737472792e5f7365745061757365723a207a65726f2060448201526c1859191c995cdcc81a5b9c1d5d609a1b6064820152608401610106565b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f65d3a1fd4c13f05cba164f80d03ce90fb4b5e21946bfc3ab7dbd434c2d0b9152910160405180910390a15050565b6001600160a01b03811661028e5760405162461bcd60e51b815260206004820152602f60248201527f50617573657252656769737472792e5f736574556e7061757365723a207a657260448201526e1bc81859191c995cdcc81a5b9c1d5d608a1b6064820152608401610106565b600154604080516001600160a01b03928316815291831660208301527f06b4167a2528887a1e97a366eefe8549bfbf1ea3e6ac81cb2564a934d20e8892910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b80356001600160a01b038116811461030e57600080fd5b919050565b60006020828403121561032557600080fd5b61032e826102f7565b9392505050565b6000806040838503121561034857600080fd5b610351836102f7565b91506020830135801515811461036657600080fd5b809150509250929050565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b60608201526080019056fea26469706673582212203b45f7c66225e5887e8907d44b53ad76d03563101c6febf801e78006f96642e664736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_pausers\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"_unpauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isPauser\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setIsPauser\",\"inputs\":[{\"name\":\"newPauser\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setUnpauser\",\"inputs\":[{\"name\":\"newUnpauser\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpauser\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"PauserStatusChanged\",\"inputs\":[{\"name\":\"pauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"canPause\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnpauserChanged\",\"inputs\":[{\"name\":\"previousUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newUnpauser\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]}]", + Bin: "0x608060405234801561001057600080fd5b506040516105e23803806105e283398101604081905261002f916101c8565b60005b825181101561006d57610065838281518110610050576100506102a9565b6020026020010151600161007e60201b60201c565b600101610032565b5061007781610106565b50506102bf565b6001600160a01b0382166100a5576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f65d3a1fd4c13f05cba164f80d03ce90fb4b5e21946bfc3ab7dbd434c2d0b9152910160405180910390a15050565b6001600160a01b03811661012d576040516339b190bb60e11b815260040160405180910390fd5b600154604080516001600160a01b03928316815291831660208301527f06b4167a2528887a1e97a366eefe8549bfbf1ea3e6ac81cb2564a934d20e8892910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146101c357600080fd5b919050565b600080604083850312156101db57600080fd5b82516001600160401b038111156101f157600080fd5b8301601f8101851361020257600080fd5b80516001600160401b0381111561021b5761021b610196565b604051600582901b90603f8201601f191681016001600160401b038111828210171561024957610249610196565b60405291825260208184018101929081018884111561026757600080fd5b6020850194505b8385101561028d5761027f856101ac565b81526020948501940161026e565b5094506102a092505050602084016101ac565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b610314806102ce6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806346fbf68e146100515780638568520614610089578063ce5484281461009e578063eab66d7a146100b1575b600080fd5b61007461005f366004610280565b60006020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b61009c6100973660046102a2565b6100dc565b005b61009c6100ac366004610280565b610115565b6001546100c4906001600160a01b031681565b6040516001600160a01b039091168152602001610080565b6001546001600160a01b031633146101075760405163794821ff60e01b815260040160405180910390fd5b610111828261014c565b5050565b6001546001600160a01b031633146101405760405163794821ff60e01b815260040160405180910390fd5b610149816101d4565b50565b6001600160a01b038216610173576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b03821660008181526020818152604091829020805460ff19168515159081179091558251938452908301527f65d3a1fd4c13f05cba164f80d03ce90fb4b5e21946bfc3ab7dbd434c2d0b9152910160405180910390a15050565b6001600160a01b0381166101fb576040516339b190bb60e11b815260040160405180910390fd5b600154604080516001600160a01b03928316815291831660208301527f06b4167a2528887a1e97a366eefe8549bfbf1ea3e6ac81cb2564a934d20e8892910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b80356001600160a01b038116811461027b57600080fd5b919050565b60006020828403121561029257600080fd5b61029b82610264565b9392505050565b600080604083850312156102b557600080fd5b6102be83610264565b9150602083013580151581146102d357600080fd5b80915050925092905056fea2646970667358221220c830be36ce06a0db5660c408a5a0d7df5ad2178b0c4afdf2e1569a2d68511a7264736f6c634300081b0033", } // PauserRegistryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/RewardsCoordinator/binding.go b/pkg/bindings/RewardsCoordinator/binding.go index 2e8d7e02f..045666ed7 100644 --- a/pkg/bindings/RewardsCoordinator/binding.go +++ b/pkg/bindings/RewardsCoordinator/binding.go @@ -77,8 +77,8 @@ type IRewardsCoordinatorTokenTreeMerkleLeaf struct { // RewardsCoordinatorMetaData contains all meta data concerning the RewardsCoordinator contract. var RewardsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegationManager\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"},{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_CALCULATION_INTERVAL_SECONDS\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_REWARDS_DURATION\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_RETROACTIVE_LENGTH\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_FUTURE_LENGTH\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"__GENESIS_REWARDS_TIMESTAMP\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isAVSRewardsSubmissionHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllEarnersHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x6101806040523480156200001257600080fd5b5060405162004593380380620045938339810160408190526200003591620002e4565b868686868686866200004885826200037e565b63ffffffff1615620000ed5760405162461bcd60e51b815260206004820152606060248201527f52657761726473436f6f7264696e61746f723a2047454e455349535f5245574160448201527f5244535f54494d455354414d50206d7573742062652061206d756c7469706c6560648201527f206f662043414c43554c4154494f4e5f494e54455256414c5f5345434f4e4453608482015260a4015b60405180910390fd5b620000fc62015180866200037e565b63ffffffff16156200019d5760405162461bcd60e51b815260206004820152605760248201527f52657761726473436f6f7264696e61746f723a2043414c43554c4154494f4e5f60448201527f494e54455256414c5f5345434f4e4453206d7573742062652061206d756c746960648201527f706c65206f6620534e415053484f545f434144454e4345000000000000000000608482015260a401620000e4565b6001600160a01b0396871661012052949095166101405263ffffffff92831660805290821660a052811660c05291821660e0521661010052620001df620001f2565b5050466101605250620003b09350505050565b600054610100900460ff16156200025c5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608401620000e4565b60005460ff9081161015620002af576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b0381168114620002c757600080fd5b50565b805163ffffffff81168114620002df57600080fd5b919050565b600080600080600080600060e0888a0312156200030057600080fd5b87516200030d81620002b1565b60208901519097506200032081620002b1565b95506200033060408901620002ca565b94506200034060608901620002ca565b93506200035060808901620002ca565b92506200036060a08901620002ca565b91506200037060c08901620002ca565b905092959891949750929550565b600063ffffffff80841680620003a457634e487b7160e01b600052601260045260246000fd5b92169190910692915050565b60805160a05160c05160e0516101005161012051610140516101605161414c620004476000396000611a6b0152600081816104fd01526128d3015260006107bd015260008181610406015261270201526000818161033201526127ae0152600081816104d601526126b101526000818161071c0152612428015260008181610694015281816124df01526125ba015261414c6000f3fe608060405234801561001057600080fd5b50600436106102f05760003560e01c80637b8f8b051161019d578063d4540a55116100e9578063f698da25116100a2578063fabc1cbc1161007c578063fabc1cbc14610820578063fbf1e2c114610833578063fce36c7d14610846578063ff9f6cce1461085957600080fd5b8063f698da25146107f2578063f8cd8448146107fa578063f96abf2e1461080d57600080fd5b8063d4540a551461076c578063de02e5031461077f578063e221b24514610792578063e810ce21146107a5578063ea4d3c9b146107b8578063f2fde38b146107df57600080fd5b80639be3d4e411610156578063aebd8bae11610130578063aebd8bae146106c9578063bb7e451f146106f7578063bf21a8aa14610717578063c46db6061461073e57600080fd5b80639be3d4e4146106875780639d45c2811461068f578063a0169ddd146106b657600080fd5b80637b8f8b0514610602578063863cb9a91461060a578063865c69531461061d578063886f1195146106485780638da5cb5b1461065b5780639104c3191461066c57600080fd5b806337838ed01161025c57806358baaa3e116102155780635c975abb116101ef5780635c975abb146105b15780635e9d8348146105b95780636d21117e146105cc578063715018a6146105fa57600080fd5b806358baaa3e14610573578063595c6a67146105865780635ac86ab71461058e57600080fd5b806337838ed0146104d157806339b70e38146104f85780633a8c07861461051f5780633ccc861d146105365780633efe1db6146105495780634d18cc351461055c57600080fd5b8063131433b4116102ae578063131433b414610401578063136439dd14610428578063149bc8721461043b57806322f19a641461045c5780632b9f64a41461047d57806336af41fa146104be57600080fd5b806218572c146102f557806304a0c5021461032d578063092db007146103695780630e9a53cf146103915780630eb38345146103d957806310d67a2f146103ee575b600080fd5b61031861030336600461375e565b60d16020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6103547f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff9091168152602001610324565b60cb5461037e90600160e01b900461ffff1681565b60405161ffff9091168152602001610324565b61039961086c565b604080518251815260208084015163ffffffff90811691830191909152838301511691810191909152606091820151151591810191909152608001610324565b6103ec6103e7366004613789565b61094b565b005b6103ec6103fc36600461375e565b6109cd565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b6103ec6104363660046137c2565b610a89565b61044e6104493660046137f3565b610bc8565b604051908152602001610324565b61037e61046a36600461380f565b505060cb54600160e01b900461ffff1690565b6104a661048b36600461375e565b60cc602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610324565b6103ec6104cc36600461383d565b610c3e565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b6104a67f000000000000000000000000000000000000000000000000000000000000000081565b60cb5461035490600160a01b900463ffffffff1681565b6103ec6105443660046138c5565b610e08565b6103ec610557366004613925565b6111cc565b60cb5461035490600160c01b900463ffffffff1681565b6103ec610581366004613951565b61149d565b6103ec6114ae565b61031861059c36600461396c565b606654600160ff9092169190911b9081161490565b60665461044e565b6103186105c736600461398f565b611575565b6103186105da3660046139c4565b60cf60209081526000928352604080842090915290825290205460ff1681565b6103ec611602565b60ca5461044e565b6103ec61061836600461375e565b611616565b61044e61062b36600461380f565b60cd60209081526000928352604080842090915290825290205481565b6065546104a6906001600160a01b031681565b6033546001600160a01b03166104a6565b6104a673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b610399611627565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b6103ec6106c436600461375e565b6116c5565b6103186106d73660046139c4565b60d260209081526000928352604080842090915290825290205460ff1681565b61044e61070536600461375e565b60ce6020526000908152604090205481565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b61031861074c3660046139c4565b60d060209081526000928352604080842090915290825290205460ff1681565b6103ec61077a366004613a0d565b611724565b61039961078d3660046137c2565b61186c565b6103ec6107a0366004613a80565b6118fe565b6103546107b33660046137c2565b61190f565b6104a67f000000000000000000000000000000000000000000000000000000000000000081565b6103ec6107ed36600461375e565b6119f1565b61044e611a67565b61044e6108083660046137f3565b611aa5565b6103ec61081b366004613951565b611ab6565b6103ec61082e3660046137c2565b611cec565b60cb546104a6906001600160a01b031681565b6103ec61085436600461383d565b611e48565b6103ec61086736600461383d565b611fc7565b60408051608081018252600080825260208201819052918101829052606081019190915260ca545b801561094757600060ca6108a9600184613ab1565b815481106108b9576108b9613ac8565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615801560608301819052919250906109295750806040015163ffffffff164210155b156109345792915050565b508061093f81613ade565b915050610894565b5090565b610953612175565b6001600160a01b038216600081815260d1602052604080822054905160ff9091169284151592841515927f4de6293e668df1398422e1def12118052c1539a03cbfedc145895d48d7685f1c9190a4506001600160a01b0391909116600090815260d160205260409020805460ff1916911515919091179055565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a449190613af5565b6001600160a01b0316336001600160a01b031614610a7d5760405162461bcd60e51b8152600401610a7490613b12565b60405180910390fd5b610a86816121cf565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af59190613b5c565b610b115760405162461bcd60e51b8152600401610a7490613b79565b60665481811614610b8a5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610a74565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600080610bd8602084018461375e565b8360200135604051602001610c219392919060f89390931b6001600160f81b031916835260609190911b6bffffffffffffffffffffffff19166001830152601582015260350190565b604051602081830303815290604052805190602001209050919050565b60665460019060029081161415610c675760405162461bcd60e51b8152600401610a7490613bc1565b33600090815260d1602052604090205460ff16610c965760405162461bcd60e51b8152600401610a7490613bf8565b60026097541415610cb95760405162461bcd60e51b8152600401610a7490613c6f565b600260975560005b82811015610dfd5736848483818110610cdc57610cdc613ac8565b9050602002810190610cee9190613ca6565b33600081815260ce60209081526040808320549051949550939192610d199290918591879101613deb565b604051602081830303815290604052805190602001209050610d3a836122c6565b33600090815260d0602090815260408083208484529091529020805460ff19166001908117909155610d6d908390613e1b565b33600081815260ce602052604090819020929092559051829184917f51088b8c89628df3a8174002c2a034d0152fce6af8415d651b2a4734bf27048290610db5908890613e33565b60405180910390a4610de7333060408601803590610dd6906020890161375e565b6001600160a01b0316929190612a9e565b5050508080610df590613e46565b915050610cc1565b505060016097555050565b60665460029060049081161415610e315760405162461bcd60e51b8152600401610a7490613bc1565b60026097541415610e545760405162461bcd60e51b8152600401610a7490613c6f565b6002609755600060ca610e6a6020860186613951565b63ffffffff1681548110610e8057610e80613ac8565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff16151560608201529050610ee18482612b0f565b6000610ef3608086016060870161375e565b6001600160a01b03808216600090815260cc60205260409020549192501680610f195750805b336001600160a01b03821614610f975760405162461bcd60e51b815260206004820152603c60248201527f52657761726473436f6f7264696e61746f722e70726f63657373436c61696d3a60448201527f2063616c6c6572206973206e6f742076616c696420636c61696d6572000000006064820152608401610a74565b60005b610fa760a0880188613e61565b90508110156111be5736610fbe60e0890189613eb2565b83818110610fce57610fce613ac8565b6001600160a01b038716600090815260cd6020908152604080832093029490940194509290915082906110039085018561375e565b6001600160a01b03166001600160a01b03168152602001908152602001600020549050808260200135116110bd5760405162461bcd60e51b815260206004820152605560248201527f52657761726473436f6f7264696e61746f722e70726f63657373436c61696d3a60448201527f2063756d756c61746976654561726e696e6773206d75737420626520677420746064820152741a185b8818dd5b5d5b185d1a5d9950db185a5b5959605a1b608482015260a401610a74565b60006110cd826020850135613ab1565b6001600160a01b038716600090815260cd602090815260408220929350850180359291906110fb908761375e565b6001600160a01b031681526020808201929092526040016000209190915561113d908a90839061112d9087018761375e565b6001600160a01b03169190612ddb565b86516001600160a01b03808b1691878216918916907f9543dbd55580842586a951f0386e24d68a5df99ae29e3b216588b45fd684ce3190611181602089018961375e565b604080519283526001600160a01b039091166020830152810186905260600160405180910390a450505080806111b690613e46565b915050610f9a565b505060016097555050505050565b606654600390600890811614156111f55760405162461bcd60e51b8152600401610a7490613bc1565b60cb546001600160a01b0316331461121f5760405162461bcd60e51b8152600401610a7490613efc565b60cb5463ffffffff600160c01b9091048116908316116112bb5760405162461bcd60e51b815260206004820152604b60248201527f52657761726473436f6f7264696e61746f722e7375626d6974526f6f743a206e60448201527f657720726f6f74206d75737420626520666f72206e657765722063616c63756c60648201526a185d1959081c195c9a5bd960aa1b608482015260a401610a74565b428263ffffffff16106113545760405162461bcd60e51b815260206004820152605560248201527f52657761726473436f6f7264696e61746f722e7375626d6974526f6f743a207260448201527f65776172647343616c63756c6174696f6e456e6454696d657374616d702063616064820152746e6e6f7420626520696e207468652066757475726560581b608482015260a401610a74565b60ca5460cb5460009061137490600160a01b900463ffffffff1642613f50565b6040805160808101825287815263ffffffff878116602080840182815286841685870181815260006060880181815260ca8054600181018255925297517f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee160029092029182015592517f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee290930180549151975193871667ffffffffffffffff1990921691909117600160201b978716979097029690961760ff60401b1916600160401b921515929092029190911790945560cb805463ffffffff60c01b1916600160c01b840217905593519283529394508892908616917fecd866c3c158fa00bf34d803d5f6023000b57080bcb48af004c2b4b46b3afd08910160405180910390a45050505050565b6114a5612175565b610a8681612e0b565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156114f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061151a9190613b5c565b6115365760405162461bcd60e51b8152600401610a7490613b79565b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b60006115fa8260ca61158a6020830183613951565b63ffffffff16815481106115a0576115a0613ac8565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615156060820152612b0f565b506001919050565b61160a612175565b6116146000612e7c565b565b61161e612175565b610a8681612ece565b60408051608081018252600080825260208201819052918101829052606081019190915260ca805461165b90600190613ab1565b8154811061166b5761166b613ac8565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615156060820152919050565b33600081815260cc602052604080822080546001600160a01b031981166001600160a01b038781169182179093559251911692839185917fbab947934d42e0ad206f25c9cab18b5bb6ae144acfb00f40b4e3aa59590ca31291a4505050565b600054610100900460ff16158080156117445750600054600160ff909116105b8061175e5750303b15801561175e575060005460ff166001145b6117c15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a74565b6000805460ff1916600117905580156117e4576000805461ff0019166101001790555b6117ec612f2a565b60c9556117f98686612fc1565b61180287612e7c565b61180b84612ece565b61181483612e0b565b61181d826130ab565b8015611863576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260ca82815481106118a3576118a3613ac8565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff161515606082015292915050565b611906612175565b610a86816130ab565b60ca546000905b63ffffffff811615611982578260ca611930600184613f78565b63ffffffff168154811061194657611946613ac8565b906000526020600020906002020160000154141561197057611969600182613f78565b9392505050565b8061197a81613f9d565b915050611916565b5060405162461bcd60e51b815260206004820152603760248201527f52657761726473436f6f7264696e61746f722e676574526f6f74496e6465784660448201527f726f6d486173683a20726f6f74206e6f7420666f756e640000000000000000006064820152608401610a74565b6119f9612175565b6001600160a01b038116611a5e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a74565b610a8681612e7c565b60007f0000000000000000000000000000000000000000000000000000000000000000461415611a98575060c95490565b611aa0612f2a565b905090565b60006001610bd8602084018461375e565b60665460039060089081161415611adf5760405162461bcd60e51b8152600401610a7490613bc1565b60cb546001600160a01b03163314611b095760405162461bcd60e51b8152600401610a7490613efc565b60ca5463ffffffff831610611b7a5760405162461bcd60e51b815260206004820152603160248201527f52657761726473436f6f7264696e61746f722e64697361626c65526f6f743a206044820152700d2dcecc2d8d2c840e4dedee892dcc8caf607b1b6064820152608401610a74565b600060ca8363ffffffff1681548110611b9557611b95613ac8565b906000526020600020906002020190508060010160089054906101000a900460ff1615611c225760405162461bcd60e51b815260206004820152603560248201527f52657761726473436f6f7264696e61746f722e64697361626c65526f6f743a206044820152741c9bdbdd08185b1c9958591e48191a5cd8589b1959605a1b6064820152608401610a74565b6001810154600160201b900463ffffffff164210611ca15760405162461bcd60e51b815260206004820152603660248201527f52657761726473436f6f7264696e61746f722e64697361626c65526f6f743a206044820152751c9bdbdd08185b1c9958591e481858dd1a5d985d195960521b6064820152608401610a74565b60018101805460ff60401b1916600160401b17905560405163ffffffff8416907fd850e6e5dfa497b72661fa73df2923464eaed9dc2ff1d3cb82bccbfeabe5c41e90600090a2505050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d639190613af5565b6001600160a01b0316336001600160a01b031614611d935760405162461bcd60e51b8152600401610a7490613b12565b606654198119606654191614611e115760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610a74565b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610bbd565b60665460009060019081161415611e715760405162461bcd60e51b8152600401610a7490613bc1565b60026097541415611e945760405162461bcd60e51b8152600401610a7490613c6f565b600260975560005b82811015610dfd5736848483818110611eb757611eb7613ac8565b9050602002810190611ec99190613ca6565b33600081815260ce60209081526040808320549051949550939192611ef49290918591879101613deb565b604051602081830303815290604052805190602001209050611f15836122c6565b33600090815260cf602090815260408083208484529091529020805460ff19166001908117909155611f48908390613e1b565b33600081815260ce602052604090819020929092559051829184917f450a367a380c4e339e5ae7340c8464ef27af7781ad9945cfe8abd828f89e628190611f90908890613e33565b60405180910390a4611fb1333060408601803590610dd6906020890161375e565b5050508080611fbf90613e46565b915050611e9c565b60665460049060109081161415611ff05760405162461bcd60e51b8152600401610a7490613bc1565b33600090815260d1602052604090205460ff1661201f5760405162461bcd60e51b8152600401610a7490613bf8565b600260975414156120425760405162461bcd60e51b8152600401610a7490613c6f565b600260975560005b82811015610dfd573684848381811061206557612065613ac8565b90506020028101906120779190613ca6565b33600081815260ce602090815260408083205490519495509391926120a29290918591879101613deb565b6040516020818303038152906040528051906020012090506120c3836122c6565b33600090815260d2602090815260408083208484529091529020805460ff191660019081179091556120f6908390613e1b565b33600081815260ce602052604090819020929092559051829184917f5251b6fdefcb5d81144e735f69ea4c695fd43b0289ca53dc075033f5fc80068b9061213e908890613e33565b60405180910390a461215f333060408601803590610dd6906020890161375e565b505050808061216d90613e46565b91505061204a565b6033546001600160a01b031633146116145760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a74565b6001600160a01b03811661225d5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610a74565b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b60006122d28280613eb2565b905011612337576040805162461bcd60e51b81526020600482015260248101919091526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a206e6f2073747261746567696573207365746064820152608401610a74565b60008160400135116123a95760405162461bcd60e51b815260206004820152604160248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20616d6f756e742063616e6e6f74206265206064820152600360fc1b608482015260a401610a74565b6f4b3b4ca85a86c47a098a223fffffffff816040013511156124215760405162461bcd60e51b815260206004820152603f60248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20616d6f756e7420746f6f206c61726765006064820152608401610a74565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000001661245860a0830160808401613951565b63ffffffff1611156124dd5760405162461bcd60e51b815260206004820152605460248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a206475726174696f6e20657863656564732060648201527326a0ac2fa922aba0a92229afa22aa920aa24a7a760611b608482015260a401610a74565b7f000000000000000000000000000000000000000000000000000000000000000061250e60a0830160808401613951565b6125189190613fd3565b63ffffffff16156125b85760405162461bcd60e51b815260206004820152606a60248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a206475726174696f6e206d7573742062652060648201527f61206d756c7469706c65206f662043414c43554c4154494f4e5f494e54455256608482015269414c5f5345434f4e445360b01b60a482015260c401610a74565b7f00000000000000000000000000000000000000000000000000000000000000006125e96080830160608401613951565b6125f39190613fd3565b63ffffffff16156126995760405162461bcd60e51b815260206004820152607060248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20737461727454696d657374616d70206d7560648201527f73742062652061206d756c7469706c65206f662043414c43554c4154494f4e5f60848201526f494e54455256414c5f5345434f4e445360801b60a482015260c401610a74565b6126a96080820160608301613951565b63ffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff16426126e19190613ab1565b1115801561272a57506126fa6080820160608301613951565b63ffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff1611155b6127a45760405162461bcd60e51b815260206004820152605160248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20737461727454696d657374616d7020746f6064820152701bc819985c881a5b881d1a19481c185cdd607a1b608482015260a401610a74565b6127d463ffffffff7f00000000000000000000000000000000000000000000000000000000000000001642613e1b565b6127e46080830160608401613951565b63ffffffff1611156128685760405162461bcd60e51b815260206004820152605360248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20737461727454696d657374616d7020746f6064820152726f2066617220696e207468652066757475726560681b608482015260a401610a74565b6000805b6128768380613eb2565b9050811015612a9957600061288b8480613eb2565b8381811061289b5761289b613ac8565b6128b1926020604090920201908101915061375e565b60405163198f077960e21b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063663c1de490602401602060405180830381865afa15801561291c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129409190613b5c565b8061296757506001600160a01b03811673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0145b6129da5760405162461bcd60e51b815260206004820152604a60248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a20696e76616c69642073747261746567792060648201526918dbdb9cda59195c995960b21b608482015260a401610a74565b806001600160a01b0316836001600160a01b031610612a875760405162461bcd60e51b815260206004820152606960248201526000805160206140f783398151915260448201527f7264735375626d697373696f6e3a2073747261746567696573206d757374206260648201527f6520696e20617363656e64696e67206f7264657220746f2068616e646c65206460848201526875706c69636174657360b81b60a482015260c401610a74565b9150612a9281613e46565b905061286c565b505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612b099085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613116565b50505050565b806060015115612b685760405162461bcd60e51b815260206004820152603060248201526000805160206140d783398151915260448201526f1c9bdbdd081a5cc8191a5cd8589b195960821b6064820152608401610a74565b806040015163ffffffff16421015612bcf5760405162461bcd60e51b815260206004820152603660248201526000805160206140d78339815191526044820152751c9bdbdd081b9bdd081858dd1a5d985d1959081e595d60521b6064820152608401610a74565b612bdc60c0830183613e61565b9050612beb60a0840184613e61565b905014612c635760405162461bcd60e51b815260206004820152604c60248201526000805160206140d783398151915260448201527f746f6b656e496e646963657320616e6420746f6b656e50726f6f6673206c656e60648201526b0cee8d040dad2e6dac2e8c6d60a31b608482015260a401610a74565b612c7060e0830183613eb2565b9050612c7f60c0840184613e61565b905014612cf55760405162461bcd60e51b815260206004820152604a60248201526000805160206140d783398151915260448201527f746f6b656e5472656550726f6f667320616e64206c6561766573206c656e67746064820152690d040dad2e6dac2e8c6d60b31b608482015260a401610a74565b8051612d2190612d0b6040850160208601613951565b612d186040860186613ff6565b866060016131e8565b60005b612d3160a0840184613e61565b9050811015612a9957612dcb6080840135612d4f60a0860186613e61565b84818110612d5f57612d5f613ac8565b9050602002016020810190612d749190613951565b612d8160c0870187613e61565b85818110612d9157612d91613ac8565b9050602002810190612da39190613ff6565b612db060e0890189613eb2565b87818110612dc057612dc0613ac8565b90506040020161335c565b612dd481613e46565b9050612d24565b6040516001600160a01b038316602482015260448101829052612a9990849063a9059cbb60e01b90606401612ad2565b60cb546040805163ffffffff600160a01b9093048316815291831660208301527faf557c6c02c208794817a705609cfa935f827312a1adfdd26494b6b95dd2b4b3910160405180910390a160cb805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60cb546040516001600160a01b038084169216907f237b82f438d75fc568ebab484b75b01d9287b9e98b490b7c23221623b6705dbb90600090a360cb80546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b6065546001600160a01b0316158015612fe257506001600160a01b03821615155b6130645760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610a74565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26130a7826121cf565b5050565b60cb546040805161ffff600160e01b9093048316815291831660208301527f8cdc428b0431b82d1619763f443a48197db344ba96905f3949643acd1c863a06910160405180910390a160cb805461ffff909216600160e01b0261ffff60e01b19909216919091179055565b600061316b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134ad9092919063ffffffff16565b805190915015612a9957808060200190518101906131899190613b5c565b612a995760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a74565b6131f360208361403d565b6001901b8463ffffffff161061327d5760405162461bcd60e51b815260206004820152604360248201527f52657761726473436f6f7264696e61746f722e5f7665726966794561726e657260448201527f436c61696d50726f6f663a20696e76616c6964206561726e65724c656166496e6064820152620c8caf60eb1b608482015260a401610a74565b600061328882610bc8565b90506132d384848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a92508591505063ffffffff89166134c4565b6133545760405162461bcd60e51b815260206004820152604660248201527f52657761726473436f6f7264696e61746f722e5f7665726966794561726e657260448201527f436c61696d50726f6f663a20696e76616c6964206561726e657220636c61696d60648201526510383937b7b360d11b608482015260a401610a74565b505050505050565b61336760208361403d565b6001901b8463ffffffff16106133e55760405162461bcd60e51b815260206004820152603c60248201527f52657761726473436f6f7264696e61746f722e5f766572696679546f6b656e4360448201527f6c61696d3a20696e76616c696420746f6b656e4c656166496e646578000000006064820152608401610a74565b60006133f082611aa5565b905061343b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a92508591505063ffffffff89166134c4565b6133545760405162461bcd60e51b815260206004820152603f60248201527f52657761726473436f6f7264696e61746f722e5f766572696679546f6b656e4360448201527f6c61696d3a20696e76616c696420746f6b656e20636c61696d2070726f6f66006064820152608401610a74565b60606134bc84846000856134dc565b949350505050565b6000836134d286858561360d565b1495945050505050565b60608247101561353d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a74565b6001600160a01b0385163b6135945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a74565b600080866001600160a01b031685876040516135b0919061407d565b60006040518083038185875af1925050503d80600081146135ed576040519150601f19603f3d011682016040523d82523d6000602084013e6135f2565b606091505b5091509150613602828286613710565b979650505050505050565b60006020845161361d919061408f565b156136a45760405162461bcd60e51b815260206004820152604b60248201527f4d65726b6c652e70726f63657373496e636c7573696f6e50726f6f664b65636360448201527f616b3a2070726f6f66206c656e6774682073686f756c642062652061206d756c60648201526a3a34b836329037b310199960a91b608482015260a401610a74565b8260205b85518111613707576136bb60028561408f565b6136dc578160005280860151602052604060002091506002840493506136f5565b8086015160005281602052604060002091506002840493505b613700602082613e1b565b90506136a8565b50949350505050565b6060831561371f575081611969565b82511561372f5782518084602001fd5b8160405162461bcd60e51b8152600401610a7491906140a3565b6001600160a01b0381168114610a8657600080fd5b60006020828403121561377057600080fd5b813561196981613749565b8015158114610a8657600080fd5b6000806040838503121561379c57600080fd5b82356137a781613749565b915060208301356137b78161377b565b809150509250929050565b6000602082840312156137d457600080fd5b5035919050565b6000604082840312156137ed57600080fd5b50919050565b60006040828403121561380557600080fd5b61196983836137db565b6000806040838503121561382257600080fd5b823561382d81613749565b915060208301356137b781613749565b6000806020838503121561385057600080fd5b823567ffffffffffffffff8082111561386857600080fd5b818501915085601f83011261387c57600080fd5b81358181111561388b57600080fd5b8660208260051b85010111156138a057600080fd5b60209290920196919550909350505050565b600061010082840312156137ed57600080fd5b600080604083850312156138d857600080fd5b823567ffffffffffffffff8111156138ef57600080fd5b6138fb858286016138b2565b92505060208301356137b781613749565b803563ffffffff8116811461392057600080fd5b919050565b6000806040838503121561393857600080fd5b823591506139486020840161390c565b90509250929050565b60006020828403121561396357600080fd5b6119698261390c565b60006020828403121561397e57600080fd5b813560ff8116811461196957600080fd5b6000602082840312156139a157600080fd5b813567ffffffffffffffff8111156139b857600080fd5b6134bc848285016138b2565b600080604083850312156139d757600080fd5b82356139e281613749565b946020939093013593505050565b803561392081613749565b803561ffff8116811461392057600080fd5b60008060008060008060c08789031215613a2657600080fd5b8635613a3181613749565b95506020870135613a4181613749565b9450604087013593506060870135613a5881613749565b9250613a666080880161390c565b9150613a7460a088016139fb565b90509295509295509295565b600060208284031215613a9257600080fd5b611969826139fb565b634e487b7160e01b600052601160045260246000fd5b600082821015613ac357613ac3613a9b565b500390565b634e487b7160e01b600052603260045260246000fd5b600081613aed57613aed613a9b565b506000190190565b600060208284031215613b0757600080fd5b815161196981613749565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215613b6e57600080fd5b81516119698161377b565b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b60208082526019908201527f5061757361626c653a20696e6465782069732070617573656400000000000000604082015260600190565b60208082526051908201527f52657761726473436f6f7264696e61746f723a2063616c6c6572206973206e6f60408201527f7420612076616c69642063726561746552657761726473466f72416c6c53756260608201527036b4b9b9b4b7b71039bab136b4ba3a32b960791b608082015260a00190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008235609e19833603018112613cbc57600080fd5b9190910192915050565b818352600060208085019450826000805b86811015613d2b578235613cea81613749565b6001600160a01b03168852828401356bffffffffffffffffffffffff8116808214613d13578384fd5b89860152506040978801979290920191600101613cd7565b50959695505050505050565b60008135601e19833603018112613d4d57600080fd5b8201803567ffffffffffffffff811115613d6657600080fd5b8060061b3603841315613d7857600080fd5b60a08552613d8d60a086018260208501613cc6565b915050613d9c602084016139f0565b6001600160a01b0316602085015260408381013590850152613dc06060840161390c565b63ffffffff166060850152613dd76080840161390c565b63ffffffff81166080860152509392505050565b60018060a01b0384168152826020820152606060408201526000613e126060830184613d37565b95945050505050565b60008219821115613e2e57613e2e613a9b565b500190565b6020815260006119696020830184613d37565b6000600019821415613e5a57613e5a613a9b565b5060010190565b6000808335601e19843603018112613e7857600080fd5b83018035915067ffffffffffffffff821115613e9357600080fd5b6020019150600581901b3603821315613eab57600080fd5b9250929050565b6000808335601e19843603018112613ec957600080fd5b83018035915067ffffffffffffffff821115613ee457600080fd5b6020019150600681901b3603821315613eab57600080fd5b60208082526034908201527f52657761726473436f6f7264696e61746f723a2063616c6c6572206973206e6f6040820152733a103a3432903932bbb0b93239aab83230ba32b960611b606082015260800190565b600063ffffffff808316818516808303821115613f6f57613f6f613a9b565b01949350505050565b600063ffffffff83811690831681811015613f9557613f95613a9b565b039392505050565b600063ffffffff821680613fb357613fb3613a9b565b6000190192915050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff80841680613fea57613fea613fbd565b92169190910692915050565b6000808335601e1984360301811261400d57600080fd5b83018035915067ffffffffffffffff82111561402857600080fd5b602001915036819003821315613eab57600080fd5b60008261404c5761404c613fbd565b500490565b60005b8381101561406c578181015183820152602001614054565b83811115612b095750506000910152565b60008251613cbc818460208701614051565b60008261409e5761409e613fbd565b500690565b60208152600082518060208401526140c2816040850160208701614051565b601f01601f1916919091016040019291505056fe52657761726473436f6f7264696e61746f722e5f636865636b436c61696d3a2052657761726473436f6f7264696e61746f722e5f76616c696461746552657761a264697066735822122036f8834ea90be93d8ffaadfdccbc5c85edd0361a90fe4b8b14a9345e0ebdd2e064736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegationManager\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"},{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"},{\"name\":\"_CALCULATION_INTERVAL_SECONDS\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_REWARDS_DURATION\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_RETROACTIVE_LENGTH\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_MAX_FUTURE_LENGTH\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"__GENESIS_REWARDS_TIMESTAMP\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beaconChainETHStrategy\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isAVSRewardsSubmissionHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllEarnersHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AmountIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DurationExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EarningsNotGreaterThanClaimed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidClaimProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDurationRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEarnerLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProofLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRoot\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRootIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidStartTimestampRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidTokenLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewRootMustBeForNewCalculatedPeriod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RewardsEndTimestampNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootAlreadyActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootNotActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInFuture\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategiesNotInAscendingOrder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", + Bin: "0x61018060405234801561001157600080fd5b5060405161377a38038061377a833981016040819052610030916102cf565b86868686868686610041858261035a565b63ffffffff16156100e55760405162461bcd60e51b815260206004820152606060248201527f52657761726473436f6f7264696e61746f723a2047454e455349535f5245574160448201527f5244535f54494d455354414d50206d7573742062652061206d756c7469706c6560648201527f206f662043414c43554c4154494f4e5f494e54455256414c5f5345434f4e4453608482015260a4015b60405180910390fd5b6100f2620151808661035a565b63ffffffff16156101915760405162461bcd60e51b815260206004820152605760248201527f52657761726473436f6f7264696e61746f723a2043414c43554c4154494f4e5f60448201527f494e54455256414c5f5345434f4e4453206d7573742062652061206d756c746960648201527f706c65206f6620534e415053484f545f434144454e4345000000000000000000608482015260a4016100dc565b6001600160a01b0396871661012052949095166101405263ffffffff92831660805290821660a052811660c05291821660e05216610100526101d16101e3565b50504661016052506103909350505050565b600054610100900460ff161561024b5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b60648201526084016100dc565b60005460ff9081161461029c576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146102b357600080fd5b50565b805163ffffffff811681146102ca57600080fd5b919050565b600080600080600080600060e0888a0312156102ea57600080fd5b87516102f58161029e565b60208901519097506103068161029e565b9550610314604089016102b6565b9450610322606089016102b6565b9350610330608089016102b6565b925061033e60a089016102b6565b915061034c60c089016102b6565b905092959891949750929550565b600063ffffffff83168061037e57634e487b7160e01b600052601260045260246000fd5b8063ffffffff84160691505092915050565b60805160a05160c05160e0516101005161012051610140516101605161335461042660003960006117d90152600081816104f501526121b7015260006107b501526000818161040c01526120a201526000818161033201526120f10152600081816104ce01526120510152600081816107140152611f2601526000818161068c01528181611f7d0152611fdc01526133546000f3fe608060405234801561001057600080fd5b50600436106102f05760003560e01c80637b8f8b051161019d578063d4540a55116100e9578063f698da25116100a2578063fabc1cbc1161007c578063fabc1cbc14610818578063fbf1e2c11461082b578063fce36c7d1461083e578063ff9f6cce1461085157600080fd5b8063f698da25146107ea578063f8cd8448146107f2578063f96abf2e1461080557600080fd5b8063d4540a5514610764578063de02e50314610777578063e221b2451461078a578063e810ce211461079d578063ea4d3c9b146107b0578063f2fde38b146107d757600080fd5b80639be3d4e411610156578063aebd8bae11610130578063aebd8bae146106c1578063bb7e451f146106ef578063bf21a8aa1461070f578063c46db6061461073657600080fd5b80639be3d4e41461067f5780639d45c28114610687578063a0169ddd146106ae57600080fd5b80637b8f8b05146105fa578063863cb9a914610602578063865c695314610615578063886f1195146106405780638da5cb5b146106535780639104c3191461066457600080fd5b806337838ed01161025c57806358baaa3e116102155780635c975abb116101ef5780635c975abb146105a95780635e9d8348146105b15780636d21117e146105c4578063715018a6146105f257600080fd5b806358baaa3e1461056b578063595c6a671461057e5780635ac86ab71461058657600080fd5b806337838ed0146104c957806339b70e38146104f05780633a8c0786146105175780633ccc861d1461052e5780633efe1db6146105415780634d18cc351461055457600080fd5b8063131433b4116102ae578063131433b414610407578063136439dd1461042e578063149bc8721461044157806322f19a64146104625780632b9f64a41461047557806336af41fa146104b657600080fd5b806218572c146102f557806304a0c5021461032d578063092db007146103695780630e9a53cf146103915780630eb38345146103df57806310d67a2f146103f4575b600080fd5b610318610303366004612bab565b60d16020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6103547f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff9091168152602001610324565b60cb5461037e90600160e01b900461ffff1681565b60405161ffff9091168152602001610324565b610399610864565b604051610324919060006080820190508251825263ffffffff602084015116602083015263ffffffff604084015116604083015260608301511515606083015292915050565b6103f26103ed366004612bd6565b610943565b005b6103f2610402366004612bab565b6109c5565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b6103f261043c366004612c0f565b610a79565b61045461044f366004612c40565b610b64565b604051908152602001610324565b61037e610470366004612c5c565b610bda565b61049e610483366004612bab565b60cc602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610324565b6103f26104c4366004612c8a565b610bef565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b61049e7f000000000000000000000000000000000000000000000000000000000000000081565b60cb5461035490600160a01b900463ffffffff1681565b6103f261053c366004612d14565b610d94565b6103f261054f366004612d74565b611065565b60cb5461035490600160c01b900463ffffffff1681565b6103f2610579366004612da0565b61125b565b6103f261126c565b610318610594366004612dbb565b606654600160ff9092169190911b9081161490565b606654610454565b6103186105bf366004612dde565b611334565b6103186105d2366004612e13565b60cf60209081526000928352604080842090915290825290205460ff1681565b6103f26113c1565b60ca54610454565b6103f2610610366004612bab565b6113d5565b610454610623366004612c5c565b60cd60209081526000928352604080842090915290825290205481565b60655461049e906001600160a01b031681565b6033546001600160a01b031661049e565b61049e73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b6103996113e6565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b6103f26106bc366004612bab565b611484565b6103186106cf366004612e13565b60d260209081526000928352604080842090915290825290205460ff1681565b6104546106fd366004612bab565b60ce6020526000908152604090205481565b6103547f000000000000000000000000000000000000000000000000000000000000000081565b610318610744366004612e13565b60d060209081526000928352604080842090915290825290205460ff1681565b6103f2610772366004612e5c565b6114e3565b610399610785366004612c0f565b611630565b6103f2610798366004612ecf565b6116c2565b6103546107ab366004612c0f565b6116d3565b61049e7f000000000000000000000000000000000000000000000000000000000000000081565b6103f26107e5366004612bab565b61175f565b6104546117d5565b610454610800366004612c40565b611812565b6103f2610813366004612da0565b611823565b6103f2610826366004612c0f565b611976565b60cb5461049e906001600160a01b031681565b6103f261084c366004612c8a565b611a7e565b6103f261085f366004612c8a565b611bd2565b60408051608081018252600080825260208201819052918101829052606081019190915260ca545b801561093f57600060ca6108a1600184612f00565b815481106108b1576108b1612f13565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615801560608301819052919250906109215750806040015163ffffffff164210155b1561092c5792915050565b508061093781612f29565b91505061088c565b5090565b61094b611d56565b6001600160a01b038216600081815260d1602052604080822054905160ff9091169284151592841515927f4de6293e668df1398422e1def12118052c1539a03cbfedc145895d48d7685f1c9190a4506001600160a01b0391909116600090815260d160205260409020805460ff1916911515919091179055565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3c9190612f40565b6001600160a01b0316336001600160a01b031614610a6d5760405163794821ff60e01b815260040160405180910390fd5b610a7681611db0565b50565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae59190612f5d565b610b0257604051631d77d47760e21b815260040160405180910390fd5b60665481811614610b265760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600080610b746020840184612bab565b8360200135604051602001610bbd9392919060f89390931b6001600160f81b031916835260609190911b6bffffffffffffffffffffffff19166001830152601582015260350190565b604051602081830303815290604052805190602001209050919050565b60cb54600160e01b900461ffff165b92915050565b606654600190600290811603610c185760405163840a48d560e01b815260040160405180910390fd5b33600090815260d1602052604090205460ff16610c4857604051635c427cd960e01b815260040160405180910390fd5b610c50611e40565b60005b82811015610d845736848483818110610c6e57610c6e612f13565b9050602002810190610c809190612f7a565b33600081815260ce60209081526040808320549051949550939192610cab92909185918791016130bf565b604051602081830303815290604052805190602001209050610ccc83611e99565b33600090815260d0602090815260408083208484529091529020805460ff19166001908117909155610cff9083906130ef565b33600081815260ce602052604090819020929092559051829184917f51088b8c89628df3a8174002c2a034d0152fce6af8415d651b2a4734bf27048290610d47908890613102565b60405180910390a4610d79333060408601803590610d689060208901612bab565b6001600160a01b03169291906122a4565b505050600101610c53565b50610d8f6001609755565b505050565b606654600290600490811603610dbd5760405163840a48d560e01b815260040160405180910390fd5b610dc5611e40565b600060ca610dd66020860186612da0565b63ffffffff1681548110610dec57610dec612f13565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff16151560608201529050610e4d8482612315565b6000610e5f6080860160608701612bab565b6001600160a01b03808216600090815260cc60205260409020549192501680610e855750805b336001600160a01b03821614610eae57604051635c427cd960e01b815260040160405180910390fd5b60005b610ebe60a0880188613115565b90508110156110575736610ed560e0890189613166565b83818110610ee557610ee5612f13565b6001600160a01b038716600090815260cd602090815260408083209302949094019450929091508290610f1a90850185612bab565b6001600160a01b03166001600160a01b0316815260200190815260200160002054905080826020013511610f615760405163aa385e8160e01b815260040160405180910390fd5b6000610f71826020850135612f00565b6001600160a01b038716600090815260cd60209081526040822092935085018035929190610f9f9087612bab565b6001600160a01b0316815260208082019290925260400160002091909155610fe1908a908390610fd190870187612bab565b6001600160a01b031691906124b9565b86516001600160a01b03808b1691878216918916907f9543dbd55580842586a951f0386e24d68a5df99ae29e3b216588b45fd684ce31906110256020890189612bab565b604080519283526001600160a01b039091166020830152810186905260600160405180910390a4505050600101610eb1565b50505050610d8f6001609755565b60665460039060089081160361108e5760405163840a48d560e01b815260040160405180910390fd5b60cb546001600160a01b031633146110b957604051635c427cd960e01b815260040160405180910390fd5b60cb5463ffffffff600160c01b9091048116908316116110ec57604051631ca7e50b60e21b815260040160405180910390fd5b428263ffffffff1610611112576040516306957c9160e11b815260040160405180910390fd5b60ca5460cb5460009061113290600160a01b900463ffffffff16426131b0565b6040805160808101825287815263ffffffff878116602080840182815286841685870181815260006060880181815260ca8054600181018255925297517f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee160029092029182015592517f42d72674974f694b5f5159593243114d38a5c39c89d6b62fee061ff523240ee290930180549151975193871667ffffffffffffffff1990921691909117600160201b978716979097029690961760ff60401b1916600160401b921515929092029190911790945560cb805463ffffffff60c01b1916600160c01b840217905593519283529394508892908616917fecd866c3c158fa00bf34d803d5f6023000b57080bcb48af004c2b4b46b3afd08910160405180910390a45050505050565b611263611d56565b610a76816124e9565b60655460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d89190612f5d565b6112f557604051631d77d47760e21b815260040160405180910390fd5b600019606681905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b60006113b98260ca6113496020830183612da0565b63ffffffff168154811061135f5761135f612f13565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615156060820152612315565b506001919050565b6113c9611d56565b6113d3600061255a565b565b6113dd611d56565b610a76816125ac565b60408051608081018252600080825260208201819052918101829052606081019190915260ca805461141a90600190612f00565b8154811061142a5761142a612f13565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff1615156060820152919050565b33600081815260cc602052604080822080546001600160a01b031981166001600160a01b038781169182179093559251911692839185917fbab947934d42e0ad206f25c9cab18b5bb6ae144acfb00f40b4e3aa59590ca31291a4505050565b600054610100900460ff16158080156115035750600054600160ff909116105b8061151d5750303b15801561151d575060005460ff166001145b6115855760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156115a8576000805461ff0019166101001790555b6115b0612608565b60c9556115bd868661269f565b6115c68761255a565b6115cf846125ac565b6115d8836124e9565b6115e182612724565b8015611627576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915260ca828154811061166757611667612f13565b600091825260209182902060408051608081018252600293909302909101805483526001015463ffffffff80821694840194909452600160201b810490931690820152600160401b90910460ff161515606082015292915050565b6116ca611d56565b610a7681612724565b60ca546000905b63ffffffff811615611745578260ca6116f46001846131cc565b63ffffffff168154811061170a5761170a612f13565b906000526020600020906002020160000154036117335761172c6001826131cc565b9392505050565b8061173d816131e8565b9150506116da565b5060405163504570e360e01b815260040160405180910390fd5b611767611d56565b6001600160a01b0381166117cc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161157c565b610a768161255a565b60007f00000000000000000000000000000000000000000000000000000000000000004603611805575060c95490565b61180d612608565b905090565b60006001610b746020840184612bab565b60665460039060089081160361184c5760405163840a48d560e01b815260040160405180910390fd5b60cb546001600160a01b0316331461187757604051635c427cd960e01b815260040160405180910390fd5b60ca5463ffffffff83161061189f576040516394a8d38960e01b815260040160405180910390fd5b600060ca8363ffffffff16815481106118ba576118ba612f13565b906000526020600020906002020190508060010160089054906101000a900460ff16156118fa57604051631b14174b60e01b815260040160405180910390fd5b6001810154600160201b900463ffffffff16421061192b57604051630c36f66560e21b815260040160405180910390fd5b60018101805460ff60401b1916600160401b17905560405163ffffffff8416907fd850e6e5dfa497b72661fa73df2923464eaed9dc2ff1d3cb82bccbfeabe5c41e90600090a2505050565b606560009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ed9190612f40565b6001600160a01b0316336001600160a01b031614611a1e5760405163794821ff60e01b815260040160405180910390fd5b606654198119606654191614611a475760405163c61dca5d60e01b815260040160405180910390fd5b606681905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610b59565b606654600090600190811603611aa75760405163840a48d560e01b815260040160405180910390fd5b611aaf611e40565b60005b82811015610d845736848483818110611acd57611acd612f13565b9050602002810190611adf9190612f7a565b33600081815260ce60209081526040808320549051949550939192611b0a92909185918791016130bf565b604051602081830303815290604052805190602001209050611b2b83611e99565b33600090815260cf602090815260408083208484529091529020805460ff19166001908117909155611b5e9083906130ef565b33600081815260ce602052604090819020929092559051829184917f450a367a380c4e339e5ae7340c8464ef27af7781ad9945cfe8abd828f89e628190611ba6908890613102565b60405180910390a4611bc7333060408601803590610d689060208901612bab565b505050600101611ab2565b606654600490601090811603611bfb5760405163840a48d560e01b815260040160405180910390fd5b33600090815260d1602052604090205460ff16611c2b57604051635c427cd960e01b815260040160405180910390fd5b611c33611e40565b60005b82811015610d845736848483818110611c5157611c51612f13565b9050602002810190611c639190612f7a565b33600081815260ce60209081526040808320549051949550939192611c8e92909185918791016130bf565b604051602081830303815290604052805190602001209050611caf83611e99565b33600090815260d2602090815260408083208484529091529020805460ff19166001908117909155611ce29083906130ef565b33600081815260ce602052604090819020929092559051829184917f5251b6fdefcb5d81144e735f69ea4c695fd43b0289ca53dc075033f5fc80068b90611d2a908890613102565b60405180910390a4611d4b333060408601803590610d689060208901612bab565b505050600101611c36565b6033546001600160a01b031633146113d35760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161157c565b6001600160a01b038116611dd7576040516339b190bb60e11b815260040160405180910390fd5b606554604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b600260975403611e925760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161157c565b6002609755565b6000611ea58280613166565b905011611ec55760405163796cc52560e01b815260040160405180910390fd5b6000816040013511611eea576040516310eb483f60e21b815260040160405180910390fd5b6f4b3b4ca85a86c47a098a223fffffffff81604001351115611f1f5760405163070b5a6f60e21b815260040160405180910390fd5b63ffffffff7f000000000000000000000000000000000000000000000000000000000000000016611f5660a0830160808401612da0565b63ffffffff161115611f7b57604051630dd0b9f560e21b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000611fac60a0830160808401612da0565b611fb6919061321e565b63ffffffff1615611fda5760405163ee66470560e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000061200b6080830160608401612da0565b612015919061321e565b63ffffffff161561203957604051633c1a94f160e21b815260040160405180910390fd5b6120496080820160608301612da0565b63ffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff16426120819190612f00565b111580156120ca575061209a6080820160608301612da0565b63ffffffff167f000000000000000000000000000000000000000000000000000000000000000063ffffffff1611155b6120e75760405163041aa75760e11b815260040160405180910390fd5b61211763ffffffff7f000000000000000000000000000000000000000000000000000000000000000016426130ef565b6121276080830160608401612da0565b63ffffffff16111561214c57604051637ee2b44360e01b815260040160405180910390fd5b6000805b61215a8380613166565b9050811015610d8f57600061216f8480613166565b8381811061217f5761217f612f13565b6121959260206040909202019081019150612bab565b60405163198f077960e21b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063663c1de490602401602060405180830381865afa158015612200573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122249190612f5d565b8061224b57506001600160a01b03811673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0145b61226857604051632efd965160e11b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03161061229a5760405163dfad9ca160e01b815260040160405180910390fd5b9150600101612150565b6040516001600160a01b038085166024830152831660448201526064810182905261230f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261278f565b50505050565b80606001511561233857604051631b14174b60e01b815260040160405180910390fd5b806040015163ffffffff1642101561236357604051631437a2bb60e31b815260040160405180910390fd5b61237060c0830183613115565b905061237f60a0840184613115565b90501461239f576040516343714afd60e01b815260040160405180910390fd5b6123ac60e0830183613166565b90506123bb60c0840184613115565b9050146123db576040516343714afd60e01b815260040160405180910390fd5b8051612407906123f16040850160208601612da0565b6123fe6040860186613246565b86606001612864565b60005b61241760a0840184613115565b9050811015610d8f576124b1608084013561243560a0860186613115565b8481811061244557612445612f13565b905060200201602081019061245a9190612da0565b61246760c0870187613115565b8581811061247757612477612f13565b90506020028101906124899190613246565b61249660e0890189613166565b878181106124a6576124a6612f13565b905060400201612912565b60010161240a565b6040516001600160a01b038316602482015260448101829052610d8f90849063a9059cbb60e01b906064016122d8565b60cb546040805163ffffffff600160a01b9093048316815291831660208301527faf557c6c02c208794817a705609cfa935f827312a1adfdd26494b6b95dd2b4b3910160405180910390a160cb805463ffffffff909216600160a01b0263ffffffff60a01b19909216919091179055565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60cb546040516001600160a01b038084169216907f237b82f438d75fc568ebab484b75b01d9287b9e98b490b7c23221623b6705dbb90600090a360cb80546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b6065546001600160a01b03161580156126c057506001600160a01b03821615155b6126dd576040516339b190bb60e11b815260040160405180910390fd5b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a261272082611db0565b5050565b60cb546040805161ffff600160e01b9093048316815291831660208301527f8cdc428b0431b82d1619763f443a48197db344ba96905f3949643acd1c863a06910160405180910390a160cb805461ffff909216600160e01b0261ffff60e01b19909216919091179055565b60006127e4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166129519092919063ffffffff16565b90508051600014806128055750808060200190518101906128059190612f5d565b610d8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161157c565b61286f60208361328d565b6001901b8463ffffffff16106128975760405162c6c39d60e71b815260040160405180910390fd5b60006128a282610b64565b90506128ed84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a92508591505063ffffffff8916612968565b61290a576040516369ca16c960e01b815260040160405180910390fd5b505050505050565b61291d60208361328d565b6001901b8463ffffffff16106129465760405163054ff4df60e51b815260040160405180910390fd5b60006128a282611812565b60606129608484600085612980565b949350505050565b600083612976868585612a5b565b1495945050505050565b6060824710156129e15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161157c565b600080866001600160a01b031685876040516129fd91906132c5565b60006040518083038185875af1925050503d8060008114612a3a576040519150601f19603f3d011682016040523d82523d6000602084013e612a3f565b606091505b5091509150612a5087838387612af8565b979650505050505050565b600060208451612a6b91906132d7565b15612a89576040516313717da960e21b815260040160405180910390fd5b8260205b85518111612aef57612aa06002856132d7565b600003612ac457816000528086015160205260406000209150600284049350612add565b8086015160005281602052604060002091506002840493505b612ae86020826130ef565b9050612a8d565b50949350505050565b60608315612b67578251600003612b60576001600160a01b0385163b612b605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161157c565b5081612960565b6129608383815115612b7c5781518083602001fd5b8060405162461bcd60e51b815260040161157c91906132eb565b6001600160a01b0381168114610a7657600080fd5b600060208284031215612bbd57600080fd5b813561172c81612b96565b8015158114610a7657600080fd5b60008060408385031215612be957600080fd5b8235612bf481612b96565b91506020830135612c0481612bc8565b809150509250929050565b600060208284031215612c2157600080fd5b5035919050565b600060408284031215612c3a57600080fd5b50919050565b600060408284031215612c5257600080fd5b61172c8383612c28565b60008060408385031215612c6f57600080fd5b8235612c7a81612b96565b91506020830135612c0481612b96565b60008060208385031215612c9d57600080fd5b823567ffffffffffffffff811115612cb457600080fd5b8301601f81018513612cc557600080fd5b803567ffffffffffffffff811115612cdc57600080fd5b8560208260051b8401011115612cf157600080fd5b6020919091019590945092505050565b60006101008284031215612c3a57600080fd5b60008060408385031215612d2757600080fd5b823567ffffffffffffffff811115612d3e57600080fd5b612d4a85828601612d01565b9250506020830135612c0481612b96565b803563ffffffff81168114612d6f57600080fd5b919050565b60008060408385031215612d8757600080fd5b82359150612d9760208401612d5b565b90509250929050565b600060208284031215612db257600080fd5b61172c82612d5b565b600060208284031215612dcd57600080fd5b813560ff8116811461172c57600080fd5b600060208284031215612df057600080fd5b813567ffffffffffffffff811115612e0757600080fd5b61296084828501612d01565b60008060408385031215612e2657600080fd5b8235612e3181612b96565b946020939093013593505050565b8035612d6f81612b96565b803561ffff81168114612d6f57600080fd5b60008060008060008060c08789031215612e7557600080fd5b8635612e8081612b96565b95506020870135612e9081612b96565b9450604087013593506060870135612ea781612b96565b9250612eb560808801612d5b565b9150612ec360a08801612e4a565b90509295509295509295565b600060208284031215612ee157600080fd5b61172c82612e4a565b634e487b7160e01b600052601160045260246000fd5b81810381811115610be957610be9612eea565b634e487b7160e01b600052603260045260246000fd5b600081612f3857612f38612eea565b506000190190565b600060208284031215612f5257600080fd5b815161172c81612b96565b600060208284031215612f6f57600080fd5b815161172c81612bc8565b60008235609e19833603018112612f9057600080fd5b9190910192915050565b81835260208301925060008160005b84811015613000578135612fbc81612b96565b6001600160a01b0316865260208201356bffffffffffffffffffffffff8116808214612fe757600080fd5b6020880152506040958601959190910190600101612fa9565b5093949350505050565b60008135601e1983360301811261302057600080fd5b820160208101903567ffffffffffffffff81111561303d57600080fd5b8060061b360382131561304f57600080fd5b60a0855261306160a086018284612f9a565b91505061307060208401612e3f565b6001600160a01b031660208501526040838101359085015261309460608401612d5b565b63ffffffff1660608501526130ab60808401612d5b565b63ffffffff81166080860152509392505050565b60018060a01b03841681528260208201526060604082015260006130e6606083018461300a565b95945050505050565b80820180821115610be957610be9612eea565b60208152600061172c602083018461300a565b6000808335601e1984360301811261312c57600080fd5b83018035915067ffffffffffffffff82111561314757600080fd5b6020019150600581901b360382131561315f57600080fd5b9250929050565b6000808335601e1984360301811261317d57600080fd5b83018035915067ffffffffffffffff82111561319857600080fd5b6020019150600681901b360382131561315f57600080fd5b63ffffffff8181168382160190811115610be957610be9612eea565b63ffffffff8281168282160390811115610be957610be9612eea565b600063ffffffff8216806131fe576131fe612eea565b6000190192915050565b634e487b7160e01b600052601260045260246000fd5b600063ffffffff83168061323457613234613208565b8063ffffffff84160691505092915050565b6000808335601e1984360301811261325d57600080fd5b83018035915067ffffffffffffffff82111561327857600080fd5b60200191503681900382131561315f57600080fd5b60008261329c5761329c613208565b500490565b60005b838110156132bc5781810151838201526020016132a4565b50506000910152565b60008251612f908184602087016132a1565b6000826132e6576132e6613208565b500690565b602081526000825180602084015261330a8160408501602087016132a1565b601f01601f1916919091016040019291505056fea26469706673582212202bee8412ee374b8fa10c52a69ba7784c634c77526b99fd1d5298b6f30d2802b764736f6c634300081b0033", } // RewardsCoordinatorABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/RewardsCoordinatorStorage/binding.go b/pkg/bindings/RewardsCoordinatorStorage/binding.go index a5c813df9..fe83adebc 100644 --- a/pkg/bindings/RewardsCoordinatorStorage/binding.go +++ b/pkg/bindings/RewardsCoordinatorStorage/binding.go @@ -77,7 +77,7 @@ type IRewardsCoordinatorTokenTreeMerkleLeaf struct { // RewardsCoordinatorStorageMetaData contains all meta data concerning the RewardsCoordinatorStorage contract. var RewardsCoordinatorStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmission\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isAVSRewardsSubmissionHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllEarnersHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"CALCULATION_INTERVAL_SECONDS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_REWARDS_TIMESTAMP\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_FUTURE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_RETROACTIVE_LENGTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_REWARDS_DURATION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activationDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"calculateEarnerLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"calculateTokenLeafHash\",\"inputs\":[{\"name\":\"leaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"checkClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimerFor\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createAVSRewardsSubmission\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllEarners\",\"inputs\":[{\"name\":\"rewardsSubmissions\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"createRewardsForAllSubmission\",\"inputs\":[{\"name\":\"rewardsSubmission\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.RewardsSubmission[]\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cumulativeClaimed\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currRewardsCalculationEndTimestamp\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableRoot\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getCurrentClaimableDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentDistributionRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootAtIndex\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.DistributionRoot\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"disabled\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDistributionRootsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRootIndexFromHash\",\"inputs\":[{\"name\":\"rootHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"globalOperatorCommissionBips\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isAVSRewardsSubmissionHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllEarnersHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isRewardsSubmissionForAllHash\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatorCommissionBips\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"avs\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"processClaim\",\"inputs\":[{\"name\":\"claim\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.RewardsMerkleClaim\",\"components\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"earnerTreeProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"earnerLeaf\",\"type\":\"tuple\",\"internalType\":\"structIRewardsCoordinator.EarnerTreeMerkleLeaf\",\"components\":[{\"name\":\"earner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"earnerTokenRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"tokenIndices\",\"type\":\"uint32[]\",\"internalType\":\"uint32[]\"},{\"name\":\"tokenTreeProofs\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"tokenLeaves\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.TokenTreeMerkleLeaf[]\",\"components\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"cumulativeEarnings\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]},{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rewardsUpdater\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setActivationDelay\",\"inputs\":[{\"name\":\"_activationDelay\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setClaimerFor\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGlobalOperatorCommission\",\"inputs\":[{\"name\":\"_globalCommissionBips\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsForAllSubmitter\",\"inputs\":[{\"name\":\"_submitter\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_newValue\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRewardsUpdater\",\"inputs\":[{\"name\":\"_rewardsUpdater\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submissionNonce\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"submitRoot\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AVSRewardsSubmissionCreated\",\"inputs\":[{\"name\":\"avs\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ActivationDelaySet\",\"inputs\":[{\"name\":\"oldActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"},{\"name\":\"newActivationDelay\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimerForSet\",\"inputs\":[{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldClaimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootDisabled\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DistributionRootSubmitted\",\"inputs\":[{\"name\":\"rootIndex\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsCalculationEndTimestamp\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"uint32\"},{\"name\":\"activatedAt\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"GlobalCommissionBipsSet\",\"inputs\":[{\"name\":\"oldGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"},{\"name\":\"newGlobalCommissionBips\",\"type\":\"uint16\",\"indexed\":false,\"internalType\":\"uint16\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsClaimed\",\"inputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"earner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"claimedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsForAllSubmitterSet\",\"inputs\":[{\"name\":\"rewardsForAllSubmitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"oldValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"},{\"name\":\"newValue\",\"type\":\"bool\",\"indexed\":true,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllCreated\",\"inputs\":[{\"name\":\"submitter\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsSubmissionForAllEarnersCreated\",\"inputs\":[{\"name\":\"tokenHopper\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"submissionNonce\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"rewardsSubmissionHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"rewardsSubmission\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIRewardsCoordinator.RewardsSubmission\",\"components\":[{\"name\":\"strategiesAndMultipliers\",\"type\":\"tuple[]\",\"internalType\":\"structIRewardsCoordinator.StrategyAndMultiplier[]\",\"components\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"multiplier\",\"type\":\"uint96\",\"internalType\":\"uint96\"}]},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startTimestamp\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"duration\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RewardsUpdaterSet\",\"inputs\":[{\"name\":\"oldRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newRewardsUpdater\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AmountExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AmountIsZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DurationExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EarningsNotGreaterThanClaimed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidClaimProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDurationRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEarnerLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRoot\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRootIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidStartTimestampRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidTokenLeafIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewRootMustBeForNewCalculatedPeriod\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RewardsEndTimestampNotElapsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootAlreadyActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"RootNotActivated\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInFuture\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StartTimestampTooFarInPast\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategiesNotInAscendingOrder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // RewardsCoordinatorStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/SlashingConstants/binding.go b/pkg/bindings/SlashingConstants/binding.go new file mode 100644 index 000000000..0a9cb4c71 --- /dev/null +++ b/pkg/bindings/SlashingConstants/binding.go @@ -0,0 +1,327 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package SlashingConstants + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// SlashingConstantsMetaData contains all meta data concerning the SlashingConstants contract. +var SlashingConstantsMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"DEALLOCATION_DELAY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"INITIAL_TOTAL_MAGNITUDE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PRECISION_FACTOR\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PRECISION_FACTOR_SQUARED\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"}]", + Bin: "0x61010561003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060515760003560e01c806321afdf8e1460565780632981eb7714607e5780639a543ca414609b578063ccd34cd51460c1575b600080fd5b606b6ec097ce7bc90715b34b9f100000000081565b6040519081526020015b60405180910390f35b60876217124081565b60405163ffffffff90911681526020016075565b60a9670de0b6b3a764000081565b60405167ffffffffffffffff90911681526020016075565b606b670de0b6b3a76400008156fea264697066735822122051573b877db53ce7fd9202510ed740ac5b29774096c961210de6c69c249f537264736f6c634300080c0033", +} + +// SlashingConstantsABI is the input ABI used to generate the binding from. +// Deprecated: Use SlashingConstantsMetaData.ABI instead. +var SlashingConstantsABI = SlashingConstantsMetaData.ABI + +// SlashingConstantsBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SlashingConstantsMetaData.Bin instead. +var SlashingConstantsBin = SlashingConstantsMetaData.Bin + +// DeploySlashingConstants deploys a new Ethereum contract, binding an instance of SlashingConstants to it. +func DeploySlashingConstants(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SlashingConstants, error) { + parsed, err := SlashingConstantsMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SlashingConstantsBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SlashingConstants{SlashingConstantsCaller: SlashingConstantsCaller{contract: contract}, SlashingConstantsTransactor: SlashingConstantsTransactor{contract: contract}, SlashingConstantsFilterer: SlashingConstantsFilterer{contract: contract}}, nil +} + +// SlashingConstants is an auto generated Go binding around an Ethereum contract. +type SlashingConstants struct { + SlashingConstantsCaller // Read-only binding to the contract + SlashingConstantsTransactor // Write-only binding to the contract + SlashingConstantsFilterer // Log filterer for contract events +} + +// SlashingConstantsCaller is an auto generated read-only Go binding around an Ethereum contract. +type SlashingConstantsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SlashingConstantsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SlashingConstantsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SlashingConstantsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SlashingConstantsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SlashingConstantsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SlashingConstantsSession struct { + Contract *SlashingConstants // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SlashingConstantsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SlashingConstantsCallerSession struct { + Contract *SlashingConstantsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SlashingConstantsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SlashingConstantsTransactorSession struct { + Contract *SlashingConstantsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SlashingConstantsRaw is an auto generated low-level Go binding around an Ethereum contract. +type SlashingConstantsRaw struct { + Contract *SlashingConstants // Generic contract binding to access the raw methods on +} + +// SlashingConstantsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SlashingConstantsCallerRaw struct { + Contract *SlashingConstantsCaller // Generic read-only contract binding to access the raw methods on +} + +// SlashingConstantsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SlashingConstantsTransactorRaw struct { + Contract *SlashingConstantsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSlashingConstants creates a new instance of SlashingConstants, bound to a specific deployed contract. +func NewSlashingConstants(address common.Address, backend bind.ContractBackend) (*SlashingConstants, error) { + contract, err := bindSlashingConstants(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SlashingConstants{SlashingConstantsCaller: SlashingConstantsCaller{contract: contract}, SlashingConstantsTransactor: SlashingConstantsTransactor{contract: contract}, SlashingConstantsFilterer: SlashingConstantsFilterer{contract: contract}}, nil +} + +// NewSlashingConstantsCaller creates a new read-only instance of SlashingConstants, bound to a specific deployed contract. +func NewSlashingConstantsCaller(address common.Address, caller bind.ContractCaller) (*SlashingConstantsCaller, error) { + contract, err := bindSlashingConstants(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SlashingConstantsCaller{contract: contract}, nil +} + +// NewSlashingConstantsTransactor creates a new write-only instance of SlashingConstants, bound to a specific deployed contract. +func NewSlashingConstantsTransactor(address common.Address, transactor bind.ContractTransactor) (*SlashingConstantsTransactor, error) { + contract, err := bindSlashingConstants(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SlashingConstantsTransactor{contract: contract}, nil +} + +// NewSlashingConstantsFilterer creates a new log filterer instance of SlashingConstants, bound to a specific deployed contract. +func NewSlashingConstantsFilterer(address common.Address, filterer bind.ContractFilterer) (*SlashingConstantsFilterer, error) { + contract, err := bindSlashingConstants(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SlashingConstantsFilterer{contract: contract}, nil +} + +// bindSlashingConstants binds a generic wrapper to an already deployed contract. +func bindSlashingConstants(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SlashingConstantsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SlashingConstants *SlashingConstantsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SlashingConstants.Contract.SlashingConstantsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SlashingConstants *SlashingConstantsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SlashingConstants.Contract.SlashingConstantsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SlashingConstants *SlashingConstantsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SlashingConstants.Contract.SlashingConstantsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SlashingConstants *SlashingConstantsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SlashingConstants.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SlashingConstants *SlashingConstantsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SlashingConstants.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SlashingConstants *SlashingConstantsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SlashingConstants.Contract.contract.Transact(opts, method, params...) +} + +// DEALLOCATIONDELAY is a free data retrieval call binding the contract method 0x2981eb77. +// +// Solidity: function DEALLOCATION_DELAY() view returns(uint32) +func (_SlashingConstants *SlashingConstantsCaller) DEALLOCATIONDELAY(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _SlashingConstants.contract.Call(opts, &out, "DEALLOCATION_DELAY") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// DEALLOCATIONDELAY is a free data retrieval call binding the contract method 0x2981eb77. +// +// Solidity: function DEALLOCATION_DELAY() view returns(uint32) +func (_SlashingConstants *SlashingConstantsSession) DEALLOCATIONDELAY() (uint32, error) { + return _SlashingConstants.Contract.DEALLOCATIONDELAY(&_SlashingConstants.CallOpts) +} + +// DEALLOCATIONDELAY is a free data retrieval call binding the contract method 0x2981eb77. +// +// Solidity: function DEALLOCATION_DELAY() view returns(uint32) +func (_SlashingConstants *SlashingConstantsCallerSession) DEALLOCATIONDELAY() (uint32, error) { + return _SlashingConstants.Contract.DEALLOCATIONDELAY(&_SlashingConstants.CallOpts) +} + +// INITIALTOTALMAGNITUDE is a free data retrieval call binding the contract method 0x9a543ca4. +// +// Solidity: function INITIAL_TOTAL_MAGNITUDE() view returns(uint64) +func (_SlashingConstants *SlashingConstantsCaller) INITIALTOTALMAGNITUDE(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _SlashingConstants.contract.Call(opts, &out, "INITIAL_TOTAL_MAGNITUDE") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// INITIALTOTALMAGNITUDE is a free data retrieval call binding the contract method 0x9a543ca4. +// +// Solidity: function INITIAL_TOTAL_MAGNITUDE() view returns(uint64) +func (_SlashingConstants *SlashingConstantsSession) INITIALTOTALMAGNITUDE() (uint64, error) { + return _SlashingConstants.Contract.INITIALTOTALMAGNITUDE(&_SlashingConstants.CallOpts) +} + +// INITIALTOTALMAGNITUDE is a free data retrieval call binding the contract method 0x9a543ca4. +// +// Solidity: function INITIAL_TOTAL_MAGNITUDE() view returns(uint64) +func (_SlashingConstants *SlashingConstantsCallerSession) INITIALTOTALMAGNITUDE() (uint64, error) { + return _SlashingConstants.Contract.INITIALTOTALMAGNITUDE(&_SlashingConstants.CallOpts) +} + +// PRECISIONFACTOR is a free data retrieval call binding the contract method 0xccd34cd5. +// +// Solidity: function PRECISION_FACTOR() view returns(uint256) +func (_SlashingConstants *SlashingConstantsCaller) PRECISIONFACTOR(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SlashingConstants.contract.Call(opts, &out, "PRECISION_FACTOR") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// PRECISIONFACTOR is a free data retrieval call binding the contract method 0xccd34cd5. +// +// Solidity: function PRECISION_FACTOR() view returns(uint256) +func (_SlashingConstants *SlashingConstantsSession) PRECISIONFACTOR() (*big.Int, error) { + return _SlashingConstants.Contract.PRECISIONFACTOR(&_SlashingConstants.CallOpts) +} + +// PRECISIONFACTOR is a free data retrieval call binding the contract method 0xccd34cd5. +// +// Solidity: function PRECISION_FACTOR() view returns(uint256) +func (_SlashingConstants *SlashingConstantsCallerSession) PRECISIONFACTOR() (*big.Int, error) { + return _SlashingConstants.Contract.PRECISIONFACTOR(&_SlashingConstants.CallOpts) +} + +// PRECISIONFACTORSQUARED is a free data retrieval call binding the contract method 0x21afdf8e. +// +// Solidity: function PRECISION_FACTOR_SQUARED() view returns(uint256) +func (_SlashingConstants *SlashingConstantsCaller) PRECISIONFACTORSQUARED(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SlashingConstants.contract.Call(opts, &out, "PRECISION_FACTOR_SQUARED") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// PRECISIONFACTORSQUARED is a free data retrieval call binding the contract method 0x21afdf8e. +// +// Solidity: function PRECISION_FACTOR_SQUARED() view returns(uint256) +func (_SlashingConstants *SlashingConstantsSession) PRECISIONFACTORSQUARED() (*big.Int, error) { + return _SlashingConstants.Contract.PRECISIONFACTORSQUARED(&_SlashingConstants.CallOpts) +} + +// PRECISIONFACTORSQUARED is a free data retrieval call binding the contract method 0x21afdf8e. +// +// Solidity: function PRECISION_FACTOR_SQUARED() view returns(uint256) +func (_SlashingConstants *SlashingConstantsCallerSession) PRECISIONFACTORSQUARED() (*big.Int, error) { + return _SlashingConstants.Contract.PRECISIONFACTORSQUARED(&_SlashingConstants.CallOpts) +} diff --git a/pkg/bindings/StrategyBase/binding.go b/pkg/bindings/StrategyBase/binding.go index 02377ad8a..440d8c96a 100644 --- a/pkg/bindings/StrategyBase/binding.go +++ b/pkg/bindings/StrategyBase/binding.go @@ -31,8 +31,8 @@ var ( // StrategyBaseMetaData contains all meta data concerning the StrategyBase contract. var StrategyBaseMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001ab438038062001ab4833981016040819052620000349162000114565b6001600160a01b0381166080526200004b62000052565b5062000146565b600054610100900460ff1615620000bf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000112576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012757600080fd5b81516001600160a01b03811681146200013f57600080fd5b9392505050565b60805161193d620001776000396000818161019901528181610570015281816109f50152610ac0015261193d6000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80635c975abb116100b8578063ab5921e11161007c578063ab5921e11461029c578063ce7c2ac2146102b1578063d9caed12146102c4578063e3dae51c146102d7578063f3e73875146102ea578063fabc1cbc146102fd57600080fd5b80635c975abb146102425780637a8b26371461024a578063886f11951461025d5780638c871019146102765780638f6a62401461028957600080fd5b806347e7ef24116100ff57806347e7ef24146101d2578063485cc955146101e5578063553ca5f8146101f8578063595c6a671461020b5780635ac86ab71461021357600080fd5b806310d67a2f1461013c578063136439dd146101515780632495a5991461016457806339b70e38146101945780633a98ef39146101bb575b600080fd5b61014f61014a3660046115a6565b610310565b005b61014f61015f3660046115c3565b6103cc565b603254610177906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101777f000000000000000000000000000000000000000000000000000000000000000081565b6101c460335481565b60405190815260200161018b565b6101c46101e03660046115dc565b610510565b61014f6101f3366004611608565b610754565b6101c46102063660046115a6565b610869565b61014f61087d565b610232610221366004611650565b6001805460ff9092161b9081161490565b604051901515815260200161018b565b6001546101c4565b6101c46102583660046115c3565b610949565b600054610177906201000090046001600160a01b031681565b6101c46102843660046115c3565b610994565b6101c46102973660046115a6565b61099f565b6102a46109ad565b60405161018b919061169d565b6101c46102bf3660046115a6565b6109cd565b61014f6102d23660046116d0565b610a62565b6101c46102e53660046115c3565b610c48565b6101c46102f83660046115c3565b610c81565b61014f61030b3660046115c3565b610c8c565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103879190611711565b6001600160a01b0316336001600160a01b0316146103c05760405162461bcd60e51b81526004016103b79061172e565b60405180910390fd5b6103c981610de8565b50565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043d9190611778565b6104595760405162461bcd60e51b81526004016103b79061179a565b600154818116146104d25760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c697479000000000000000060648201526084016103b7565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b600180546000918291811614156105655760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b60448201526064016103b7565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105dd5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e6167657260448201526064016103b7565b6105e78484610eed565b60335460006105f86103e8836117f8565b905060006103e8610607610f6d565b61061191906117f8565b9050600061061f8783611810565b90508061062c8489611827565b6106369190611846565b95508561069c5760405162461bcd60e51b815260206004820152602e60248201527f5374726174656779426173652e6465706f7369743a206e65775368617265732060448201526d63616e6e6f74206265207a65726f60901b60648201526084016103b7565b6106a686856117f8565b60338190556f4b3b4ca85a86c47a098a223fffffffff10156107305760405162461bcd60e51b815260206004820152603c60248201527f5374726174656779426173652e6465706f7369743a20746f74616c536861726560448201527f73206578636565647320604d41585f544f54414c5f534841524553600000000060648201526084016103b7565b610749826103e860335461074491906117f8565b610fdf565b505050505092915050565b600054610100900460ff16158080156107745750600054600160ff909116105b8061078e5750303b15801561078e575060005460ff166001145b6107f15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103b7565b6000805460ff191660011790558015610814576000805461ff0019166101001790555b61081e8383611033565b8015610864576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610877610258836109cd565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa1580156108ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ee9190611778565b61090a5760405162461bcd60e51b81526004016103b79061179a565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e860335461095c91906117f8565b905060006103e861096b610f6d565b61097591906117f8565b9050816109828583611827565b61098c9190611846565b949350505050565b600061087782610c48565b60006108776102f8836109cd565b60606040518060800160405280604d81526020016118bb604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108779190611868565b6001805460029081161415610ab55760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b60448201526064016103b7565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b2d5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e6167657260448201526064016103b7565b610b3884848461117e565b60335480831115610bc75760405162461bcd60e51b815260206004820152604d60248201527f5374726174656779426173652e77697468647261773a20616d6f756e7453686160448201527f726573206d757374206265206c657373207468616e206f7220657175616c207460648201526c6f20746f74616c53686172657360981b608482015260a4016103b7565b6000610bd56103e8836117f8565b905060006103e8610be4610f6d565b610bee91906117f8565b9050600082610bfd8784611827565b610c079190611846565b9050610c138685611810565b603355610c33610c238284611810565b6103e860335461074491906117f8565b610c3e888883611201565b5050505050505050565b6000806103e8603354610c5b91906117f8565b905060006103e8610c6a610f6d565b610c7491906117f8565b9050806109828386611827565b600061087782610949565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d039190611711565b6001600160a01b0316336001600160a01b031614610d335760405162461bcd60e51b81526004016103b79061172e565b600154198119600154191614610db15760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c697479000000000000000060648201526084016103b7565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610505565b6001600160a01b038116610e765760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a4016103b7565b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6032546001600160a01b03838116911614610f695760405162461bcd60e51b815260206004820152603660248201527f5374726174656779426173652e6465706f7369743a2043616e206f6e6c79206460448201527532b837b9b4ba103ab73232b9363cb4b733aa37b5b2b760511b60648201526084016103b7565b5050565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190611868565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be88161101384670de0b6b3a7640000611827565b61101d9190611846565b6040519081526020015b60405180910390a15050565b600054610100900460ff1661109e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016103b7565b603280546001600160a01b0319166001600160a01b0384161790556110c4816000611215565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115d9190611881565b604080516001600160a01b03909316835260ff909116602083015201611027565b6032546001600160a01b038381169116146108645760405162461bcd60e51b815260206004820152603b60248201527f5374726174656779426173652e77697468647261773a2043616e206f6e6c792060448201527f77697468647261772074686520737472617465677920746f6b656e000000000060648201526084016103b7565b6108646001600160a01b0383168483611301565b6000546201000090046001600160a01b031615801561123c57506001600160a01b03821615155b6112be5760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a4016103b7565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610f6982610de8565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908401526108649286929160009161139191851690849061140e565b80519091501561086457808060200190518101906113af9190611778565b6108645760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103b7565b606061141d8484600085611427565b90505b9392505050565b6060824710156114885760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103b7565b6001600160a01b0385163b6114df5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103b7565b600080866001600160a01b031685876040516114fb919061189e565b60006040518083038185875af1925050503d8060008114611538576040519150601f19603f3d011682016040523d82523d6000602084013e61153d565b606091505b509150915061154d828286611558565b979650505050505050565b60608315611567575081611420565b8251156115775782518084602001fd5b8160405162461bcd60e51b81526004016103b7919061169d565b6001600160a01b03811681146103c957600080fd5b6000602082840312156115b857600080fd5b813561142081611591565b6000602082840312156115d557600080fd5b5035919050565b600080604083850312156115ef57600080fd5b82356115fa81611591565b946020939093013593505050565b6000806040838503121561161b57600080fd5b823561162681611591565b9150602083013561163681611591565b809150509250929050565b60ff811681146103c957600080fd5b60006020828403121561166257600080fd5b813561142081611641565b60005b83811015611688578181015183820152602001611670565b83811115611697576000848401525b50505050565b60208152600082518060208401526116bc81604085016020870161166d565b601f01601f19169190910160400192915050565b6000806000606084860312156116e557600080fd5b83356116f081611591565b9250602084013561170081611591565b929592945050506040919091013590565b60006020828403121561172357600080fd5b815161142081611591565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b60006020828403121561178a57600080fd5b8151801515811461142057600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6000821982111561180b5761180b6117e2565b500190565b600082821015611822576118226117e2565b500390565b6000816000190483118215151615611841576118416117e2565b500290565b60008261186357634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561187a57600080fd5b5051919050565b60006020828403121561189357600080fd5b815161142081611641565b600082516118b081846020870161166d565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a264697066735822122010a959346f6109c589a9783919e1f435adfbf8e6f523baaaa3307a9e4b75ffcb64736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"BalanceExceedsMaxTotalDeposits\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxPerDepositExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewSharesZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnderlyingToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TotalSharesExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalAmountExceedsTotalDeposits\",\"inputs\":[]}]", + Bin: "0x60a060405234801561001057600080fd5b506040516115cf3803806115cf83398101604081905261002f91610109565b6001600160a01b03811660805261004461004a565b50610139565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610107576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011b57600080fd5b81516001600160a01b038116811461013257600080fd5b9392505050565b60805161146661016960003960008181610199015281816104e8015281816108ac015261094b01526114666000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80635c975abb116100b8578063ab5921e11161007c578063ab5921e11461029c578063ce7c2ac2146102b1578063d9caed12146102c4578063e3dae51c146102d7578063f3e73875146102ea578063fabc1cbc146102fd57600080fd5b80635c975abb146102425780637a8b26371461024a578063886f11951461025d5780638c871019146102765780638f6a62401461028957600080fd5b806347e7ef24116100ff57806347e7ef24146101d2578063485cc955146101e5578063553ca5f8146101f8578063595c6a671461020b5780635ac86ab71461021357600080fd5b806310d67a2f1461013c578063136439dd146101515780632495a5991461016457806339b70e38146101945780633a98ef39146101bb575b600080fd5b61014f61014a366004611177565b610310565b005b61014f61015f36600461119b565b6103c4565b603254610177906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101777f000000000000000000000000000000000000000000000000000000000000000081565b6101c460335481565b60405190815260200161018b565b6101c46101e03660046111b4565b6104b4565b61014f6101f33660046111e0565b610605565b6101c4610206366004611177565b61071f565b61014f610733565b610232610221366004611228565b6001805460ff9092161b9081161490565b604051901515815260200161018b565b6001546101c4565b6101c461025836600461119b565b610800565b600054610177906201000090046001600160a01b031681565b6101c461028436600461119b565b61084b565b6101c4610297366004611177565b610856565b6102a4610864565b60405161018b9190611269565b6101c46102bf366004611177565b610884565b61014f6102d236600461129c565b610919565b6101c46102e536600461119b565b610a39565b6101c46102f836600461119b565b610a72565b61014f61030b36600461119b565b610a7d565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610363573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038791906112dd565b6001600160a01b0316336001600160a01b0316146103b85760405163794821ff60e01b815260040160405180910390fd5b6103c181610b85565b50565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610411573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043591906112fa565b61045257604051631d77d47760e21b815260040160405180910390fd5b600154818116146104765760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116036104dd5760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461052657604051635c427cd960e01b815260040160405180910390fd5b6105308484610c23565b60335460006105416103e883611332565b905060006103e8610550610c55565b61055a9190611332565b905060006105688783611345565b9050806105758489611358565b61057f919061136f565b9550856000036105a257604051630c392ed360e11b815260040160405180910390fd5b6105ac8685611332565b60338190556f4b3b4ca85a86c47a098a223fffffffff10156105e157604051632f14e8a360e11b815260040160405180910390fd5b6105fa826103e86033546105f59190611332565b610cc7565b505050505092915050565b600054610100900460ff16158080156106255750600054600160ff909116105b8061063f5750303b15801561063f575060005460ff166001145b6106a75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156106ca576000805461ff0019166101001790555b6106d48383610d1b565b801561071a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600061072d61025883610884565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a491906112fa565b6107c157604051631d77d47760e21b815260040160405180910390fd5b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e86033546108139190611332565b905060006103e8610822610c55565b61082c9190611332565b9050816108398583611358565b610843919061136f565b949350505050565b600061072d82610a39565b600061072d6102f883610884565b60606040518060800160405280604d81526020016113e4604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa1580156108f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072d9190611391565b600180546002908116036109405760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461098957604051635c427cd960e01b815260040160405180910390fd5b610994848484610e66565b603354808311156109b857604051630b469df360e41b815260040160405180910390fd5b60006109c66103e883611332565b905060006103e86109d5610c55565b6109df9190611332565b90506000826109ee8784611358565b6109f8919061136f565b9050610a048685611345565b603355610a24610a148284611345565b6103e86033546105f59190611332565b610a2f888883610e94565b5050505050505050565b6000806103e8603354610a4c9190611332565b905060006103e8610a5b610c55565b610a659190611332565b9050806108398386611358565b600061072d82610800565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ad0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af491906112dd565b6001600160a01b0316336001600160a01b031614610b255760405163794821ff60e01b815260040160405180910390fd5b600154198119600154191614610b4e5760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016104a9565b6001600160a01b038116610bac576040516339b190bb60e11b815260040160405180910390fd5b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6032546001600160a01b03838116911614610c5157604051630312abdd60e61b815260040160405180910390fd5b5050565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190611391565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be881610cfb84670de0b6b3a7640000611358565b610d05919061136f565b6040519081526020015b60405180910390a15050565b600054610100900460ff16610d865760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840161069e565b603280546001600160a01b0319166001600160a01b038416179055610dac816000610ea8565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4591906113aa565b604080516001600160a01b03909316835260ff909116602083015201610d0f565b6032546001600160a01b0383811691161461071a57604051630312abdd60e61b815260040160405180910390fd5b61071a6001600160a01b0383168483610f2f565b6000546201000090046001600160a01b0316158015610ecf57506001600160a01b03821615155b610eec576040516339b190bb60e11b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610c5182610b85565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649084015261071a92869291600091610fbf91851690849061103f565b9050805160001480610fe0575080806020019051810190610fe091906112fa565b61071a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161069e565b6060610843848460008585600080866001600160a01b0316858760405161106691906113c7565b60006040518083038185875af1925050503d80600081146110a3576040519150601f19603f3d011682016040523d82523d6000602084013e6110a8565b606091505b50915091506110b9878383876110c4565b979650505050505050565b6060831561113357825160000361112c576001600160a01b0385163b61112c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069e565b5081610843565b61084383838151156111485781518083602001fd5b8060405162461bcd60e51b815260040161069e9190611269565b6001600160a01b03811681146103c157600080fd5b60006020828403121561118957600080fd5b813561119481611162565b9392505050565b6000602082840312156111ad57600080fd5b5035919050565b600080604083850312156111c757600080fd5b82356111d281611162565b946020939093013593505050565b600080604083850312156111f357600080fd5b82356111fe81611162565b9150602083013561120e81611162565b809150509250929050565b60ff811681146103c157600080fd5b60006020828403121561123a57600080fd5b813561119481611219565b60005b83811015611260578181015183820152602001611248565b50506000910152565b6020815260008251806020840152611288816040850160208701611245565b601f01601f19169190910160400192915050565b6000806000606084860312156112b157600080fd5b83356112bc81611162565b925060208401356112cc81611162565b929592945050506040919091013590565b6000602082840312156112ef57600080fd5b815161119481611162565b60006020828403121561130c57600080fd5b8151801515811461119457600080fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561072d5761072d61131c565b8181038181111561072d5761072d61131c565b808202811582820484141761072d5761072d61131c565b60008261138c57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156113a357600080fd5b5051919050565b6000602082840312156113bc57600080fd5b815161119481611219565b600082516113d9818460208701611245565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a264697066735822122045c4c9a0037e35032ada52a7c8860a29aa19f51fcbd46efff1eeb8a25c34f1ff64736f6c634300081b0033", } // StrategyBaseABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StrategyBaseTVLLimits/binding.go b/pkg/bindings/StrategyBaseTVLLimits/binding.go index c0b5f85d3..acf8f4e8a 100644 --- a/pkg/bindings/StrategyBaseTVLLimits/binding.go +++ b/pkg/bindings/StrategyBaseTVLLimits/binding.go @@ -31,8 +31,8 @@ var ( // StrategyBaseTVLLimitsMetaData contains all meta data concerning the StrategyBaseTVLLimits contract. var StrategyBaseTVLLimitsMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getTVLLimits\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_maxPerDeposit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_maxTotalDeposits\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPerDeposit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxTotalDeposits\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setTVLLimits\",\"inputs\":[{\"name\":\"newMaxPerDeposit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"newMaxTotalDeposits\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPerDepositUpdated\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxTotalDepositsUpdated\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001f4d38038062001f4d833981016040819052620000349162000116565b6001600160a01b038116608052806200004c62000054565b505062000148565b600054610100900460ff1615620000c15760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000114576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012957600080fd5b81516001600160a01b03811681146200014157600080fd5b9392505050565b608051611dd46200017960003960008181610216015281816107a901528181610be70152610cb20152611dd46000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80635c975abb116100de578063ab5921e111610097578063df6fadc111610071578063df6fadc114610366578063e3dae51c14610381578063f3e7387514610394578063fabc1cbc146103a757600080fd5b8063ab5921e11461032b578063ce7c2ac214610340578063d9caed121461035357600080fd5b80635c975abb146102c857806361b01b5d146102d05780637a8b2637146102d9578063886f1195146102ec5780638c871019146103055780638f6a62401461031857600080fd5b80633a98ef391161014b578063485cc95511610125578063485cc9551461026b578063553ca5f81461027e578063595c6a67146102915780635ac86ab71461029957600080fd5b80633a98ef391461023857806343fe08b01461024f57806347e7ef241461025857600080fd5b8063019e27291461019357806310d67a2f146101a857806311c70c9d146101bb578063136439dd146101ce5780632495a599146101e157806339b70e3814610211575b600080fd5b6101a66101a1366004611983565b6103ba565b005b6101a66101b63660046119cd565b61049d565b6101a66101c93660046119ea565b610550565b6101a66101dc366004611a0c565b610605565b6032546101f4906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101f47f000000000000000000000000000000000000000000000000000000000000000081565b61024160335481565b604051908152602001610208565b61024160645481565b610241610266366004611a25565b610749565b6101a6610279366004611a51565b61098d565b61024161028c3660046119cd565b610a5b565b6101a6610a6f565b6102b86102a7366004611a99565b6001805460ff9092161b9081161490565b6040519015158152602001610208565b600154610241565b61024160655481565b6102416102e7366004611a0c565b610b3b565b6000546101f4906201000090046001600160a01b031681565b610241610313366004611a0c565b610b86565b6102416103263660046119cd565b610b91565b610333610b9f565b6040516102089190611ae6565b61024161034e3660046119cd565b610bbf565b6101a6610361366004611b19565b610c54565b60645460655460408051928352602083019190915201610208565b61024161038f366004611a0c565b610e3a565b6102416103a2366004611a0c565b610e73565b6101a66103b5366004611a0c565b610e7e565b600054610100900460ff16158080156103da5750600054600160ff909116105b806103f45750303b1580156103f4575060005460ff166001145b6104195760405162461bcd60e51b815260040161041090611b5a565b60405180910390fd5b6000805460ff19166001179055801561043c576000805461ff0019166101001790555b6104468585610fda565b61045083836110e7565b8015610496576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105149190611ba8565b6001600160a01b0316336001600160a01b0316146105445760405162461bcd60e51b815260040161041090611bc5565b61054d8161123a565b50565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c79190611ba8565b6001600160a01b0316336001600160a01b0316146105f75760405162461bcd60e51b815260040161041090611bc5565b6106018282610fda565b5050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106769190611c0f565b6106925760405162461bcd60e51b815260040161041090611c31565b6001548181161461070b5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116141561079e5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108165760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b610820848461133f565b60335460006108316103e883611c8f565b905060006103e8610840611421565b61084a9190611c8f565b905060006108588783611ca7565b9050806108658489611cbe565b61086f9190611cdd565b9550856108d55760405162461bcd60e51b815260206004820152602e60248201527f5374726174656779426173652e6465706f7369743a206e65775368617265732060448201526d63616e6e6f74206265207a65726f60901b6064820152608401610410565b6108df8685611c8f565b60338190556f4b3b4ca85a86c47a098a223fffffffff10156109695760405162461bcd60e51b815260206004820152603c60248201527f5374726174656779426173652e6465706f7369743a20746f74616c536861726560448201527f73206578636565647320604d41585f544f54414c5f53484152455360000000006064820152608401610410565b610982826103e860335461097d9190611c8f565b611493565b505050505092915050565b600054610100900460ff16158080156109ad5750600054600160ff909116105b806109c75750303b1580156109c7575060005460ff166001145b6109e35760405162461bcd60e51b815260040161041090611b5a565b6000805460ff191660011790558015610a06576000805461ff0019166101001790555b610a1083836110e7565b8015610a56576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610a696102e783610bbf565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae09190611c0f565b610afc5760405162461bcd60e51b815260040161041090611c31565b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e8603354610b4e9190611c8f565b905060006103e8610b5d611421565b610b679190611c8f565b905081610b748583611cbe565b610b7e9190611cdd565b949350505050565b6000610a6982610e3a565b6000610a696103a283610bbf565b60606040518060800160405280604d8152602001611d52604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a699190611cff565b6001805460029081161415610ca75760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610410565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d1f5760405162461bcd60e51b815260206004820181905260248201527f5374726174656779426173652e6f6e6c7953747261746567794d616e616765726044820152606401610410565b610d2a8484846114df565b60335480831115610db95760405162461bcd60e51b815260206004820152604d60248201527f5374726174656779426173652e77697468647261773a20616d6f756e7453686160448201527f726573206d757374206265206c657373207468616e206f7220657175616c207460648201526c6f20746f74616c53686172657360981b608482015260a401610410565b6000610dc76103e883611c8f565b905060006103e8610dd6611421565b610de09190611c8f565b9050600082610def8784611cbe565b610df99190611cdd565b9050610e058685611ca7565b603355610e25610e158284611ca7565b6103e860335461097d9190611c8f565b610e30888883611562565b5050505050505050565b6000806103e8603354610e4d9190611c8f565b905060006103e8610e5c611421565b610e669190611c8f565b905080610b748386611cbe565b6000610a6982610b3b565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef59190611ba8565b6001600160a01b0316336001600160a01b031614610f255760405162461bcd60e51b815260040161041090611bc5565b600154198119600154191614610fa35760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610410565b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161073e565b60645460408051918252602082018490527ff97ed4e083acac67830025ecbc756d8fe847cdbdca4cee3fe1e128e98b54ecb5910160405180910390a160655460408051918252602082018390527f6ab181e0440bfbf4bacdf2e99674735ce6638005490688c5f994f5399353e452910160405180910390a1808211156110dc5760405162461bcd60e51b815260206004820152604b60248201527f53747261746567794261736554564c4c696d6974732e5f73657454564c4c696d60448201527f6974733a206d61785065724465706f7369742065786365656473206d6178546f60648201526a74616c4465706f7369747360a81b608482015260a401610410565b606491909155606555565b600054610100900460ff166111525760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610410565b603280546001600160a01b0319166001600160a01b038416179055611178816000611576565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112119190611d18565b604080516001600160a01b03909316835260ff9091166020830152015b60405180910390a15050565b6001600160a01b0381166112c85760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610410565b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6064548111156113a95760405162461bcd60e51b815260206004820152602f60248201527f53747261746567794261736554564c4c696d6974733a206d617820706572206460448201526e195c1bdcda5d08195e18d959591959608a1b6064820152608401610410565b6065546113b4611421565b11156114175760405162461bcd60e51b815260206004820152602c60248201527f53747261746567794261736554564c4c696d6974733a206d6178206465706f7360448201526b1a5d1cc8195e18d95959195960a21b6064820152608401610410565b6106018282611662565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561146a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148e9190611cff565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be8816114c784670de0b6b3a7640000611cbe565b6114d19190611cdd565b60405190815260200161122e565b6032546001600160a01b03838116911614610a565760405162461bcd60e51b815260206004820152603b60248201527f5374726174656779426173652e77697468647261773a2043616e206f6e6c792060448201527f77697468647261772074686520737472617465677920746f6b656e00000000006064820152608401610410565b610a566001600160a01b03831684836116de565b6000546201000090046001600160a01b031615801561159d57506001600160a01b03821615155b61161f5760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610410565b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26106018261123a565b6032546001600160a01b038381169116146106015760405162461bcd60e51b815260206004820152603660248201527f5374726174656779426173652e6465706f7369743a2043616e206f6e6c79206460448201527532b837b9b4ba103ab73232b9363cb4b733aa37b5b2b760511b6064820152608401610410565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490840152610a569286929160009161176e9185169084906117eb565b805190915015610a56578080602001905181019061178c9190611c0f565b610a565760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b60606117fa8484600085611804565b90505b9392505050565b6060824710156118655760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610410565b6001600160a01b0385163b6118bc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b600080866001600160a01b031685876040516118d89190611d35565b60006040518083038185875af1925050503d8060008114611915576040519150601f19603f3d011682016040523d82523d6000602084013e61191a565b606091505b509150915061192a828286611935565b979650505050505050565b606083156119445750816117fd565b8251156119545782518084602001fd5b8160405162461bcd60e51b81526004016104109190611ae6565b6001600160a01b038116811461054d57600080fd5b6000806000806080858703121561199957600080fd5b843593506020850135925060408501356119b28161196e565b915060608501356119c28161196e565b939692955090935050565b6000602082840312156119df57600080fd5b81356117fd8161196e565b600080604083850312156119fd57600080fd5b50508035926020909101359150565b600060208284031215611a1e57600080fd5b5035919050565b60008060408385031215611a3857600080fd5b8235611a438161196e565b946020939093013593505050565b60008060408385031215611a6457600080fd5b8235611a6f8161196e565b91506020830135611a7f8161196e565b809150509250929050565b60ff8116811461054d57600080fd5b600060208284031215611aab57600080fd5b81356117fd81611a8a565b60005b83811015611ad1578181015183820152602001611ab9565b83811115611ae0576000848401525b50505050565b6020815260008251806020840152611b05816040850160208701611ab6565b601f01601f19169190910160400192915050565b600080600060608486031215611b2e57600080fd5b8335611b398161196e565b92506020840135611b498161196e565b929592945050506040919091013590565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600060208284031215611bba57600080fd5b81516117fd8161196e565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215611c2157600080fd5b815180151581146117fd57600080fd5b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611ca257611ca2611c79565b500190565b600082821015611cb957611cb9611c79565b500390565b6000816000190483118215151615611cd857611cd8611c79565b500290565b600082611cfa57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611d1157600080fd5b5051919050565b600060208284031215611d2a57600080fd5b81516117fd81611a8a565b60008251611d47818460208701611ab6565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a26469706673582212208549fd2100ff79e56d7fded410ac662be502dbe16e18a815844148c99c0b5bc864736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"newShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"explanation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getTVLLimits\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_maxPerDeposit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_maxTotalDeposits\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_underlyingToken\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPerDeposit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxTotalDeposits\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setTVLLimits\",\"inputs\":[{\"name\":\"newMaxPerDeposit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"newMaxTotalDeposits\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"shares\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlying\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sharesToUnderlyingView\",\"inputs\":[{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToShares\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToSharesView\",\"inputs\":[{\"name\":\"amountUnderlying\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"underlyingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlying\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"userUnderlyingView\",\"inputs\":[{\"name\":\"user\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amountShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ExchangeRateEmitted\",\"inputs\":[{\"name\":\"rate\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPerDepositUpdated\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxTotalDepositsUpdated\",\"inputs\":[{\"name\":\"previousValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyTokenSet\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"decimals\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"BalanceExceedsMaxTotalDeposits\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxPerDepositExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NewSharesZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnderlyingToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TotalSharesExceedsMax\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WithdrawalAmountExceedsTotalDeposits\",\"inputs\":[]}]", + Bin: "0x60a060405234801561001057600080fd5b5060405161197938038061197983398101604081905261002f9161010b565b6001600160a01b0381166080528061004561004c565b505061013b565b600054610100900460ff16156100b85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610109576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011d57600080fd5b81516001600160a01b038116811461013457600080fd5b9392505050565b60805161180e61016b600039600081816102160152818161072b01528181610aa30152610b42015261180e6000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80635c975abb116100de578063ab5921e111610097578063df6fadc111610071578063df6fadc114610366578063e3dae51c14610381578063f3e7387514610394578063fabc1cbc146103a757600080fd5b8063ab5921e11461032b578063ce7c2ac214610340578063d9caed121461035357600080fd5b80635c975abb146102c857806361b01b5d146102d05780637a8b2637146102d9578063886f1195146102ec5780638c871019146103055780638f6a62401461031857600080fd5b80633a98ef391161014b578063485cc95511610125578063485cc9551461026b578063553ca5f81461027e578063595c6a67146102915780635ac86ab71461029957600080fd5b80633a98ef391461023857806343fe08b01461024f57806347e7ef241461025857600080fd5b8063019e27291461019357806310d67a2f146101a857806311c70c9d146101bb578063136439dd146101ce5780632495a599146101e157806339b70e3814610211575b600080fd5b6101a66101a1366004611465565b6103ba565b005b6101a66101b63660046114af565b61049d565b6101a66101c93660046114d3565b610551565b6101a66101dc3660046114f5565b610607565b6032546101f4906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101f47f000000000000000000000000000000000000000000000000000000000000000081565b61024160335481565b604051908152602001610208565b61024160645481565b61024161026636600461150e565b6106f7565b6101a661027936600461153a565b610848565b61024161028c3660046114af565b610916565b6101a661092a565b6102b86102a7366004611582565b6001805460ff9092161b9081161490565b6040519015158152602001610208565b600154610241565b61024160655481565b6102416102e73660046114f5565b6109f7565b6000546101f4906201000090046001600160a01b031681565b6102416103133660046114f5565b610a42565b6102416103263660046114af565b610a4d565b610333610a5b565b60405161020891906115c3565b61024161034e3660046114af565b610a7b565b6101a66103613660046115f6565b610b10565b60645460655460408051928352602083019190915201610208565b61024161038f3660046114f5565b610c30565b6102416103a23660046114f5565b610c69565b6101a66103b53660046114f5565b610c74565b600054610100900460ff16158080156103da5750600054600160ff909116105b806103f45750303b1580156103f4575060005460ff166001145b6104195760405162461bcd60e51b815260040161041090611637565b60405180910390fd5b6000805460ff19166001179055801561043c576000805461ff0019166101001790555b6104468585610d7c565b6104508383610e20565b8015610496576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105149190611685565b6001600160a01b0316336001600160a01b0316146105455760405163794821ff60e01b815260040160405180910390fd5b61054e81610f73565b50565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c89190611685565b6001600160a01b0316336001600160a01b0316146105f95760405163794821ff60e01b815260040160405180910390fd5b6106038282610d7c565b5050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610654573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067891906116a2565b61069557604051631d77d47760e21b815260040160405180910390fd5b600154818116146106b95760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6001805460009182918116036107205760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461076957604051635c427cd960e01b815260040160405180910390fd5b6107738484611011565b60335460006107846103e8836116da565b905060006103e8610793611068565b61079d91906116da565b905060006107ab87836116ed565b9050806107b88489611700565b6107c29190611717565b9550856000036107e557604051630c392ed360e11b815260040160405180910390fd5b6107ef86856116da565b60338190556f4b3b4ca85a86c47a098a223fffffffff101561082457604051632f14e8a360e11b815260040160405180910390fd5b61083d826103e860335461083891906116da565b6110da565b505050505092915050565b600054610100900460ff16158080156108685750600054600160ff909116105b806108825750303b158015610882575060005460ff166001145b61089e5760405162461bcd60e51b815260040161041090611637565b6000805460ff1916600117905580156108c1576000805461ff0019166101001790555b6108cb8383610e20565b8015610911576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b60006109246102e783610a7b565b92915050565b60005460405163237dfb4760e11b8152336004820152620100009091046001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099b91906116a2565b6109b857604051631d77d47760e21b815260040160405180910390fd5b600019600181905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6000806103e8603354610a0a91906116da565b905060006103e8610a19611068565b610a2391906116da565b905081610a308583611700565b610a3a9190611717565b949350505050565b600061092482610c30565b60006109246103a283610a7b565b60606040518060800160405280604d815260200161178c604d9139905090565b604051633d3f06c960e11b81526001600160a01b0382811660048301523060248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690637a7e0d9290604401602060405180830381865afa158015610aec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109249190611739565b60018054600290811603610b375760405163840a48d560e01b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610b8057604051635c427cd960e01b815260040160405180910390fd5b610b8b848484611126565b60335480831115610baf57604051630b469df360e41b815260040160405180910390fd5b6000610bbd6103e8836116da565b905060006103e8610bcc611068565b610bd691906116da565b9050600082610be58784611700565b610bef9190611717565b9050610bfb86856116ed565b603355610c1b610c0b82846116ed565b6103e860335461083891906116da565b610c26888883611154565b5050505050505050565b6000806103e8603354610c4391906116da565b905060006103e8610c52611068565b610c5c91906116da565b905080610a308386611700565b6000610924826109f7565b600060029054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ceb9190611685565b6001600160a01b0316336001600160a01b031614610d1c5760405163794821ff60e01b815260040160405180910390fd5b600154198119600154191614610d455760405163c61dca5d60e01b815260040160405180910390fd5b600181905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016106ec565b60645460408051918252602082018490527ff97ed4e083acac67830025ecbc756d8fe847cdbdca4cee3fe1e128e98b54ecb5910160405180910390a160655460408051918252602082018390527f6ab181e0440bfbf4bacdf2e99674735ce6638005490688c5f994f5399353e452910160405180910390a180821115610e155760405163052b07b760e21b815260040160405180910390fd5b606491909155606555565b600054610100900460ff16610e8b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610410565b603280546001600160a01b0319166001600160a01b038416179055610eb1816000611168565b7f1c540707b00eb5427b6b774fc799d756516a54aee108b64b327acc55af557507603260009054906101000a90046001600160a01b0316836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4a9190611752565b604080516001600160a01b03909316835260ff9091166020830152015b60405180910390a15050565b6001600160a01b038116610f9a576040516339b190bb60e11b815260040160405180910390fd5b600054604080516001600160a01b03620100009093048316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1600080546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6064548111156110345760405163052b07b760e21b815260040160405180910390fd5b60655461103f611068565b111561105e5760405163d86bae6760e01b815260040160405180910390fd5b61060382826111ef565b6032546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156110b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d59190611739565b905090565b7fd2494f3479e5da49d386657c292c610b5b01df313d07c62eb0cfa49924a31be88161110e84670de0b6b3a7640000611700565b6111189190611717565b604051908152602001610f67565b6032546001600160a01b0383811691161461091157604051630312abdd60e61b815260040160405180910390fd5b6109116001600160a01b038316848361121d565b6000546201000090046001600160a01b031615801561118f57506001600160a01b03821615155b6111ac576040516339b190bb60e11b815260040160405180910390fd5b600181905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a261060382610f73565b6032546001600160a01b0383811691161461060357604051630312abdd60e61b815260040160405180910390fd5b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490840152610911928692916000916112ad91851690849061132d565b90508051600014806112ce5750808060200190518101906112ce91906116a2565b6109115760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610410565b6060610a3a848460008585600080866001600160a01b03168587604051611354919061176f565b60006040518083038185875af1925050503d8060008114611391576040519150601f19603f3d011682016040523d82523d6000602084013e611396565b606091505b50915091506113a7878383876113b2565b979650505050505050565b6060831561142157825160000361141a576001600160a01b0385163b61141a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610410565b5081610a3a565b610a3a83838151156114365781518083602001fd5b8060405162461bcd60e51b815260040161041091906115c3565b6001600160a01b038116811461054e57600080fd5b6000806000806080858703121561147b57600080fd5b8435935060208501359250604085013561149481611450565b915060608501356114a481611450565b939692955090935050565b6000602082840312156114c157600080fd5b81356114cc81611450565b9392505050565b600080604083850312156114e657600080fd5b50508035926020909101359150565b60006020828403121561150757600080fd5b5035919050565b6000806040838503121561152157600080fd5b823561152c81611450565b946020939093013593505050565b6000806040838503121561154d57600080fd5b823561155881611450565b9150602083013561156881611450565b809150509250929050565b60ff8116811461054e57600080fd5b60006020828403121561159457600080fd5b81356114cc81611573565b60005b838110156115ba5781810151838201526020016115a2565b50506000910152565b60208152600082518060208401526115e281604085016020870161159f565b601f01601f19169190910160400192915050565b60008060006060848603121561160b57600080fd5b833561161681611450565b9250602084013561162681611450565b929592945050506040919091013590565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006020828403121561169757600080fd5b81516114cc81611450565b6000602082840312156116b457600080fd5b815180151581146114cc57600080fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610924576109246116c4565b81810381811115610924576109246116c4565b8082028115828204841417610924576109246116c4565b60008261173457634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561174b57600080fd5b5051919050565b60006020828403121561176457600080fd5b81516114cc81611573565b6000825161178181846020870161159f565b919091019291505056fe4261736520537472617465677920696d706c656d656e746174696f6e20746f20696e68657269742066726f6d20666f72206d6f726520636f6d706c657820696d706c656d656e746174696f6e73a2646970667358221220157a20e01838d39b4218a085891d3df22a8b6658ac7d57efbba7bf84d229193964736f6c634300081b0033", } // StrategyBaseTVLLimitsABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StrategyFactory/binding.go b/pkg/bindings/StrategyFactory/binding.go index cd0633c74..9b8bc249d 100644 --- a/pkg/bindings/StrategyFactory/binding.go +++ b/pkg/bindings/StrategyFactory/binding.go @@ -31,8 +31,8 @@ var ( // StrategyFactoryMetaData contains all meta data concerning the StrategyFactory contract. var StrategyFactoryMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"blacklistTokens\",\"inputs\":[{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"_initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_strategyBeacon\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isBlacklisted\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620024ae380380620024ae833981016040819052620000349162000114565b6001600160a01b0381166080526200004b62000052565b5062000146565b603354610100900460ff1615620000bf5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60335460ff908116101562000112576033805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200012757600080fd5b81516001600160a01b03811681146200013f57600080fd5b9392505050565b608051612329620001856000396000818161019701528181610829015281816108cc01528181610a1d01528181610d4a015261111101526123296000f3fe60806040523480156200001157600080fd5b5060043610620001455760003560e01c80636b9b622911620000bb578063f0062d9a116200007a578063f0062d9a14620002e1578063f2fde38b14620002f5578063fabc1cbc146200030c578063fe38b32d1462000323578063fe575a87146200033a57600080fd5b80636b9b62291462000283578063715018a6146200029a578063886f119514620002a45780638da5cb5b14620002b8578063be20309414620002ca57600080fd5b8063581dfd651162000108578063581dfd6514620001ed578063595c6a6714620002195780635ac86ab714620002235780635c975abb146200025a578063697d54b4146200026c57600080fd5b806310d67a2f146200014a578063136439dd146200016357806323103c41146200017a57806339b70e3814620001915780634e5a426314620001d6575b600080fd5b620001616200015b366004620014d8565b62000360565b005b6200016162000174366004620014ff565b62000424565b620001616200018b36600462001568565b6200056b565b620001b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b62000161620001e7366004620015bd565b6200089b565b620001b9620001fe366004620014d8565b6001602052600090815260409020546001600160a01b031681565b620001616200092f565b6200024962000234366004620015fb565b609954600160ff9092169190911b9081161490565b6040519015158152602001620001cd565b609954604051908152602001620001cd565b620001616200027d36600462001620565b620009fc565b620001b962000294366004620014d8565b62000a5a565b6200016162000dc1565b609854620001b9906001600160a01b031681565b6066546001600160a01b0316620001b9565b62000161620002db36600462001693565b62000dd9565b600054620001b9906001600160a01b031681565b6200016162000306366004620014d8565b62000f0f565b620001616200031d366004620014ff565b62000f8b565b620001616200033436600462001568565b620010f0565b620002496200034b366004620014d8565b60026020526000908152604090205460ff1681565b609860009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003da9190620016ed565b6001600160a01b0316336001600160a01b031614620004165760405162461bcd60e51b81526004016200040d906200170d565b60405180910390fd5b62000421816200114a565b50565b60985460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa1580156200046d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000493919062001757565b620004b25760405162461bcd60e51b81526004016200040d9062001777565b609954818116146200052d5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c697479000000000000000060648201526084016200040d565b609981905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6200057562001243565b60008167ffffffffffffffff811115620005935762000593620017bf565b604051908082528060200260200182016040528015620005bd578160200160208202803683370190505b5090506000805b83811015620008075760026000868684818110620005e657620005e6620017d5565b9050602002016020810190620005fd9190620014d8565b6001600160a01b0316815260208101919091526040016000205460ff16156200069b5760405162461bcd60e51b815260206004820152604360248201527f5374726174656779466163746f72792e626c61636b6c697374546f6b656e733a60448201527f2043616e6e6f7420626c61636b6c697374206465706c6f79656420737472617460648201526265677960e81b608482015260a4016200040d565b600160026000878785818110620006b657620006b6620017d5565b9050602002016020810190620006cd9190620014d8565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f75519c51f39873ec0e27dd3bbc09549e4865a113f505393fb9eab5898f6418b38585838181106200072b576200072b620017d5565b9050602002016020810190620007429190620014d8565b6040516001600160a01b03909116815260200160405180910390a1600060016000878785818110620007785762000778620017d5565b90506020020160208101906200078f9190620014d8565b6001600160a01b0390811682526020820192909252604001600020541690508015620007f35780848481518110620007cb57620007cb620017d5565b6001600160a01b039092166020928302919091019091015282620007ef81620017eb565b9350505b50620007ff81620017eb565b9050620005c4565b50808252801562000895576040516316bb16b760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5d8b5b890620008609085906004016200185b565b600060405180830381600087803b1580156200087b57600080fd5b505af115801562000890573d6000803e3d6000fd5b505050505b50505050565b620008a562001243565b604051634e5a426360e01b81526001600160a01b03838116600483015282151560248301527f00000000000000000000000000000000000000000000000000000000000000001690634e5a4263906044015b600060405180830381600087803b1580156200091257600080fd5b505af115801562000927573d6000803e3d6000fd5b505050505050565b60985460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801562000978573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200099e919062001757565b620009bd5760405162461bcd60e51b81526004016200040d9062001777565b600019609981905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b62000a0662001243565b60405163df5b354760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063df5b35479062000860908790879087908790600401620018b2565b60995460009081906001908116141562000ab75760405162461bcd60e51b815260206004820152601960248201527f5061757361626c653a20696e646578206973207061757365640000000000000060448201526064016200040d565b6001600160a01b03831660009081526002602052604090205460ff161562000b485760405162461bcd60e51b815260206004820152603760248201527f5374726174656779466163746f72792e6465706c6f794e65775374726174656760448201527f793a20546f6b656e20697320626c61636b6c697374656400000000000000000060648201526084016200040d565b6001600160a01b03838116600090815260016020526040902054161562000be65760405162461bcd60e51b8152602060048201526044602482018190527f5374726174656779466163746f72792e6465706c6f794e657753747261746567908201527f793a20537472617465677920616c72656164792065786973747320666f72207460648201526337b5b2b760e11b608482015260a4016200040d565b600080546098546040516001600160a01b038781166024830152918216604482015291169063485cc95560e01b9060640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905162000c5690620014b4565b62000c6392919062001916565b604051809103906000f08015801562000c80573d6000803e3d6000fd5b50905062000c8f84826200129f565b604080516001808252818301909252600091602080830190803683375050604080516001808252818301909252929350600092915060208083019080368337019050509050828260008151811062000ceb5762000ceb620017d5565b60200260200101906001600160a01b031690816001600160a01b03168152505060008160008151811062000d235762000d23620017d5565b9115156020928302919091019091015260405163df5b354760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063df5b35479062000d8390859085906004016200197e565b600060405180830381600087803b15801562000d9e57600080fd5b505af115801562000db3573d6000803e3d6000fd5b509498975050505050505050565b62000dcb62001243565b62000dd760006200130a565b565b603354610100900460ff161580801562000dfa5750603354600160ff909116105b8062000e165750303b15801562000e16575060335460ff166001145b62000e7b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200040d565b6033805460ff19166001179055801562000e9f576033805461ff0019166101001790555b62000eaa856200130a565b62000eb684846200135c565b62000ec1826200144b565b801562000f08576033805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b62000f1962001243565b6001600160a01b03811662000f805760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200040d565b62000421816200130a565b609860009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000fdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010059190620016ed565b6001600160a01b0316336001600160a01b031614620010385760405162461bcd60e51b81526004016200040d906200170d565b609954198119609954191614620010b85760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c697479000000000000000060648201526084016200040d565b609981905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200162000560565b620010fa62001243565b6040516316bb16b760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5d8b5b890620008f79085908590600401620019db565b6001600160a01b038116620011da5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a4016200040d565b609854604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1609880546001600160a01b0319166001600160a01b0392909216919091179055565b6066546001600160a01b0316331462000dd75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200040d565b6001600160a01b0382811660008181526001602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527f6852a55230ef089d785bce7ffbf757985de34026df90a87d7b4a6e56f95d251f910160405180910390a15050565b606680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6098546001600160a01b03161580156200137e57506001600160a01b03821615155b620014025760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a4016200040d565b609981905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a262001447826200114a565b5050565b600054604080516001600160a01b03928316815291831660208301527fe21755962a7d7e100b59b9c3e4d4b54085b146313719955efb6a7a25c5c7feee910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6108fa80620019fa83390190565b6001600160a01b03811681146200042157600080fd5b600060208284031215620014eb57600080fd5b8135620014f881620014c2565b9392505050565b6000602082840312156200151257600080fd5b5035919050565b60008083601f8401126200152c57600080fd5b50813567ffffffffffffffff8111156200154557600080fd5b6020830191508360208260051b85010111156200156157600080fd5b9250929050565b600080602083850312156200157c57600080fd5b823567ffffffffffffffff8111156200159457600080fd5b620015a28582860162001519565b90969095509350505050565b80151581146200042157600080fd5b60008060408385031215620015d157600080fd5b8235620015de81620014c2565b91506020830135620015f081620015ae565b809150509250929050565b6000602082840312156200160e57600080fd5b813560ff81168114620014f857600080fd5b600080600080604085870312156200163757600080fd5b843567ffffffffffffffff808211156200165057600080fd5b6200165e8883890162001519565b909650945060208701359150808211156200167857600080fd5b50620016878782880162001519565b95989497509550505050565b60008060008060808587031215620016aa57600080fd5b8435620016b781620014c2565b93506020850135620016c981620014c2565b9250604085013591506060850135620016e281620014c2565b939692955090935050565b6000602082840312156200170057600080fd5b8151620014f881620014c2565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b6000602082840312156200176a57600080fd5b8151620014f881620015ae565b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006000198214156200180e57634e487b7160e01b600052601160045260246000fd5b5060010190565b600081518084526020808501945080840160005b83811015620018505781516001600160a01b03168752958201959082019060010162001829565b509495945050505050565b602081526000620014f8602083018462001815565b8183526000602080850194508260005b85811015620018505781356200189681620014c2565b6001600160a01b03168752958201959082019060010162001880565b604081526000620018c860408301868862001870565b8281036020848101919091528482528591810160005b8681101562001909578335620018f481620015ae565b151582529282019290820190600101620018de565b5098975050505050505050565b60018060a01b038316815260006020604081840152835180604085015260005b81811015620019545785810183015185820160600152820162001936565b8181111562001967576000606083870101525b50601f01601f191692909201606001949350505050565b60408152600062001993604083018562001815565b82810360208481019190915284518083528582019282019060005b81811015620019ce578451151583529383019391830191600101620019ae565b5090979650505050505050565b602081526000620019f160208301848662001870565b94935050505056fe60806040526040516108fa3803806108fa83398101604081905261002291610456565b61002e82826000610035565b5050610580565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610516565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610516565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108d3602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b60606001600160a01b0384163b6103495760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610169565b600080856001600160a01b0316856040516103649190610531565b600060405180830381855af49150503d806000811461039f576040519150601f19603f3d011682016040523d82523d6000602084013e6103a4565b606091505b5090925090506103b58282866103bf565b9695505050505050565b606083156103ce5750816102c8565b8251156103de5782518084602001fd5b8160405162461bcd60e51b8152600401610169919061054d565b80516001600160a01b038116811461040f57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044557818101518382015260200161042d565b838111156100f95750506000910152565b6000806040838503121561046957600080fd5b610472836103f8565b60208401519092506001600160401b038082111561048f57600080fd5b818501915085601f8301126104a357600080fd5b8151818111156104b5576104b5610414565b604051601f8201601f19908116603f011681019083821181831017156104dd576104dd610414565b816040528281528860208487010111156104f657600080fd5b61050783602083016020880161042a565b80955050505050509250929050565b60006020828403121561052857600080fd5b6102c8826103f8565b6000825161054381846020870161042a565b9190910192915050565b602081526000825180602084015261056c81604085016020870161042a565b601f01601f19169190910160400192915050565b6103448061058f6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102e860279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061023f565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b60606001600160a01b0384163b6101915760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516101ac9190610298565b600060405180830381855af49150503d80600081146101e7576040519150601f19603f3d011682016040523d82523d6000602084013e6101ec565b606091505b50915091506101fc828286610206565b9695505050505050565b6060831561021557508161004e565b8251156102255782518084602001fd5b8160405162461bcd60e51b815260040161018891906102b4565b60006020828403121561025157600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028357818101518382015260200161026b565b83811115610292576000848401525b50505050565b600082516102aa818460208701610268565b9190910192915050565b60208152600082518060208401526102d3816040850160208701610268565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206225174df4b558257f66ac9aa53b52c29cdd29a561b03eb6d75a95018aff3e5864736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212205ec4c51d66eda3a5cc6c4836684b038a334a62fe205ea7e8aaa91c0a44cd1bb364736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_strategyManager\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"blacklistTokens\",\"inputs\":[{\"name\":\"tokens\",\"type\":\"address[]\",\"internalType\":\"contractIERC20[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"_initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_strategyBeacon\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isBlacklisted\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategyManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyBlacklisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BlacklistedToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyAlreadyExists\",\"inputs\":[]}]", + Bin: "0x60a060405234801561001057600080fd5b50604051611dfe380380611dfe83398101604081905261002f91610109565b6001600160a01b03811660805261004461004a565b50610139565b603354610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60335460ff90811614610107576033805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011b57600080fd5b81516001600160a01b038116811461013257600080fd5b9392505050565b608051611c8761017760003960008181610171015281816106d901528181610776015281816108be01528181610aee0152610e400152611c876000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80636b9b6229116100ad578063f0062d9a11610071578063f0062d9a1461029d578063f2fde38b146102b0578063fabc1cbc146102c3578063fe38b32d146102d6578063fe575a87146102e957600080fd5b80636b9b62291461024b578063715018a61461025e578063886f1195146102665780638da5cb5b14610279578063be2030941461028a57600080fd5b8063581dfd65116100f4578063581dfd65146101c3578063595c6a67146101ec5780635ac86ab7146101f45780635c975abb14610227578063697d54b41461023857600080fd5b806310d67a2f14610131578063136439dd1461014657806323103c411461015957806339b70e381461016c5780634e5a4263146101b0575b600080fd5b61014461013f36600461112e565b61030c565b005b610144610154366004611152565b6103c0565b6101446101673660046111b7565b6104ab565b6101937f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101446101be366004611207565b610747565b6101936101d136600461112e565b6001602052600090815260409020546001600160a01b031681565b6101446107d7565b610217610202366004611240565b609954600160ff9092169190911b9081161490565b60405190151581526020016101a7565b6099546040519081526020016101a7565b610144610246366004611263565b61089f565b61019361025936600461112e565b6108f9565b610144610b61565b609854610193906001600160a01b031681565b6066546001600160a01b0316610193565b6101446102983660046112d4565b610b75565b600054610193906001600160a01b031681565b6101446102be36600461112e565b610ca3565b6101446102d1366004611152565b610d19565b6101446102e43660046111b7565b610e21565b6102176102f736600461112e565b60026020526000908152604090205460ff1681565b609860009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561035f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103839190611327565b6001600160a01b0316336001600160a01b0316146103b45760405163794821ff60e01b815260040160405180910390fd5b6103bd81610e77565b50565b60985460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042c9190611344565b61044957604051631d77d47760e21b815260040160405180910390fd5b6099548181161461046d5760405163c61dca5d60e01b815260040160405180910390fd5b609981905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6104b3610f07565b60008167ffffffffffffffff8111156104ce576104ce611361565b6040519080825280602002602001820160405280156104f7578160200160208202803683370190505b5090506000805b838110156106b8576002600086868481811061051c5761051c611377565b9050602002016020810190610531919061112e565b6001600160a01b0316815260208101919091526040016000205460ff161561056c5760405163f53de75f60e01b815260040160405180910390fd5b60016002600087878581811061058457610584611377565b9050602002016020810190610599919061112e565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f75519c51f39873ec0e27dd3bbc09549e4865a113f505393fb9eab5898f6418b38585838181106105f4576105f4611377565b9050602002016020810190610609919061112e565b6040516001600160a01b03909116815260200160405180910390a160006001600087878581811061063c5761063c611377565b9050602002016020810190610651919061112e565b6001600160a01b03908116825260208201929092526040016000205416905080156106af578084848151811061068957610689611377565b6001600160a01b0390921660209283029190910190910152826106ab8161138d565b9350505b506001016104fe565b508082528015610741576040516316bb16b760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5d8b5b89061070e9085906004016113f9565b600060405180830381600087803b15801561072857600080fd5b505af115801561073c573d6000803e3d6000fd5b505050505b50505050565b61074f610f07565b604051634e5a426360e01b81526001600160a01b03838116600483015282151560248301527f00000000000000000000000000000000000000000000000000000000000000001690634e5a4263906044015b600060405180830381600087803b1580156107bb57600080fd5b505af11580156107cf573d6000803e3d6000fd5b505050505050565b60985460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561081f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108439190611344565b61086057604051631d77d47760e21b815260040160405180910390fd5b600019609981905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6108a7610f07565b60405163df5b354760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063df5b35479061070e90879087908790879060040161144c565b60995460009081906001908116036109245760405163840a48d560e01b815260040160405180910390fd5b6001600160a01b03831660009081526002602052604090205460ff161561095e5760405163091867bd60e11b815260040160405180910390fd5b6001600160a01b0383811660009081526001602052604090205416156109975760405163c45546f760e01b815260040160405180910390fd5b600080546098546040516001600160a01b038781166024830152918216604482015291169063485cc95560e01b9060640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610a059061110c565b610a109291906114aa565b604051809103906000f080158015610a2c573d6000803e3d6000fd5b509050610a398482610f61565b6040805160018082528183019092526000916020808301908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090508282600081518110610a9257610a92611377565b60200260200101906001600160a01b031690816001600160a01b031681525050600081600081518110610ac757610ac7611377565b9115156020928302919091019091015260405163df5b354760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063df5b354790610b259085908590600401611507565b600060405180830381600087803b158015610b3f57600080fd5b505af1158015610b53573d6000803e3d6000fd5b509498975050505050505050565b610b69610f07565b610b736000610fcc565b565b603354610100900460ff1615808015610b955750603354600160ff909116105b80610baf5750303b158015610baf575060335460ff166001145b610c175760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6033805460ff191660011790558015610c3a576033805461ff0019166101001790555b610c4385610fcc565b610c4d848461101e565b610c56826110a3565b8015610c9c576033805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610cab610f07565b6001600160a01b038116610d105760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c0e565b6103bd81610fcc565b609860009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d909190611327565b6001600160a01b0316336001600160a01b031614610dc15760405163794821ff60e01b815260040160405180910390fd5b609954198119609954191614610dea5760405163c61dca5d60e01b815260040160405180910390fd5b609981905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020016104a0565b610e29610f07565b6040516316bb16b760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5d8b5b8906107a19085908590600401611563565b6001600160a01b038116610e9e576040516339b190bb60e11b815260040160405180910390fd5b609854604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1609880546001600160a01b0319166001600160a01b0392909216919091179055565b6066546001600160a01b03163314610b735760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c0e565b6001600160a01b0382811660008181526001602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527f6852a55230ef089d785bce7ffbf757985de34026df90a87d7b4a6e56f95d251f910160405180910390a15050565b606680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6098546001600160a01b031615801561103f57506001600160a01b03821615155b61105c576040516339b190bb60e11b815260040160405180910390fd5b609981905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a261109f82610e77565b5050565b600054604080516001600160a01b03928316815291831660208301527fe21755962a7d7e100b59b9c3e4d4b54085b146313719955efb6a7a25c5c7feee910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6106d28061158083390190565b6001600160a01b03811681146103bd57600080fd5b60006020828403121561114057600080fd5b813561114b81611119565b9392505050565b60006020828403121561116457600080fd5b5035919050565b60008083601f84011261117d57600080fd5b50813567ffffffffffffffff81111561119557600080fd5b6020830191508360208260051b85010111156111b057600080fd5b9250929050565b600080602083850312156111ca57600080fd5b823567ffffffffffffffff8111156111e157600080fd5b6111ed8582860161116b565b90969095509350505050565b80151581146103bd57600080fd5b6000806040838503121561121a57600080fd5b823561122581611119565b91506020830135611235816111f9565b809150509250929050565b60006020828403121561125257600080fd5b813560ff8116811461114b57600080fd5b6000806000806040858703121561127957600080fd5b843567ffffffffffffffff81111561129057600080fd5b61129c8782880161116b565b909550935050602085013567ffffffffffffffff8111156112bc57600080fd5b6112c88782880161116b565b95989497509550505050565b600080600080608085870312156112ea57600080fd5b84356112f581611119565b9350602085013561130581611119565b925060408501359150606085013561131c81611119565b939692955090935050565b60006020828403121561133957600080fd5b815161114b81611119565b60006020828403121561135657600080fd5b815161114b816111f9565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000600182016113ad57634e487b7160e01b600052601160045260246000fd5b5060010190565b600081518084526020840193506020830160005b828110156113ef5781516001600160a01b03168652602095860195909101906001016113c8565b5093949350505050565b60208152600061114b60208301846113b4565b81835260208301925060008160005b848110156113ef57813561142e81611119565b6001600160a01b03168652602095860195919091019060010161141b565b60408152600061146060408301868861140c565b82810360208085019190915284825285910160005b8581101561149e578235611488816111f9565b1515825260209283019290910190600101611475565b50979650505050505050565b60018060a01b0383168152604060208201526000825180604084015260005b818110156114e657602081860181015160608684010152016114c9565b506000606082850101526060601f19601f8301168401019150509392505050565b60408152600061151a60408301856113b4565b828103602084015280845180835260208301915060208601925060005b818110156115575783511515835260209384019390920191600101611537565b50909695505050505050565b60208152600061157760208301848661140c565b94935050505056fe60806040526040516106d23803806106d283398101604081905261002291610420565b61002e82826000610035565b5050610550565b61003e836100f6565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100f1576100ef836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e991906104e6565b8361027a565b505b505050565b6001600160a01b0381163b6101605760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101d4816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c591906104e6565b6001600160a01b03163b151590565b6102395760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610157565b7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392909216919091179055565b606061029f83836040518060600160405280602781526020016106ab602791396102a6565b9392505050565b6060600080856001600160a01b0316856040516102c39190610501565b600060405180830381855af49150503d80600081146102fe576040519150601f19603f3d011682016040523d82523d6000602084013e610303565b606091505b5090925090506103158683838761031f565b9695505050505050565b6060831561038e578251600003610387576001600160a01b0385163b6103875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610157565b5081610398565b61039883836103a0565b949350505050565b8151156103b05781518083602001fd5b8060405162461bcd60e51b8152600401610157919061051d565b80516001600160a01b03811681146103e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156104175781810151838201526020016103ff565b50506000910152565b6000806040838503121561043357600080fd5b61043c836103ca565b60208401519092506001600160401b0381111561045857600080fd5b8301601f8101851361046957600080fd5b80516001600160401b03811115610482576104826103e6565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104b0576104b06103e6565b6040528181528282016020018710156104c857600080fd5b6104d98260208301602086016103fc565b8093505050509250929050565b6000602082840312156104f857600080fd5b61029f826103ca565b600082516105138184602087016103fc565b9190910192915050565b602081526000825180602084015261053c8160408501602087016103fc565b601f01601f19169190910160400192915050565b61014c8061055f6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610029565b6100c2565b565b600061005c7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100bd91906100e6565b905090565b3660008037600080366000845af43d6000803e8080156100e1573d6000f35b3d6000fd5b6000602082840312156100f857600080fd5b81516001600160a01b038116811461010f57600080fd5b939250505056fea2646970667358221220cb944d3abd4df8c3f6ee344d91680dd11bc4b5cd56dbc90431015960711da23464736f6c634300081b0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c9d8514d0938ade8407b3ea7be5e1cd523f80a5a594143de4e74eb1c5765188264736f6c634300081b0033", } // StrategyFactoryABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StrategyFactoryStorage/binding.go b/pkg/bindings/StrategyFactoryStorage/binding.go index 3a164f025..e7c06ebae 100644 --- a/pkg/bindings/StrategyFactoryStorage/binding.go +++ b/pkg/bindings/StrategyFactoryStorage/binding.go @@ -31,7 +31,7 @@ var ( // StrategyFactoryStorageMetaData contains all meta data concerning the StrategyFactoryStorage contract. var StrategyFactoryStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isBlacklisted\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"deployNewStrategy\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"newStrategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deployedStrategies\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isBlacklisted\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"strategyBeacon\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIBeacon\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"whitelistStrategies\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"StrategyBeaconModified\",\"inputs\":[{\"name\":\"previousBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"},{\"name\":\"newBeacon\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIBeacon\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategySetForToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenBlacklisted\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyBlacklisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BlacklistedToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyAlreadyExists\",\"inputs\":[]}]", } // StrategyFactoryStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StrategyManager/binding.go b/pkg/bindings/StrategyManager/binding.go index 65ecc0fdd..b2e46d5df 100644 --- a/pkg/bindings/StrategyManager/binding.go +++ b/pkg/bindings/StrategyManager/binding.go @@ -31,8 +31,8 @@ var ( // StrategyManagerMetaData contains all meta data concerning the StrategyManager contract. var StrategyManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegation\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEPOSIT_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"initialStrategyWhitelister\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setStrategyWhitelister\",\"inputs\":[{\"name\":\"newStrategyWhitelister\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyList\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false}]", - Bin: "0x6101006040523480156200001257600080fd5b506040516200338a3803806200338a833981016040819052620000359162000140565b6001600160a01b0380841660805280831660a052811660c0526200005862000065565b50504660e0525062000194565b600054610100900460ff1615620000d25760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000125576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146200013d57600080fd5b50565b6000806000606084860312156200015657600080fd5b8351620001638162000127565b6020850151909350620001768162000127565b6040850151909250620001898162000127565b809150509250925092565b60805160a05160c05160e0516131a0620001ea60003960006114bb0152600061046e0152600061028501526000818161051a01528181610b8401528181610ed101528181610f250152611a7101526131a06000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c80638da5cb5b1161011a578063c6656702116100ad578063df5cf7231161007c578063df5cf72314610515578063e7a050aa1461053c578063f2fde38b1461054f578063f698da2514610562578063fabc1cbc1461056a57600080fd5b8063c6656702146104c9578063cbc2bd62146104dc578063cf756fdf146104ef578063df5b35471461050257600080fd5b8063b1344271116100e9578063b134427114610469578063b5d8b5b814610490578063c4623ea1146104a3578063c608c7f3146104b657600080fd5b80638da5cb5b1461040157806394f649dd14610412578063967fc0d2146104335780639b4da03d1461044657600080fd5b80635ac86ab71161019d5780637a7e0d921161016c5780637a7e0d92146103675780637ecebe0014610392578063886f1195146103b25780638b8aac3c146103c55780638c80d4e5146103ee57600080fd5b80635ac86ab7146103015780635c975abb14610334578063663c1de41461033c578063715018a61461035f57600080fd5b80634665bcda116101d95780634665bcda1461028057806348825e94146102bf5780634e5a4263146102e6578063595c6a67146102f957600080fd5b806310d67a2f1461020b578063136439dd1461022057806320606b701461023357806332e89ace1461026d575b600080fd5b61021e6102193660046129e8565b61057d565b005b61021e61022e366004612a05565b610639565b61025a7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b61025a61027b366004612a34565b610778565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610264565b61025a7f4337f82d142e41f2a8c10547cd8c859bddb92262a61058e77842e24d9dea922481565b61021e6102f4366004612b3d565b610a66565b61021e610a9e565b61032461030f366004612b76565b609854600160ff9092169190911b9081161490565b6040519015158152602001610264565b60985461025a565b61032461034a3660046129e8565b60d16020526000908152604090205460ff1681565b61021e610b65565b61025a610375366004612b99565b60cd60209081526000928352604080842090915290825290205481565b61025a6103a03660046129e8565b60ca6020526000908152604090205481565b6097546102a7906001600160a01b031681565b61025a6103d33660046129e8565b6001600160a01b0316600090815260ce602052604090205490565b61021e6103fc366004612bc7565b610b79565b6033546001600160a01b03166102a7565b6104256104203660046129e8565b610bd2565b604051610264929190612c08565b60cb546102a7906001600160a01b031681565b6103246104543660046129e8565b60d36020526000908152604090205460ff1681565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b61021e61049e366004612cd1565b610d52565b61021e6104b1366004612d13565b610ec6565b61021e6104c4366004612d64565b610f1a565b61021e6104d73660046129e8565b610fd2565b6102a76104ea366004612db7565b610fe3565b61021e6104fd366004612d13565b61101b565b61021e610510366004612de3565b61114f565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b61025a61054a366004612bc7565b611378565b61021e61055d3660046129e8565b611441565b61025a6114b7565b61021e610578366004612a05565b6114f5565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f49190612e4f565b6001600160a01b0316336001600160a01b03161461062d5760405162461bcd60e51b815260040161062490612e6c565b60405180910390fd5b61063681611651565b50565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610681573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a59190612eb6565b6106c15760405162461bcd60e51b815260040161062490612ed3565b6098548181161461073a5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e70617573653a20696e76616c696420617474656d70742060448201527f746f20756e70617573652066756e6374696f6e616c69747900000000000000006064820152608401610624565b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b6098546000908190600190811614156107cf5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610624565b600260655414156108225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610624565b60026065556001600160a01b038816600090815260d3602052604090205460ff16156108c95760405162461bcd60e51b815260206004820152604a60248201527f53747261746567794d616e616765722e6465706f736974496e746f537472617460448201527f656779576974685369676e61747572653a207468697264207472616e736665726064820152691cc8191a5cd8589b195960b21b608482015260a401610624565b4284101561094b5760405162461bcd60e51b815260206004820152604360248201527f53747261746567794d616e616765722e6465706f736974496e746f537472617460448201527f656779576974685369676e61747572653a207369676e617475726520657870696064820152621c995960ea1b608482015260a401610624565b6001600160a01b03858116600081815260ca602090815260408083205481517f4337f82d142e41f2a8c10547cd8c859bddb92262a61058e77842e24d9dea922493810193909352908201939093528b84166060820152928a16608084015260a0830189905260c0830182905260e0830187905290916101000160408051601f1981840301815291815281516020928301206001600160a01b038a16600090815260ca9093529082206001850190559150610a036114b7565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050610a46888288611748565b610a52888c8c8c611907565b60016065559b9a5050505050505050505050565b60cb546001600160a01b03163314610a905760405162461bcd60e51b815260040161062490612f1b565b610a9a8282611ad6565b5050565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190612eb6565b610b265760405162461bcd60e51b815260040161062490612ed3565b600019609881905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b610b6d611b44565b610b776000611b9e565b565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610bc15760405162461bcd60e51b815260040161062490612f85565b610bcc838383611bf0565b50505050565b6001600160a01b038116600090815260ce60205260408120546060918291908167ffffffffffffffff811115610c0a57610c0a612a1e565b604051908082528060200260200182016040528015610c33578160200160208202803683370190505b50905060005b82811015610cc4576001600160a01b038616600090815260cd6020908152604080832060ce9092528220805491929184908110610c7857610c78612fe3565b60009182526020808320909101546001600160a01b031683528201929092526040019020548251839083908110610cb157610cb1612fe3565b6020908102919091010152600101610c39565b5060ce6000866001600160a01b03166001600160a01b031681526020019081526020016000208181805480602002602001604051908101604052809291908181526020018280548015610d4057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d22575b50505050509150935093505050915091565b60cb546001600160a01b03163314610d7c5760405162461bcd60e51b815260040161062490612f1b565b8060005b81811015610bcc5760d16000858584818110610d9e57610d9e612fe3565b9050602002016020810190610db391906129e8565b6001600160a01b0316815260208101919091526040016000205460ff1615610ebe57600060d16000868685818110610ded57610ded612fe3565b9050602002016020810190610e0291906129e8565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f4074413b4b443e4e58019f2855a8765113358c7c72e39509c6af45fc0f5ba030848483818110610e5d57610e5d612fe3565b9050602002016020810190610e7291906129e8565b6040516001600160a01b03909116815260200160405180910390a1610ebe848483818110610ea257610ea2612fe3565b9050602002016020810190610eb791906129e8565b6000611ad6565b600101610d80565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f0e5760405162461bcd60e51b815260040161062490612f85565b610bcc84848484611d4c565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f625760405162461bcd60e51b815260040161062490612f85565b604051636ce5768960e11b81526001600160a01b03858116600483015282811660248301526044820184905284169063d9caed1290606401600060405180830381600087803b158015610fb457600080fd5b505af1158015610fc8573d6000803e3d6000fd5b5050505050505050565b610fda611b44565b61063681611fd9565b60ce6020528160005260406000208181548110610fff57600080fd5b6000918252602090912001546001600160a01b03169150829050565b600054610100900460ff161580801561103b5750600054600160ff909116105b806110555750303b158015611055575060005460ff166001145b6110b85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610624565b6000805460ff1916600117905580156110db576000805461ff0019166101001790555b6110e3612042565b60c9556110f083836120d9565b6110f985611b9e565b61110284611fd9565b8015611148576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b60cb546001600160a01b031633146111795760405162461bcd60e51b815260040161062490612f1b565b8281146112025760405162461bcd60e51b815260206004820152604b60248201527f53747261746567794d616e616765722e61646453747261746567696573546f4460448201527f65706f73697457686974656c6973743a206172726179206c656e67746873206460648201526a0de40dcdee840dac2e8c6d60ab1b608482015260a401610624565b8260005b818110156113705760d1600087878481811061122457611224612fe3565b905060200201602081019061123991906129e8565b6001600160a01b0316815260208101919091526040016000205460ff1661136857600160d1600088888581811061127257611272612fe3565b905060200201602081019061128791906129e8565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f0c35b17d91c96eb2751cd456e1252f42a386e524ef9ff26ecc9950859fdc04fe8686838181106112e2576112e2612fe3565b90506020020160208101906112f791906129e8565b6040516001600160a01b03909116815260200160405180910390a161136886868381811061132757611327612fe3565b905060200201602081019061133c91906129e8565b85858481811061134e5761134e612fe3565b90506020020160208101906113639190612ff9565b611ad6565b600101611206565b505050505050565b6098546000908190600190811614156113cf5760405162461bcd60e51b815260206004820152601960248201527814185d5cd8589b194e881a5b99195e081a5cc81c185d5cd959603a1b6044820152606401610624565b600260655414156114225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610624565b600260655561143333868686611907565b600160655595945050505050565b611449611b44565b6001600160a01b0381166114ae5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610624565b61063681611b9e565b60007f00000000000000000000000000000000000000000000000000000000000000004614156114e8575060c95490565b6114f0612042565b905090565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611548573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156c9190612e4f565b6001600160a01b0316336001600160a01b03161461159c5760405162461bcd60e51b815260040161062490612e6c565b60985419811960985419161461161a5760405162461bcd60e51b815260206004820152603860248201527f5061757361626c652e756e70617573653a20696e76616c696420617474656d7060448201527f7420746f2070617573652066756e6374696f6e616c69747900000000000000006064820152608401610624565b609881905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c9060200161076d565b6001600160a01b0381166116df5760405162461bcd60e51b815260206004820152604960248201527f5061757361626c652e5f73657450617573657252656769737472793a206e657760448201527f50617573657252656769737472792063616e6e6f7420626520746865207a65726064820152686f206164647265737360b81b608482015260a401610624565b609754604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1609780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0383163b1561186757604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e90611788908690869060040161306e565b602060405180830381865afa1580156117a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c99190613087565b6001600160e01b031916146118625760405162461bcd60e51b815260206004820152605360248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a2045524331323731207369676e6174757265206064820152721d995c9a599a58d85d1a5bdb8819985a5b1959606a1b608482015260a401610624565b505050565b826001600160a01b031661187b83836121bf565b6001600160a01b0316146118625760405162461bcd60e51b815260206004820152604760248201527f454950313237315369676e61747572655574696c732e636865636b5369676e6160448201527f747572655f454950313237313a207369676e6174757265206e6f742066726f6d6064820152661039b4b3b732b960c91b608482015260a401610624565b6001600160a01b038316600090815260d16020526040812054849060ff166119ad5760405162461bcd60e51b815260206004820152604d60248201527f53747261746567794d616e616765722e6f6e6c7953747261746567696573576860448201527f6974656c6973746564466f724465706f7369743a207374726174656779206e6f60648201526c1d081dda1a5d195b1a5cdd1959609a1b608482015260a401610624565b6119c26001600160a01b0385163387866121e3565b6040516311f9fbc960e21b81526001600160a01b038581166004830152602482018590528616906347e7ef24906044016020604051808303816000875af1158015611a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3591906130b1565b9150611a4386858785611d4c565b604051631452b9d760e11b81526001600160a01b0387811660048301528681166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906328a573ae90606401600060405180830381600087803b158015611ab557600080fd5b505af1158015611ac9573d6000803e3d6000fd5b5050505050949350505050565b604080516001600160a01b038416815282151560208201527f77d930df4937793473a95024d87a98fd2ccb9e92d3c2463b3dacd65d3e6a5786910160405180910390a16001600160a01b0391909116600090815260d360205260409020805460ff1916911515919091179055565b6033546001600160a01b03163314610b775760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610624565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081611c655760405162461bcd60e51b815260206004820152603e60248201527f53747261746567794d616e616765722e5f72656d6f76655368617265733a207360448201527f68617265416d6f756e742073686f756c64206e6f74206265207a65726f2100006064820152608401610624565b6001600160a01b03808516600090815260cd602090815260408083209387168352929052205480831115611cf75760405162461bcd60e51b815260206004820152603360248201527f53747261746567794d616e616765722e5f72656d6f76655368617265733a20736044820152720d0c2e4ca82dadeeadce840e8dede40d0d2ced606b1b6064820152608401610624565b6001600160a01b03808616600090815260cd602090815260408083209388168352929052208382039081905590831415611d3f57611d35858561223d565b6001915050611d45565b60009150505b9392505050565b6001600160a01b038416611dc85760405162461bcd60e51b815260206004820152603960248201527f53747261746567794d616e616765722e5f6164645368617265733a207374616b60448201527f65722063616e6e6f74206265207a65726f2061646472657373000000000000006064820152608401610624565b80611e345760405162461bcd60e51b815260206004820152603660248201527f53747261746567794d616e616765722e5f6164645368617265733a207368617260448201527565732073686f756c64206e6f74206265207a65726f2160501b6064820152608401610624565b6001600160a01b03808516600090815260cd6020908152604080832093861683529290522054611f45576001600160a01b038416600090815260ce602090815260409091205410611f065760405162461bcd60e51b815260206004820152605060248201527f53747261746567794d616e616765722e5f6164645368617265733a206465706f60448201527f73697420776f756c6420657863656564204d41585f5354414b45525f5354524160648201526f0a88a8eb2be9892a6a8be988a9c8ea8960831b608482015260a401610624565b6001600160a01b03848116600090815260ce602090815260408220805460018101825590835291200180546001600160a01b0319169184169190911790555b6001600160a01b03808516600090815260cd6020908152604080832093861683529290529081208054839290611f7c9084906130e0565b9091555050604080516001600160a01b03868116825285811660208301528416818301526060810183905290517f7cfff908a4b583f36430b25d75964c458d8ede8a99bd61be750e97ee1b2f3a969181900360800190a150505050565b60cb54604080516001600160a01b03928316815291831660208301527f4264275e593955ff9d6146a51a4525f6ddace2e81db9391abcc9d1ca48047d29910160405180910390a160cb80546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b6097546001600160a01b03161580156120fa57506001600160a01b03821615155b61217c5760405162461bcd60e51b815260206004820152604760248201527f5061757361626c652e5f696e697469616c697a655061757365723a205f696e6960448201527f7469616c697a6550617573657228292063616e206f6e6c792062652063616c6c6064820152666564206f6e636560c81b608482015260a401610624565b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2610a9a82611651565b60008060006121ce858561242f565b915091506121db8161249f565b509392505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610bcc90859061265a565b6001600160a01b038216600090815260ce6020526040812054905b81811015612358576001600160a01b03848116600090815260ce602052604090208054918516918390811061228f5761228f612fe3565b6000918252602090912001546001600160a01b03161415612350576001600160a01b038416600090815260ce6020526040902080546122d0906001906130f8565b815481106122e0576122e0612fe3565b60009182526020808320909101546001600160a01b03878116845260ce909252604090922080549190921691908390811061231d5761231d612fe3565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550612358565b600101612258565b818114156123e05760405162461bcd60e51b815260206004820152604960248201527f53747261746567794d616e616765722e5f72656d6f766553747261746567794660448201527f726f6d5374616b657253747261746567794c6973743a207374726174656779206064820152681b9bdd08199bdd5b9960ba1b608482015260a401610624565b6001600160a01b038416600090815260ce602052604090208054806124075761240761310f565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b6000808251604114156124665760208301516040840151606085015160001a61245a8782858561272c565b94509450505050612498565b8251604014156124905760208301516040840151612485868383612819565b935093505050612498565b506000905060025b9250929050565b60008160048111156124b3576124b3613125565b14156124bc5750565b60018160048111156124d0576124d0613125565b141561251e5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610624565b600281600481111561253257612532613125565b14156125805760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610624565b600381600481111561259457612594613125565b14156125ed5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610624565b600481600481111561260157612601613125565b14156106365760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610624565b60006126af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166128529092919063ffffffff16565b80519091501561186257808060200190518101906126cd9190612eb6565b6118625760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610624565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156127635750600090506003612810565b8460ff16601b1415801561277b57508460ff16601c14155b1561278c5750600090506004612810565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156127e0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661280957600060019250925050612810565b9150600090505b94509492505050565b6000806001600160ff1b0383168161283660ff86901c601b6130e0565b90506128448782888561272c565b935093505050935093915050565b60606128618484600085612869565b949350505050565b6060824710156128ca5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610624565b6001600160a01b0385163b6129215760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610624565b600080866001600160a01b0316858760405161293d919061313b565b60006040518083038185875af1925050503d806000811461297a576040519150601f19603f3d011682016040523d82523d6000602084013e61297f565b606091505b509150915061298f82828661299a565b979650505050505050565b606083156129a9575081611d45565b8251156129b95782518084602001fd5b8160405162461bcd60e51b81526004016106249190613157565b6001600160a01b038116811461063657600080fd5b6000602082840312156129fa57600080fd5b8135611d45816129d3565b600060208284031215612a1757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060c08789031215612a4d57600080fd5b8635612a58816129d3565b95506020870135612a68816129d3565b9450604087013593506060870135612a7f816129d3565b92506080870135915060a087013567ffffffffffffffff80821115612aa357600080fd5b818901915089601f830112612ab757600080fd5b813581811115612ac957612ac9612a1e565b604051601f8201601f19908116603f01168101908382118183101715612af157612af1612a1e565b816040528281528c6020848701011115612b0a57600080fd5b8260208601602083013760006020848301015280955050505050509295509295509295565b801515811461063657600080fd5b60008060408385031215612b5057600080fd5b8235612b5b816129d3565b91506020830135612b6b81612b2f565b809150509250929050565b600060208284031215612b8857600080fd5b813560ff81168114611d4557600080fd5b60008060408385031215612bac57600080fd5b8235612bb7816129d3565b91506020830135612b6b816129d3565b600080600060608486031215612bdc57600080fd5b8335612be7816129d3565b92506020840135612bf7816129d3565b929592945050506040919091013590565b604080825283519082018190526000906020906060840190828701845b82811015612c4a5781516001600160a01b031684529284019290840190600101612c25565b5050508381038285015284518082528583019183019060005b81811015612c7f57835183529284019291840191600101612c63565b5090979650505050505050565b60008083601f840112612c9e57600080fd5b50813567ffffffffffffffff811115612cb657600080fd5b6020830191508360208260051b850101111561249857600080fd5b60008060208385031215612ce457600080fd5b823567ffffffffffffffff811115612cfb57600080fd5b612d0785828601612c8c565b90969095509350505050565b60008060008060808587031215612d2957600080fd5b8435612d34816129d3565b93506020850135612d44816129d3565b92506040850135612d54816129d3565b9396929550929360600135925050565b60008060008060808587031215612d7a57600080fd5b8435612d85816129d3565b93506020850135612d95816129d3565b9250604085013591506060850135612dac816129d3565b939692955090935050565b60008060408385031215612dca57600080fd5b8235612dd5816129d3565b946020939093013593505050565b60008060008060408587031215612df957600080fd5b843567ffffffffffffffff80821115612e1157600080fd5b612e1d88838901612c8c565b90965094506020870135915080821115612e3657600080fd5b50612e4387828801612c8c565b95989497509550505050565b600060208284031215612e6157600080fd5b8151611d45816129d3565b6020808252602a908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526939903ab73830bab9b2b960b11b606082015260800190565b600060208284031215612ec857600080fd5b8151611d4581612b2f565b60208082526028908201527f6d73672e73656e646572206973206e6f74207065726d697373696f6e6564206160408201526739903830bab9b2b960c11b606082015260800190565b60208082526044908201527f53747261746567794d616e616765722e6f6e6c7953747261746567795768697460408201527f656c69737465723a206e6f742074686520737472617465677957686974656c6960608201526339ba32b960e11b608082015260a00190565b602080825260409082018190527f53747261746567794d616e616765722e6f6e6c7944656c65676174696f6e4d61908201527f6e616765723a206e6f74207468652044656c65676174696f6e4d616e61676572606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561300b57600080fd5b8135611d4581612b2f565b60005b83811015613031578181015183820152602001613019565b83811115610bcc5750506000910152565b6000815180845261305a816020860160208601613016565b601f01601f19169290920160200192915050565b8281526040602082015260006128616040830184613042565b60006020828403121561309957600080fd5b81516001600160e01b031981168114611d4557600080fd5b6000602082840312156130c357600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082198211156130f3576130f36130ca565b500190565b60008282101561310a5761310a6130ca565b500390565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b6000825161314d818460208701613016565b9190910192915050565b602081526000611d45602083018461304256fea2646970667358221220e1eb2321685fb63a9aec2a407059955dbb014f9ba1598fed273d59a1889501d764736f6c634300080c0033", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_delegation\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"},{\"name\":\"_eigenPodManager\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"},{\"name\":\"_slasher\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEPOSIT_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"domainSeparator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"initialStrategyWhitelister\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_pauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"initialPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pauseAll\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pauserRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPauserRegistry\",\"inputs\":[{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"internalType\":\"contractIPauserRegistry\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setStrategyWhitelister\",\"inputs\":[{\"name\":\"newStrategyWhitelister\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyList\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PauserRegistrySet\",\"inputs\":[{\"name\":\"pauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"},{\"name\":\"newPauserRegistry\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIPauserRegistry\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newPausedStatus\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CurrentlyPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientShares\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNewPausedStatus\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEIP1271\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureEOA\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxStrategiesExceeded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyPauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyUnpauser\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesAmountZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ThirdPartyTransfersDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", + Bin: "0x61010060405234801561001157600080fd5b50604051612ab0380380612ab083398101604081905261003091610134565b6001600160a01b0380841660805280831660a052811660c05261005161005d565b50504660e05250610181565b600054610100900460ff16156100c95760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161461011a576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811461013157600080fd5b50565b60008060006060848603121561014957600080fd5b83516101548161011c565b60208501519093506101658161011c565b60408501519092506101768161011c565b809150509250925092565b60805160a05160c05160e0516128da6101d6600039600061124d0152600061046e0152600061028501526000818161051a015281816109eb01528181610d3a01528181610d8f015261165f01526128da6000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c80638da5cb5b1161011a578063c6656702116100ad578063df5cf7231161007c578063df5cf72314610515578063e7a050aa1461053c578063f2fde38b1461054f578063f698da2514610562578063fabc1cbc1461056a57600080fd5b8063c6656702146104c9578063cbc2bd62146104dc578063cf756fdf146104ef578063df5b35471461050257600080fd5b8063b1344271116100e9578063b134427114610469578063b5d8b5b814610490578063c4623ea1146104a3578063c608c7f3146104b657600080fd5b80638da5cb5b1461040157806394f649dd14610412578063967fc0d2146104335780639b4da03d1461044657600080fd5b80635ac86ab71161019d5780637a7e0d921161016c5780637a7e0d92146103675780637ecebe0014610392578063886f1195146103b25780638b8aac3c146103c55780638c80d4e5146103ee57600080fd5b80635ac86ab7146103015780635c975abb14610334578063663c1de41461033c578063715018a61461035f57600080fd5b80634665bcda116101d95780634665bcda1461028057806348825e94146102bf5780634e5a4263146102e6578063595c6a67146102f957600080fd5b806310d67a2f1461020b578063136439dd1461022057806320606b701461023357806332e89ace1461026d575b600080fd5b61021e610219366004612279565b61057d565b005b61021e61022e366004612296565b610631565b61025a7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b61025a61027b3660046122c5565b61071c565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610264565b61025a7f4337f82d142e41f2a8c10547cd8c859bddb92262a61058e77842e24d9dea922481565b61021e6102f43660046123d6565b6108cb565b61021e610904565b61032461030f36600461240f565b609854600160ff9092169190911b9081161490565b6040519015158152602001610264565b60985461025a565b61032461034a366004612279565b60d16020526000908152604090205460ff1681565b61021e6109cc565b61025a610375366004612432565b60cd60209081526000928352604080842090915290825290205481565b61025a6103a0366004612279565b60ca6020526000908152604090205481565b6097546102a7906001600160a01b031681565b61025a6103d3366004612279565b6001600160a01b0316600090815260ce602052604090205490565b61021e6103fc366004612460565b6109e0565b6033546001600160a01b03166102a7565b610425610420366004612279565b610a3a565b6040516102649291906124a1565b60cb546102a7906001600160a01b031681565b610324610454366004612279565b60d36020526000908152604090205460ff1681565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b61021e61049e366004612571565b610bba565b61021e6104b13660046125b3565b610d2f565b61021e6104c4366004612604565b610d84565b61021e6104d7366004612279565b610e3d565b6102a76104ea366004612657565b610e4e565b61021e6104fd3660046125b3565b610e86565b61021e610510366004612683565b610fbf565b6102a77f000000000000000000000000000000000000000000000000000000000000000081565b61025a61054a366004612460565b611180565b61021e61055d366004612279565b6111d3565b61025a611249565b61021e610578366004612296565b611286565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f491906126f4565b6001600160a01b0316336001600160a01b0316146106255760405163794821ff60e01b815260040160405180910390fd5b61062e8161138e565b50565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa158015610679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069d9190612711565b6106ba57604051631d77d47760e21b815260040160405180910390fd5b609854818116146106de5760405163c61dca5d60e01b815260040160405180910390fd5b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d906020015b60405180910390a250565b60985460009081906001908116036107475760405163840a48d560e01b815260040160405180910390fd5b61074f61141e565b6001600160a01b038816600090815260d3602052604090205460ff16156107895760405163dc34227160e01b815260040160405180910390fd5b428410156107aa57604051630819bdcd60e01b815260040160405180910390fd5b6001600160a01b03858116600081815260ca602090815260408083205481517f4337f82d142e41f2a8c10547cd8c859bddb92262a61058e77842e24d9dea922493810193909352908201939093528b84166060820152928a16608084015260a0830189905260c0830182905260e0830187905290916101000160408051601f1981840301815291815281516020928301206001600160a01b038a16600090815260ca9093529082206001850190559150610862611249565b60405161190160f01b60208201526022810191909152604281018390526062016040516020818303038152906040528051906020012090506108a5888288611477565b6108b1888c8c8c611560565b94505050506108c06001606555565b509695505050505050565b60cb546001600160a01b031633146108f657604051635c427cd960e01b815260040160405180910390fd5b61090082826116c4565b5050565b60975460405163237dfb4760e11b81523360048201526001600160a01b03909116906346fbf68e90602401602060405180830381865afa15801561094c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109709190612711565b61098d57604051631d77d47760e21b815260040160405180910390fd5b600019609881905560405190815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a2565b6109d4611732565b6109de600061178c565b565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a2957604051635c427cd960e01b815260040160405180910390fd5b610a348383836117de565b50505050565b6001600160a01b038116600090815260ce60205260408120546060918291908167ffffffffffffffff811115610a7257610a726122af565b604051908082528060200260200182016040528015610a9b578160200160208202803683370190505b50905060005b82811015610b2c576001600160a01b038616600090815260cd6020908152604080832060ce9092528220805491929184908110610ae057610ae061272e565b60009182526020808320909101546001600160a01b031683528201929092526040019020548251839083908110610b1957610b1961272e565b6020908102919091010152600101610aa1565b5060ce6000866001600160a01b03166001600160a01b031681526020019081526020016000208181805480602002602001604051908101604052809291908181526020018280548015610ba857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610b8a575b50505050509150935093505050915091565b60cb546001600160a01b03163314610be557604051635c427cd960e01b815260040160405180910390fd5b8060005b81811015610a345760d16000858584818110610c0757610c0761272e565b9050602002016020810190610c1c9190612279565b6001600160a01b0316815260208101919091526040016000205460ff1615610d2757600060d16000868685818110610c5657610c5661272e565b9050602002016020810190610c6b9190612279565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f4074413b4b443e4e58019f2855a8765113358c7c72e39509c6af45fc0f5ba030848483818110610cc657610cc661272e565b9050602002016020810190610cdb9190612279565b6040516001600160a01b03909116815260200160405180910390a1610d27848483818110610d0b57610d0b61272e565b9050602002016020810190610d209190612279565b60006116c4565b600101610be9565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610d7857604051635c427cd960e01b815260040160405180910390fd5b610a348484848461189f565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610dcd57604051635c427cd960e01b815260040160405180910390fd5b604051636ce5768960e11b81526001600160a01b03858116600483015282811660248301526044820184905284169063d9caed1290606401600060405180830381600087803b158015610e1f57600080fd5b505af1158015610e33573d6000803e3d6000fd5b5050505050505050565b610e45611732565b61062e81611a22565b60ce6020528160005260406000208181548110610e6a57600080fd5b6000918252602090912001546001600160a01b03169150829050565b600054610100900460ff1615808015610ea65750600054600160ff909116105b80610ec05750303b158015610ec0575060005460ff166001145b610f285760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610f4b576000805461ff0019166101001790555b610f53611a8b565b60c955610f608383611b22565b610f698561178c565b610f7284611a22565b8015610fb8576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b60cb546001600160a01b03163314610fea57604051635c427cd960e01b815260040160405180910390fd5b82811461100a576040516343714afd60e01b815260040160405180910390fd5b8260005b818110156111785760d1600087878481811061102c5761102c61272e565b90506020020160208101906110419190612279565b6001600160a01b0316815260208101919091526040016000205460ff1661117057600160d1600088888581811061107a5761107a61272e565b905060200201602081019061108f9190612279565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f0c35b17d91c96eb2751cd456e1252f42a386e524ef9ff26ecc9950859fdc04fe8686838181106110ea576110ea61272e565b90506020020160208101906110ff9190612279565b6040516001600160a01b03909116815260200160405180910390a161117086868381811061112f5761112f61272e565b90506020020160208101906111449190612279565b8585848181106111565761115661272e565b905060200201602081019061116b9190612744565b6116c4565b60010161100e565b505050505050565b60985460009081906001908116036111ab5760405163840a48d560e01b815260040160405180910390fd5b6111b361141e565b6111bf33868686611560565b91506111cb6001606555565b509392505050565b6111db611732565b6001600160a01b0381166112405760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610f1f565b61062e8161178c565b60007f00000000000000000000000000000000000000000000000000000000000000004603611279575060c95490565b611281611a8b565b905090565b609760009054906101000a90046001600160a01b03166001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fd91906126f4565b6001600160a01b0316336001600160a01b03161461132e5760405163794821ff60e01b815260040160405180910390fd5b6098541981196098541916146113575760405163c61dca5d60e01b815260040160405180910390fd5b609881905560405181815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c90602001610711565b6001600160a01b0381166113b5576040516339b190bb60e11b815260040160405180910390fd5b609754604080516001600160a01b03928316815291831660208301527f6e9fcd539896fca60e8b0f01dd580233e48a6b0f7df013b89ba7f565869acdb6910160405180910390a1609780546001600160a01b0319166001600160a01b0392909216919091179055565b6002606554036114705760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f1f565b6002606555565b6001600160a01b0383163b1561152557604051630b135d3f60e11b808252906001600160a01b03851690631626ba7e906114b790869086906004016127b1565b602060405180830381865afa1580156114d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f891906127ca565b6001600160e01b031916146115205760405163026aa43360e31b815260040160405180910390fd5b505050565b826001600160a01b03166115398383611ba3565b6001600160a01b031614611520576040516306c653c360e31b815260040160405180910390fd5b6001600160a01b038316600090815260d16020526040812054849060ff1661159b57604051632efd965160e11b815260040160405180910390fd5b6115b06001600160a01b038516338786611bc9565b6040516311f9fbc960e21b81526001600160a01b038581166004830152602482018590528616906347e7ef24906044016020604051808303816000875af11580156115ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162391906127f4565b91506116318685878561189f565b604051631452b9d760e11b81526001600160a01b0387811660048301528681166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906328a573ae90606401600060405180830381600087803b1580156116a357600080fd5b505af11580156116b7573d6000803e3d6000fd5b5050505050949350505050565b604080516001600160a01b038416815282151560208201527f77d930df4937793473a95024d87a98fd2ccb9e92d3c2463b3dacd65d3e6a5786910160405180910390a16001600160a01b0391909116600090815260d360205260409020805460ff1916911515919091179055565b6033546001600160a01b031633146109de5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610f1f565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600081600003611801576040516342061b2560e11b815260040160405180910390fd5b6001600160a01b03808516600090815260cd60209081526040808320938716835292905220548083111561184857604051633999656760e01b815260040160405180910390fd5b6001600160a01b03808616600090815260cd6020908152604080832093881683529290529081209184900391829055819003611892576118888585611c23565b6001915050611898565b60009150505b9392505050565b6001600160a01b0384166118c6576040516316f2ccc960e01b815260040160405180910390fd5b806000036118e7576040516342061b2560e11b815260040160405180910390fd5b6001600160a01b03808516600090815260cd60209081526040808320938616835292905290812054900361198e576001600160a01b038416600090815260ce60209081526040909120541061194f576040516301a1443960e31b815260040160405180910390fd5b6001600160a01b03848116600090815260ce602090815260408220805460018101825590835291200180546001600160a01b0319169184169190911790555b6001600160a01b03808516600090815260cd60209081526040808320938616835292905290812080548392906119c5908490612823565b9091555050604080516001600160a01b03868116825285811660208301528416818301526060810183905290517f7cfff908a4b583f36430b25d75964c458d8ede8a99bd61be750e97ee1b2f3a969181900360800190a150505050565b60cb54604080516001600160a01b03928316815291831660208301527f4264275e593955ff9d6146a51a4525f6ddace2e81db9391abcc9d1ca48047d29910160405180910390a160cb80546001600160a01b0319166001600160a01b0392909216919091179055565b604080518082018252600a81526922b4b3b2b72630bcb2b960b11b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea81840152466060820152306080808301919091528351808303909101815260a0909101909252815191012090565b6097546001600160a01b0316158015611b4357506001600160a01b03821615155b611b60576040516339b190bb60e11b815260040160405180910390fd5b609881905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a26109008261138e565b6000806000611bb28585611dac565b91509150611bbf81611df1565b5090505b92915050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610a34908590611f3b565b6001600160a01b038216600090815260ce6020526040812054905b81811015611d3d576001600160a01b03848116600090815260ce6020526040902080549185169183908110611c7557611c7561272e565b6000918252602090912001546001600160a01b031603611d35576001600160a01b038416600090815260ce602052604090208054611cb590600190612836565b81548110611cc557611cc561272e565b60009182526020808320909101546001600160a01b03878116845260ce9092526040909220805491909216919083908110611d0257611d0261272e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611d3d565b600101611c3e565b818103611d5d57604051632df15a4160e11b815260040160405180910390fd5b6001600160a01b038416600090815260ce60205260409020805480611d8457611d84612849565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b6000808251604103611de25760208301516040840151606085015160001a611dd687828585612010565b94509450505050611dea565b506000905060025b9250929050565b6000816004811115611e0557611e0561285f565b03611e0d5750565b6001816004811115611e2157611e2161285f565b03611e6e5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610f1f565b6002816004811115611e8257611e8261285f565b03611ecf5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610f1f565b6003816004811115611ee357611ee361285f565b0361062e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610f1f565b6000611f90826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166120d49092919063ffffffff16565b9050805160001480611fb1575080806020019051810190611fb19190612711565b6115205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610f1f565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561204757506000905060036120cb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561209b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166120c4576000600192509250506120cb565b9150600090505b94509492505050565b60606120e384846000856120eb565b949350505050565b60608247101561214c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610f1f565b600080866001600160a01b031685876040516121689190612875565b60006040518083038185875af1925050503d80600081146121a5576040519150601f19603f3d011682016040523d82523d6000602084013e6121aa565b606091505b50915091506121bb878383876121c6565b979650505050505050565b6060831561223557825160000361222e576001600160a01b0385163b61222e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610f1f565b50816120e3565b6120e3838381511561224a5781518083602001fd5b8060405162461bcd60e51b8152600401610f1f9190612891565b6001600160a01b038116811461062e57600080fd5b60006020828403121561228b57600080fd5b813561189881612264565b6000602082840312156122a857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060008060c087890312156122de57600080fd5b86356122e981612264565b955060208701356122f981612264565b945060408701359350606087013561231081612264565b92506080870135915060a087013567ffffffffffffffff81111561233357600080fd5b8701601f8101891361234457600080fd5b803567ffffffffffffffff81111561235e5761235e6122af565b604051601f8201601f19908116603f0116810167ffffffffffffffff8111828210171561238d5761238d6122af565b6040528181528282016020018b10156123a557600080fd5b816020840160208301376000602083830101528093505050509295509295509295565b801515811461062e57600080fd5b600080604083850312156123e957600080fd5b82356123f481612264565b91506020830135612404816123c8565b809150509250929050565b60006020828403121561242157600080fd5b813560ff8116811461189857600080fd5b6000806040838503121561244557600080fd5b823561245081612264565b9150602083013561240481612264565b60008060006060848603121561247557600080fd5b833561248081612264565b9250602084013561249081612264565b929592945050506040919091013590565b6040808252835190820181905260009060208501906060840190835b818110156124e45783516001600160a01b03168352602093840193909201916001016124bd565b50508381036020808601919091528551808352918101925085019060005b81811015612520578251845260209384019390920191600101612502565b50919695505050505050565b60008083601f84011261253e57600080fd5b50813567ffffffffffffffff81111561255657600080fd5b6020830191508360208260051b8501011115611dea57600080fd5b6000806020838503121561258457600080fd5b823567ffffffffffffffff81111561259b57600080fd5b6125a78582860161252c565b90969095509350505050565b600080600080608085870312156125c957600080fd5b84356125d481612264565b935060208501356125e481612264565b925060408501356125f481612264565b9396929550929360600135925050565b6000806000806080858703121561261a57600080fd5b843561262581612264565b9350602085013561263581612264565b925060408501359150606085013561264c81612264565b939692955090935050565b6000806040838503121561266a57600080fd5b823561267581612264565b946020939093013593505050565b6000806000806040858703121561269957600080fd5b843567ffffffffffffffff8111156126b057600080fd5b6126bc8782880161252c565b909550935050602085013567ffffffffffffffff8111156126dc57600080fd5b6126e88782880161252c565b95989497509550505050565b60006020828403121561270657600080fd5b815161189881612264565b60006020828403121561272357600080fd5b8151611898816123c8565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561275657600080fd5b8135611898816123c8565b60005b8381101561277c578181015183820152602001612764565b50506000910152565b6000815180845261279d816020860160208601612761565b601f01601f19169290920160200192915050565b8281526040602082015260006120e36040830184612785565b6000602082840312156127dc57600080fd5b81516001600160e01b03198116811461189857600080fd5b60006020828403121561280657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611bc357611bc361280d565b81810381811115611bc357611bc361280d565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60008251612887818460208701612761565b9190910192915050565b602081526000611898602083018461278556fea264697066735822122086e8759551f71e5ffb864657923f6f2299b4c0c63c14c1195ec4ec039e504d2764736f6c634300081b0033", } // StrategyManagerABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StrategyManagerStorage/binding.go b/pkg/bindings/StrategyManagerStorage/binding.go index 3dc3ddcac..4e9b56d9b 100644 --- a/pkg/bindings/StrategyManagerStorage/binding.go +++ b/pkg/bindings/StrategyManagerStorage/binding.go @@ -31,7 +31,7 @@ var ( // StrategyManagerStorageMetaData contains all meta data concerning the StrategyManagerStorage contract. var StrategyManagerStorageMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DEPOSIT_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyList\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"DEPOSIT_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DOMAIN_TYPEHASH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addStrategiesToDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"thirdPartyTransfersForbiddenValues\",\"type\":\"bool[]\",\"internalType\":\"bool[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delegation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIDelegationManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositIntoStrategy\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositIntoStrategyWithSignature\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expiry\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eigenPodManager\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIEigenPodManager\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDeposits\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"},{\"name\":\"\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeShares\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeStrategiesFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategiesToRemoveFromWhitelist\",\"type\":\"address[]\",\"internalType\":\"contractIStrategy[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISlasher\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyList\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyListLength\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakerStrategyShares\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyIsWhitelistedForDeposit\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"strategyWhitelister\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"thirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawSharesAsTokens\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"strategy\",\"type\":\"address\",\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"contractIERC20\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIERC20\"},{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyAddedToDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyRemovedFromDepositWhitelist\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StrategyWhitelisterChanged\",\"inputs\":[{\"name\":\"previousAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdatedThirdPartyTransfersForbidden\",\"inputs\":[{\"name\":\"strategy\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"contractIStrategy\"},{\"name\":\"value\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"InputArrayLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientShares\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxStrategiesExceeded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SharesAmountZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SignatureExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StakerAddressZero\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StrategyNotWhitelisted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ThirdPartyTransfersDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnauthorizedCaller\",\"inputs\":[]}]", } // StrategyManagerStorageABI is the input ABI used to generate the binding from. diff --git a/pkg/bindings/StructuredLinkedList/binding.go b/pkg/bindings/StructuredLinkedList/binding.go index b291ef98d..5de10dd1b 100644 --- a/pkg/bindings/StructuredLinkedList/binding.go +++ b/pkg/bindings/StructuredLinkedList/binding.go @@ -32,7 +32,7 @@ var ( // StructuredLinkedListMetaData contains all meta data concerning the StructuredLinkedList contract. var StructuredLinkedListMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200b0f3aa07997f25ddb2b0dd17a1b6104304d811d2cec7f2d2dfcae3e3d618f6964736f6c634300080c0033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220b3d8cd97ef52a473687961fd194936f54822b92a1bc319ace882ae14dd29ccfc64736f6c634300081b0033", } // StructuredLinkedListABI is the input ABI used to generate the binding from. diff --git a/remappings.txt b/remappings.txt deleted file mode 100644 index 91c1fde59..000000000 --- a/remappings.txt +++ /dev/null @@ -1,6 +0,0 @@ -@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable/ -@openzeppelin/=lib/openzeppelin-contracts/ -@openzeppelin-v4.9.0/=lib/openzeppelin-contracts-v4.9.0/ -@openzeppelin-upgrades-v4.9.0/=lib/openzeppelin-contracts-upgradeable-v4.9.0/ -ds-test/=lib/ds-test/src/ -forge-std/=lib/forge-std/src/ \ No newline at end of file diff --git a/script/admin/mainnet/Mainnet_Unpause_Deposits.s.sol b/script/admin/mainnet/Mainnet_Unpause_Deposits.s.sol index 47d96a354..832556c57 100644 --- a/script/admin/mainnet/Mainnet_Unpause_Deposits.s.sol +++ b/script/admin/mainnet/Mainnet_Unpause_Deposits.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; import "../../utils/TimelockEncoding.sol"; diff --git a/script/configs/devnet/deploy_from_scratch.anvil.config.json b/script/configs/devnet/deploy_from_scratch.anvil.config.json new file mode 100644 index 000000000..96df127e1 --- /dev/null +++ b/script/configs/devnet/deploy_from_scratch.anvil.config.json @@ -0,0 +1,55 @@ +{ + "maintainer": "samlaf@eigenlabs.org", + "multisig_addresses": { + "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "timelock": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + }, + "strategies": [ + { + "token_address": "0x0000000000000000000000000000000000000000", + "token_symbol": "WETH", + "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 + } + ], + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "eigenPod": { + "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" + }, + "eigenPodManager": { + "init_paused_status": 30 + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "slasher": { + "init_paused_status": 0 + }, + "delegation": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" +} \ No newline at end of file diff --git a/script/configs/devnet/deploy_from_scratch.holesky.config.json b/script/configs/devnet/deploy_from_scratch.holesky.config.json new file mode 100644 index 000000000..3dc1f204d --- /dev/null +++ b/script/configs/devnet/deploy_from_scratch.holesky.config.json @@ -0,0 +1,55 @@ +{ + "maintainer": "samlaf@eigenlabs.org", + "multisig_addresses": { + "operationsMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", + "communityMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", + "pauserMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", + "executorMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", + "timelock": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479" + }, + "strategies": [ + { + "token_address": "0x0000000000000000000000000000000000000000", + "token_symbol": "WETH", + "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 + } + ], + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "eigenPod": { + "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" + }, + "eigenPodManager": { + "init_paused_status": 30 + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "slasher": { + "init_paused_status": 0 + }, + "delegation": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" +} \ No newline at end of file diff --git a/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json b/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json new file mode 100644 index 000000000..bcd808f71 --- /dev/null +++ b/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json @@ -0,0 +1,47 @@ +{ + "multisig_addresses": { + "operationsMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "communityMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "pauserMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "executorMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "timelock": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07" + }, + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "eigenPod": { + "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" + }, + "eigenPodManager": { + "init_paused_status": 115792089237316195423570985008687907853269984665640564039457584007913129639935 + }, + "slasher": { + "init_paused_status": 0 + }, + "delegation": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "rewardsCoordinator": { + "init_paused_status": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "allocationManager": { + "init_paused_status": 0, + "DEALLOCATION_DELAY": 86400, + "ALLOCATION_CONFIGURATION_DELAY": 600 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242" + } \ No newline at end of file diff --git a/script/configs/holesky/Deploy_RewardsCoordinator.holesky.config.json b/script/configs/holesky/Deploy_RewardsCoordinator.holesky.config.json new file mode 100644 index 000000000..ecd86e029 --- /dev/null +++ b/script/configs/holesky/Deploy_RewardsCoordinator.holesky.config.json @@ -0,0 +1,60 @@ +{ + "chainInfo": { + "chainId": 17000 + }, + "multisig_addresses": { + "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", + "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", + "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", + "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" + }, + "strategies": { + "numStrategies": 0, + "MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "strategiesToDeploy": [] + }, + "strategyManager": { + "init_strategy_whitelister": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "init_paused_status": 0 + }, + "delegationManager": { + "init_paused_status": 0, + "init_minWithdrawalDelayBlocks": 10 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "avsDirectory": { + "init_paused_status": 0 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPod": { + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000, + "GENESIS_TIME": 1695902400 + }, + "eigenPodManager": { + "init_paused_status": 0, + "deneb_fork_timestamp": "1707305664" + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawalDelayBlocks": 10 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "beaconOracleAddress": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" +} \ No newline at end of file diff --git a/script/configs/local/deploy_from_scratch.anvil.config.json b/script/configs/local/deploy_from_scratch.anvil.config.json index 96df127e1..994ba7532 100644 --- a/script/configs/local/deploy_from_scratch.anvil.config.json +++ b/script/configs/local/deploy_from_scratch.anvil.config.json @@ -51,5 +51,10 @@ "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 }, + "allocationManager": { + "init_paused_status": 0, + "DEALLOCATION_DELAY": 900, + "ALLOCATION_CONFIGURATION_DELAY": 1200 + }, "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" } \ No newline at end of file diff --git a/script/configs/local/deploy_from_scratch.slashing.anvil.config.json b/script/configs/local/deploy_from_scratch.slashing.anvil.config.json new file mode 100644 index 000000000..313bd1827 --- /dev/null +++ b/script/configs/local/deploy_from_scratch.slashing.anvil.config.json @@ -0,0 +1,61 @@ +{ + "maintainer": "samlaf@eigenlabs.org", + "multisig_addresses": { + "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "timelock": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + }, + "strategies": [ + { + "token_address": "0x0000000000000000000000000000000000000000", + "token_symbol": "WETH", + "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 + } + ], + "allocationManager": { + "init_paused_status": 0, + "DEALLOCATION_DELAY": 86400, + "ALLOCATION_CONFIGURATION_DELAY": 600 + }, + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "eigenPod": { + "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" + }, + "eigenPodManager": { + "init_paused_status": 30 + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "slasher": { + "init_paused_status": 0 + }, + "delegation": { + "withdrawal_delay_blocks": 5, + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" +} \ No newline at end of file diff --git a/script/deploy/devnet/Upgrade.s.sol b/script/deploy/devnet/Upgrade.s.sol new file mode 100644 index 000000000..b9b430512 --- /dev/null +++ b/script/deploy/devnet/Upgrade.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "../../utils/ExistingDeploymentParser.sol"; + +// # To load the variables in the .env file +// source .env + +// Generic upgrade script, DOES NOT UPDATE IMPLEMENTATION IN OUTPUT FILE +// forge script script/deploy/devnet/Upgrade.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY +contract Upgrade is ExistingDeploymentParser { + + function run() external { + // EDIT this for your script + _parseDeployedContracts("script/output/holesky/pre_preprod_slashing.holesky.json"); + + vm.startBroadcast(); + AVSDirectory newAVSDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); + eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(newAVSDirectoryImplementation)); + vm.stopBroadcast(); + + } +} \ No newline at end of file diff --git a/script/deploy/devnet/deploy_from_scratch.s.sol b/script/deploy/devnet/deploy_from_scratch.s.sol new file mode 100644 index 000000000..cfa395059 --- /dev/null +++ b/script/deploy/devnet/deploy_from_scratch.s.sol @@ -0,0 +1,653 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; + +import "../../../src/contracts/interfaces/IETHPOSDeposit.sol"; + +import "../../../src/contracts/core/StrategyManager.sol"; +import "../../../src/contracts/core/DelegationManager.sol"; +import "../../../src/contracts/core/AVSDirectory.sol"; +import "../../../src/contracts/core/RewardsCoordinator.sol"; +import "../../../src/contracts/core/AllocationManager.sol"; +import "../../../src/contracts/permissions/PermissionController.sol"; + +import "../../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; +import "../../../src/contracts/strategies/StrategyFactory.sol"; +import "../../../src/contracts/strategies/StrategyBase.sol"; + +import "../../../src/contracts/pods/EigenPod.sol"; +import "../../../src/contracts/pods/EigenPodManager.sol"; + +import "../../../src/contracts/permissions/PauserRegistry.sol"; + +import "../../../src/test/mocks/EmptyContract.sol"; +import "../../../src/test/mocks/ETHDepositMock.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// # To load the variables in the .env file +// source .env + +// # To deploy and verify our contract +// forge script script/deploy/devnet/deploy_from_scratch.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/deploy_from_scratch.anvil.config.json +contract DeployFromScratch is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + string public deployConfigPath; + + // EigenLayer Contracts + ProxyAdmin public eigenLayerProxyAdmin; + PauserRegistry public eigenLayerPauserReg; + DelegationManager public delegation; + DelegationManager public delegationImplementation; + StrategyManager public strategyManager; + StrategyManager public strategyManagerImplementation; + RewardsCoordinator public rewardsCoordinator; + RewardsCoordinator public rewardsCoordinatorImplementation; + AVSDirectory public avsDirectory; + AVSDirectory public avsDirectoryImplementation; + EigenPodManager public eigenPodManager; + EigenPodManager public eigenPodManagerImplementation; + UpgradeableBeacon public eigenPodBeacon; + EigenPod public eigenPodImplementation; + StrategyFactory public strategyFactory; + StrategyFactory public strategyFactoryImplementation; + UpgradeableBeacon public strategyBeacon; + StrategyBase public baseStrategyImplementation; + AllocationManager public allocationManagerImplementation; + AllocationManager public allocationManager; + PermissionController public permissionController; + PermissionController public permissionControllerImplementation; + + EmptyContract public emptyContract; + + address executorMultisig; + address operationsMultisig; + address pauserMultisig; + + // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in + IETHPOSDeposit public ethPOSDeposit; + + // strategies deployed + StrategyBaseTVLLimits[] public deployedStrategyArray; + + // IMMUTABLES TO SET + uint64 GOERLI_GENESIS_TIME = 1616508000; + + // OTHER DEPLOYMENT PARAMETERS + uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + uint256 DELEGATION_INIT_PAUSED_STATUS; + uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; + uint256 REWARDS_COORDINATOR_INIT_PAUSED_STATUS; + + // DelegationManager + uint32 MIN_WITHDRAWAL_DELAY = 86400; + + // AllocationManager + uint32 DEALLOCATION_DELAY; + uint32 ALLOCATION_CONFIGURATION_DELAY; + + // RewardsCoordinator + uint32 REWARDS_COORDINATOR_MAX_REWARDS_DURATION; + uint32 REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH; + uint32 REWARDS_COORDINATOR_MAX_FUTURE_LENGTH; + uint32 REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP; + address REWARDS_COORDINATOR_UPDATER; + uint32 REWARDS_COORDINATOR_ACTIVATION_DELAY; + uint32 REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS; + uint32 REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH; + + // AllocationManager + uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; + + // one week in blocks -- 50400 + uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS; + uint256 DELEGATION_WITHDRAWAL_DELAY_BLOCKS; + + function run(string memory configFileName) public { + // read and log the chainID + uint256 chainId = block.chainid; + emit log_named_uint("You are deploying on ChainID", chainId); + + // READ JSON CONFIG DATA + deployConfigPath = string(bytes(string.concat("script/configs/", configFileName))); + string memory config_data = vm.readFile(deployConfigPath); + // bytes memory parsedData = vm.parseJson(config_data); + + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); + DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); + DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); + EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".eigenPodManager.init_paused_status"); + REWARDS_COORDINATOR_INIT_PAUSED_STATUS = stdJson.readUint( + config_data, + ".rewardsCoordinator.init_paused_status" + ); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.CALCULATION_INTERVAL_SECONDS") + ); + REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_REWARDS_DURATION")); + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_RETROACTIVE_LENGTH")); + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_FUTURE_LENGTH")); + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP")); + REWARDS_COORDINATOR_UPDATER = stdJson.readAddress(config_data, ".rewardsCoordinator.rewards_updater_address"); + REWARDS_COORDINATOR_ACTIVATION_DELAY = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.activation_delay")); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.calculation_interval_seconds") + ); + REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.global_operator_commission_bips") + ); + REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP") + ); + REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.OPERATOR_SET_MAX_RETROACTIVE_LENGTH") + ); + + STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( + stdJson.readUint(config_data, ".strategyManager.init_withdrawal_delay_blocks") + ); + + ALLOCATION_MANAGER_INIT_PAUSED_STATUS = uint32( + stdJson.readUint(config_data, ".allocationManager.init_paused_status") + ); + DEALLOCATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.DEALLOCATION_DELAY") + ); + ALLOCATION_CONFIGURATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.ALLOCATION_CONFIGURATION_DELAY") + ); + + executorMultisig = stdJson.readAddress(config_data, ".multisig_addresses.executorMultisig"); + operationsMultisig = stdJson.readAddress(config_data, ".multisig_addresses.operationsMultisig"); + pauserMultisig = stdJson.readAddress(config_data, ".multisig_addresses.pauserMultisig"); + + require(executorMultisig != address(0), "executorMultisig address not configured correctly!"); + require(operationsMultisig != address(0), "operationsMultisig address not configured correctly!"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // deploy proxy admin for ability to upgrade proxy contracts + eigenLayerProxyAdmin = new ProxyAdmin(); + + //deploy pauser registry + { + address[] memory pausers = new address[](3); + pausers[0] = executorMultisig; + pausers[1] = operationsMultisig; + pausers[2] = pauserMultisig; + eigenLayerPauserReg = new PauserRegistry(pausers, executorMultisig); + } + + /** + * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are + * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. + */ + emptyContract = new EmptyContract(); + delegation = DelegationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyManager = StrategyManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + avsDirectory = AVSDirectory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenPodManager = EigenPodManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + rewardsCoordinator = RewardsCoordinator( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + allocationManager = AllocationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyFactory = StrategyFactory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + permissionController = PermissionController( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // if on mainnet, use the ETH2 deposit contract address + if (chainId == 1) { + ethPOSDeposit = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); + // if not on mainnet, deploy a mock + } else { + ethPOSDeposit = IETHPOSDeposit(stdJson.readAddress(config_data, ".ethPOSDepositAddress")); + } + eigenPodImplementation = new EigenPod( + ethPOSDeposit, + eigenPodManager, + GOERLI_GENESIS_TIME + ); + + eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); + + // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs + + delegationImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); + eigenPodManagerImplementation = new EigenPodManager( + ethPOSDeposit, + eigenPodBeacon, + strategyManager, + delegation, + eigenLayerPauserReg + ); + rewardsCoordinatorImplementation = new RewardsCoordinator( + delegation, + strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + ); + allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); + permissionControllerImplementation = new PermissionController(); + strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg); + + // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. + { + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(delegation))), + address(delegationImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + executorMultisig, + DELEGATION_INIT_PAUSED_STATUS + ) + ); + } + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(strategyManager))), + address(strategyManagerImplementation), + abi.encodeWithSelector( + StrategyManager.initialize.selector, + executorMultisig, + operationsMultisig, + STRATEGY_MANAGER_INIT_PAUSED_STATUS + ) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation), + abi.encodeWithSelector(AVSDirectory.initialize.selector, executorMultisig, eigenLayerPauserReg, 0) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), + abi.encodeWithSelector( + EigenPodManager.initialize.selector, + executorMultisig, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + address(rewardsCoordinatorImplementation), + abi.encodeWithSelector( + RewardsCoordinator.initialize.selector, + executorMultisig, + REWARDS_COORDINATOR_INIT_PAUSED_STATUS, + REWARDS_COORDINATOR_UPDATER, + REWARDS_COORDINATOR_ACTIVATION_DELAY, + REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS + ) + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), + abi.encodeWithSelector( + AllocationManager.initialize.selector, + executorMultisig, + ALLOCATION_MANAGER_INIT_PAUSED_STATUS + ) + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector( + PermissionController.initialize.selector + ) + ); + + // Deploy strategyFactory & base + // Create base strategy implementation + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); + + // Create a proxy beacon for base strategy implementation + strategyBeacon = new UpgradeableBeacon(address(baseStrategyImplementation)); + + // Strategy Factory, upgrade and initalized + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(strategyFactory))), + address(strategyFactoryImplementation), + abi.encodeWithSelector( + StrategyFactory.initialize.selector, + executorMultisig, + 0, // initial paused status + IBeacon(strategyBeacon) + ) + ); + + // Set the strategyWhitelister to the factory + strategyManager.setStrategyWhitelister(address(strategyFactory)); + + // Deploy a WETH strategy + strategyFactory.deployNewStrategy(IERC20(address(0x94373a4919B3240D86eA41593D5eBa789FEF3848))); + + // Transfer ownership + eigenLayerProxyAdmin.transferOwnership(executorMultisig); + eigenPodBeacon.transferOwnership(executorMultisig); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + // CHECK CORRECTNESS OF DEPLOYMENT + _verifyContractsPointAtOneAnother( + delegationImplementation, + strategyManagerImplementation, + eigenPodManagerImplementation, + rewardsCoordinatorImplementation, + allocationManagerImplementation + ); + _verifyContractsPointAtOneAnother( + delegation, + strategyManager, + eigenPodManager, + rewardsCoordinator, + allocationManager + ); + _verifyImplementationsSetCorrectly(); + _verifyInitialOwners(); + _checkPauserInitializations(); + _verifyInitializationParams(); + + // Check DM and AM have same withdrawa/deallocation delay + // TODO: Update after AllocationManager is converted to timestamps as well + // require( + // delegation.MIN_WITHDRAWAL_DELAY_BLOCKS() == allocationManager.DEALLOCATION_DELAY(), + // "DelegationManager and AllocationManager have different withdrawal/deallocation delays" + // ); + require( + allocationManager.DEALLOCATION_DELAY() == 1 days + ); + require( + allocationManager.ALLOCATION_CONFIGURATION_DELAY() == 10 minutes + ); + + // WRITE JSON DATA + string memory parent_object = "parent object"; + + string memory deployed_strategies_output = ""; + + string memory deployed_addresses = "addresses"; + vm.serializeUint(deployed_addresses, "numStrategiesDeployed", 0); // for compatibility with other scripts + vm.serializeAddress(deployed_addresses, "eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); + vm.serializeAddress(deployed_addresses, "eigenLayerPauserReg", address(eigenLayerPauserReg)); + vm.serializeAddress(deployed_addresses, "delegationManager", address(delegation)); + vm.serializeAddress(deployed_addresses, "delegationManagerImplementation", address(delegationImplementation)); + vm.serializeAddress(deployed_addresses, "avsDirectory", address(avsDirectory)); + vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); + vm.serializeAddress(deployed_addresses, "allocationManager", address(allocationManager)); + vm.serializeAddress(deployed_addresses, "allocationManagerImplementation", address(allocationManagerImplementation)); + vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); + vm.serializeAddress( + deployed_addresses, + "strategyManagerImplementation", + address(strategyManagerImplementation) + ); + vm.serializeAddress( + deployed_addresses, "strategyFactory", address(strategyFactory) + ); + vm.serializeAddress( + deployed_addresses, "strategyFactoryImplementation", address(strategyFactoryImplementation) + ); + vm.serializeAddress(deployed_addresses, "strategyBeacon", address(strategyBeacon)); + vm.serializeAddress(deployed_addresses, "baseStrategyImplementation", address(baseStrategyImplementation)); + vm.serializeAddress(deployed_addresses, "eigenPodManager", address(eigenPodManager)); + vm.serializeAddress( + deployed_addresses, + "eigenPodManagerImplementation", + address(eigenPodManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "rewardsCoordinator", address(rewardsCoordinator)); + vm.serializeAddress( + deployed_addresses, + "rewardsCoordinatorImplementation", + address(rewardsCoordinatorImplementation) + ); + vm.serializeAddress(deployed_addresses, "eigenPodBeacon", address(eigenPodBeacon)); + vm.serializeAddress(deployed_addresses, "eigenPodImplementation", address(eigenPodImplementation)); + vm.serializeAddress(deployed_addresses, "emptyContract", address(emptyContract)); + + string memory deployed_addresses_output = vm.serializeString( + deployed_addresses, + "strategies", + deployed_strategies_output + ); + + { + // dummy token data + string memory token = '{"tokenProxyAdmin": "0x0000000000000000000000000000000000000000", "EIGEN": "0x0000000000000000000000000000000000000000","bEIGEN": "0x0000000000000000000000000000000000000000","EIGENImpl": "0x0000000000000000000000000000000000000000","bEIGENImpl": "0x0000000000000000000000000000000000000000","eigenStrategy": "0x0000000000000000000000000000000000000000","eigenStrategyImpl": "0x0000000000000000000000000000000000000000"}'; + deployed_addresses_output = vm.serializeString(deployed_addresses, "token", token); + } + + string memory parameters = "parameters"; + vm.serializeAddress(parameters, "executorMultisig", executorMultisig); + vm.serializeAddress(parameters, "communityMultisig", operationsMultisig); + vm.serializeAddress(parameters, "pauserMultisig", pauserMultisig); + vm.serializeAddress(parameters, "timelock", address(0)); + string memory parameters_output = vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); + + string memory chain_info = "chainInfo"; + vm.serializeUint(chain_info, "deploymentBlock", block.number); + string memory chain_info_output = vm.serializeUint(chain_info, "chainId", chainId); + + // serialize all the data + vm.serializeString(parent_object, deployed_addresses, deployed_addresses_output); + vm.serializeString(parent_object, chain_info, chain_info_output); + string memory finalJson = vm.serializeString(parent_object, parameters, parameters_output); + // TODO: should output to different file depending on configFile passed to run() + // so that we don't override mainnet output by deploying to goerli for eg. + vm.writeJson(finalJson, "script/output/devnet/slashing_output.json"); + } + + function _verifyContractsPointAtOneAnother( + DelegationManager delegationContract, + StrategyManager strategyManagerContract, + EigenPodManager eigenPodManagerContract, + RewardsCoordinator rewardsCoordinatorContract, + AllocationManager allocationManagerContract + ) internal view { + require( + delegationContract.strategyManager() == strategyManager, + "delegation: strategyManager address not set correctly" + ); + + require( + strategyManagerContract.delegation() == delegation, + "strategyManager: delegation address not set correctly" + ); + require( + eigenPodManagerContract.ethPOS() == ethPOSDeposit, + " eigenPodManager: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodManagerContract.eigenPodBeacon() == eigenPodBeacon, + "eigenPodManager: eigenPodBeacon contract address not set correctly" + ); + require( + eigenPodManagerContract.strategyManager() == strategyManager, + "eigenPodManager: strategyManager contract address not set correctly" + ); + + require( + rewardsCoordinatorContract.delegationManager() == delegation, + "rewardsCoordinator: delegation address not set correctly" + ); + require( + rewardsCoordinatorContract.strategyManager() == strategyManager, + "rewardsCoordinator: strategyManager address not set correctly" + ); + require( + delegationContract.allocationManager() == allocationManager, + "delegationManager: allocationManager address not set correctly" + ); + require( + allocationManagerContract.delegation() == delegation, + "allocationManager: delegation address not set correctly" + ); + } + + function _verifyImplementationsSetCorrectly() internal view { + require( + eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(delegation)))) == + address(delegationImplementation), + "delegation: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(strategyManager))) + ) == address(strategyManagerImplementation), + "strategyManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(eigenPodManager))) + ) == address(eigenPodManagerImplementation), + "eigenPodManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))) + ) == address(rewardsCoordinatorImplementation), + "rewardsCoordinator: implementation set incorrectly" + ); + + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(allocationManager))) + ) == address(allocationManagerImplementation), + "allocationManager: implementation set incorrectly" + ); + + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(strategyFactory))) + ) == address(strategyFactoryImplementation), + "strategyFactory: implementation set incorrectly" + ); + + require( + eigenPodBeacon.implementation() == address(eigenPodImplementation), + "eigenPodBeacon: implementation set incorrectly" + ); + + require( + strategyBeacon.implementation() == address(baseStrategyImplementation), + "strategyBeacon: implementation set incorrectly" + ); + } + + function _verifyInitialOwners() internal view { + require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); + require(delegation.owner() == executorMultisig, "delegation: owner not set correctly"); + require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); + require(allocationManager.owner() == executorMultisig, "allocationManager: owner not set correctly"); + require(eigenLayerProxyAdmin.owner() == executorMultisig, "eigenLayerProxyAdmin: owner not set correctly"); + require(eigenPodBeacon.owner() == executorMultisig, "eigenPodBeacon: owner not set correctly"); + require(strategyBeacon.owner() == executorMultisig, "strategyBeacon: owner not set correctly"); + } + + function _checkPauserInitializations() internal view { + require(delegation.pauserRegistry() == eigenLayerPauserReg, "delegation: pauser registry not set correctly"); + require( + strategyManager.pauserRegistry() == eigenLayerPauserReg, + "strategyManager: pauser registry not set correctly" + ); + require( + eigenPodManager.pauserRegistry() == eigenLayerPauserReg, + "eigenPodManager: pauser registry not set correctly" + ); + require( + rewardsCoordinator.pauserRegistry() == eigenLayerPauserReg, + "rewardsCoordinator: pauser registry not set correctly" + ); + require( + allocationManager.pauserRegistry() == eigenLayerPauserReg, + "allocationManager: pauser registry not set correctly" + ); + + require(eigenLayerPauserReg.isPauser(operationsMultisig), "pauserRegistry: operationsMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(executorMultisig), "pauserRegistry: executorMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), "pauserRegistry: pauserMultisig is not pauser"); + require(eigenLayerPauserReg.unpauser() == executorMultisig, "pauserRegistry: unpauser not set correctly"); + + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, + "StrategyBaseTVLLimits: pauser registry not set correctly" + ); + require( + deployedStrategyArray[i].paused() == 0, + "StrategyBaseTVLLimits: init paused status set incorrectly" + ); + } + + // // pause *nothing* + // uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS = 0; + // // pause *everything* + // // pause *everything* + // uint256 DELEGATION_INIT_PAUSED_STATUS = type(uint256).max; + // // pause *all of the proof-related functionality* (everything that can be paused other than creation of EigenPods) + // uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS = (2**1) + (2**2) + (2**3) + (2**4); /* = 30 */ + // // pause *nothing* + // require(strategyManager.paused() == 0, "strategyManager: init paused status set incorrectly"); + // require(delegation.paused() == type(uint256).max, "delegation: init paused status set incorrectly"); + // require(eigenPodManager.paused() == 30, "eigenPodManager: init paused status set incorrectly"); + } + + function _verifyInitializationParams() internal view { + // // one week in blocks -- 50400 + // uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = 7 days / 12 seconds; + // require(strategyManager.withdrawalDelayBlocks() == 7 days / 12 seconds, + // "strategyManager: withdrawalDelayBlocks initialized incorrectly"); + // uint256 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32 ether; + + require( + address(strategyManager.strategyWhitelister()) == address(strategyFactory), + "strategyManager: strategyWhitelister address not set correctly" + ); + + require( + baseStrategyImplementation.strategyManager() == strategyManager, + "baseStrategyImplementation: strategyManager set incorrectly" + ); + + require( + eigenPodImplementation.ethPOS() == ethPOSDeposit, + "eigenPodImplementation: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodImplementation.eigenPodManager() == eigenPodManager, + " eigenPodImplementation: eigenPodManager contract address not set correctly" + ); + } +} diff --git a/script/deploy/holesky/Deploy_Preprod_RewardsCoordinator.s.sol b/script/deploy/holesky/Deploy_Preprod_RewardsCoordinator.s.sol index c395c2f5f..61c504c94 100644 --- a/script/deploy/holesky/Deploy_Preprod_RewardsCoordinator.s.sol +++ b/script/deploy/holesky/Deploy_Preprod_RewardsCoordinator.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./Deploy_Test_RewardsCoordinator.s.sol"; diff --git a/script/deploy/holesky/Deploy_Test_RewardsCoordinator.s.sol b/script/deploy/holesky/Deploy_Test_RewardsCoordinator.s.sol index 11bb5f61c..402007876 100644 --- a/script/deploy/holesky/Deploy_Test_RewardsCoordinator.s.sol +++ b/script/deploy/holesky/Deploy_Test_RewardsCoordinator.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; @@ -46,6 +46,9 @@ contract Deploy_Test_RewardsCoordinator is ExistingDeploymentParser { rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -60,7 +63,6 @@ contract Deploy_Test_RewardsCoordinator is ExistingDeploymentParser { abi.encodeWithSelector( RewardsCoordinator.initialize.selector, executorMultisig, - eigenLayerPauserReg, REWARDS_COORDINATOR_INIT_PAUSED_STATUS, REWARDS_COORDINATOR_UPDATER, REWARDS_COORDINATOR_ACTIVATION_DELAY, @@ -79,6 +81,9 @@ contract Deploy_Test_RewardsCoordinator is ExistingDeploymentParser { rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -87,7 +92,7 @@ contract Deploy_Test_RewardsCoordinator is ExistingDeploymentParser { ); eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), address(rewardsCoordinatorImplementation) ); } @@ -119,6 +124,9 @@ contract Deploy_Test_RewardsCoordinator is ExistingDeploymentParser { rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, diff --git a/script/deploy/holesky/Eigen_Strategy_Deploy.s.sol b/script/deploy/holesky/Eigen_Strategy_Deploy.s.sol index 233f158bb..a33a50381 100644 --- a/script/deploy/holesky/Eigen_Strategy_Deploy.s.sol +++ b/script/deploy/holesky/Eigen_Strategy_Deploy.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; @@ -30,7 +30,7 @@ contract Eigen_Strategy_Deploy is ExistingDeploymentParser { } function _deployStrategy() internal { - eigenStrategyImpl = new EigenStrategy(strategyManager); + eigenStrategyImpl = new EigenStrategy(strategyManager, eigenLayerPauserReg); eigenStrategy = EigenStrategy( address( @@ -40,8 +40,7 @@ contract Eigen_Strategy_Deploy is ExistingDeploymentParser { abi.encodeWithSelector( EigenStrategy.initialize.selector, EIGEN, - bEIGEN, - eigenLayerPauserReg + bEIGEN ) ) ) @@ -58,11 +57,9 @@ contract Eigen_Strategy_Deploy is ExistingDeploymentParser { function _verifyDeployment() internal { IStrategy[] memory strategies = new IStrategy[](1); strategies[0] = eigenStrategy; - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); - thirdPartyTransfersForbiddenValues[0] = true; vm.prank(executorMultisig); - strategyManager.addStrategiesToDepositWhitelist(strategies, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategies); vm.startPrank(msg.sender); EIGEN.approve(address(strategyManager), type(uint256).max); diff --git a/script/deploy/holesky/Eigen_Token_Deploy.s.sol b/script/deploy/holesky/Eigen_Token_Deploy.s.sol index bd130a034..6f5e78878 100644 --- a/script/deploy/holesky/Eigen_Token_Deploy.s.sol +++ b/script/deploy/holesky/Eigen_Token_Deploy.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; @@ -71,7 +71,7 @@ contract Eigen_Token_Deploy is Script, Test { // upgrade and initialize proxies tokenProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(EIGEN))), + ITransparentUpgradeableProxy(payable(address(EIGEN))), address(EIGENImpl), abi.encodeWithSelector( Eigen.initialize.selector, @@ -85,7 +85,7 @@ contract Eigen_Token_Deploy is Script, Test { EIGEN.mint(); tokenProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(bEIGEN))), + ITransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl), abi.encodeWithSelector( BackingEigen.initialize.selector, @@ -106,8 +106,8 @@ contract Eigen_Token_Deploy is Script, Test { require(EIGEN.owner() == msg.sender, "Eigen_Token_Deploy: EIGEN owner mismatch"); require(bEIGEN.owner() == msg.sender, "Eigen_Token_Deploy: bEIGEN owner mismatch"); - require(tokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN)))) == address(EIGENImpl), "Eigen_Token_Deploy: EIGEN implementation mismatch"); - require(tokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN)))) == address(bEIGENImpl), "Eigen_Token_Deploy: bEIGEN implementation mismatch"); + require(tokenProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(EIGEN)))) == address(EIGENImpl), "Eigen_Token_Deploy: EIGEN implementation mismatch"); + require(tokenProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(bEIGEN)))) == address(bEIGENImpl), "Eigen_Token_Deploy: bEIGEN implementation mismatch"); require(tokenProxyAdmin.owner() == operationsMultisig, "Eigen_Token_Deploy: ProxyAdmin owner mismatch"); } diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index c495cf650..6d90221c5 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; @@ -61,12 +61,13 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { strategyManager = StrategyManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); - slasher = Slasher( + eigenPodManager = EigenPodManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); - eigenPodManager = EigenPodManager( + allocationManager = AllocationManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); + // Deploy EigenPod Contracts eigenPodImplementation = new EigenPod( IETHPOSDeposit(ETHPOSDepositAddress), @@ -75,24 +76,25 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { ); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); - avsDirectoryImplementation = new AVSDirectory(delegationManager); - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); + avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); + delegationManagerImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); eigenPodManagerImplementation = new EigenPodManager( IETHPOSDeposit(ETHPOSDepositAddress), eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); + allocationManagerImplementation = new AllocationManager(delegationManager, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); + permissionControllerImplementation = new PermissionController(); // Third, upgrade the proxy contracts to point to the implementations IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); // AVSDirectory eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), + ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation), abi.encodeWithSelector( AVSDirectory.initialize.selector, @@ -103,7 +105,7 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { ); // DelegationManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegationManager))), + ITransparentUpgradeableProxy(payable(address(delegationManager))), address(delegationManagerImplementation), abi.encodeWithSelector( DelegationManager.initialize.selector, @@ -117,7 +119,7 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { ); // StrategyManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), + ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation), abi.encodeWithSelector( StrategyManager.initialize.selector, @@ -127,35 +129,42 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { STRATEGY_MANAGER_INIT_PAUSED_STATUS ) ); - // Slasher + // EigenPodManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), abi.encodeWithSelector( - Slasher.initialize.selector, - executorMultisig, + EigenPodManager.initialize.selector, + msg.sender, // initialOwner is msg.sender for now to set forktimestamp later eigenLayerPauserReg, - SLASHER_INIT_PAUSED_STATUS + EIGENPOD_MANAGER_INIT_PAUSED_STATUS ) ); - // EigenPodManager + // AllocationManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation), + ITransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), abi.encodeWithSelector( - EigenPodManager.initialize.selector, + AllocationManager.initialize.selector, msg.sender, // initialOwner is msg.sender for now to set forktimestamp later eigenLayerPauserReg, - EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ALLOCATION_MANAGER_INIT_PAUSED_STATUS + ) + ); + // PermissionController + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector( + PermissionController.initialize.selector ) ); // Deploy Strategies - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg); uint256 numStrategiesToDeploy = strategiesToDeploy.length; // whitelist params IStrategy[] memory strategiesToWhitelist = new IStrategy[](numStrategiesToDeploy); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](numStrategiesToDeploy); for (uint256 i = 0; i < numStrategiesToDeploy; i++) { StrategyUnderlyingTokenConfig memory strategyConfig = strategiesToDeploy[i]; @@ -165,25 +174,23 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategy))), + ITransparentUpgradeableProxy(payable(address(strategy))), address(baseStrategyImplementation), abi.encodeWithSelector( StrategyBaseTVLLimits.initialize.selector, STRATEGY_MAX_PER_DEPOSIT, STRATEGY_MAX_TOTAL_DEPOSITS, - IERC20(strategyConfig.tokenAddress), - eigenLayerPauserReg + IERC20(strategyConfig.tokenAddress) ) ); strategiesToWhitelist[i] = strategy; - thirdPartyTransfersForbiddenValues[i] = false; deployedStrategyArray.push(strategy); } // Add strategies to whitelist and set whitelister to STRATEGY_MANAGER_WHITELISTER - strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist); strategyManager.setStrategyWhitelister(STRATEGY_MANAGER_WHITELISTER); // Transfer ownership diff --git a/script/deploy/holesky/M2_Deploy_Preprod.s.sol b/script/deploy/holesky/M2_Deploy_Preprod.s.sol index f5c0562f9..349de9b1b 100644 --- a/script/deploy/holesky/M2_Deploy_Preprod.s.sol +++ b/script/deploy/holesky/M2_Deploy_Preprod.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./M2_Deploy_From_Scratch.s.sol"; diff --git a/script/deploy/holesky/Preprod_Upgrade_bEIGEN_and_EIGEN.s.sol b/script/deploy/holesky/Preprod_Upgrade_bEIGEN_and_EIGEN.s.sol index bd454b90b..097cac3b1 100644 --- a/script/deploy/holesky/Preprod_Upgrade_bEIGEN_and_EIGEN.s.sol +++ b/script/deploy/holesky/Preprod_Upgrade_bEIGEN_and_EIGEN.s.sol @@ -61,11 +61,11 @@ contract Preprod_Upgrade_bEIGEN_and_EIGEN is Script, Test { // Perform upgrade vm.startBroadcast(); EIGEN_ProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(bEIGEN_proxy))), + ITransparentUpgradeableProxy(payable(address(bEIGEN_proxy))), address(bEIGEN_implementation) ); EIGEN_ProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(EIGEN_proxy))), + ITransparentUpgradeableProxy(payable(address(EIGEN_proxy))), address(EIGEN_implementation) ); vm.stopBroadcast(); @@ -77,11 +77,11 @@ contract Preprod_Upgrade_bEIGEN_and_EIGEN is Script, Test { function checkUpgradeCorrectness() public { cheats.startPrank(address(proxyAdminOwner)); - require(EIGEN_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), + require(EIGEN_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), "implementation set incorrectly"); require(EIGEN_proxy.bEIGEN() == bEIGEN_addressBefore, "bEIGEN address changed unexpectedly"); - require(EIGEN_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), + require(EIGEN_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), "implementation set incorrectly"); require(bEIGEN_proxy.EIGEN() == EIGEN_addressBefore, "EIGEN address changed unexpectedly"); diff --git a/script/deploy/holesky/bEIGEN_and_EIGEN_upgrade.s.sol b/script/deploy/holesky/bEIGEN_and_EIGEN_upgrade.s.sol index 516bdebf7..c8e1184a2 100644 --- a/script/deploy/holesky/bEIGEN_and_EIGEN_upgrade.s.sol +++ b/script/deploy/holesky/bEIGEN_and_EIGEN_upgrade.s.sol @@ -70,18 +70,18 @@ contract bEIGEN_and_EIGEN_upgrade is Script, Test { function simulatePerformingUpgrade() public { cheats.startPrank(opsMultisig); // Upgrade contracts - token_ProxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(EIGEN_proxy))), address(EIGEN_implementation)); - token_ProxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(bEIGEN_proxy))), address(bEIGEN_implementation)); + token_ProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(EIGEN_proxy))), address(EIGEN_implementation)); + token_ProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(bEIGEN_proxy))), address(bEIGEN_implementation)); cheats.stopPrank(); } function checkUpgradeCorrectness() public { vm.startPrank(opsMultisig); - require(token_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), + require(token_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), "implementation set incorrectly"); require(EIGEN_proxy.bEIGEN() == bEIGEN_addressBefore, "bEIGEN address changed unexpectedly"); - require(token_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), + require(token_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), "implementation set incorrectly"); require(bEIGEN_proxy.EIGEN() == EIGEN_addressBefore, "EIGEN address changed unexpectedly"); diff --git a/script/deploy/holesky/longtail-preprod-upgrade.s.sol b/script/deploy/holesky/longtail-preprod-upgrade.s.sol index 2a9b7b9cf..ba833e7b2 100644 --- a/script/deploy/holesky/longtail-preprod-upgrade.s.sol +++ b/script/deploy/holesky/longtail-preprod-upgrade.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; @@ -39,8 +39,8 @@ contract Longtail_Upgrade_Preprod is ExistingDeploymentParser { function _deployLongtail() internal { // Deploy implementations - strategyFactoryImplementation = new StrategyFactory(strategyManager); - strategyFactoryBeaconImplementation = new StrategyBase(strategyManager); + strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg); + strategyFactoryBeaconImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); // Deploy and initialize proxies strategyBeacon = new UpgradeableBeacon(address(strategyFactoryBeaconImplementation)); @@ -88,8 +88,8 @@ contract Longtail_Upgrade_Preprod is ExistingDeploymentParser { function _sanityChecks() internal { // Sanity checks - require(eigenLayerProxyAdmin.getProxyAdmin(TransparentUpgradeableProxy(payable(address(strategyFactory)))) == address(eigenLayerProxyAdmin), "proxy admin not set correctly"); - require(eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(strategyFactory)))) == address(strategyFactoryImplementation), "proxy impl not set correctly"); + require(eigenLayerProxyAdmin.getProxyAdmin(ITransparentUpgradeableProxy(payable(address(strategyFactory)))) == address(eigenLayerProxyAdmin), "proxy admin not set correctly"); + require(eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(strategyFactory)))) == address(strategyFactoryImplementation), "proxy impl not set correctly"); require(strategyFactory.owner() == initOwner, "owner not set correctly"); require(strategyFactory.pauserRegistry() == eigenLayerPauserReg, "pauser not set correctly"); diff --git a/script/deploy/holesky/v0.4.3-upgrade_testnet_rewardsCoordinator.s.sol b/script/deploy/holesky/v0.4.3-upgrade_testnet_rewardsCoordinator.s.sol index 108b588e9..fa21699b7 100644 --- a/script/deploy/holesky/v0.4.3-upgrade_testnet_rewardsCoordinator.s.sol +++ b/script/deploy/holesky/v0.4.3-upgrade_testnet_rewardsCoordinator.s.sol @@ -24,6 +24,9 @@ contract Upgrade_Testnet_RewardsCoordinator is Deploy_Test_RewardsCoordinator, T rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -39,7 +42,7 @@ contract Upgrade_Testnet_RewardsCoordinator is Deploy_Test_RewardsCoordinator, T // Create Upgrade Tx via Community Multisig bytes memory calldata_to_proxy_admin = abi.encodeWithSelector( ProxyAdmin.upgrade.selector, - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), rewardsCoordinatorImplementation ); @@ -63,7 +66,7 @@ contract Upgrade_Testnet_RewardsCoordinator is Deploy_Test_RewardsCoordinator, T _verifyInitializationParams(); } - function _sanityCheckImplementations(RewardsCoordinator oldRc, RewardsCoordinator newRc) internal { + function _sanityCheckImplementations(RewardsCoordinator oldRc, RewardsCoordinator newRc) internal view { // Verify configs between both rewardsCoordinatorImplementations assertEq( address(oldRc.delegationManager()), diff --git a/script/deploy/holesky/v040-holesky-pepe.s.sol b/script/deploy/holesky/v040-holesky-pepe.s.sol index 6b12ccf56..4b8d0cf5b 100644 --- a/script/deploy/holesky/v040-holesky-pepe.s.sol +++ b/script/deploy/holesky/v040-holesky-pepe.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../utils/ExistingDeploymentParser.sol"; @@ -33,7 +33,6 @@ contract PEPE_Deploy_Preprod is ExistingDeploymentParser { emit log_named_address("- epm.ethPOS", address(eigenPodManagerImplementation.ethPOS())); emit log_named_address("- epm.eigenPodBeacon", address(eigenPodManagerImplementation.eigenPodBeacon())); emit log_named_address("- epm.strategyManager", address(eigenPodManagerImplementation.strategyManager())); - emit log_named_address("- epm.slasher", address(eigenPodManagerImplementation.slasher())); emit log_named_address("- epm.delegationManager", address(eigenPodManagerImplementation.delegationManager())); // START RECORDING TRANSACTIONS FOR DEPLOYMENT @@ -60,8 +59,8 @@ contract PEPE_Deploy_Preprod is ExistingDeploymentParser { IETHPOSDeposit(ETHPOSDepositAddress), eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); } @@ -71,7 +70,7 @@ contract PEPE_Deploy_Preprod is ExistingDeploymentParser { // upgrade TUPS eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) ); } diff --git a/script/deploy/local/Deploy_From_Scratch.s.sol b/script/deploy/local/Deploy_From_Scratch.s.sol index 564e43afe..857f09582 100644 --- a/script/deploy/local/Deploy_From_Scratch.s.sol +++ b/script/deploy/local/Deploy_From_Scratch.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; @@ -9,10 +9,11 @@ import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "../../../src/contracts/interfaces/IETHPOSDeposit.sol"; import "../../../src/contracts/core/StrategyManager.sol"; -import "../../../src/contracts/core/Slasher.sol"; import "../../../src/contracts/core/DelegationManager.sol"; import "../../../src/contracts/core/AVSDirectory.sol"; import "../../../src/contracts/core/RewardsCoordinator.sol"; +import "../../../src/contracts/core/AllocationManager.sol"; +import "../../../src/contracts/permissions/PermissionController.sol"; import "../../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; @@ -31,7 +32,7 @@ import "forge-std/Test.sol"; // source .env // # To deploy and verify our contract -// RUST_LOG=forge,foundry=trace forge script script/deploy/local/Deploy_From_Scratch.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/deploy_from_scratch.anvil.config.json +// forge script script/deploy/local/Deploy_From_Scratch.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/deploy_from_scratch.anvil.config.json contract DeployFromScratch is Script, Test { Vm cheats = Vm(VM_ADDRESS); @@ -48,8 +49,6 @@ contract DeployFromScratch is Script, Test { // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; PauserRegistry public eigenLayerPauserReg; - Slasher public slasher; - Slasher public slasherImplementation; DelegationManager public delegation; DelegationManager public delegationImplementation; StrategyManager public strategyManager; @@ -63,6 +62,10 @@ contract DeployFromScratch is Script, Test { UpgradeableBeacon public eigenPodBeacon; EigenPod public eigenPodImplementation; StrategyBase public baseStrategyImplementation; + AllocationManager public allocationManagerImplementation; + AllocationManager public allocationManager; + PermissionController public permissionController; + PermissionController public permissionControllerImplementation; EmptyContract public emptyContract; @@ -81,11 +84,17 @@ contract DeployFromScratch is Script, Test { // OTHER DEPLOYMENT PARAMETERS uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; - uint256 SLASHER_INIT_PAUSED_STATUS; uint256 DELEGATION_INIT_PAUSED_STATUS; uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; uint256 REWARDS_COORDINATOR_INIT_PAUSED_STATUS; + // DelegationManager + uint32 MIN_WITHDRAWAL_DELAY; + + // AllocationManager + uint32 DEALLOCATION_DELAY; + uint32 ALLOCATION_CONFIGURATION_DELAY; + // RewardsCoordinator uint32 REWARDS_COORDINATOR_MAX_REWARDS_DURATION; uint32 REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH; @@ -98,6 +107,9 @@ contract DeployFromScratch is Script, Test { uint32 REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP; uint32 REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH; + // AllocationManager + uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; + // one week in blocks -- 50400 uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS; uint256 DELEGATION_WITHDRAWAL_DELAY_BLOCKS; @@ -113,7 +125,6 @@ contract DeployFromScratch is Script, Test { // bytes memory parsedData = vm.parseJson(config_data); STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); - SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".slasher.init_paused_status"); DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".eigenPodManager.init_paused_status"); @@ -147,6 +158,16 @@ contract DeployFromScratch is Script, Test { stdJson.readUint(config_data, ".strategyManager.init_withdrawal_delay_blocks") ); + ALLOCATION_MANAGER_INIT_PAUSED_STATUS = uint32( + stdJson.readUint(config_data, ".allocationManager.init_paused_status") + ); + DEALLOCATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.DEALLOCATION_DELAY") + ); + ALLOCATION_CONFIGURATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.ALLOCATION_CONFIGURATION_DELAY") + ); + // tokens to deploy strategies for StrategyConfig[] memory strategyConfigs; @@ -189,15 +210,18 @@ contract DeployFromScratch is Script, Test { avsDirectory = AVSDirectory( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); eigenPodManager = EigenPodManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); rewardsCoordinator = RewardsCoordinator( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); + allocationManager = AllocationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + permissionController = PermissionController( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); // if on mainnet, use the ETH2 deposit contract address if (chainId == 1) { @@ -215,38 +239,42 @@ contract DeployFromScratch is Script, Test { eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegation, eigenPodManager, slasher); - avsDirectoryImplementation = new AVSDirectory(delegation); - slasherImplementation = new Slasher(strategyManager, delegation); + + delegationImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, - slasher, - delegation + delegation, + eigenLayerPauserReg ); rewardsCoordinatorImplementation = new RewardsCoordinator( delegation, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP ); + allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); + permissionControllerImplementation = new PermissionController(); // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. { IStrategy[] memory _strategies; uint256[] memory _withdrawalDelayBlocks; eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegation))), + ITransparentUpgradeableProxy(payable(address(delegation))), address(delegationImplementation), abi.encodeWithSelector( DelegationManager.initialize.selector, executorMultisig, - eigenLayerPauserReg, DELEGATION_INIT_PAUSED_STATUS, DELEGATION_WITHDRAWAL_DELAY_BLOCKS, _strategies, @@ -255,48 +283,35 @@ contract DeployFromScratch is Script, Test { ); } eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), + ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation), abi.encodeWithSelector( StrategyManager.initialize.selector, executorMultisig, operationsMultisig, - eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS ) ); eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - executorMultisig, - eigenLayerPauserReg, - SLASHER_INIT_PAUSED_STATUS - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), + ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation), - abi.encodeWithSelector(AVSDirectory.initialize.selector, executorMultisig, eigenLayerPauserReg, 0) + abi.encodeWithSelector(AVSDirectory.initialize.selector, executorMultisig, 0) ); eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, executorMultisig, - eigenLayerPauserReg, EIGENPOD_MANAGER_INIT_PAUSED_STATUS ) ); eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), address(rewardsCoordinatorImplementation), abi.encodeWithSelector( RewardsCoordinator.initialize.selector, executorMultisig, - eigenLayerPauserReg, REWARDS_COORDINATOR_INIT_PAUSED_STATUS, REWARDS_COORDINATOR_UPDATER, REWARDS_COORDINATOR_ACTIVATION_DELAY, @@ -304,8 +319,26 @@ contract DeployFromScratch is Script, Test { ) ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), + abi.encodeWithSelector( + AllocationManager.initialize.selector, + executorMultisig, + ALLOCATION_MANAGER_INIT_PAUSED_STATUS + ) + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector( + PermissionController.initialize.selector + ) + ); + // deploy StrategyBaseTVLLimits contract implementation - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg); // create upgradeable proxies that each point to the implementation and initialize them for (uint256 i = 0; i < strategyConfigs.length; ++i) { if (strategyConfigs[i].tokenAddress == address(0)) { @@ -321,8 +354,7 @@ contract DeployFromScratch is Script, Test { StrategyBaseTVLLimits.initialize.selector, strategyConfigs[i].maxPerDeposit, strategyConfigs[i].maxDeposits, - IERC20(strategyConfigs[i].tokenAddress), - eigenLayerPauserReg + IERC20(strategyConfigs[i].tokenAddress) ) ) ) @@ -330,9 +362,11 @@ contract DeployFromScratch is Script, Test { ); } + // Transfer ownership eigenLayerProxyAdmin.transferOwnership(executorMultisig); eigenPodBeacon.transferOwnership(executorMultisig); + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT vm.stopBroadcast(); @@ -340,14 +374,12 @@ contract DeployFromScratch is Script, Test { _verifyContractsPointAtOneAnother( delegationImplementation, strategyManagerImplementation, - slasherImplementation, eigenPodManagerImplementation, rewardsCoordinatorImplementation ); _verifyContractsPointAtOneAnother( delegation, strategyManager, - slasher, eigenPodManager, rewardsCoordinator ); @@ -375,12 +407,12 @@ contract DeployFromScratch is Script, Test { vm.serializeUint(deployed_addresses, "numStrategiesDeployed", 0); // for compatibility with other scripts vm.serializeAddress(deployed_addresses, "eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); vm.serializeAddress(deployed_addresses, "eigenLayerPauserReg", address(eigenLayerPauserReg)); - vm.serializeAddress(deployed_addresses, "slasher", address(slasher)); - vm.serializeAddress(deployed_addresses, "slasherImplementation", address(slasherImplementation)); vm.serializeAddress(deployed_addresses, "delegationManager", address(delegation)); vm.serializeAddress(deployed_addresses, "delegationManagerImplementation", address(delegationImplementation)); vm.serializeAddress(deployed_addresses, "avsDirectory", address(avsDirectory)); vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); + vm.serializeAddress(deployed_addresses, "allocationManager", address(allocationManager)); + vm.serializeAddress(deployed_addresses, "allocationManagerImplementation", address(allocationManagerImplementation)); vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); vm.serializeAddress( deployed_addresses, @@ -433,42 +465,24 @@ contract DeployFromScratch is Script, Test { string memory finalJson = vm.serializeString(parent_object, parameters, parameters_output); // TODO: should output to different file depending on configFile passed to run() // so that we don't override mainnet output by deploying to goerli for eg. - vm.writeJson(finalJson, "script/output/devnet/local_from_scratch_deployment_data.json"); - - // generate + write eigenpods to file - address podAddress = eigenPodManager.createPod(); - string memory eigenpodStruct = "eigenpodStruct"; - string memory json = vm.serializeAddress(eigenpodStruct, "podAddress", podAddress); - vm.writeJson(json, "script/output/eigenpods.json"); + vm.writeJson(finalJson, "script/output/devnet/M2_from_scratch_deployment_data.json"); } function _verifyContractsPointAtOneAnother( DelegationManager delegationContract, StrategyManager strategyManagerContract, - Slasher /*slasherContract*/, EigenPodManager eigenPodManagerContract, RewardsCoordinator rewardsCoordinatorContract ) internal view { - require(delegationContract.slasher() == slasher, "delegation: slasher address not set correctly"); require( delegationContract.strategyManager() == strategyManager, "delegation: strategyManager address not set correctly" ); - require(strategyManagerContract.slasher() == slasher, "strategyManager: slasher address not set correctly"); require( strategyManagerContract.delegation() == delegation, "strategyManager: delegation address not set correctly" ); - require( - strategyManagerContract.eigenPodManager() == eigenPodManager, - "strategyManager: eigenPodManager address not set correctly" - ); - - // removing slasher requirements because there is no slasher as part of m2-mainnet release - // require(slasherContract.strategyManager() == strategyManager, "slasher: strategyManager not set correctly"); - // require(slasherContract.delegation() == delegation, "slasher: delegation not set correctly"); - require( eigenPodManagerContract.ethPOS() == ethPOSDeposit, " eigenPodManager: ethPOSDeposit contract address not set correctly" @@ -481,10 +495,6 @@ contract DeployFromScratch is Script, Test { eigenPodManagerContract.strategyManager() == strategyManager, "eigenPodManager: strategyManager contract address not set correctly" ); - require( - eigenPodManagerContract.slasher() == slasher, - "eigenPodManager: slasher contract address not set correctly" - ); require( rewardsCoordinatorContract.delegationManager() == delegation, @@ -499,38 +509,40 @@ contract DeployFromScratch is Script, Test { function _verifyImplementationsSetCorrectly() internal view { require( - eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(delegation)))) == + eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(delegation)))) == address(delegationImplementation), "delegation: implementation set incorrectly" ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(strategyManager))) + ITransparentUpgradeableProxy(payable(address(strategyManager))) ) == address(strategyManagerImplementation), "strategyManager: implementation set incorrectly" ); - require( - eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(slasher)))) == - address(slasherImplementation), - "slasher: implementation set incorrectly" - ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(eigenPodManager))) + ITransparentUpgradeableProxy(payable(address(eigenPodManager))) ) == address(eigenPodManagerImplementation), "eigenPodManager: implementation set incorrectly" ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))) + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))) ) == address(rewardsCoordinatorImplementation), "rewardsCoordinator: implementation set incorrectly" ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(allocationManager))) + ) == address(allocationManagerImplementation), + "allocationManager: implementation set incorrectly" + ); + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) + ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) ) == address(baseStrategyImplementation), "strategy: implementation set incorrectly" ); @@ -545,8 +557,6 @@ contract DeployFromScratch is Script, Test { function _verifyInitialOwners() internal view { require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); require(delegation.owner() == executorMultisig, "delegation: owner not set correctly"); - // removing slasher requirements because there is no slasher as part of m2-mainnet release - // require(slasher.owner() == executorMultisig, "slasher: owner not set correctly"); require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); require(eigenLayerProxyAdmin.owner() == executorMultisig, "eigenLayerProxyAdmin: owner not set correctly"); @@ -559,8 +569,6 @@ contract DeployFromScratch is Script, Test { strategyManager.pauserRegistry() == eigenLayerPauserReg, "strategyManager: pauser registry not set correctly" ); - // removing slasher requirements because there is no slasher as part of m2-mainnet release - // require(slasher.pauserRegistry() == eigenLayerPauserReg, "slasher: pauser registry not set correctly"); require( eigenPodManager.pauserRegistry() == eigenLayerPauserReg, "eigenPodManager: pauser registry not set correctly" @@ -589,19 +597,17 @@ contract DeployFromScratch is Script, Test { // // pause *nothing* // uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS = 0; // // pause *everything* - // uint256 SLASHER_INIT_PAUSED_STATUS = type(uint256).max; // // pause *everything* // uint256 DELEGATION_INIT_PAUSED_STATUS = type(uint256).max; // // pause *all of the proof-related functionality* (everything that can be paused other than creation of EigenPods) // uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS = (2**1) + (2**2) + (2**3) + (2**4); /* = 30 */ // // pause *nothing* // require(strategyManager.paused() == 0, "strategyManager: init paused status set incorrectly"); - // require(slasher.paused() == type(uint256).max, "slasher: init paused status set incorrectly"); // require(delegation.paused() == type(uint256).max, "delegation: init paused status set incorrectly"); // require(eigenPodManager.paused() == 30, "eigenPodManager: init paused status set incorrectly"); } - function _verifyInitializationParams() internal { + function _verifyInitializationParams() internal view { // // one week in blocks -- 50400 // uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = 7 days / 12 seconds; // require(strategyManager.withdrawalDelayBlocks() == 7 days / 12 seconds, diff --git a/script/deploy/local/deploy_from_scratch.slashing.s.sol b/script/deploy/local/deploy_from_scratch.slashing.s.sol new file mode 100644 index 000000000..692290be4 --- /dev/null +++ b/script/deploy/local/deploy_from_scratch.slashing.s.sol @@ -0,0 +1,657 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; + +import "../../../src/contracts/interfaces/IETHPOSDeposit.sol"; + +import "../../../src/contracts/core/StrategyManager.sol"; +import "../../../src/contracts/core/DelegationManager.sol"; +import "../../../src/contracts/core/AVSDirectory.sol"; +import "../../../src/contracts/core/RewardsCoordinator.sol"; +import "../../../src/contracts/core/AllocationManager.sol"; +import "../../../src/contracts/permissions/PermissionController.sol"; + +import "../../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; + +import "../../../src/contracts/pods/EigenPod.sol"; +import "../../../src/contracts/pods/EigenPodManager.sol"; + +import "../../../src/contracts/permissions/PauserRegistry.sol"; + +import "../../../src/test/mocks/EmptyContract.sol"; +import "../../../src/test/mocks/ETHDepositMock.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// # To load the variables in the .env file +// source .env + +// # To deploy and verify our contract +// forge script script/deploy/local/deploy_from_scratch.slashing.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/deploy_from_scratch.slashing.anvil.config.json +contract DeployFromScratch is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + // struct used to encode token info in config file + struct StrategyConfig { + uint256 maxDeposits; + uint256 maxPerDeposit; + address tokenAddress; + string tokenSymbol; + } + + string public deployConfigPath; + + // EigenLayer Contracts + ProxyAdmin public eigenLayerProxyAdmin; + PauserRegistry public eigenLayerPauserReg; + DelegationManager public delegation; + DelegationManager public delegationImplementation; + StrategyManager public strategyManager; + StrategyManager public strategyManagerImplementation; + RewardsCoordinator public rewardsCoordinator; + RewardsCoordinator public rewardsCoordinatorImplementation; + AVSDirectory public avsDirectory; + AVSDirectory public avsDirectoryImplementation; + EigenPodManager public eigenPodManager; + EigenPodManager public eigenPodManagerImplementation; + UpgradeableBeacon public eigenPodBeacon; + EigenPod public eigenPodImplementation; + StrategyBase public baseStrategyImplementation; + AllocationManager public allocationManagerImplementation; + AllocationManager public allocationManager; + PermissionController public permissionControllerImplementation; + PermissionController public permissionController; + + EmptyContract public emptyContract; + + address executorMultisig; + address operationsMultisig; + address pauserMultisig; + + // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in + IETHPOSDeposit public ethPOSDeposit; + + // strategies deployed + StrategyBaseTVLLimits[] public deployedStrategyArray; + + // IMMUTABLES TO SET + uint64 GOERLI_GENESIS_TIME = 1616508000; + + // OTHER DEPLOYMENT PARAMETERS + uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + uint256 DELEGATION_INIT_PAUSED_STATUS; + uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; + uint256 REWARDS_COORDINATOR_INIT_PAUSED_STATUS; + + // DelegationManager + uint32 MIN_WITHDRAWAL_DELAY; + + // AllocationManager + uint32 DEALLOCATION_DELAY; + uint32 ALLOCATION_CONFIGURATION_DELAY; + + // RewardsCoordinator + uint32 REWARDS_COORDINATOR_MAX_REWARDS_DURATION; + uint32 REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH; + uint32 REWARDS_COORDINATOR_MAX_FUTURE_LENGTH; + uint32 REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP; + address REWARDS_COORDINATOR_UPDATER; + uint32 REWARDS_COORDINATOR_ACTIVATION_DELAY; + uint32 REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS; + uint32 REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH; + + // AllocationManager + uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; + + // one week in blocks -- 50400 + uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS; + uint256 DELEGATION_WITHDRAWAL_DELAY_BLOCKS; + + function run(string memory configFileName) public { + // read and log the chainID + uint256 chainId = block.chainid; + emit log_named_uint("You are deploying on ChainID", chainId); + + // READ JSON CONFIG DATA + deployConfigPath = string(bytes(string.concat("script/configs/", configFileName))); + string memory config_data = vm.readFile(deployConfigPath); + // bytes memory parsedData = vm.parseJson(config_data); + + MIN_WITHDRAWAL_DELAY = uint32(stdJson.readUint(config_data, ".delegation.withdrawal_delay_blocks")); + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); + DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); + DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); + EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".eigenPodManager.init_paused_status"); + REWARDS_COORDINATOR_INIT_PAUSED_STATUS = stdJson.readUint( + config_data, + ".rewardsCoordinator.init_paused_status" + ); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.CALCULATION_INTERVAL_SECONDS") + ); + REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_REWARDS_DURATION")); + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_RETROACTIVE_LENGTH")); + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_FUTURE_LENGTH")); + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP")); + REWARDS_COORDINATOR_UPDATER = stdJson.readAddress(config_data, ".rewardsCoordinator.rewards_updater_address"); + REWARDS_COORDINATOR_ACTIVATION_DELAY = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.activation_delay")); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.calculation_interval_seconds") + ); + REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.global_operator_commission_bips") + ); + REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP") + ); + REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH = uint32( + stdJson.readUint(config_data, ".rewardsCoordinator.OPERATOR_SET_MAX_RETROACTIVE_LENGTH") + ); + + STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( + stdJson.readUint(config_data, ".strategyManager.init_withdrawal_delay_blocks") + ); + + ALLOCATION_MANAGER_INIT_PAUSED_STATUS = uint32( + stdJson.readUint(config_data, ".allocationManager.init_paused_status") + ); + DEALLOCATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.DEALLOCATION_DELAY") + ); + ALLOCATION_CONFIGURATION_DELAY = uint32( + stdJson.readUint(config_data, ".allocationManager.ALLOCATION_CONFIGURATION_DELAY") + ); + + // tokens to deploy strategies for + StrategyConfig[] memory strategyConfigs; + + executorMultisig = stdJson.readAddress(config_data, ".multisig_addresses.executorMultisig"); + operationsMultisig = stdJson.readAddress(config_data, ".multisig_addresses.operationsMultisig"); + pauserMultisig = stdJson.readAddress(config_data, ".multisig_addresses.pauserMultisig"); + // load token list + bytes memory strategyConfigsRaw = stdJson.parseRaw(config_data, ".strategies"); + strategyConfigs = abi.decode(strategyConfigsRaw, (StrategyConfig[])); + + require(executorMultisig != address(0), "executorMultisig address not configured correctly!"); + require(operationsMultisig != address(0), "operationsMultisig address not configured correctly!"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // deploy proxy admin for ability to upgrade proxy contracts + eigenLayerProxyAdmin = new ProxyAdmin(); + + //deploy pauser registry + { + address[] memory pausers = new address[](3); + pausers[0] = executorMultisig; + pausers[1] = operationsMultisig; + pausers[2] = pauserMultisig; + eigenLayerPauserReg = new PauserRegistry(pausers, executorMultisig); + } + + /** + * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are + * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. + */ + emptyContract = new EmptyContract(); + delegation = DelegationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyManager = StrategyManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + avsDirectory = AVSDirectory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenPodManager = EigenPodManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + rewardsCoordinator = RewardsCoordinator( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + allocationManager = AllocationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + permissionController = PermissionController( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // if on mainnet, use the ETH2 deposit contract address + if (chainId == 1) { + ethPOSDeposit = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); + // if not on mainnet, deploy a mock + } else { + ethPOSDeposit = IETHPOSDeposit(stdJson.readAddress(config_data, ".ethPOSDepositAddress")); + } + eigenPodImplementation = new EigenPod( + ethPOSDeposit, + eigenPodManager, + GOERLI_GENESIS_TIME + ); + + eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); + + // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs + + delegationImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg); + eigenPodManagerImplementation = new EigenPodManager( + ethPOSDeposit, + eigenPodBeacon, + strategyManager, + delegation, + eigenLayerPauserReg + ); + rewardsCoordinatorImplementation = new RewardsCoordinator( + delegation, + strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + ); + allocationManagerImplementation = new AllocationManager(delegation, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); + permissionControllerImplementation = new PermissionController(); + + // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. + { + IStrategy[] memory _strategies; + uint256[] memory _withdrawalDelayBlocks; + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(delegation))), + address(delegationImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + executorMultisig, + DELEGATION_INIT_PAUSED_STATUS, + DELEGATION_WITHDRAWAL_DELAY_BLOCKS, + _strategies, + _withdrawalDelayBlocks + ) + ); + } + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(strategyManager))), + address(strategyManagerImplementation), + abi.encodeWithSelector( + StrategyManager.initialize.selector, + executorMultisig, + operationsMultisig, + STRATEGY_MANAGER_INIT_PAUSED_STATUS + ) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation), + abi.encodeWithSelector(AVSDirectory.initialize.selector, executorMultisig, 0) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), + abi.encodeWithSelector( + EigenPodManager.initialize.selector, + executorMultisig, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ) + ); + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + address(rewardsCoordinatorImplementation), + abi.encodeWithSelector( + RewardsCoordinator.initialize.selector, + executorMultisig, + REWARDS_COORDINATOR_INIT_PAUSED_STATUS, + REWARDS_COORDINATOR_UPDATER, + REWARDS_COORDINATOR_ACTIVATION_DELAY, + REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS + ) + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), + abi.encodeWithSelector( + AllocationManager.initialize.selector, + executorMultisig, + ALLOCATION_MANAGER_INIT_PAUSED_STATUS + ) + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector(PermissionController.initialize.selector) + ); + + // deploy StrategyBaseTVLLimits contract implementation + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg); + // create upgradeable proxies that each point to the implementation and initialize them + for (uint256 i = 0; i < strategyConfigs.length; ++i) { + if (strategyConfigs[i].tokenAddress == address(0)) { + strategyConfigs[i].tokenAddress = address(new ERC20PresetFixedSupply("TestToken", "TEST", uint256(type(uint128).max), executorMultisig)); + } + deployedStrategyArray.push( + StrategyBaseTVLLimits( + address( + new TransparentUpgradeableProxy( + address(baseStrategyImplementation), + address(eigenLayerProxyAdmin), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + strategyConfigs[i].maxPerDeposit, + strategyConfigs[i].maxDeposits, + IERC20(strategyConfigs[i].tokenAddress) + ) + ) + ) + ) + ); + } + + { + // Whitelist the strategies + IStrategy[] memory strategies = new IStrategy[](deployedStrategyArray.length); + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + strategies[i] = IStrategy(deployedStrategyArray[i]); + } + strategyManager.addStrategiesToDepositWhitelist(strategies); + } + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + // CHECK CORRECTNESS OF DEPLOYMENT + _verifyContractsPointAtOneAnother( + delegationImplementation, + strategyManagerImplementation, + eigenPodManagerImplementation, + rewardsCoordinatorImplementation + ); + _verifyContractsPointAtOneAnother( + delegation, + strategyManager, + eigenPodManager, + rewardsCoordinator + ); + _verifyImplementationsSetCorrectly(); + _verifyInitialOwners(); + _checkPauserInitializations(); + _verifyInitializationParams(); + + // WRITE JSON DATA + string memory parent_object = "parent object"; + + string memory deployed_strategies = "strategies"; + for (uint256 i = 0; i < strategyConfigs.length; ++i) { + vm.serializeAddress(deployed_strategies, strategyConfigs[i].tokenSymbol, address(deployedStrategyArray[i])); + } + string memory deployed_strategies_output = strategyConfigs.length == 0 + ? "" + : vm.serializeAddress( + deployed_strategies, + strategyConfigs[strategyConfigs.length - 1].tokenSymbol, + address(deployedStrategyArray[strategyConfigs.length - 1]) + ); + + string memory deployed_addresses = "addresses"; + vm.serializeUint(deployed_addresses, "numStrategiesDeployed", 0); // for compatibility with other scripts + vm.serializeAddress(deployed_addresses, "eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); + vm.serializeAddress(deployed_addresses, "eigenLayerPauserReg", address(eigenLayerPauserReg)); + vm.serializeAddress(deployed_addresses, "delegationManager", address(delegation)); + vm.serializeAddress(deployed_addresses, "delegationManagerImplementation", address(delegationImplementation)); + vm.serializeAddress(deployed_addresses, "avsDirectory", address(avsDirectory)); + vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); + vm.serializeAddress(deployed_addresses, "allocationManager", address(allocationManager)); + vm.serializeAddress(deployed_addresses, "allocationManagerImplementation", address(allocationManagerImplementation)); + vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); + vm.serializeAddress( + deployed_addresses, + "strategyManagerImplementation", + address(strategyManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "eigenPodManager", address(eigenPodManager)); + vm.serializeAddress( + deployed_addresses, + "eigenPodManagerImplementation", + address(eigenPodManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "rewardsCoordinator", address(rewardsCoordinator)); + vm.serializeAddress( + deployed_addresses, + "rewardsCoordinatorImplementation", + address(rewardsCoordinatorImplementation) + ); + vm.serializeAddress(deployed_addresses, "eigenPodBeacon", address(eigenPodBeacon)); + vm.serializeAddress(deployed_addresses, "eigenPodImplementation", address(eigenPodImplementation)); + vm.serializeAddress(deployed_addresses, "baseStrategyImplementation", address(baseStrategyImplementation)); + vm.serializeAddress(deployed_addresses, "emptyContract", address(emptyContract)); + + vm.serializeAddress(deployed_addresses, "strategy", address(deployedStrategyArray[0])); + vm.serializeAddress(deployed_addresses, "TestToken", address(strategyConfigs[0].tokenAddress)); + + string memory deployed_addresses_output = vm.serializeString( + deployed_addresses, + "strategies", + deployed_strategies_output + ); + + { + // dummy token data + string memory token = '{"tokenProxyAdmin": "0x0000000000000000000000000000000000000000", "EIGEN": "0x0000000000000000000000000000000000000000","bEIGEN": "0x0000000000000000000000000000000000000000","EIGENImpl": "0x0000000000000000000000000000000000000000","bEIGENImpl": "0x0000000000000000000000000000000000000000","eigenStrategy": "0x0000000000000000000000000000000000000000","eigenStrategyImpl": "0x0000000000000000000000000000000000000000"}'; + deployed_addresses_output = vm.serializeString(deployed_addresses, "token", token); + } + + string memory parameters = "parameters"; + vm.serializeAddress(parameters, "executorMultisig", executorMultisig); + vm.serializeAddress(parameters, "communityMultisig", operationsMultisig); + vm.serializeAddress(parameters, "pauserMultisig", pauserMultisig); + vm.serializeAddress(parameters, "timelock", address(0)); + string memory parameters_output = vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); + + string memory chain_info = "chainInfo"; + vm.serializeUint(chain_info, "deploymentBlock", block.number); + string memory chain_info_output = vm.serializeUint(chain_info, "chainId", chainId); + + // serialize all the data + vm.serializeString(parent_object, deployed_addresses, deployed_addresses_output); + vm.serializeString(parent_object, chain_info, chain_info_output); + string memory finalJson = vm.serializeString(parent_object, parameters, parameters_output); + // TODO: should output to different file depending on configFile passed to run() + // so that we don't override mainnet output by deploying to goerli for eg. + vm.writeJson(finalJson, "script/output/local/slashing_output.json"); + } + + function _verifyContractsPointAtOneAnother( + DelegationManager delegationContract, + StrategyManager strategyManagerContract, + EigenPodManager eigenPodManagerContract, + RewardsCoordinator rewardsCoordinatorContract + ) internal view { + require( + delegationContract.strategyManager() == strategyManager, + "delegation: strategyManager address not set correctly" + ); + + require( + strategyManagerContract.delegation() == delegation, + "strategyManager: delegation address not set correctly" + ); + require( + eigenPodManagerContract.ethPOS() == ethPOSDeposit, + " eigenPodManager: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodManagerContract.eigenPodBeacon() == eigenPodBeacon, + "eigenPodManager: eigenPodBeacon contract address not set correctly" + ); + require( + eigenPodManagerContract.strategyManager() == strategyManager, + "eigenPodManager: strategyManager contract address not set correctly" + ); + + require( + rewardsCoordinatorContract.delegationManager() == delegation, + "rewardsCoordinator: delegation address not set correctly" + ); + + require( + rewardsCoordinatorContract.strategyManager() == strategyManager, + "rewardsCoordinator: strategyManager address not set correctly" + ); + } + + function _verifyImplementationsSetCorrectly() internal view { + require( + eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(delegation)))) == + address(delegationImplementation), + "delegation: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(strategyManager))) + ) == address(strategyManagerImplementation), + "strategyManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(eigenPodManager))) + ) == address(eigenPodManagerImplementation), + "eigenPodManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))) + ) == address(rewardsCoordinatorImplementation), + "rewardsCoordinator: implementation set incorrectly" + ); + + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(allocationManager))) + ) == address(allocationManagerImplementation), + "allocationManager: implementation set incorrectly" + ); + + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + eigenLayerProxyAdmin.getProxyImplementation( + ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) + ) == address(baseStrategyImplementation), + "strategy: implementation set incorrectly" + ); + } + + require( + eigenPodBeacon.implementation() == address(eigenPodImplementation), + "eigenPodBeacon: implementation set incorrectly" + ); + } + + function _verifyInitialOwners() internal view { + require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); + require(delegation.owner() == executorMultisig, "delegation: owner not set correctly"); + require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); + + require(eigenLayerProxyAdmin.owner() == executorMultisig, "eigenLayerProxyAdmin: owner not set correctly"); + require(eigenPodBeacon.owner() == executorMultisig, "eigenPodBeacon: owner not set correctly"); + } + + function _checkPauserInitializations() internal view { + require(delegation.pauserRegistry() == eigenLayerPauserReg, "delegation: pauser registry not set correctly"); + require( + strategyManager.pauserRegistry() == eigenLayerPauserReg, + "strategyManager: pauser registry not set correctly" + ); + require( + eigenPodManager.pauserRegistry() == eigenLayerPauserReg, + "eigenPodManager: pauser registry not set correctly" + ); + require( + rewardsCoordinator.pauserRegistry() == eigenLayerPauserReg, + "rewardsCoordinator: pauser registry not set correctly" + ); + + require(eigenLayerPauserReg.isPauser(operationsMultisig), "pauserRegistry: operationsMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(executorMultisig), "pauserRegistry: executorMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), "pauserRegistry: pauserMultisig is not pauser"); + require(eigenLayerPauserReg.unpauser() == executorMultisig, "pauserRegistry: unpauser not set correctly"); + + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, + "StrategyBaseTVLLimits: pauser registry not set correctly" + ); + require( + deployedStrategyArray[i].paused() == 0, + "StrategyBaseTVLLimits: init paused status set incorrectly" + ); + } + + // // pause *nothing* + // uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS = 0; + // // pause *everything* + // // pause *everything* + // uint256 DELEGATION_INIT_PAUSED_STATUS = type(uint256).max; + // // pause *all of the proof-related functionality* (everything that can be paused other than creation of EigenPods) + // uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS = (2**1) + (2**2) + (2**3) + (2**4); /* = 30 */ + // // pause *nothing* + // require(strategyManager.paused() == 0, "strategyManager: init paused status set incorrectly"); + // require(delegation.paused() == type(uint256).max, "delegation: init paused status set incorrectly"); + // require(eigenPodManager.paused() == 30, "eigenPodManager: init paused status set incorrectly"); + } + + function _verifyInitializationParams() internal view { + // // one week in blocks -- 50400 + // uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = 7 days / 12 seconds; + // require(strategyManager.withdrawalDelayBlocks() == 7 days / 12 seconds, + // "strategyManager: withdrawalDelayBlocks initialized incorrectly"); + // uint256 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32 ether; + + require( + strategyManager.strategyWhitelister() == operationsMultisig, + "strategyManager: strategyWhitelister address not set correctly" + ); + + require( + baseStrategyImplementation.strategyManager() == strategyManager, + "baseStrategyImplementation: strategyManager set incorrectly" + ); + + require( + eigenPodImplementation.ethPOS() == ethPOSDeposit, + "eigenPodImplementation: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodImplementation.eigenPodManager() == eigenPodManager, + " eigenPodImplementation: eigenPodManager contract address not set correctly" + ); + + string memory config_data = vm.readFile(deployConfigPath); + for (uint i = 0; i < deployedStrategyArray.length; i++) { + uint256 maxPerDeposit = stdJson.readUint( + config_data, + string.concat(".strategies[", vm.toString(i), "].max_per_deposit") + ); + uint256 maxDeposits = stdJson.readUint( + config_data, + string.concat(".strategies[", vm.toString(i), "].max_deposits") + ); + (uint256 setMaxPerDeposit, uint256 setMaxDeposits) = deployedStrategyArray[i].getTVLLimits(); + require(setMaxPerDeposit == maxPerDeposit, "setMaxPerDeposit not set correctly"); + require(setMaxDeposits == maxDeposits, "setMaxDeposits not set correctly"); + } + } +} diff --git a/script/deploy/local/operatorSets/DeployStrategies.s.sol b/script/deploy/local/operatorSets/DeployStrategies.s.sol new file mode 100644 index 000000000..e2f05e806 --- /dev/null +++ b/script/deploy/local/operatorSets/DeployStrategies.s.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "../../../utils/ExistingDeploymentParser.sol"; + +// # To load the variables in the .env file +// source .env + +// # To deploy and verify our contract +contract DeployStrategies is ExistingDeploymentParser { + + function run() external { + _parseDeployedContracts("script/output/devnet/M2_from_scratch_deployment_data.json"); + + vm.startBroadcast(); + StrategyDeployer strategyDeployer = new StrategyDeployer( + executorMultisig, + address(baseStrategyImplementation) + ); + uint256 batches = 1; + uint256 batchSize = 100; + + IStrategy[] memory strategies = new IStrategy[](batchSize * batches); + + for (uint256 i = 0; i < batches; i++) { + IStrategy[] memory strategiesJustDeployed = strategyDeployer.createManyStrategies(batchSize); + for (uint256 j = 0; j < batchSize; j++) { + strategies[i * batchSize + j] = strategiesJustDeployed[j]; + } + strategyManager.addStrategiesToDepositWhitelist(strategiesJustDeployed); + } + + vm.stopBroadcast(); + + address[] memory strategyAddresses; + assembly { + strategyAddresses := strategies + } + string memory deployed_strategies = vm.serializeAddress("", "strategies", strategyAddresses); + + vm.writeJson(deployed_strategies, "script/output/devnet/deployed_strategies.json"); + } +} + + +contract StrategyDeployer { + address immutable beneficiary; + address immutable baseStrategyImplementation; + + constructor(address _beneficiary, address _baseStrategyImplementation) { + beneficiary = _beneficiary; + baseStrategyImplementation = _baseStrategyImplementation; + } + + function createManyStrategies(uint256 numStrategies) external returns(IStrategy[] memory) { + IStrategy[] memory strategies = new IStrategy[](numStrategies); + for (uint256 i = 0; i < numStrategies; i++) { + // create a strategy + strategies[i] = + StrategyBaseTVLLimits( + address( + new TransparentUpgradeableProxy( + address(baseStrategyImplementation), + address(1), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + type(uint256).max, + type(uint256).max, + new ERC20PresetFixedSupply("Test", "TST", uint256(type(uint128).max), beneficiary), + address(1) + ) + ) + ) + ); + } + return strategies; + } +} \ No newline at end of file diff --git a/script/deploy/mainnet/Deploy_Strategy_Factory.s.sol b/script/deploy/mainnet/Deploy_Strategy_Factory.s.sol new file mode 100644 index 000000000..027d7ecdc --- /dev/null +++ b/script/deploy/mainnet/Deploy_Strategy_Factory.s.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "../../utils/ExistingDeploymentParser.sol"; + +import "../../../src/contracts/strategies/StrategyFactory.sol"; + +/** + * @notice Script used for the first deployment of EigenLayer core contracts to Holesky + * FORK LOCAL + * anvil --fork-url $RPC_MAINNET + * forge script script/deploy/mainnet/Deploy_Strategy_Factory.s.sol:MainnetStrategyFactoryDeploy --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv + * + * MAINNET + * forge script script/deploy/mainnet/Deploy_Strategy_Factory.s.sol:MainnetStrategyFactoryDeploy --rpc-url $RPC_MAINNET --private-key $PRIVATE_KEY --verify --broadcast -vvvv + * + */ + +contract MainnetStrategyFactoryDeploy is ExistingDeploymentParser { + function run() external virtual { + // Use rewards config + _parseInitialDeploymentParams( + "script/configs/mainnet/v0.3.0-mainnet-rewards.config.json" + ); + _parseDeployedContracts( + "script/configs/mainnet/Mainnet_curent_deployment.config.json" + ); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + emit log_named_address("Deployer Address", msg.sender); + + _deployStrategyFactory(); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized(false); + _verifyInitializationParams(); + + logAndOutputContractAddresses("script/output/mainnet/v0.3.2-mainnet-strategy-factory.output.json"); + } + + /** + * @notice Deploy StrategyFactory for Mainnet + */ + + function _deployStrategyFactory() internal { + strategyFactoryImplementation = new StrategyFactory( + strategyManager, eigenLayerPauserReg + ); + + + + } +} \ No newline at end of file diff --git a/script/deploy/mainnet/EIGEN_upgrade.s.sol b/script/deploy/mainnet/EIGEN_upgrade.s.sol index 259cde0ce..54f4e8155 100644 --- a/script/deploy/mainnet/EIGEN_upgrade.s.sol +++ b/script/deploy/mainnet/EIGEN_upgrade.s.sol @@ -97,7 +97,7 @@ contract EIGEN_upgrade is Script, Test { function checkUpgradeCorrectness() public { vm.prank(address(EIGEN_TimelockController)); - require(EIGEN_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), + require(EIGEN_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(EIGEN_proxy)))) == address(EIGEN_implementation), "implementation set incorrectly"); require(EIGEN_proxy.bEIGEN() == bEIGEN_addressBefore, "bEIGEN address changed unexpectedly"); diff --git a/script/deploy/mainnet/EigenPod_Minor_Upgrade_Deploy.s.sol b/script/deploy/mainnet/EigenPod_Minor_Upgrade_Deploy.s.sol index b4ae9cc91..33723678b 100644 --- a/script/deploy/mainnet/EigenPod_Minor_Upgrade_Deploy.s.sol +++ b/script/deploy/mainnet/EigenPod_Minor_Upgrade_Deploy.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; @@ -9,7 +9,6 @@ import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "../../../src/contracts/interfaces/IETHPOSDeposit.sol"; import "../../../src/contracts/core/StrategyManager.sol"; -import "../../../src/contracts/core/Slasher.sol"; import "../../../src/contracts/core/DelegationManager.sol"; import "../../../src/contracts/pods/EigenPod.sol"; @@ -32,7 +31,6 @@ contract EigenPod_Minor_Upgrade_Deploy is Script, Test { string public freshOutputPath; // EigenLayer core contracts - ISlasher public slasher; IDelegationManager public delegation; DelegationManager public delegationImplementation; IStrategyManager public strategyManager; @@ -70,10 +68,9 @@ contract EigenPod_Minor_Upgrade_Deploy is Script, Test { // Read json data string memory deployment_data = vm.readFile(m2DeploymentOutputPath); - slasher = Slasher(stdJson.readAddress(deployment_data, ".addresses.slasher")); delegation = DelegationManager(stdJson.readAddress(deployment_data, ".addresses.delegationManager")); strategyManager = DelegationManager(address(delegation)).strategyManager(); - eigenPodManager = strategyManager.eigenPodManager(); + eigenPodManager = DelegationManager(address(delegation)).eigenPodManager(); eigenPodBeacon = eigenPodManager.eigenPodBeacon(); ethPOS = eigenPodManager.ethPOS(); diff --git a/script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol b/script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol deleted file mode 100644 index cc35e069f..000000000 --- a/script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol +++ /dev/null @@ -1,335 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../../utils/ExistingDeploymentParser.sol"; -import "../../utils/TimelockEncoding.sol"; -import "../../utils/Multisend.sol"; - -/** - * @notice Script used for the first deployment of EigenLayer core contracts to Holesky - * anvil --fork-url $RPC_MAINNET - * forge script script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol:M2_Mainnet_Upgrade --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv - * - * forge script script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol:M2_Mainnet_Upgrade --rpc-url $RPC_MAINNET --private-key $PRIVATE_KEY --broadcast -vvvv - * - */ -contract M2_Mainnet_Upgrade is ExistingDeploymentParser { - function run() external virtual { - _parseDeployedContracts("script/output/mainnet/M1_deployment_mainnet_2023_6_9.json"); - _parseInitialDeploymentParams("script/configs/mainnet/M2_mainnet_upgrade.config.json"); - - // START RECORDING TRANSACTIONS FOR DEPLOYMENT - vm.startBroadcast(); - - emit log_named_address("Deployer Address", msg.sender); - - _deployImplementationContracts(); - - // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT - vm.stopBroadcast(); - - // Simulate upgrade of contracts to new implementations - _simulateUpgrade(); - - // Sanity Checks - _verifyContractPointers(); - _verifyImplementations(); - _verifyContractsInitialized(true); - _verifyInitializationParams(); - - logAndOutputContractAddresses("script/output/mainnet/M2_mainnet_upgrade.output.json"); - } - - /** - * @notice Deploy EigenLayer contracts from scratch for Holesky - */ - function _deployImplementationContracts() internal { - // 1. Deploy New TUPS - avsDirectoryImplementation = new AVSDirectory(delegationManager); - avsDirectory = AVSDirectory( - address( - new TransparentUpgradeableProxy( - address(avsDirectoryImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - AVSDirectory.initialize.selector, - executorMultisig, // initialOwner - eigenLayerPauserReg, - AVS_DIRECTORY_INIT_PAUSED_STATUS - ) - ) - ) - ); - - // 2. Deploy Implementations - eigenPodImplementation = new EigenPod( - IETHPOSDeposit(ETHPOSDepositAddress), - eigenPodManager, - EIGENPOD_GENESIS_TIME - ); - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); - eigenPodManagerImplementation = new EigenPodManager( - IETHPOSDeposit(ETHPOSDepositAddress), - eigenPodBeacon, - strategyManager, - slasher, - delegationManager - ); - } - - function _simulateUpgrade() internal { - - vm.startPrank(executorMultisig); - - // First, upgrade the proxy contracts to point to the implementations - // AVSDirectory - // eigenLayerProxyAdmin.upgrade( - // TransparentUpgradeableProxy(payable(address(avsDirectory))), - // address(avsDirectoryImplementation) - // ); - // DelegationManager - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(delegationManager))), - address(delegationManagerImplementation) - ); - // StrategyManager - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation) - ); - // Slasher - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation) - ); - // EigenPodManager - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation) - ); - - // Second, configure additional settings and paused statuses - delegationManager.setMinWithdrawalDelayBlocks(DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS); - delegationManager.unpause(0); - eigenPodManager.unpause(0); - - eigenPodBeacon.upgradeTo(address(eigenPodImplementation)); - - vm.stopPrank(); - } -} - -// forge t --mt test_queueUpgrade --fork-url $RPC_MAINNET -vvvv -contract Queue_M2_Upgrade is M2_Mainnet_Upgrade, TimelockEncoding { - Vm cheats = Vm(VM_ADDRESS); - - // Thurs Apr 08 2024 12:00:00 GMT-0700 (Pacific Daylight Time) - uint256 timelockEta = 1712559600; - - function test_queueUpgrade() external { - _parseDeployedContracts("script/output/mainnet/M2_mainnet_upgrade.output.json"); - _parseInitialDeploymentParams("script/configs/mainnet/M2_mainnet_upgrade.config.json"); - - Tx[] memory txs = new Tx[](11); - // upgrade the DelegationManager, Slasher, StrategyManager, DelayedWithdrawalRouter, EigenPodManager, & EigenPod contracts - txs[0] = Tx( - address(eigenLayerProxyAdmin), - 0, - abi.encodeWithSelector( - ProxyAdmin.upgrade.selector, - TransparentUpgradeableProxy(payable(address(delegationManager))), - delegationManagerImplementation - ) - ); - - txs[1] = Tx( - address(eigenLayerProxyAdmin), - 0, - abi.encodeWithSelector( - ProxyAdmin.upgrade.selector, - TransparentUpgradeableProxy(payable(address(slasher))), - slasherImplementation - ) - ); - - txs[2] = Tx( - address(eigenLayerProxyAdmin), - 0, - abi.encodeWithSelector( - ProxyAdmin.upgrade.selector, - TransparentUpgradeableProxy(payable(address(strategyManager))), - strategyManagerImplementation - ) - ); - - // txs[3] = Tx( - // address(eigenLayerProxyAdmin), - // 0, - // abi.encodeWithSelector( - // ProxyAdmin.upgrade.selector, - // TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), - // delayedWithdrawalRouterImplementation - // ) - // ); - - txs[4] = Tx( - address(eigenLayerProxyAdmin), - 0, - abi.encodeWithSelector( - ProxyAdmin.upgrade.selector, - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - eigenPodManagerImplementation - ) - ); - - txs[5] = Tx( - address(eigenPodBeacon), - 0, - abi.encodeWithSelector( - UpgradeableBeacon.upgradeTo.selector, - eigenPodImplementation - ) - ); - - // set the min withdrawal delay blocks on the DelegationManager - txs[6] = Tx( - address(delegationManager), - 0, // value - abi.encodeWithSelector(DelegationManager.setMinWithdrawalDelayBlocks.selector, DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS) - ); - - // set beacon chain oracle on EigenPodManager - // txs[7] = Tx( - // address(eigenPodManager), - // 0, // value - // abi.encodeWithSelector(EigenPodManager.updateBeaconChainOracle.selector, beaconOracle) - // ); - - // set Deneb fork timestamp on EigenPodManager - // txs[8] = Tx( - // address(eigenPodManager), - // 0, // value - // abi.encodeWithSelector(EigenPodManager.setDenebForkTimestamp.selector, EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP) - // ); - - // unpause everything on DelegationManager - txs[9] = Tx( - address(delegationManager), - 0, // value - abi.encodeWithSelector(Pausable.unpause.selector, 0) - ); - - // unpause everything on EigenPodManager - txs[10] = Tx( - address(eigenPodManager), - 0, // value - abi.encodeWithSelector(Pausable.unpause.selector, 0) - ); - - bytes memory calldata_to_multisend_contract = abi.encodeWithSelector(MultiSendCallOnly.multiSend.selector, encodeMultisendTxs(txs)); - emit log_named_bytes("calldata_to_multisend_contract", calldata_to_multisend_contract); - - bytes memory final_calldata_to_executor_multisig = encodeForExecutor({ - // call to executor will be from the timelock - from: timelock, - // performing many operations at the same time - to: multiSendCallOnly, - // value to send in tx - value: 0, - // calldata for the operation - data: calldata_to_multisend_contract, - // operation type (for performing many operations at the same time) - operation: ISafe.Operation.DelegateCall - }); - - (bytes memory calldata_to_timelock_queuing_action, bytes memory calldata_to_timelock_executing_action) = encodeForTimelock({ - // address to be called from the timelock - to: executorMultisig, - // value to send in tx - value: 0, - // calldata for the operation - data: final_calldata_to_executor_multisig, - // time at which the tx will become executable - timelockEta: timelockEta - }); - - bytes32 expectedTxHash = getTxHash({ - target: executorMultisig, - _value: 0, - _data: final_calldata_to_executor_multisig, - eta: timelockEta - }); - emit log_named_bytes32("expectedTxHash", expectedTxHash); - - cheats.prank(operationsMultisig); - (bool success, ) = timelock.call(calldata_to_timelock_queuing_action); - require(success, "call to timelock queuing action failed"); - - require(ITimelock(timelock).queuedTransactions(expectedTxHash), "expectedTxHash not queued"); - - // test performing the upgrade - cheats.warp(timelockEta); - cheats.prank(operationsMultisig); - (success, ) = timelock.call(calldata_to_timelock_executing_action); - require(success, "call to timelock executing action failed"); - - // Check correctness after upgrade - _verifyContractPointers(); - _verifyImplementations(); - _verifyContractsInitialized(true); - _verifyInitializationParams(); - _postUpgradeChecks(); - } - - function _postUpgradeChecks() internal { - // check that LST deposits are paused - address rETH = 0xae78736Cd615f374D3085123A210448E74Fc6393; - address rETH_Strategy = 0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2; - uint256 amount = 1e18; - cheats.prank(rETH); - // this works because rETH has more than 1 ETH of its own token at its address :) - IERC20(rETH).transfer(address(this), amount); - IERC20(rETH).approve(address(strategyManager), amount); - cheats.expectRevert("Pausable: index is paused"); - strategyManager.depositIntoStrategy({ - strategy: IStrategy(rETH_Strategy), - token: IERC20(rETH), - amount: amount - }); - - // unpause LST deposits and check that a deposit works - cheats.prank(executorMultisig); - strategyManager.unpause(0); - strategyManager.depositIntoStrategy({ - strategy: IStrategy(rETH_Strategy), - token: IERC20(rETH), - amount: amount - }); - - // check that EigenPod proofs are live (although this still reverts later in the call) - EigenPod existingEigenPod = EigenPod(payable(0x0b347D5E38296277E829CE1D8C6b82e4c63C2Df3)); - BeaconChainProofs.StateRootProof memory stateRootProof; - uint40[] memory validatorIndices; - bytes[] memory validatorFieldsProofs; - bytes32[][] memory validatorFields; - cheats.startPrank(existingEigenPod.podOwner()); - existingEigenPod.startCheckpoint(false); - cheats.expectRevert("EigenPodManager.getBlockRootAtTimestamp: state root at timestamp not yet finalized"); - existingEigenPod.verifyWithdrawalCredentials( - uint64(block.timestamp), - stateRootProof, - validatorIndices, - validatorFieldsProofs, - validatorFields - ); - } - - function getTxHash(address target, uint256 _value, bytes memory _data, uint256 eta) public pure returns (bytes32) { - // empty bytes - bytes memory signature; - bytes32 txHash = keccak256(abi.encode(target, _value, signature, _data, eta)); - return txHash; - } -} diff --git a/script/deploy/mainnet/bEIGEN_upgrade.s.sol b/script/deploy/mainnet/bEIGEN_upgrade.s.sol index 42093a68a..4a7c40aa2 100644 --- a/script/deploy/mainnet/bEIGEN_upgrade.s.sol +++ b/script/deploy/mainnet/bEIGEN_upgrade.s.sol @@ -96,7 +96,7 @@ contract bEIGEN_upgrade is Script, Test { function checkUpgradeCorrectness() public { vm.prank(address(bEIGEN_TimelockController)); - require(bEIGEN_ProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), + require(bEIGEN_ProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(bEIGEN_proxy)))) == address(bEIGEN_implementation), "implementation set incorrectly"); require(bEIGEN_proxy.EIGEN() == EIGEN_addressBefore, "EIGEN address changed unexpectedly"); diff --git a/script/deploy/mainnet/v0.3.0-mainnet-rewards.s.sol b/script/deploy/mainnet/v0.3.0-mainnet-rewards.s.sol index 947402fa9..916003908 100644 --- a/script/deploy/mainnet/v0.3.0-mainnet-rewards.s.sol +++ b/script/deploy/mainnet/v0.3.0-mainnet-rewards.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/Create2.sol"; import "../../utils/ExistingDeploymentParser.sol"; @@ -52,6 +52,9 @@ contract MainnetRewardsCoordinatorDeploy is ExistingDeploymentParser { rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -66,7 +69,6 @@ contract MainnetRewardsCoordinatorDeploy is ExistingDeploymentParser { abi.encodeWithSelector( RewardsCoordinator.initialize.selector, executorMultisig, - eigenLayerPauserReg, REWARDS_COORDINATOR_INIT_PAUSED_STATUS, REWARDS_COORDINATOR_UPDATER, REWARDS_COORDINATOR_ACTIVATION_DELAY, @@ -85,6 +87,9 @@ contract MainnetRewardsCoordinatorDeploy is ExistingDeploymentParser { rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -93,7 +98,7 @@ contract MainnetRewardsCoordinatorDeploy is ExistingDeploymentParser { ); eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), address(rewardsCoordinatorImplementation) ); } diff --git a/script/deploy/mainnet/v0.4.2-mainnet-pepe.s.sol b/script/deploy/mainnet/v0.4.2-mainnet-pepe.s.sol index 65873b487..14d2dbc29 100644 --- a/script/deploy/mainnet/v0.4.2-mainnet-pepe.s.sol +++ b/script/deploy/mainnet/v0.4.2-mainnet-pepe.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/Create2.sol"; import "../../utils/ExistingDeploymentParser.sol"; @@ -58,8 +58,8 @@ contract MainnetPEPEDeploy is ExistingDeploymentParser { IETHPOSDeposit(ETHPOSDepositAddress), eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); } @@ -71,7 +71,7 @@ contract MainnetPEPEDeploy is ExistingDeploymentParser { // upgrade TUPS eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) ); diff --git a/script/deploy/mainnet/v0.4.3-upgrade_rewardsCoordinator.s.sol b/script/deploy/mainnet/v0.4.3-upgrade_rewardsCoordinator.s.sol index e1d961aad..688b98b7a 100644 --- a/script/deploy/mainnet/v0.4.3-upgrade_rewardsCoordinator.s.sol +++ b/script/deploy/mainnet/v0.4.3-upgrade_rewardsCoordinator.s.sol @@ -49,6 +49,9 @@ contract Upgrade_Mainnet_RewardsCoordinator is ExistingDeploymentParser, Timeloc rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, strategyManager, + allocationManager, + eigenLayerPauserReg, + permissionController, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, @@ -120,7 +123,7 @@ contract Upgrade_Mainnet_RewardsCoordinator is ExistingDeploymentParser, Timeloc emit log_named_bytes("calldata_to_timelock_executing_action", calldata_to_timelock_executing_action); } - function test_mainnet_rc_upgrade() public { + function run_mainnet_rc_upgrade() public { run(); vm.warp(dayToQueueAction); @@ -146,7 +149,7 @@ contract Upgrade_Mainnet_RewardsCoordinator is ExistingDeploymentParser, Timeloc _verifyInitializationParams(); } - function _sanityCheckImplementations(RewardsCoordinator oldRc, RewardsCoordinator newRc) internal { + function _sanityCheckImplementations(RewardsCoordinator oldRc, RewardsCoordinator newRc) internal view { // Verify configs between both rewardsCoordinatorImplementations assertEq( address(oldRc.delegationManager()), @@ -185,8 +188,8 @@ contract Upgrade_Mainnet_RewardsCoordinator is ExistingDeploymentParser, Timeloc ); } - function test_set_reward_for_all_submitter(address hopper) public { - test_mainnet_rc_upgrade(); + function run_set_reward_for_all_submitter(address hopper) public { + run_mainnet_rc_upgrade(); // Set reward for all submitters vm.prank(operationsMultisig); diff --git a/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json b/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json new file mode 100644 index 000000000..b83fcb7d8 --- /dev/null +++ b/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json @@ -0,0 +1,52 @@ +{ + "addresses": { + "allocationManager": "0xAbD5Dd30CaEF8598d4EadFE7D45Fd582EDEade15", + "allocationManagerImplementation": "0xBFF7154bAa41e702E78Fb082a8Ce257Ce13E6f55", + "avsDirectory": "0xCa839541648D3e23137457b1Fd4A06bccEADD33a", + "avsDirectoryImplementation": "0x1362e9Cb37831C433095f1f1568215B7FDeD37Ef", + "baseStrategyImplementation": "0x61C6A250AEcAbf6b5e4611725b4f99C4DC85DB34", + "delegationManager": "0x3391eBafDD4b2e84Eeecf1711Ff9FC06EF9Ed182", + "delegationManagerImplementation": "0x4073a9B0fb0f31420C2A2263fB6E9adD33ea6F2A", + "eigenLayerPauserReg": "0xBb02ACE793e921D6a454062D2933064F31Fae0B2", + "eigenLayerProxyAdmin": "0xBf0c97a7df334BD83e0912c1218E44FD7953d122", + "eigenPodBeacon": "0x8ad244c2a986e48862c5bE1FdCA27cef0aaa6E15", + "eigenPodImplementation": "0x93cecf40F05389E99e163539F8d1CCbd4267f9A7", + "eigenPodManager": "0x8C9781FD55c67CE4DC08e3035ECbdB2B67a07307", + "eigenPodManagerImplementation": "0x3013B13BF3a464ff9078EFa40b7dbfF8fA67138d", + "emptyContract": "0x689CEE9134e4234caEF6c15Bf1D82779415daFAe", + "rewardsCoordinator": "0xa7DB7B0E63B5B75e080924F9C842758711177c07", + "rewardsCoordinatorImplementation": "0x0e93df1A21CA53F93160AbDee19A92A20f8b397B", + "strategies": [ + { + "strategy_address": "0x4f812633943022fA97cb0881683aAf9f318D5Caa", + "token_address": "0x94373a4919B3240D86eA41593D5eBa789FEF3848", + "token_symbol": "WETH" + } + ], + "strategyBeacon": "0x957c04A5666079255fD75220a15918ecBA6039c6", + "strategyFactory": "0x09F8f1c1ca1815083a8a05E1b4A0c65EFB509141", + "strategyFactoryImplementation": "0x8b1F09f8292fd658Da35b9b3b1d4F7d1C0F3F592", + "strategyManager": "0x70f8bC2Da145b434de66114ac539c9756eF64fb3", + "strategyManagerImplementation": "0x1562BfE7Cb4644ff030C1dE4aA5A9aBb88a61aeC", + "token": { + "tokenProxyAdmin": "0x0000000000000000000000000000000000000000", + "EIGEN": "0x0000000000000000000000000000000000000000", + "bEIGEN": "0x0000000000000000000000000000000000000000", + "EIGENImpl": "0x0000000000000000000000000000000000000000", + "bEIGENImpl": "0x0000000000000000000000000000000000000000", + "eigenStrategy": "0x0000000000000000000000000000000000000000", + "eigenStrategyImpl": "0x0000000000000000000000000000000000000000" + } + }, + "chainInfo": { + "chainId": 17000, + "deploymentBlock": 2548240 + }, + "parameters": { + "communityMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "executorMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "operationsMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "pauserMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "timelock": "0x0000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/script/tasks/README.md b/script/tasks/README.md new file mode 100644 index 000000000..c93b8aa66 --- /dev/null +++ b/script/tasks/README.md @@ -0,0 +1,155 @@ +# Setup slashing locally + +These tasks deploy the `slashing-magnitudes` contracts and set up the sender (`address(PRIVATE_KEY)`) as an `AVS`, `Operator` and `Staker`. + +We then register the `Operator` to an `OperatorSet`, allocate the `Strategy` in that `OperatorSet` and perform a `slashing`. + +--- + +1. Start `anvil` in one terminal +```sh +anvil +``` + +2. Run the full setup in another terminal +```sh +./run.sh +``` + +OR + +2. Deploy contracts in another terminal (this will save addresses to [../output/local/slashing_output.json](../output/local/slashing_output.json)) +```sh +export RPC_URL=127.0.0.1:8545 +export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +export SENDER=$(cast wallet address --private-key $PRIVATE_KEY) + +mkdir ./script/output/local +forge script -C src/contracts --via-ir ../deploy/local/deploy_from_scratch.slashing.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile)" \ + -- local/deploy_from_scratch.slashing.anvil.config.json +``` + +3. Build the task scripts +```sh +forge build -C script/tasks +``` + +4. Extract `DELEGATION_MANAGER`, `STRATEGY_MANAGER`, `STRATEGY` and `TOKEN` addresses from deployment output +```sh +export DELEGATION_MANAGER=$(jq -r '.addresses.delegationManager' "../output/local/slashing_output.json") +export STRATEGY_MANAGER=$(jq -r '.addresses.strategyManager' "../output/local/slashing_output.json") +export STRATEGY=$(jq -r '.addresses.strategy' "../output/local/slashing_output.json") +export TOKEN=$(jq -r '.addresses.TestToken' "../output/local/slashing_output.json") +``` + +5. Unpause the `avsDirectory` +```sh +forge script ../tasks/unpause_avsDirectory.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile)" \ + -- local/slashing_output.json +``` + +6. Deposit into `Strategy` +```sh +forge script ../tasks/deposit_into_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount)" \ + -- local/slashing_output.json $STRATEGY $TOKEN 1000 +``` + +7. Register as `Operator` +```sh +forge script ../tasks/register_as_operator.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address operator,string metadataURI)" \ + -- local/slashing_output.json $SENDER "metadataURI" +``` + +8. Register `Operator` to `OperatorSet` +```sh +forge script ../tasks/register_operator_to_operatorSet.s.sol \ + --tc RegisterOperatorToOperatorSets \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile)" \ + -- local/slashing_output.json +``` + +9. Move the chain by **600** blocks (to move beyond `pendingDelay`) +``` +cast rpc anvil_mine 600 --rpc-url $RPC_URL +``` + +10. Allocate the `OperatorSet` **(50%)** +```sh +forge script ../tasks/allocate_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" \ + -- local/slashing_output.json $STRATEGY $SENDER 00000001 0500000000000000000 +``` + +11. Slash the `OperatorSet` **(50%)** - we expect that 25% of our shares will be slashed when we withdraw them +```sh +forge script ../tasks/slash_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" \ + -- local/slashing_output.json $SENDER 00000001 0500000000000000000 +``` + +12. Verify that the sender holds **1000** Deposited `TOKEN` shares: +```sh +cast call $STRATEGY_MANAGER "getDeposits(address)(address[],uint256[])" $SENDER --rpc-url $RPC_URL +``` + +13. Verify that the sender holds **750** Withdrawable `TOKEN` shares: +```sh +cast call $DELEGATION_MANAGER "getWithdrawableShares(address,address[])(uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL +``` + +14. Withdraw slashed shares from `DelegationManager` + +- Extract Nonce and available shares from $DELEGATION_MANAGER +```sh +export DEPOSITS=$(cast call $DELEGATION_MANAGER "getDepositedShares(address)(address[],uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL | sed -n '2p' | tr -d '[]') +export SHARES=$(cast call $DELEGATION_MANAGER "getWithdrawableShares(address,address[])(uint256[],uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL | sed -n '1p' | tr -d '[]') +export NONCE=$(cast call $DELEGATION_MANAGER "cumulativeWithdrawalsQueued(address)(uint256)" $SENDER --rpc-url $RPC_URL) +``` + +- Queue withdrawal +```sh +forge script ../tasks/withdraw_from_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $DEPOSITS +``` + +- Record the withdrawal `START_BLOCK` +```sh +export WITHDRAWAL_START_BLOCK_NUMBER=$(cast block-number --rpc-url $RPC_URL) +``` + +- Move the chain by 5 blocks (to move beyond `MIN_WITHDRAWAL_DELAY_BLOCKS` (5)) +```sh +cast rpc anvil_mine 5 --rpc-url $RPC_URL +``` + +- Complete withdrawal + +```sh +forge script ../tasks/complete_withdrawal_from_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount,uint256 nonce,uint32 startBlock)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $SHARES $NONCE $WITHDRAWAL_START_BLOCK_NUMBER +``` + +15. Verify that the `SHARES` we're withdrawn back to the sender +```sh +cast call $TOKEN "balanceOf(address)(uint256)" $SENDER --rpc-url $RPC_URL +``` + +16. Verify that the sender holds 0 withdrawable `TOKEN` shares: +```sh +cast call $DELEGATION_MANAGER "getWithdrawableShares(address,address[])(uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL +``` diff --git a/script/tasks/allocate_operatorSet.s.sol b/script/tasks/allocate_operatorSet.s.sol new file mode 100644 index 000000000..ab3d633a6 --- /dev/null +++ b/script/tasks/allocate_operatorSet.s.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AVSDirectory.sol"; +import "../../src/contracts/core/AllocationManager.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/allocate_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/allocate_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 00000001 0500000000000000000 +contract AllocateOperatorSet is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile, address strategy, address avs, uint32 operatorSetId, uint64 magnitude) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull allocationManager address + address allocationManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach to the AllocationManager + AllocationManager am = AllocationManager(allocationManager); + + // Correct array initialization + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = IStrategy(strategy); + + // Set OperatorSets + OperatorSet[] memory sets = new OperatorSet[](1); + sets[0] = OperatorSet({ + avs: avs, + id: operatorSetId + }); + + // Set new mangitudes + uint64[] memory magnitudes = new uint64[](1); + magnitudes[0] = magnitude; + + // Define a single MagnitudeAllocation and wrap it in an array + IAllocationManagerTypes.AllocateParams[] memory allocations = new IAllocationManagerTypes.AllocateParams[](1); + allocations[0] = IAllocationManagerTypes.AllocateParams({ + operatorSet: sets[0], + strategies: strategies, + newMagnitudes: magnitudes + }); + + // Perform allocation + am.modifyAllocations(msg.sender, allocations); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/tasks/complete_withdrawal_from_strategy.s.sol b/script/tasks/complete_withdrawal_from_strategy.s.sol new file mode 100644 index 000000000..6ea79380e --- /dev/null +++ b/script/tasks/complete_withdrawal_from_strategy.s.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AllocationManager.sol"; +import "../../src/contracts/core/DelegationManager.sol"; +import "../../src/contracts/pods/EigenPodManager.sol"; +import "../../src/contracts/libraries/SlashingLib.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/complete_withdrawal_from_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,,address strategy,address token,uint256 amount)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/complete_withdrawal_from_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,,address strategy,address token,uint256 amount,uint256 nonce,uint32 startBlock)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 750 0 630 +contract CompleteWithdrawFromStrategy is Script, Test { + using SlashingLib for *; + + Vm cheats = Vm(VM_ADDRESS); + + string public deployConfigPath; + string public config_data; + + function run(string memory configFile, address strategy, address token, uint256 amount, uint256 nonce, uint32 startBlock) public { + // Load config + deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + config_data = vm.readFile(deployConfigPath); + + // Pull addresses from config + AllocationManager am = AllocationManager(stdJson.readAddress(config_data, ".addresses.allocationManager")); + DelegationManager dm = DelegationManager(stdJson.readAddress(config_data, ".addresses.delegationManager")); + EigenPodManager em = EigenPodManager(stdJson.readAddress(config_data, ".addresses.eigenPodManager")); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Add token to array + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(token); + + // Get the withdrawal struct + IDelegationManagerTypes.Withdrawal memory withdrawal = getWithdrawalStruct( + am, + dm, + em, + strategy, + amount, + nonce, + startBlock + ); + + // complete + dm.completeQueuedWithdrawal(withdrawal, tokens, true); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } + + function getWithdrawalStruct( + AllocationManager am, + DelegationManager dm, + EigenPodManager em, + address strategy, + uint256 amount, + uint256 nonce, + uint32 startBlock + ) internal returns (IDelegationManagerTypes.Withdrawal memory) { + // Add strategy to array + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = IStrategy(strategy); + // Add shares to array + uint256[] memory shares = new uint256[](1); + shares[0] = amount; + + // Get DSF for Staker in strategy + DepositScalingFactor memory dsf = DepositScalingFactor(dm.depositScalingFactor(msg.sender, strategies[0])); + + // Get TM for Operator in strategies + uint64[] memory maxMagnitudes = am.getMaxMagnitudesAtBlock(msg.sender, strategies, startBlock); + uint256 slashingFactor = _getSlashingFactor(em, msg.sender, strategies[0], maxMagnitudes[0]); + uint256 sharesToWithdraw = dsf.calcWithdrawable(amount, slashingFactor); + + // Get scaled shares for the given amount + uint256[] memory scaledShares = new uint256[](1); + scaledShares[0] = SlashingLib.scaleForQueueWithdrawal({ + sharesToWithdraw: sharesToWithdraw, + slashingFactor: slashingFactor + }); + + // Log the current state before completing + emit log_uint(dsf.scalingFactor()); + emit log_uint(maxMagnitudes[0]); + emit log_uint(scaledShares[0]); + + // Create the withdrawal struct + IDelegationManagerTypes.Withdrawal memory withdrawal = IDelegationManagerTypes.Withdrawal({ + staker: msg.sender, + delegatedTo: msg.sender, + withdrawer: msg.sender, + nonce: nonce, + startBlock: startBlock, + strategies: strategies, + scaledShares: scaledShares + }); + + // Return the withdrawal struct + return withdrawal; + } + + function _getSlashingFactor( + EigenPodManager em, + address staker, + IStrategy strategy, + uint64 operatorMaxMagnitude + ) internal view returns (uint256) { + if (strategy == em.beaconChainETHStrategy()) { + uint64 beaconChainSlashingFactor = em.beaconChainSlashingFactor(staker); + return operatorMaxMagnitude.mulWad(beaconChainSlashingFactor); + } + + return operatorMaxMagnitude; + } +} diff --git a/script/tasks/deposit_into_strategy.s.sol b/script/tasks/deposit_into_strategy.s.sol new file mode 100644 index 000000000..7ccf244f1 --- /dev/null +++ b/script/tasks/deposit_into_strategy.s.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/StrategyManager.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use cast: +// +// cast send "approve(address,uint256)" \ +// \ +// \ +// --private-key +// +// cast send "depositIntoStrategy(address,address,uint256)" \ +// \ +// \ +// \ +// --private-key + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/deposit_into_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/deposit_into_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 $DEPOSIT_SHARES +contract DepositIntoStrategy is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile, address strategy, address token, uint256 amount) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull strategy manager address + address strategyManager = stdJson.readAddress(config_data, ".addresses.strategyManager"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + IERC20 tkn = IERC20(token); + StrategyManager sm = StrategyManager(strategyManager); + + // approve spend + tkn.approve(strategyManager, amount); + + // do deposit + sm.depositIntoStrategy(IStrategy(strategy), IERC20(token), amount); + + vm.stopBroadcast(); + } +} diff --git a/script/tasks/register_as_operator.s.sol b/script/tasks/register_as_operator.s.sol new file mode 100644 index 000000000..57ee4f9bc --- /dev/null +++ b/script/tasks/register_as_operator.s.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/DelegationManager.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use cast: +// cast send "registerAsOperator((address,address,uint32),uint256,string)" \ +// "(address(0), , 0)" \ +// 0 \ +// "" \ +// --private-key + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/register_as_operator.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,string memory metadataURI)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/register_as_operator.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,string metadataURI)" -- local/slashing_output.json 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 "test" +contract RegisterAsOperator is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile, address operator, string memory metadataURI) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull delegation manager address + address delegationManager = stdJson.readAddress(config_data, ".addresses.delegationManager"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach the delegationManager + DelegationManager delegation = DelegationManager(delegationManager); + + // Register the sender as an Operator + delegation.registerAsOperator(operator, 0, metadataURI); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/tasks/register_operator_to_operatorSet.s.sol b/script/tasks/register_operator_to_operatorSet.s.sol new file mode 100644 index 000000000..9ab8dc252 --- /dev/null +++ b/script/tasks/register_operator_to_operatorSet.s.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AVSDirectory.sol"; +import "../../src/contracts/interfaces/IAVSDirectory.sol"; +import "../../src/contracts/core/AllocationManager.sol"; +import "../../src/contracts/interfaces/IAllocationManager.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// Define dummy AVSRegistrar contract to prevent revert +contract AVSRegistrar is IAVSRegistrar { + function registerOperator(address operator, uint32[] calldata operatorSetIds, bytes calldata data) external {} + function deregisterOperator(address operator, uint32[] calldata operatorSetIds) external {} + fallback () external {} +} + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/register_operator_to_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/register_operator_to_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/slashing_output.json +contract RegisterOperatorToOperatorSets is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull avs directory address + address avsDir = stdJson.readAddress(config_data, ".addresses.avsDirectory"); + address allocManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); + address strategy = stdJson.readAddress(config_data, ".addresses.strategy"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach to the deployed contracts + AVSDirectory avsDirectory = AVSDirectory(avsDir); + AllocationManager allocationManager = AllocationManager(allocManager); + + // Use privateKey to register as an operator + address operator = cheats.addr(vm.envUint("PRIVATE_KEY")); + uint256 expiry = type(uint256).max; + uint32[] memory oids = new uint32[](1); + oids[0] = 1; + + // Sign as Operator + (uint8 v, bytes32 r, bytes32 s) = cheats.sign( + operator, avsDirectory.calculateOperatorAVSRegistrationDigestHash(operator, operator, bytes32(uint256(0) + 1), expiry) + ); + + // Add strategies to array + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = IStrategy(strategy); + + // Create OperatorSet(s) + IAllocationManagerTypes.CreateSetParams[] memory sets = new IAllocationManagerTypes.CreateSetParams[](1); + sets[0] = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: 1, + strategies: strategies + }); + allocationManager.createOperatorSets(msg.sender, sets); + + // Register the Operator to the AVS + avsDirectory.registerOperatorToAVS( + operator, ISignatureUtils.SignatureWithSaltAndExpiry(abi.encodePacked(r, s, v), bytes32(uint256(0) + 1), expiry) + ); + + // Deploy and set registrar. + allocationManager.setAVSRegistrar(msg.sender, new AVSRegistrar()); + + // Register OperatorSet(s) + IAllocationManagerTypes.RegisterParams memory register = IAllocationManagerTypes.RegisterParams({ + avs: operator, + operatorSetIds: oids, + data: "" + }); + allocationManager.registerForOperatorSets(operator, register); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/tasks/run.sh b/script/tasks/run.sh new file mode 100755 index 000000000..bfacd50ce --- /dev/null +++ b/script/tasks/run.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +# These tasks deploy the `slashing-magnitudes` contracts and set up the sender (`address(PRIVATE_KEY)`) as an `AVS`, `Operator` and `Staker`. +# We then register the `Operator` to an `OperatorSet`, allocate the `strategy` in that `OperatorSet`, deposit `TestTokens` and perform a `slashing`. + +# Environment Configuration +RPC_URL="127.0.0.1:8545" +PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +SENDER=$(cast wallet address --private-key $PRIVATE_KEY) +OUTPUT_DIR="../output/local" + +# Define amount of shares to deposit/withdraw +DEPOSIT_SHARES=1000 + +# Ensure output directory exists +mkdir -p $OUTPUT_DIR + +# Deploy contracts +forge script -C src/contracts --via-ir ../deploy/local/deploy_from_scratch.slashing.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile)" \ + -- local/deploy_from_scratch.slashing.anvil.config.json + +# Compile task contracts +forge build -C script/tasks + +# Extract contract addresses from deployment output +DELEGATION_MANAGER=$(jq -r '.addresses.delegationManager' "$OUTPUT_DIR/slashing_output.json") +STRATEGY=$(jq -r '.addresses.strategy' "$OUTPUT_DIR/slashing_output.json") +TOKEN=$(jq -r '.addresses.TestToken' "$OUTPUT_DIR/slashing_output.json") +BALANCE=$(cast call $TOKEN "balanceOf(address)(uint256)" $SENDER --rpc-url $RPC_URL) + +# Unpause the AVS Directory +forge script ../tasks/unpause_avsDirectory.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile)" \ + -- local/slashing_output.json + +# Deposit shares into strategy +forge script ../tasks/deposit_into_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $DEPOSIT_SHARES + +# Register as Operator +forge script ../tasks/register_as_operator.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address operator,string metadataURI)" \ + -- local/slashing_output.json $SENDER "metadataURI" + +# Register Operator to OperatorSet +forge script ../tasks/register_operator_to_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --tc RegisterOperatorToOperatorSets \ + --sig "run(string memory configFile)" \ + -- local/slashing_output.json + +# Advance the blockchain by 600 blocks to pass pending delay +cast rpc anvil_mine 600 --rpc-url $RPC_URL + +# Allocate OperatorSet (50% allocation) +forge script ../tasks/allocate_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" \ + -- local/slashing_output.json $STRATEGY $SENDER 00000001 0500000000000000000 + +# Slash the OperatorSet (50%) +forge script ../tasks/slash_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" \ + -- local/slashing_output.json $SENDER 00000001 0500000000000000000 + +# Deposit more shares into strategy +forge script ../tasks/deposit_into_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $DEPOSIT_SHARES + +# Fetch current withdrawable shares and nonce +DEPOSITS=$(cast call $DELEGATION_MANAGER "getDepositedShares(address)(address[],uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL | sed -n '2p' | tr -d '[]') +SHARES=$(cast call $DELEGATION_MANAGER "getWithdrawableShares(address,address[])(uint256[],uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL | sed -n '1p' | tr -d '[]') +NONCE=$(cast call $DELEGATION_MANAGER "cumulativeWithdrawalsQueued(address)(uint256)" $SENDER --rpc-url $RPC_URL) + +# Withdraw slashed shares from Delegation Manager +forge script ../tasks/withdraw_from_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $DEPOSITS + +# Capture block number after initiating withdrawal +WITHDRAWAL_START_BLOCK_NUMBER=$(cast block-number --rpc-url $RPC_URL) + +# Advance the blockchain by 5 blocks to meet `MIN_WITHDRAWAL_DELAY_BLOCKS` +cast rpc anvil_mine 5 --rpc-url $RPC_URL + +# Slash the OperatorSet (50%) +forge script ../tasks/slash_operatorSet.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" \ + -- local/slashing_output.json $SENDER 00000001 0500000000000000000 + +# Complete the withdrawal process +forge script ../tasks/complete_withdrawal_from_strategy.s.sol \ + --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast \ + --sig "run(string memory configFile,address strategy,address token,uint256 amount,uint256 nonce,uint32 startBlock)" \ + -- local/slashing_output.json $STRATEGY $TOKEN $SHARES $NONCE $WITHDRAWAL_START_BLOCK_NUMBER + +# Verification +FINAL_SHARES=$(cast call $DELEGATION_MANAGER "getWithdrawableShares(address,address[])(uint256[],uint256[])" $SENDER "[$STRATEGY]" --rpc-url $RPC_URL | sed -n '1p' | tr -d '[]') +FINAL_BALANCE=$(cast call $TOKEN "balanceOf(address)(uint256)" $SENDER --rpc-url $RPC_URL) +BALANCE_AS_DEC=$(echo "$BALANCE" | awk '{print $1}') +FINAL_BALANCE_AS_DEC=$(echo "$FINAL_BALANCE" | awk '{print $1}') +SLASHED_BY_BALANCE=$(bc <<< "$BALANCE_AS_DEC - $FINAL_BALANCE_AS_DEC") + +# Print details +echo -e "==========================\n" +echo -e "Addresses saved to: $(realpath $(pwd)/../../script/output/local/slashing_output.json)" +echo -e "\n==========================\n" +echo "Number of tokens held initially: $BALANCE" +echo "Number of shares deposited: $DEPOSITS" +echo "Number of shares after slashing: $SHARES" +echo "Number of shares remaining: $FINAL_SHARES" +echo "Number of tokens held: $FINAL_BALANCE" +echo "Number of tokens slashed: $SLASHED_BY_BALANCE" +echo -e "\n==========================" diff --git a/script/tasks/slash_operatorSet.s.sol b/script/tasks/slash_operatorSet.s.sol new file mode 100644 index 000000000..d17feb63b --- /dev/null +++ b/script/tasks/slash_operatorSet.s.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AllocationManager.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/slash_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/slash_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" -- local/slashing_output.json 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 00000001 05000000 +contract SlashOperatorSet is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile, address operator, uint32 operatorSetId, uint256 wadToSlash) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull allocationManager address + address allocationManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach to the AllocationManager + AllocationManager am = AllocationManager(allocationManager); + + // Define SlashingParams struct instance with correct array initialization + IAllocationManagerTypes.SlashingParams memory slashing = IAllocationManagerTypes.SlashingParams({ + operator: operator, + operatorSetId: operatorSetId, + wadToSlash: wadToSlash, + description: "slashed" + }); + + // Perform slashing + am.slashOperator(operator, slashing); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/tasks/unpause_avsDirectory.s.sol b/script/tasks/unpause_avsDirectory.s.sol new file mode 100644 index 000000000..82b3aca08 --- /dev/null +++ b/script/tasks/unpause_avsDirectory.s.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AVSDirectory.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use cast: +// +// cast send "approve(address,uint256)" \ +// \ +// \ +// --private-key +// +// cast send "depositIntoStrategy(address,address,uint256)" \ +// \ +// \ +// \ +// --private-key + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/unpause_avsDirectory.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/unpause_avsDirectory.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/slashing_output.json +contract UnpauseAVSDirectory is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull avs directory address + address avsDir = stdJson.readAddress(config_data, ".addresses.avsDirectory"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach to the AVSDirectory + AVSDirectory avsDirectory = AVSDirectory(avsDir); + + // Unpause the AVSDirectory + avsDirectory.unpause(0); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/tasks/withdraw_from_strategy.s.sol b/script/tasks/withdraw_from_strategy.s.sol new file mode 100644 index 000000000..f06e87045 --- /dev/null +++ b/script/tasks/withdraw_from_strategy.s.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "../../src/contracts/core/AllocationManager.sol"; +import "../../src/contracts/core/DelegationManager.sol"; +import "../../src/contracts/libraries/SlashingLib.sol"; + +import "forge-std/Script.sol"; +import "forge-std/Test.sol"; + +// use forge: +// RUST_LOG=forge,foundry=trace forge script script/tasks/withdraw_from_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- +// RUST_LOG=forge,foundry=trace forge script script/tasks/withdraw_from_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 750 +contract WithdrawFromStrategy is Script, Test { + Vm cheats = Vm(VM_ADDRESS); + + function run(string memory configFile, address strategy, address token, uint256 amount) public { + // Load config + string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); + string memory config_data = vm.readFile(deployConfigPath); + + // Pull addresses from config + // address allocationManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); + address delegationManager = stdJson.readAddress(config_data, ".addresses.delegationManager"); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + // Attach to DelegationManager + // AllocationManager am = AllocationManager(allocationManager); + DelegationManager dm = DelegationManager(delegationManager); + + // Add strategy to array + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = IStrategy(strategy); + // Add shares to array + uint256[] memory shares = new uint256[](1); + shares[0] = amount; + // Add token to array + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(token); + + // Get the current withdrawal nonce for sender + uint256 nonce = dm.cumulativeWithdrawalsQueued(msg.sender); + + // Define QueuedWithdrawalParams struct instance + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queueWithdrawals = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); + queueWithdrawals[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + strategies: strategies, + depositShares: shares, + withdrawer: msg.sender + }); + + // Withdrawal roots will be returned when we queue + bytes32[] memory withdrawalRoots; + + // Log the details we need to reproduce the WithdrawalRoot + emit log_named_uint("nonce", nonce); + emit log_named_uint("startBlock", block.number + 1); + + // Queue withdrawal + withdrawalRoots = dm.queueWithdrawals(queueWithdrawals); + + // Log the withdrawalRoot + emit log_named_bytes32("withdrawalRoot", withdrawalRoots[0]); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + } +} diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index c0b2c71f3..f12a225d5 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -1,15 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "../../src/contracts/core/StrategyManager.sol"; -import "../../src/contracts/core/Slasher.sol"; import "../../src/contracts/core/DelegationManager.sol"; import "../../src/contracts/core/AVSDirectory.sol"; import "../../src/contracts/core/RewardsCoordinator.sol"; +import "../../src/contracts/core/AllocationManager.sol"; +import "../../src/contracts/permissions/PermissionController.sol"; import "../../src/contracts/strategies/StrategyFactory.sol"; import "../../src/contracts/strategies/StrategyBase.sol"; @@ -45,8 +46,6 @@ contract ExistingDeploymentParser is Script, Test { // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; PauserRegistry public eigenLayerPauserReg; - Slasher public slasher; - Slasher public slasherImplementation; AVSDirectory public avsDirectory; AVSDirectory public avsDirectoryImplementation; DelegationManager public delegationManager; @@ -62,8 +61,12 @@ contract ExistingDeploymentParser is Script, Test { StrategyBase public baseStrategyImplementation; StrategyFactory public strategyFactory; StrategyFactory public strategyFactoryImplementation; + AllocationManager public allocationManager; + AllocationManager public allocationManagerImplementation; UpgradeableBeacon public strategyBeacon; StrategyBase public strategyFactoryBeaconImplementation; + PermissionController public permissionController; + PermissionController public permissionControllerImplementation; // Token ProxyAdmin public tokenProxyAdmin; @@ -100,11 +103,10 @@ contract ExistingDeploymentParser is Script, Test { // StrategyManager uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; address STRATEGY_MANAGER_WHITELISTER; - // SLasher - uint256 SLASHER_INIT_PAUSED_STATUS; // DelegationManager uint256 DELEGATION_MANAGER_INIT_PAUSED_STATUS; uint256 DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS; + uint32 MIN_WITHDRAWAL_DELAY; // AVSDirectory uint256 AVS_DIRECTORY_INIT_PAUSED_STATUS; // RewardsCoordinator @@ -117,8 +119,14 @@ contract ExistingDeploymentParser is Script, Test { uint32 REWARDS_COORDINATOR_ACTIVATION_DELAY; uint32 REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS; uint32 REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP; + uint32 REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH; // EigenPodManager uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; + // AllocationManager + uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; + uint32 DEALLOCATION_DELAY; + uint32 ALLOCATION_CONFIGURATION_DELAY; // EigenPod uint64 EIGENPOD_GENESIS_TIME; uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; @@ -157,10 +165,6 @@ contract ExistingDeploymentParser is Script, Test { eigenLayerPauserReg = PauserRegistry( stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerPauserReg") ); - slasher = Slasher(stdJson.readAddress(existingDeploymentData, ".addresses.slasher")); - slasherImplementation = Slasher( - stdJson.readAddress(existingDeploymentData, ".addresses.slasherImplementation") - ); delegationManager = DelegationManager( stdJson.readAddress(existingDeploymentData, ".addresses.delegationManager") ); @@ -292,8 +296,6 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".strategyManager.init_strategy_whitelister" ); - // Slasher - SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); // DelegationManager DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint( initialDeploymentData, @@ -318,6 +320,12 @@ contract ExistingDeploymentParser is Script, Test { REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS = uint32( stdJson.readUint(initialDeploymentData, ".rewardsCoordinator.global_operator_commission_bips") ); + REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = uint32( + stdJson.readUint(initialDeploymentData, ".rewardsCoordinator.OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP") + ); + REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH = uint32( + stdJson.readUint(initialDeploymentData, ".rewardsCoordinator.OPERATOR_SET_MAX_RETROACTIVE_LENGTH") + ); // AVSDirectory AVS_DIRECTORY_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".avsDirectory.init_paused_status"); // EigenPodManager @@ -325,6 +333,11 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".eigenPodManager.init_paused_status" ); + // AllocationManager + ALLOCATION_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".allocationManager.init_paused_status" + ); // EigenPod EIGENPOD_GENESIS_TIME = uint64(stdJson.readUint(initialDeploymentData, ".eigenPod.GENESIS_TIME")); ETHPOSDepositAddress = stdJson.readAddress(initialDeploymentData, ".ethPOSDepositAddress"); @@ -349,7 +362,6 @@ contract ExistingDeploymentParser is Script, Test { "rewardsCoordinator: strategyManager address not set correctly" ); // DelegationManager - require(delegationManager.slasher() == slasher, "delegationManager: slasher address not set correctly"); require( delegationManager.strategyManager() == strategyManager, "delegationManager: strategyManager address not set correctly" @@ -359,15 +371,10 @@ contract ExistingDeploymentParser is Script, Test { "delegationManager: eigenPodManager address not set correctly" ); // StrategyManager - require(strategyManager.slasher() == slasher, "strategyManager: slasher address not set correctly"); require( strategyManager.delegation() == delegationManager, "strategyManager: delegationManager address not set correctly" ); - require( - strategyManager.eigenPodManager() == eigenPodManager, - "strategyManager: eigenPodManager address not set correctly" - ); // EPM require( address(eigenPodManager.ethPOS()) == ETHPOSDepositAddress, @@ -381,7 +388,6 @@ contract ExistingDeploymentParser is Script, Test { eigenPodManager.strategyManager() == strategyManager, "eigenPodManager: strategyManager contract address not set correctly" ); - require(eigenPodManager.slasher() == slasher, "eigenPodManager: slasher contract address not set correctly"); require( eigenPodManager.delegationManager() == delegationManager, "eigenPodManager: delegationManager contract address not set correctly" @@ -391,36 +397,31 @@ contract ExistingDeploymentParser is Script, Test { /// @notice verify implementations for Transparent Upgradeable Proxies function _verifyImplementations() internal view virtual { require( - eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(avsDirectory)))) == + eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(avsDirectory)))) == address(avsDirectoryImplementation), "avsDirectory: implementation set incorrectly" ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(rewardsCoordinator))) + ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))) ) == address(rewardsCoordinatorImplementation), "rewardsCoordinator: implementation set incorrectly" ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(delegationManager))) + ITransparentUpgradeableProxy(payable(address(delegationManager))) ) == address(delegationManagerImplementation), "delegationManager: implementation set incorrectly" ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(strategyManager))) + ITransparentUpgradeableProxy(payable(address(strategyManager))) ) == address(strategyManagerImplementation), "strategyManager: implementation set incorrectly" ); - require( - eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(slasher)))) == - address(slasherImplementation), - "slasher: implementation set incorrectly" - ); require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(eigenPodManager))) + ITransparentUpgradeableProxy(payable(address(eigenPodManager))) ) == address(eigenPodManagerImplementation), "eigenPodManager: implementation set incorrectly" ); @@ -428,7 +429,7 @@ contract ExistingDeploymentParser is Script, Test { for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { require( eigenLayerProxyAdmin.getProxyImplementation( - TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) + ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) ) == address(baseStrategyImplementation), "strategy: implementation set incorrectly" ); @@ -448,12 +449,11 @@ contract ExistingDeploymentParser is Script, Test { function _verifyContractsInitialized(bool /** isInitialDeployment **/) internal virtual { // AVSDirectory vm.expectRevert(bytes("Initializable: contract is already initialized")); - avsDirectory.initialize(address(0), eigenLayerPauserReg, AVS_DIRECTORY_INIT_PAUSED_STATUS); + avsDirectory.initialize(address(0), AVS_DIRECTORY_INIT_PAUSED_STATUS); // RewardsCoordinator vm.expectRevert(bytes("Initializable: contract is already initialized")); rewardsCoordinator.initialize( address(0), - eigenLayerPauserReg, 0, // initialPausedStatus address(0), // rewardsUpdater 0, // activationDelay @@ -461,24 +461,17 @@ contract ExistingDeploymentParser is Script, Test { ); // DelegationManager vm.expectRevert(bytes("Initializable: contract is already initialized")); - IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); - uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); delegationManager.initialize( address(0), - eigenLayerPauserReg, - 0, - 0, // minWithdrawalDelayBLocks - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks + 0 ); // StrategyManager vm.expectRevert(bytes("Initializable: contract is already initialized")); - strategyManager.initialize(address(0), address(0), eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS); + strategyManager.initialize(address(0), address(0), STRATEGY_MANAGER_INIT_PAUSED_STATUS); // EigenPodManager vm.expectRevert(bytes("Initializable: contract is already initialized")); eigenPodManager.initialize( address(0), - eigenLayerPauserReg, EIGENPOD_MANAGER_INIT_PAUSED_STATUS ); // Strategies @@ -487,8 +480,7 @@ contract ExistingDeploymentParser is Script, Test { StrategyBaseTVLLimits(address(deployedStrategyArray[i])).initialize( 0, 0, - IERC20(address(0)), - eigenLayerPauserReg + IERC20(address(0)) ); } } @@ -560,10 +552,6 @@ contract ExistingDeploymentParser is Script, Test { delegationManager.paused() == DELEGATION_MANAGER_INIT_PAUSED_STATUS, "delegationManager: init paused status set incorrectly" ); - require( - delegationManager.minWithdrawalDelayBlocks() == DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, - "delegationManager: minWithdrawalDelayBlocks not set correctly" - ); // StrategyManager require( strategyManager.pauserRegistry() == eigenLayerPauserReg, @@ -644,7 +632,6 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); emit log_named_address("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); - emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); emit log_named_uint( "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS @@ -695,8 +682,6 @@ contract ExistingDeploymentParser is Script, Test { string memory deployed_addresses = "addresses"; vm.serializeAddress(deployed_addresses, "eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); vm.serializeAddress(deployed_addresses, "eigenLayerPauserReg", address(eigenLayerPauserReg)); - vm.serializeAddress(deployed_addresses, "slasher", address(slasher)); - vm.serializeAddress(deployed_addresses, "slasherImplementation", address(slasherImplementation)); vm.serializeAddress(deployed_addresses, "avsDirectory", address(avsDirectory)); vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); vm.serializeAddress(deployed_addresses, "delegationManager", address(delegationManager)); diff --git a/script/utils/TimelockEncoding.sol b/script/utils/TimelockEncoding.sol index cbb0c8da3..c2eaad396 100644 --- a/script/utils/TimelockEncoding.sol +++ b/script/utils/TimelockEncoding.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Script.sol"; import "forge-std/Test.sol"; diff --git a/script/whitelist/Staker.sol b/script/whitelist/Staker.sol index f353610ce..c2ec20af1 100644 --- a/script/whitelist/Staker.sol +++ b/script/whitelist/Staker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/contracts/interfaces/IStrategyManager.sol"; import "../../src/contracts/interfaces/IStrategy.sol"; diff --git a/script/whitelist/delegationFaucet/DelegationFaucet.sol b/script/whitelist/delegationFaucet/DelegationFaucet.sol deleted file mode 100644 index 327e8e678..000000000 --- a/script/whitelist/delegationFaucet/DelegationFaucet.sol +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IStrategyManager.sol"; -import "src/contracts/interfaces/IStrategy.sol"; -import "src/contracts/interfaces/IDelegationManager.sol"; -import "src/contracts/interfaces/IDelegationFaucet.sol"; -import "script/whitelist/delegationFaucet/DelegationFaucetStaker.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; - -import "../ERC20PresetMinterPauser.sol"; - -/** - * @title DelegationFaucet for M2 - * @author Layr Labs, Inc. - * @notice Faucet contract setup with a dummy ERC20 token and strategy for M2 testnet release. - * Each operator address gets a staker contract assigned to them deterministically. - * This contract assumes minting role of the ERC20 token and that the ERC20 token has a whitelisted strategy. - */ -contract DelegationFaucet is IDelegationFaucet, Ownable { - IStrategyManager immutable strategyManager; - ERC20PresetMinterPauser immutable stakeToken; - IStrategy immutable stakeStrategy; - IDelegationManager immutable delegation; - - uint256 public constant DEFAULT_AMOUNT = 100e18; - - constructor( - IStrategyManager _strategyManager, - IDelegationManager _delegation, - ERC20PresetMinterPauser _token, - IStrategy _strategy - ) { - strategyManager = _strategyManager; - delegation = _delegation; - stakeToken = _token; - stakeStrategy = _strategy; - } - - /** - * Deploys a DelegationFaucetStaker contract if not already deployed for operator. DelegationFaucetStaker gets minted _depositAmount or - * DEFAULT_AMOUNT if _depositAmount is 0. Then DelegationFaucetStaker contract deposits into the strategy and delegates to operator. - * @param _operator The operator to delegate to - * @param _approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param _approverSalt A unique single use value tied to an individual signature. - * @param _depositAmount The amount to deposit into the strategy - */ - function mintDepositAndDelegate( - address _operator, - IDelegationManager.SignatureWithExpiry memory _approverSignatureAndExpiry, - bytes32 _approverSalt, - uint256 _depositAmount - ) public onlyOwner { - // Operator must be registered - require(delegation.isOperator(_operator), "DelegationFaucet: Operator not registered"); - address staker = getStaker(_operator); - // Set deposit amount - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - - // Deploy staker address if not already deployed, staker constructor will approve the StrategyManager to spend the stakeToken - if (!Address.isContract(staker)) { - Create2.deploy( - 0, - bytes32(uint256(uint160(_operator))), - abi.encodePacked(type(DelegationFaucetStaker).creationCode, abi.encode(strategyManager, stakeToken)) - ); - } - - // mint stakeToken to staker - stakeToken.mint(staker, _depositAmount); - // deposit into stakeToken strategy, which will increase delegated shares to operator if already delegated - _depositIntoStrategy(staker, stakeStrategy, stakeToken, _depositAmount); - // delegateTo operator if not delegated - if (!delegation.isDelegated(staker)) { - delegateTo(_operator, _approverSignatureAndExpiry, _approverSalt); - } - } - - /** - * Calls staker contract to deposit into designated strategy, mints staked token if stakeToken and stakeStrategy - * are specified. - * @param _staker address of staker contract for operator - * @param _strategy StakeToken strategy contract - * @param _token StakeToken - * @param _amount amount to get minted and to deposit - */ - function depositIntoStrategy( - address _staker, - IStrategy _strategy, - IERC20 _token, - uint256 _amount - ) public onlyOwner returns (bytes memory) { - // mint stakeToken to staker - if (_token == stakeToken && _strategy == stakeStrategy) { - stakeToken.mint(_staker, _amount); - } - return _depositIntoStrategy(_staker, _strategy, _token, _amount); - } - - /** - * Call staker to delegate to operator - * @param _operator operator to get staker address from and delegate to - * @param _approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param _approverSalt A unique single use value tied to an individual signature. - */ - function delegateTo( - address _operator, - IDelegationManager.SignatureWithExpiry memory _approverSignatureAndExpiry, - bytes32 _approverSalt - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.delegateTo.selector, - _operator, - _approverSignatureAndExpiry, - _approverSalt - ); - return DelegationFaucetStaker(getStaker(_operator)).callAddress(address(delegation), data); - } - - /** - * Call queueWithdrawal through staker contract - */ - function queueWithdrawal( - address staker, - IDelegationManager.QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.queueWithdrawals.selector, - queuedWithdrawalParams - ); - return DelegationFaucetStaker(staker).callAddress(address(delegation), data); - } - - /** - * Call completeQueuedWithdrawal through staker contract - */ - function completeQueuedWithdrawal( - address staker, - IDelegationManager.Withdrawal calldata queuedWithdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.completeQueuedWithdrawal.selector, - queuedWithdrawal, - tokens, - middlewareTimesIndex, - receiveAsTokens - ); - return DelegationFaucetStaker(staker).callAddress(address(delegation), data); - } - - /** - * Transfers tokens from staker contract to designated address - * @param staker staker contract to transfer from - * @param token ERC20 token - * @param to the to address - * @param amount transfer amount - */ - function transfer( - address staker, - address token, - address to, - uint256 amount - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector(IERC20.transfer.selector, to, amount); - return DelegationFaucetStaker(staker).callAddress(token, data); - } - - function callAddress(address to, bytes memory data) public payable onlyOwner returns (bytes memory) { - (bool ok, bytes memory res) = payable(to).call{value: msg.value}(data); - if (!ok) { - revert(string(res)); - } - return res; - } - - /** - * @notice Returns the deterministic staker contract address for the operator - * @param _operator The operator to get the staker contract address for - */ - function getStaker(address _operator) public view returns (address) { - return - Create2.computeAddress( - bytes32(uint256(uint160(_operator))), //salt - keccak256( - abi.encodePacked(type(DelegationFaucetStaker).creationCode, abi.encode(strategyManager, stakeToken)) - ) - ); - } - - /** - * @notice Internal function to deposit into a strategy, has same function signature as StrategyManager.depositIntoStrategy - */ - function _depositIntoStrategy( - address _staker, - IStrategy _strategy, - IERC20 _token, - uint256 _amount - ) internal returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IStrategyManager.depositIntoStrategy.selector, - _strategy, - _token, - _amount - ); - return DelegationFaucetStaker(_staker).callAddress(address(strategyManager), data); - } -} diff --git a/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol b/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol deleted file mode 100644 index fac0e543c..000000000 --- a/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IStrategyManager.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "forge-std/Test.sol"; - -contract DelegationFaucetStaker is Ownable { - constructor(IStrategyManager strategyManager, IERC20 token) Ownable() { - token.approve(address(strategyManager), type(uint256).max); - } - - function callAddress(address implementation, bytes memory data) external onlyOwner returns (bytes memory) { - uint256 length = data.length; - bytes memory returndata; - assembly { - let result := call(gas(), implementation, callvalue(), add(data, 32), length, 0, 0) - mstore(returndata, returndatasize()) - returndatacopy(add(returndata, 32), 0, returndatasize()) - } - - return returndata; - } -} diff --git a/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol b/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol deleted file mode 100644 index 601297a06..000000000 --- a/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IDelegationManager.sol"; -import "src/contracts/interfaces/IStrategyManager.sol"; -import "src/contracts/strategies/StrategyBase.sol"; -import "src/contracts/permissions/PauserRegistry.sol"; - -import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -import "./DelegationFaucet.sol"; - -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -/** - * @notice Deploys the following contracts: - * - ERC20 Dummy token for testing - * - StrategyBase to be added to the StrategyManager whitelist - * - DelegationFaucet contract - */ -contract DeployDelegationFaucet is Script, Test { - // EigenLayer contracts - ProxyAdmin public eigenLayerProxyAdmin; - PauserRegistry public eigenLayerPauserReg; - IDelegationManager public delegation; - IStrategyManager public strategyManager; - - DelegationFaucet public delegationFaucet; - - // M2 testing/mock contracts - ERC20PresetMinterPauser public stakeToken; - StrategyBase public stakeTokenStrat; - StrategyBase public baseStrategyImplementation; - - address eigenLayerProxyAdminAddress; - address eigenLayerPauserRegAddress; - address delegationAddress; - address strategyManagerAddress; - address operationsMultisig; - address executorMultisig; - - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - - function run() external { - string memory goerliDeploymentConfig = vm.readFile("script/output/M1_deployment_goerli_2023_3_23.json"); - _setAddresses(goerliDeploymentConfig); - - vm.startBroadcast(); - // Deploy ERC20 stakeToken - stakeToken = new ERC20PresetMinterPauser("StakeToken", "STK"); - - // Deploy StrategyBase for stakeToken & whitelist it - baseStrategyImplementation = new StrategyBase(strategyManager); - stakeTokenStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - eigenLayerProxyAdminAddress, - abi.encodeWithSelector(StrategyBase.initialize.selector, stakeToken, eigenLayerPauserRegAddress) - ) - ) - ); - - // Needs to be strategyManager.strategyWhitelister() to add STK strategy - // IStrategy[] memory _strategy = new IStrategy[](1); - // _strategy[0] = stakeTokenStrat; - // strategyManager.addStrategiesToDepositWhitelist(_strategy); - - // Deploy DelegationFaucet, grant it admin/mint/pauser roles, etc. - delegationFaucet = new DelegationFaucet(strategyManager, delegation, stakeToken, stakeTokenStrat); - stakeToken.grantRole(MINTER_ROLE, address(delegationFaucet)); - vm.stopBroadcast(); - } - - function _setAddresses(string memory config) internal { - eigenLayerProxyAdminAddress = stdJson.readAddress(config, ".addresses.eigenLayerProxyAdmin"); - eigenLayerPauserRegAddress = stdJson.readAddress(config, ".addresses.eigenLayerPauserReg"); - delegationAddress = stdJson.readAddress(config, ".addresses.delegation"); - strategyManagerAddress = stdJson.readAddress(config, ".addresses.strategyManager"); - operationsMultisig = stdJson.readAddress(config, ".parameters.operationsMultisig"); - executorMultisig = stdJson.readAddress(config, ".parameters.executorMultisig"); - } -} diff --git a/src/contracts/core/AVSDirectory.sol b/src/contracts/core/AVSDirectory.sol index 9c3a0a65f..0e9af8741 100644 --- a/src/contracts/core/AVSDirectory.sol +++ b/src/contracts/core/AVSDirectory.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; + +import "../mixins/SignatureUtils.sol"; import "../permissions/Pausable.sol"; -import "../libraries/EIP1271SignatureUtils.sol"; import "./AVSDirectoryStorage.sol"; contract AVSDirectory is @@ -13,14 +14,9 @@ contract AVSDirectory is OwnableUpgradeable, Pausable, AVSDirectoryStorage, - ReentrancyGuardUpgradeable + ReentrancyGuardUpgradeable, + SignatureUtils { - // @dev Index for flag that pauses operator register/deregister to avs when set. - uint8 internal constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; - - // @dev Chain ID at the time of contract deployment - uint256 internal immutable ORIGINAL_CHAIN_ID; - /** * * INITIALIZING FUNCTIONS @@ -28,31 +24,46 @@ contract AVSDirectory is */ /** - * @dev Initializes the immutable addresses of the strategy mananger, delegationManager, slasher, + * @dev Initializes the immutable addresses of the strategy mananger, delegationManager, * and eigenpodManager contracts */ - constructor(IDelegationManager _delegation) AVSDirectoryStorage(_delegation) { + constructor( + IDelegationManager _delegation, + IPauserRegistry _pauserRegistry + ) AVSDirectoryStorage(_delegation) Pausable(_pauserRegistry) { _disableInitializers(); - ORIGINAL_CHAIN_ID = block.chainid; + } + + /// @inheritdoc IAVSDirectory + function initialize(address initialOwner, uint256 initialPausedStatus) external initializer { + _setPausedStatus(initialPausedStatus); + _transferOwnership(initialOwner); } /** - * @dev Initializes the addresses of the initial owner, pauser registry, and paused status. - * minWithdrawalDelayBlocks is set only once here + * + * EXTERNAL FUNCTIONS + * */ - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 initialPausedStatus - ) external initializer { - _initializePauser(_pauserRegistry, initialPausedStatus); - _DOMAIN_SEPARATOR = _calculateDomainSeparator(); - _transferOwnership(initialOwner); + + /// @inheritdoc IAVSDirectory + function updateAVSMetadataURI( + string calldata metadataURI + ) external override { + emit AVSMetadataURIUpdated(msg.sender, metadataURI); + } + + /// @inheritdoc IAVSDirectory + function cancelSalt( + bytes32 salt + ) external override { + // Mutate `operatorSaltIsSpent` to `true` to prevent future spending. + operatorSaltIsSpent[msg.sender][salt] = true; } /** * - * EXTERNAL FUNCTIONS + * LEGACY EXTERNAL FUNCTIONS - SUPPORT DEPRECATED IN FUTURE RELEASE AFTER SLASHING RELEASE * */ @@ -60,57 +71,49 @@ contract AVSDirectory is function registerOperatorToAVS( address operator, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) { - require( - operatorSignature.expiry >= block.timestamp, - "AVSDirectory.registerOperatorToAVS: operator signature expired" - ); + ) external override onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) { + // Assert that the `operator` is not actively registered to the AVS. require( avsOperatorStatus[msg.sender][operator] != OperatorAVSRegistrationStatus.REGISTERED, - "AVSDirectory.registerOperatorToAVS: operator already registered" - ); - require( - !operatorSaltIsSpent[operator][operatorSignature.salt], - "AVSDirectory.registerOperatorToAVS: salt already spent" - ); - require( - delegation.isOperator(operator), - "AVSDirectory.registerOperatorToAVS: operator not registered to EigenLayer yet" + OperatorAlreadyRegisteredToAVS() ); - // Calculate the digest hash - bytes32 operatorRegistrationDigestHash = calculateOperatorAVSRegistrationDigestHash({ - operator: operator, - avs: msg.sender, - salt: operatorSignature.salt, + // Assert `operator` has not already spent `operatorSignature.salt`. + require(!operatorSaltIsSpent[operator][operatorSignature.salt], SaltSpent()); + + // Assert `operator` is a registered operator. + require(delegation.isOperator(operator), OperatorNotRegisteredToEigenLayer()); + + // Assert that `operatorSignature.signature` is a valid signature for the operator AVS registration. + _checkIsValidSignatureNow({ + signer: operator, + signableDigest: calculateOperatorAVSRegistrationDigestHash({ + operator: operator, + avs: msg.sender, + salt: operatorSignature.salt, + expiry: operatorSignature.expiry + }), + signature: operatorSignature.signature, expiry: operatorSignature.expiry }); - // forgefmt: disable-next-item - // Check that the signature is valid - EIP1271SignatureUtils.checkSignature_EIP1271( - operator, - operatorRegistrationDigestHash, - operatorSignature.signature - ); + // Mutate `operatorSaltIsSpent` to `true` to prevent future respending. + operatorSaltIsSpent[operator][operatorSignature.salt] = true; // Set the operator as registered avsOperatorStatus[msg.sender][operator] = OperatorAVSRegistrationStatus.REGISTERED; - // Mark the salt as spent - operatorSaltIsSpent[operator][operatorSignature.salt] = true; - emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.REGISTERED); } /// @inheritdoc IAVSDirectory - function deregisterOperatorFromAVS(address operator) - external - onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) - { + function deregisterOperatorFromAVS( + address operator + ) external override onlyWhenNotPaused(PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS) { + // Assert that operator is registered for the AVS. require( avsOperatorStatus[msg.sender][operator] == OperatorAVSRegistrationStatus.REGISTERED, - "AVSDirectory.deregisterOperatorFromAVS: operator not registered" + OperatorNotRegisteredToAVS() ); // Set the operator as deregistered @@ -119,17 +122,6 @@ contract AVSDirectory is emit OperatorAVSRegistrationStatusUpdated(operator, msg.sender, OperatorAVSRegistrationStatus.UNREGISTERED); } - /// @inheritdoc IAVSDirectory - function updateAVSMetadataURI(string calldata metadataURI) external { - emit AVSMetadataURIUpdated(msg.sender, metadataURI); - } - - /// @inheritdoc IAVSDirectory - function cancelSalt(bytes32 salt) external { - require(!operatorSaltIsSpent[msg.sender][salt], "AVSDirectory.cancelSalt: cannot cancel spent salt"); - operatorSaltIsSpent[msg.sender][salt] = true; - } - /** * * VIEW FUNCTIONS @@ -142,25 +134,9 @@ contract AVSDirectory is address avs, bytes32 salt, uint256 expiry - ) public view returns (bytes32) { - // calculate the struct hash - bytes32 structHash = keccak256(abi.encode(OPERATOR_AVS_REGISTRATION_TYPEHASH, operator, avs, salt, expiry)); - // calculate the digest hash - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator(), structHash)); - return digestHash; - } - - /// @inheritdoc IAVSDirectory - function domainSeparator() public view returns (bytes32) { - if (block.chainid == ORIGINAL_CHAIN_ID) { - return _DOMAIN_SEPARATOR; - } else { - return _calculateDomainSeparator(); - } - } - - // @notice Internal function for calculating the current domain separator of this contract - function _calculateDomainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this))); + ) public view override returns (bytes32) { + return _calculateSignableDigest( + keccak256(abi.encode(OPERATOR_AVS_REGISTRATION_TYPEHASH, operator, avs, salt, expiry)) + ); } } diff --git a/src/contracts/core/AVSDirectoryStorage.sol b/src/contracts/core/AVSDirectoryStorage.sol index 47a326f16..9198d246f 100644 --- a/src/contracts/core/AVSDirectoryStorage.sol +++ b/src/contracts/core/AVSDirectoryStorage.sol @@ -1,36 +1,52 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IAVSDirectory.sol"; import "../interfaces/IDelegationManager.sol"; abstract contract AVSDirectoryStorage is IAVSDirectory { - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + // Constants /// @notice The EIP-712 typehash for the `Registration` struct used by the contract bytes32 public constant OPERATOR_AVS_REGISTRATION_TYPEHASH = keccak256("OperatorAVSRegistration(address operator,address avs,bytes32 salt,uint256 expiry)"); + /// @notice The EIP-712 typehash for the `OperatorSetRegistration` struct used by the contract + bytes32 public constant OPERATOR_SET_REGISTRATION_TYPEHASH = + keccak256("OperatorSetRegistration(address avs,uint32[] operatorSetIds,bytes32 salt,uint256 expiry)"); + + /// @notice The EIP-712 typehash for the `OperatorSetMembership` struct used by the contract + bytes32 public constant OPERATOR_SET_FORCE_DEREGISTRATION_TYPEHASH = + keccak256("OperatorSetForceDeregistration(address avs,uint32[] operatorSetIds,bytes32 salt,uint256 expiry)"); + + /// @dev Index for flag that pauses operator register/deregister to avs when set. + uint8 internal constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; + + /// @dev Index for flag that pauses operator register/deregister to operator sets when set. + uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 1; + + // Immutables + /// @notice The DelegationManager contract for EigenLayer IDelegationManager public immutable delegation; - /** - * @notice Original EIP-712 Domain separator for this contract. - * @dev The domain separator may change in the event of a fork that modifies the ChainID. - * Use the getter function `domainSeparator` to get the current domain separator for this contract. - */ - bytes32 internal _DOMAIN_SEPARATOR; + // Mutatables + + /// @dev Do not remove, deprecated storage. + bytes32 internal __deprecated_DOMAIN_SEPARATOR; + + /// @notice Returns the registration status of each `operator` for a given `avs`. + /// @dev This storage will be deprecated once M2-based deregistration is removed. + mapping(address avs => mapping(address operator => OperatorAVSRegistrationStatus)) public avsOperatorStatus; - /// @notice Mapping: AVS => operator => enum of operator status to the AVS - mapping(address => mapping(address => OperatorAVSRegistrationStatus)) public avsOperatorStatus; + /// @notice Returns whether a `salt` has been used by a given `operator`. + mapping(address operator => mapping(bytes32 salt => bool isSpent)) public operatorSaltIsSpent; - /// @notice Mapping: operator => 32-byte salt => whether or not the salt has already been used by the operator. - /// @dev Salt is used in the `registerOperatorToAVS` function. - mapping(address => mapping(bytes32 => bool)) public operatorSaltIsSpent; + // Construction - constructor(IDelegationManager _delegation) { + constructor( + IDelegationManager _delegation + ) { delegation = _delegation; } @@ -39,5 +55,5 @@ abstract contract AVSDirectoryStorage is IAVSDirectory { * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[47] private __gap; + uint256[41] private __gap; } diff --git a/src/contracts/core/AllocationManager.sol b/src/contracts/core/AllocationManager.sol new file mode 100644 index 000000000..da42f2c32 --- /dev/null +++ b/src/contracts/core/AllocationManager.sol @@ -0,0 +1,832 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; + +import "../mixins/PermissionControllerMixin.sol"; +import "../permissions/Pausable.sol"; +import "../libraries/SlashingLib.sol"; +import "../libraries/OperatorSetLib.sol"; +import "./AllocationManagerStorage.sol"; + +contract AllocationManager is + Initializable, + OwnableUpgradeable, + Pausable, + AllocationManagerStorage, + ReentrancyGuardUpgradeable, + PermissionControllerMixin +{ + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + using EnumerableSet for *; + + using Snapshots for Snapshots.DefaultWadHistory; + using OperatorSetLib for OperatorSet; + using SlashingLib for uint256; + + /** + * + * INITIALIZING FUNCTIONS + * + */ + + /** + * @dev Initializes the DelegationManager address, the deallocation delay, and the allocation configuration delay. + */ + constructor( + IDelegationManager _delegation, + IPauserRegistry _pauserRegistry, + IPermissionController _permissionController, + uint32 _DEALLOCATION_DELAY, + uint32 _ALLOCATION_CONFIGURATION_DELAY + ) + AllocationManagerStorage(_delegation, _DEALLOCATION_DELAY, _ALLOCATION_CONFIGURATION_DELAY) + Pausable(_pauserRegistry) + PermissionControllerMixin(_permissionController) + { + _disableInitializers(); + } + + /// @inheritdoc IAllocationManager + function initialize(address initialOwner, uint256 initialPausedStatus) external initializer { + _setPausedStatus(initialPausedStatus); + _transferOwnership(initialOwner); + } + + /// @inheritdoc IAllocationManager + function slashOperator( + address avs, + SlashingParams calldata params + ) external onlyWhenNotPaused(PAUSED_OPERATOR_SLASHING) { + // Check that the msg.sender can call - we don't use a modifier to avoid `stack too deep` errors + require(_checkCanCall(avs), InvalidCaller()); + require(0 < params.wadToSlash && params.wadToSlash <= WAD, InvalidWadToSlash()); + + // Check that the operator set exists and the operator is registered to it + OperatorSet memory operatorSet = OperatorSet(avs, params.operatorSetId); + bool isRegistered = _isRegistered(params.operator, operatorSet); + require(_operatorSets[operatorSet.avs].contains(operatorSet.id), InvalidOperatorSet()); + require(isRegistered, NotMemberOfSet()); + + uint256 length = _operatorSetStrategies[operatorSet.key()].length(); + IStrategy[] memory strategiesSlashed = new IStrategy[](length); + uint256[] memory wadSlashed = new uint256[](length); + + // For each strategy in the operator set, slash any existing allocation + for (uint256 i = 0; i < length; i++) { + // 1. Get the operator's allocation info for the strategy and operator set + IStrategy strategy = IStrategy(_operatorSetStrategies[operatorSet.key()].at(i)); + (StrategyInfo memory info, Allocation memory allocation) = + _getUpdatedAllocation(params.operator, operatorSet.key(), strategy); + strategiesSlashed[i] = strategy; + + // 2. Skip if the operator does not have a slashable allocation + // NOTE: this "if" is equivalent to: `if (!_isAllocationSlashable)`, because the other + // conditions in this method are already true (isRegistered + operatorSetStrategies.contains) + if (allocation.currentMagnitude == 0) { + continue; + } + + // 3. Calculate the amount of magnitude being slashed, and subtract from + // the operator's currently-allocated magnitude, as well as the strategy's + // max and encumbered magnitudes + uint64 slashedMagnitude = uint64(uint256(allocation.currentMagnitude).mulWadRoundUp(params.wadToSlash)); + uint256 sharesWadSlashed = uint256(slashedMagnitude).divWad(info.maxMagnitude); + wadSlashed[i] = sharesWadSlashed; + uint64 prevMaxMagnitude = info.maxMagnitude; + + allocation.currentMagnitude -= slashedMagnitude; + + info.maxMagnitude -= slashedMagnitude; + info.encumberedMagnitude -= slashedMagnitude; + + // 4. If there is a pending deallocation, reduce the pending deallocation proportionally. + // This ensures that when the deallocation is completed, less magnitude is freed. + if (allocation.pendingDiff < 0) { + uint64 slashedPending = + uint64(uint256(uint128(-allocation.pendingDiff)).mulWadRoundUp(params.wadToSlash)); + allocation.pendingDiff += int128(uint128(slashedPending)); + + emit AllocationUpdated( + params.operator, + operatorSet, + strategy, + _addInt128(allocation.currentMagnitude, allocation.pendingDiff), + allocation.effectBlock + ); + } + + // 5. Update state + // The slash is effective immediately for the allocation + _updateAllocationInfo(params.operator, operatorSet.key(), strategy, info, allocation); + + // Emit an event for the updated allocation + emit AllocationUpdated( + params.operator, operatorSet, strategy, allocation.currentMagnitude, uint32(block.number) + ); + + _updateMaxMagnitude(params.operator, strategy, info.maxMagnitude); + + // 6. Decrease and burn operators shares in the DelegationManager + delegation.burnOperatorShares({ + operator: params.operator, + strategy: strategy, + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: info.maxMagnitude + }); + } + + emit OperatorSlashed(params.operator, operatorSet, strategiesSlashed, wadSlashed, params.description); + } + + /// @inheritdoc IAllocationManager + function modifyAllocations( + address operator, + AllocateParams[] memory params + ) external onlyWhenNotPaused(PAUSED_MODIFY_ALLOCATIONS) { + // Check that the caller is allowed to modify allocations on behalf of the operator + // We do not use a modifier to avoid `stack too deep` errors + require(_checkCanCall(operator), InvalidCaller()); + + // Check that the operator exists and has configured an allocation delay + uint32 operatorAllocationDelay; + { + (bool isSet, uint32 delay) = getAllocationDelay(operator); + require(isSet, UninitializedAllocationDelay()); + operatorAllocationDelay = delay; + } + + for (uint256 i = 0; i < params.length; i++) { + require(params[i].strategies.length == params[i].newMagnitudes.length, InputArrayLengthMismatch()); + + // Check that the operator set exists and get the operator's registration status + // Operators do not need to be registered for an operator set in order to allocate + // slashable magnitude to the set. In fact, it is expected that operators will + // allocate magnitude before registering, as AVS's will likely only accept + // registrations from operators that are already slashable. + OperatorSet memory operatorSet = params[i].operatorSet; + require(_operatorSets[operatorSet.avs].contains(operatorSet.id), InvalidOperatorSet()); + + bool isRegistered = _isRegistered(operator, operatorSet); + + for (uint256 j = 0; j < params[i].strategies.length; j++) { + IStrategy strategy = params[i].strategies[j]; + + // 1. If the operator has any pending deallocations for this strategy, clear them + // to free up magnitude for allocation. Fetch the operator's up to date allocation + // info and ensure there is no remaining pending modification. + _clearDeallocationQueue(operator, strategy, type(uint16).max); + + (StrategyInfo memory info, Allocation memory allocation) = + _getUpdatedAllocation(operator, operatorSet.key(), strategy); + require(allocation.pendingDiff == 0, ModificationAlreadyPending()); + + // 2. Check whether the operator's allocation is slashable. If not, we allow instant + // deallocation. + bool isSlashable = _isAllocationSlashable(operatorSet, strategy, allocation, isRegistered); + + // 3. Calculate the change in magnitude + allocation.pendingDiff = _calcDelta(allocation.currentMagnitude, params[i].newMagnitudes[j]); + require(allocation.pendingDiff != 0, SameMagnitude()); + + // 4. Handle deallocation/allocation + if (allocation.pendingDiff < 0) { + if (isSlashable) { + // If the operator is slashable, deallocated magnitude will be freed after + // the deallocation delay. This magnitude remains slashable until then. + deallocationQueue[operator][strategy].pushBack(operatorSet.key()); + + allocation.effectBlock = uint32(block.number) + DEALLOCATION_DELAY; + } else { + // Deallocation immediately updates/frees magnitude if the operator is not slashable + info.encumberedMagnitude = _addInt128(info.encumberedMagnitude, allocation.pendingDiff); + + allocation.currentMagnitude = params[i].newMagnitudes[j]; + allocation.pendingDiff = 0; + allocation.effectBlock = uint32(block.number); + } + } else if (allocation.pendingDiff > 0) { + // Allocation immediately consumes available magnitude, but the additional + // magnitude does not become slashable until after the allocation delay + info.encumberedMagnitude = _addInt128(info.encumberedMagnitude, allocation.pendingDiff); + require(info.encumberedMagnitude <= info.maxMagnitude, InsufficientMagnitude()); + + allocation.effectBlock = uint32(block.number) + operatorAllocationDelay; + } + + // 5. Update state + _updateAllocationInfo(operator, operatorSet.key(), strategy, info, allocation); + + // 6. Emit an event for the updated allocation + emit AllocationUpdated( + operator, + OperatorSetLib.decode(operatorSet.key()), + strategy, + _addInt128(allocation.currentMagnitude, allocation.pendingDiff), + allocation.effectBlock + ); + } + } + } + + /// @inheritdoc IAllocationManager + function clearDeallocationQueue( + address operator, + IStrategy[] calldata strategies, + uint16[] calldata numToClear + ) external onlyWhenNotPaused(PAUSED_MODIFY_ALLOCATIONS) { + require(strategies.length == numToClear.length, InputArrayLengthMismatch()); + + for (uint256 i = 0; i < strategies.length; ++i) { + _clearDeallocationQueue({operator: operator, strategy: strategies[i], numToClear: numToClear[i]}); + } + } + + /// @inheritdoc IAllocationManager + function registerForOperatorSets( + address operator, + RegisterParams calldata params + ) external onlyWhenNotPaused(PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION) checkCanCall(operator) { + // Check that the operator exists + require(delegation.isOperator(operator), InvalidOperator()); + + for (uint256 i = 0; i < params.operatorSetIds.length; i++) { + // Check the operator set exists and the operator is not currently registered to it + OperatorSet memory operatorSet = OperatorSet(params.avs, params.operatorSetIds[i]); + require(_operatorSets[operatorSet.avs].contains(operatorSet.id), InvalidOperatorSet()); + require(!_isRegistered(operator, operatorSet), AlreadyMemberOfSet()); + + // Add operator to operator set + registeredSets[operator].add(operatorSet.key()); + _operatorSetMembers[operatorSet.key()].add(operator); + emit OperatorAddedToOperatorSet(operator, operatorSet); + + // Mark the operator registered + registrationStatus[operator][operatorSet.key()].registered = true; + } + + // Call the AVS to complete registration. If the AVS reverts, registration will fail. + getAVSRegistrar(params.avs).registerOperator(operator, params.operatorSetIds, params.data); + } + + /// @inheritdoc IAllocationManager + function deregisterFromOperatorSets( + DeregisterParams calldata params + ) external onlyWhenNotPaused(PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION) { + // Check that the caller is either authorized on behalf of the operator or AVS + require(_checkCanCall(params.operator) || _checkCanCall(params.avs), InvalidCaller()); + + for (uint256 i = 0; i < params.operatorSetIds.length; i++) { + // Check the operator set exists and the operator is registered to it + OperatorSet memory operatorSet = OperatorSet(params.avs, params.operatorSetIds[i]); + require(_operatorSets[params.avs].contains(operatorSet.id), InvalidOperatorSet()); + require(registrationStatus[params.operator][operatorSet.key()].registered, NotMemberOfSet()); + + // Remove operator from operator set + registeredSets[params.operator].remove(operatorSet.key()); + _operatorSetMembers[operatorSet.key()].remove(params.operator); + emit OperatorRemovedFromOperatorSet(params.operator, operatorSet); + + // Mark operator deregistered until the DEALLOCATION_DELAY passes + // forgefmt: disable-next-item + registrationStatus[params.operator][operatorSet.key()] = RegistrationStatus({ + registered: false, + registeredUntil: uint32(block.number) + DEALLOCATION_DELAY + }); + } + + // Call the AVS to complete deregistration. Even if the AVS reverts, the operator is + // considered deregistered + try getAVSRegistrar(params.avs).deregisterOperator(params.operator, params.operatorSetIds) {} catch {} + } + + /// @inheritdoc IAllocationManager + function setAllocationDelay(address operator, uint32 delay) external { + if (msg.sender != address(delegation)) { + require(_checkCanCall(operator), InvalidCaller()); + require(delegation.isOperator(operator), InvalidOperator()); + } + _setAllocationDelay(operator, delay); + } + + /// @inheritdoc IAllocationManager + function setAVSRegistrar(address avs, IAVSRegistrar registrar) external checkCanCall(avs) { + _avsRegistrar[avs] = registrar; + emit AVSRegistrarSet(avs, getAVSRegistrar(avs)); + } + + /// @inheritdoc IAllocationManager + function updateAVSMetadataURI(address avs, string calldata metadataURI) external checkCanCall(avs) { + emit AVSMetadataURIUpdated(avs, metadataURI); + } + + /// @inheritdoc IAllocationManager + function createOperatorSets(address avs, CreateSetParams[] calldata params) external checkCanCall(avs) { + for (uint256 i = 0; i < params.length; i++) { + OperatorSet memory operatorSet = OperatorSet(avs, params[i].operatorSetId); + + // Create the operator set, ensuring it does not already exist + require(_operatorSets[avs].add(operatorSet.id), InvalidOperatorSet()); + emit OperatorSetCreated(OperatorSet(avs, operatorSet.id)); + + // Add strategies to the operator set + bytes32 operatorSetKey = operatorSet.key(); + for (uint256 j = 0; j < params[i].strategies.length; j++) { + _operatorSetStrategies[operatorSetKey].add(address(params[i].strategies[j])); + emit StrategyAddedToOperatorSet(operatorSet, params[i].strategies[j]); + } + } + } + + /// @inheritdoc IAllocationManager + function addStrategiesToOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external checkCanCall(avs) { + OperatorSet memory operatorSet = OperatorSet(avs, operatorSetId); + require(_operatorSets[avs].contains(operatorSet.id), InvalidOperatorSet()); + + bytes32 operatorSetKey = operatorSet.key(); + for (uint256 i = 0; i < strategies.length; i++) { + require(_operatorSetStrategies[operatorSetKey].add(address(strategies[i])), StrategyAlreadyInOperatorSet()); + emit StrategyAddedToOperatorSet(operatorSet, strategies[i]); + } + } + + /// @inheritdoc IAllocationManager + function removeStrategiesFromOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external checkCanCall(avs) { + OperatorSet memory operatorSet = OperatorSet(avs, operatorSetId); + require(_operatorSets[avs].contains(operatorSet.id), InvalidOperatorSet()); + + bytes32 operatorSetKey = operatorSet.key(); + for (uint256 i = 0; i < strategies.length; i++) { + require(_operatorSetStrategies[operatorSetKey].remove(address(strategies[i])), StrategyNotInOperatorSet()); + emit StrategyRemovedFromOperatorSet(operatorSet, strategies[i]); + } + } + + /** + * + * INTERNAL FUNCTIONS + * + */ + + /** + * @dev Clear one or more pending deallocations to a strategy's allocated magnitude + * @param operator the operator whose pending deallocations will be cleared + * @param strategy the strategy to update + * @param numToClear the number of pending deallocations to clear + */ + function _clearDeallocationQueue(address operator, IStrategy strategy, uint16 numToClear) internal { + uint256 numCleared; + uint256 length = deallocationQueue[operator][strategy].length(); + + while (length > 0 && numCleared < numToClear) { + bytes32 operatorSetKey = deallocationQueue[operator][strategy].front(); + (StrategyInfo memory info, Allocation memory allocation) = + _getUpdatedAllocation(operator, operatorSetKey, strategy); + + // If we've reached a pending deallocation that isn't completable yet, + // we can stop. Any subsequent deallocation will also be uncompletable. + if (block.number < allocation.effectBlock) { + break; + } + + // Update state. This completes the deallocation, because `_getUpdatedAllocation` + // gave us strategy/allocation info as if the deallocation was already completed. + _updateAllocationInfo(operator, operatorSetKey, strategy, info, allocation); + + // Remove the deallocation from the queue + deallocationQueue[operator][strategy].popFront(); + ++numCleared; + --length; + } + } + + /** + * @dev Sets the operator's allocation delay. This is the number of blocks between an operator + * allocating magnitude to an operator set, and the magnitude becoming slashable. + * @param operator The operator to set the delay on behalf of. + * @param delay The allocation delay in blocks. + */ + function _setAllocationDelay(address operator, uint32 delay) internal { + AllocationDelayInfo memory info = _allocationDelayInfo[operator]; + + // If there is a pending delay that can be applied now, set it + if (info.effectBlock != 0 && block.number >= info.effectBlock) { + info.delay = info.pendingDelay; + info.isSet = true; + } + + info.pendingDelay = delay; + info.effectBlock = uint32(block.number) + ALLOCATION_CONFIGURATION_DELAY; + + _allocationDelayInfo[operator] = info; + emit AllocationDelaySet(operator, delay, info.effectBlock); + } + + function _isRegistered(address operator, OperatorSet memory operatorSet) internal view returns (bool) { + RegistrationStatus memory status = registrationStatus[operator][operatorSet.key()]; + + return status.registered || block.number < status.registeredUntil; + } + + function _isAllocationSlashable( + OperatorSet memory operatorSet, + IStrategy strategy, + Allocation memory allocation, + bool isRegistered + ) internal view returns (bool) { + // If the operator set does not use this strategy, any allocation from it is not slashable + if (!_operatorSetStrategies[operatorSet.key()].contains(address(strategy))) { + return false; + } + + // If the operator is not registered to the operator set, any allocation is not slashable + if (!isRegistered) { + return false; + } + + // The allocation is not slashable if there is nothing allocated + if (allocation.currentMagnitude == 0) { + return false; + } + + return true; + } + + /** + * @dev For an operator set, get the operator's effective allocated magnitude. + * If the operator set has a pending deallocation that can be completed at the + * current block number, this method returns a view of the allocation as if the deallocation + * was completed. + * @return info the effective allocated and pending magnitude for the operator set, and + * the effective encumbered magnitude for all operator sets belonging to this strategy + */ + function _getUpdatedAllocation( + address operator, + bytes32 operatorSetKey, + IStrategy strategy + ) internal view returns (StrategyInfo memory, Allocation memory) { + StrategyInfo memory info = StrategyInfo({ + maxMagnitude: _maxMagnitudeHistory[operator][strategy].latest(), + encumberedMagnitude: encumberedMagnitude[operator][strategy] + }); + + Allocation memory allocation = allocations[operator][operatorSetKey][strategy]; + + // If the pending change can't be completed yet, return as-is + if (block.number < allocation.effectBlock) { + return (info, allocation); + } + + // Otherwise, complete the pending change and return updated info + allocation.currentMagnitude = _addInt128(allocation.currentMagnitude, allocation.pendingDiff); + + // If the completed change was a deallocation, update used magnitude + if (allocation.pendingDiff < 0) { + info.encumberedMagnitude = _addInt128(info.encumberedMagnitude, allocation.pendingDiff); + } + + allocation.effectBlock = 0; + allocation.pendingDiff = 0; + + return (info, allocation); + } + + function _updateAllocationInfo( + address operator, + bytes32 operatorSetKey, + IStrategy strategy, + StrategyInfo memory info, + Allocation memory allocation + ) internal { + // Update encumbered magnitude if it has changed + // The mapping should NOT be updated when there is a deallocation on a delay + if (encumberedMagnitude[operator][strategy] != info.encumberedMagnitude) { + encumberedMagnitude[operator][strategy] = info.encumberedMagnitude; + emit EncumberedMagnitudeUpdated(operator, strategy, info.encumberedMagnitude); + } + + // Update allocation for this operator set from the strategy + // We emit an `AllocationUpdated` from the `modifyAllocations` and `slashOperator` functions. + // `clearDeallocationQueue` does not emit an `AllocationUpdated` event since it was + // emitted when the deallocation was queued + allocations[operator][operatorSetKey][strategy] = allocation; + + // Note: these no-op if the sets already contain the added values (or do not contain removed ones) + if (allocation.pendingDiff != 0) { + // If we have a pending modification, ensure the allocation is in the operator's + // list of enumerable strategies/sets. + allocatedStrategies[operator][operatorSetKey].add(address(strategy)); + allocatedSets[operator].add(operatorSetKey); + } else if (allocation.currentMagnitude == 0) { + // If we do NOT have a pending modification, and no existing magnitude, remove the + // allocation from the operator's lists. + allocatedStrategies[operator][operatorSetKey].remove(address(strategy)); + + if (allocatedStrategies[operator][operatorSetKey].length() == 0) { + allocatedSets[operator].remove(operatorSetKey); + } + } + } + + function _updateMaxMagnitude(address operator, IStrategy strategy, uint64 newMaxMagnitude) internal { + _maxMagnitudeHistory[operator][strategy].push({key: uint32(block.number), value: newMaxMagnitude}); + emit MaxMagnitudeUpdated(operator, strategy, newMaxMagnitude); + } + + function _calcDelta(uint64 currentMagnitude, uint64 newMagnitude) internal pure returns (int128) { + return int128(uint128(newMagnitude)) - int128(uint128(currentMagnitude)); + } + + function _addInt128(uint64 a, int128 b) internal pure returns (uint64) { + return uint64(uint128(int128(uint128(a)) + b)); + } + + /** + * + * VIEW FUNCTIONS + * + */ + + /// @inheritdoc IAllocationManager + function getOperatorSetCount( + address avs + ) external view returns (uint256) { + return _operatorSets[avs].length(); + } + + /// @inheritdoc IAllocationManager + function getAllocatedSets( + address operator + ) external view returns (OperatorSet[] memory) { + uint256 length = allocatedSets[operator].length(); + + OperatorSet[] memory operatorSets = new OperatorSet[](length); + for (uint256 i = 0; i < length; i++) { + operatorSets[i] = OperatorSetLib.decode(allocatedSets[operator].at(i)); + } + + return operatorSets; + } + + /// @inheritdoc IAllocationManager + function getAllocatedStrategies( + address operator, + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory) { + address[] memory values = allocatedStrategies[operator][operatorSet.key()].values(); + IStrategy[] memory strategies; + + assembly { + strategies := values + } + + return strategies; + } + + /// @inheritdoc IAllocationManager + function getAllocation( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy + ) public view returns (Allocation memory) { + (, Allocation memory allocation) = _getUpdatedAllocation(operator, operatorSet.key(), strategy); + + return allocation; + } + + /// @inheritdoc IAllocationManager + function getAllocations( + address[] memory operators, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view returns (Allocation[] memory) { + Allocation[] memory _allocations = new Allocation[](operators.length); + + for (uint256 i = 0; i < operators.length; i++) { + _allocations[i] = getAllocation(operators[i], operatorSet, strategy); + } + + return _allocations; + } + + /// @inheritdoc IAllocationManager + function getStrategyAllocations( + address operator, + IStrategy strategy + ) external view returns (OperatorSet[] memory, Allocation[] memory) { + uint256 length = allocatedSets[operator].length(); + + OperatorSet[] memory operatorSets = new OperatorSet[](length); + Allocation[] memory _allocations = new Allocation[](length); + + for (uint256 i = 0; i < length; i++) { + OperatorSet memory operatorSet = OperatorSetLib.decode(allocatedSets[operator].at(i)); + + operatorSets[i] = operatorSet; + _allocations[i] = getAllocation(operator, operatorSet, strategy); + } + + return (operatorSets, _allocations); + } + + /// @inheritdoc IAllocationManager + function getAllocatableMagnitude(address operator, IStrategy strategy) external view returns (uint64) { + // This method needs to simulate clearing any pending deallocations. + // This roughly mimics the calculations done in `_clearDeallocationQueue` and + // `_getUpdatedAllocation`, while operating on a `curEncumberedMagnitude` + // rather than continually reading/updating state. + uint64 curEncumberedMagnitude = encumberedMagnitude[operator][strategy]; + + uint256 length = deallocationQueue[operator][strategy].length(); + for (uint256 i = 0; i < length; ++i) { + bytes32 operatorSetKey = deallocationQueue[operator][strategy].at(i); + Allocation memory allocation = allocations[operator][operatorSetKey][strategy]; + + // If we've reached a pending deallocation that isn't completable yet, + // we can stop. Any subsequent modifications will also be uncompletable. + if (block.number < allocation.effectBlock) { + break; + } + + // The diff is a deallocation. Add to encumbered magnitude. Note that this is a deallocation + // queue and allocations aren't considered because encumbered magnitude + // is updated as soon as the allocation is created. + curEncumberedMagnitude = _addInt128(curEncumberedMagnitude, allocation.pendingDiff); + } + + // The difference between the operator's max magnitude and its encumbered magnitude + // is the magnitude that can be allocated. + return _maxMagnitudeHistory[operator][strategy].latest() - curEncumberedMagnitude; + } + + /// @inheritdoc IAllocationManager + function getMaxMagnitude(address operator, IStrategy strategy) public view returns (uint64) { + return _maxMagnitudeHistory[operator][strategy].latest(); + } + + /// @inheritdoc IAllocationManager + function getMaxMagnitudes( + address operator, + IStrategy[] memory strategies + ) external view returns (uint64[] memory) { + uint64[] memory maxMagnitudes = new uint64[](strategies.length); + + for (uint256 i = 0; i < strategies.length; ++i) { + maxMagnitudes[i] = getMaxMagnitude(operator, strategies[i]); + } + + return maxMagnitudes; + } + + /// @inheritdoc IAllocationManager + function getMaxMagnitudes(address[] memory operators, IStrategy strategy) external view returns (uint64[] memory) { + uint64[] memory maxMagnitudes = new uint64[](operators.length); + + for (uint256 i = 0; i < operators.length; ++i) { + maxMagnitudes[i] = getMaxMagnitude(operators[i], strategy); + } + + return maxMagnitudes; + } + + /// @inheritdoc IAllocationManager + function getMaxMagnitudesAtBlock( + address operator, + IStrategy[] memory strategies, + uint32 blockNumber + ) external view returns (uint64[] memory) { + uint64[] memory maxMagnitudes = new uint64[](strategies.length); + + for (uint256 i = 0; i < strategies.length; ++i) { + maxMagnitudes[i] = _maxMagnitudeHistory[operator][strategies[i]].upperLookup({key: blockNumber}); + } + + return maxMagnitudes; + } + + /// @inheritdoc IAllocationManager + function getAllocationDelay( + address operator + ) public view returns (bool, uint32) { + AllocationDelayInfo memory info = _allocationDelayInfo[operator]; + + uint32 delay = info.delay; + bool isSet = info.isSet; + + // If there is a pending delay that can be applied, apply it + if (info.effectBlock != 0 && block.number >= info.effectBlock) { + delay = info.pendingDelay; + isSet = true; + } + + return (isSet, delay); + } + + /// @inheritdoc IAllocationManager + function getRegisteredSets( + address operator + ) public view returns (OperatorSet[] memory) { + uint256 length = registeredSets[operator].length(); + OperatorSet[] memory operatorSets = new OperatorSet[](length); + + for (uint256 i = 0; i < length; ++i) { + operatorSets[i] = OperatorSetLib.decode(registeredSets[operator].at(i)); + } + + return operatorSets; + } + + /// @inheritdoc IAllocationManager + function isOperatorSet( + OperatorSet memory operatorSet + ) external view returns (bool) { + return _operatorSets[operatorSet.avs].contains(operatorSet.id); + } + + /// @inheritdoc IAllocationManager + function getMembers( + OperatorSet memory operatorSet + ) external view returns (address[] memory) { + return _operatorSetMembers[operatorSet.key()].values(); + } + + /// @inheritdoc IAllocationManager + function getMemberCount( + OperatorSet memory operatorSet + ) external view returns (uint256) { + return _operatorSetMembers[operatorSet.key()].length(); + } + + /// @inheritdoc IAllocationManager + function getAVSRegistrar( + address avs + ) public view returns (IAVSRegistrar) { + IAVSRegistrar registrar = _avsRegistrar[avs]; + + return address(registrar) == address(0) ? IAVSRegistrar(avs) : registrar; + } + + /// @inheritdoc IAllocationManager + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory) { + address[] memory values = _operatorSetStrategies[operatorSet.key()].values(); + IStrategy[] memory strategies; + + assembly { + strategies := values + } + + return strategies; + } + + /// @inheritdoc IAllocationManager + function getMinimumSlashableStake( + OperatorSet memory operatorSet, + address[] memory operators, + IStrategy[] memory strategies, + uint32 futureBlock + ) external view returns (uint256[][] memory slashableStake) { + slashableStake = new uint256[][](operators.length); + uint256[][] memory delegatedStake = delegation.getOperatorsShares(operators, strategies); + + for (uint256 i = 0; i < operators.length; i++) { + address operator = operators[i]; + slashableStake[i] = new uint256[](strategies.length); + + for (uint256 j = 0; j < strategies.length; j++) { + IStrategy strategy = strategies[j]; + + // Fetch the max magnitude and allocation for the operator/strategy. + // Prevent division by 0 if needed. This mirrors the "FullySlashed" checks + // in the DelegationManager + uint64 maxMagnitude = _maxMagnitudeHistory[operator][strategy].latest(); + if (maxMagnitude == 0) { + continue; + } + + Allocation memory alloc = getAllocation(operator, operatorSet, strategy); + + // If the pending change takes effect before `futureBlock`, include it in `currentMagnitude` + // However, ONLY include the pending change if it is a deallocation, since this method + // is supposed to return the minimum slashable stake between now and `futureBlock` + if (alloc.effectBlock <= futureBlock && alloc.pendingDiff < 0) { + alloc.currentMagnitude = _addInt128(alloc.currentMagnitude, alloc.pendingDiff); + } + + uint256 slashableProportion = uint256(alloc.currentMagnitude).divWad(maxMagnitude); + slashableStake[i][j] = delegatedStake[i][j].mulWad(slashableProportion); + } + } + } +} diff --git a/src/contracts/core/AllocationManagerStorage.sol b/src/contracts/core/AllocationManagerStorage.sol new file mode 100644 index 000000000..9f6ce79fa --- /dev/null +++ b/src/contracts/core/AllocationManagerStorage.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import "@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol"; + +import "../interfaces/IAllocationManager.sol"; +import "../interfaces/IDelegationManager.sol"; + +import {Snapshots} from "../libraries/Snapshots.sol"; + +abstract contract AllocationManagerStorage is IAllocationManager { + using Snapshots for Snapshots.DefaultWadHistory; + + // Constants + + /// @dev Index for flag that pauses operator allocations/deallocations when set. + uint8 internal constant PAUSED_MODIFY_ALLOCATIONS = 0; + + /// @dev Index for flag that pauses operator register/deregister to operator sets when set. + uint8 internal constant PAUSED_OPERATOR_SLASHING = 1; + + /// @dev Index for flag that pauses operator register/deregister to operator sets when set. + uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 2; + + // Immutables + + /// @notice The DelegationManager contract for EigenLayer + IDelegationManager public immutable delegation; + + /// @notice Delay before deallocations are clearable and can be added back into freeMagnitude + /// In this window, deallocations still remain slashable by the operatorSet they were allocated to. + uint32 public immutable DEALLOCATION_DELAY; + + /// @notice Delay before alloaction delay modifications take effect. + uint32 public immutable ALLOCATION_CONFIGURATION_DELAY; + + // Mutatables + + /// AVS => OPERATOR SET + + /// @dev Contains the AVS's configured registrar contract that handles registration/deregistration + /// Note: if set to 0, defaults to the AVS's address + mapping(address avs => IAVSRegistrar) internal _avsRegistrar; + + /// @dev Lists the operator sets an AVS has created + mapping(address avs => EnumerableSet.UintSet) internal _operatorSets; + + /// @dev Lists the strategies an AVS supports for an operator set + mapping(bytes32 operatorSetKey => EnumerableSet.AddressSet) internal _operatorSetStrategies; + + /// @dev Lists the members of an AVS's operator set + mapping(bytes32 operatorSetKey => EnumerableSet.AddressSet) internal _operatorSetMembers; + + /// OPERATOR => OPERATOR SET (REGISTRATION/DEREGISTRATION) + + /// @notice Returns the allocation delay info for each `operator`; the delay and whether or not it's previously been set. + mapping(address operator => AllocationDelayInfo) internal _allocationDelayInfo; + + /// @dev Lists the operator sets the operator is registered for. Note that an operator + /// can be registered without allocated stake. Likewise, an operator can allocate + /// without being registered. + mapping(address operator => EnumerableSet.Bytes32Set) internal registeredSets; + + /// @dev Lists the operator sets the operator has outstanding allocations in. + mapping(address operator => EnumerableSet.Bytes32Set) internal allocatedSets; + + /// @dev Contains the operator's registration status for an operator set. + mapping(address operator => mapping(bytes32 operatorSetKey => RegistrationStatus)) internal registrationStatus; + + /// @dev For an operator set, lists all strategies an operator has outstanding allocations from. + mapping(address operator => mapping(bytes32 operatorSetKey => EnumerableSet.AddressSet)) internal + allocatedStrategies; + + /// @dev For an operator set and strategy, the current allocated magnitude and any pending modification + mapping(address operator => mapping(bytes32 operatorSetKey => mapping(IStrategy strategy => Allocation))) internal + allocations; + + /// OPERATOR => STRATEGY (MAX/USED AND DEALLOCATIONS) + + /// @dev Contains a history of the operator's maximum magnitude for a given strategy + mapping(address operator => mapping(IStrategy strategy => Snapshots.DefaultWadHistory)) internal + _maxMagnitudeHistory; + + /// @dev For a strategy, contains the amount of magnitude an operator has allocated to operator sets + /// @dev This value should be read with caution, as deallocations that are completable but not + /// popped off the queue are still included in the encumbered magnitude + mapping(address operator => mapping(IStrategy strategy => uint64)) public encumberedMagnitude; + + /// @dev For a strategy, keeps an ordered queue of operator sets that have pending deallocations + /// These must be completed in order to free up magnitude for future allocation + mapping(address operator => mapping(IStrategy strategy => DoubleEndedQueue.Bytes32Deque)) internal deallocationQueue; + + // Construction + + constructor(IDelegationManager _delegation, uint32 _DEALLOCATION_DELAY, uint32 _ALLOCATION_CONFIGURATION_DELAY) { + delegation = _delegation; + DEALLOCATION_DELAY = _DEALLOCATION_DELAY; + ALLOCATION_CONFIGURATION_DELAY = _ALLOCATION_CONFIGURATION_DELAY; + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[37] private __gap; +} diff --git a/src/contracts/core/DelegationManager.sol b/src/contracts/core/DelegationManager.sol index cdf71f070..27e2036d9 100644 --- a/src/contracts/core/DelegationManager.sol +++ b/src/contracts/core/DelegationManager.sol @@ -1,11 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; + +import "../mixins/SignatureUtils.sol"; +import "../mixins/PermissionControllerMixin.sol"; import "../permissions/Pausable.sol"; -import "../libraries/EIP1271SignatureUtils.sol"; +import "../libraries/SlashingLib.sol"; +import "../libraries/Snapshots.sol"; import "./DelegationManagerStorage.sol"; /** @@ -23,35 +27,33 @@ contract DelegationManager is OwnableUpgradeable, Pausable, DelegationManagerStorage, - ReentrancyGuardUpgradeable + ReentrancyGuardUpgradeable, + SignatureUtils, + PermissionControllerMixin { - // @dev Index for flag that pauses new delegations when set - uint8 internal constant PAUSED_NEW_DELEGATION = 0; - - // @dev Index for flag that pauses queuing new withdrawals when set. - uint8 internal constant PAUSED_ENTER_WITHDRAWAL_QUEUE = 1; - - // @dev Index for flag that pauses completing existing withdrawals when set. - uint8 internal constant PAUSED_EXIT_WITHDRAWAL_QUEUE = 2; - - // @dev Chain ID at the time of contract deployment - uint256 internal immutable ORIGINAL_CHAIN_ID; - - // @dev Maximum Value for `stakerOptOutWindowBlocks`. Approximately equivalent to 6 months in blocks. - uint256 public constant MAX_STAKER_OPT_OUT_WINDOW_BLOCKS = (180 days) / 12; - - /// @notice Canonical, virtual beacon chain ETH strategy - IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + using SlashingLib for *; + using Snapshots for Snapshots.DefaultZeroHistory; + using EnumerableSet for EnumerableSet.Bytes32Set; // @notice Simple permission for functions that are only callable by the StrategyManager contract OR by the EigenPodManagerContract modifier onlyStrategyManagerOrEigenPodManager() { require( - msg.sender == address(strategyManager) || msg.sender == address(eigenPodManager), - "DelegationManager: onlyStrategyManagerOrEigenPodManager" + (msg.sender == address(strategyManager) || msg.sender == address(eigenPodManager)), + OnlyStrategyManagerOrEigenPodManager() ); _; } + modifier onlyEigenPodManager() { + require(msg.sender == address(eigenPodManager), OnlyEigenPodManager()); + _; + } + + modifier onlyAllocationManager() { + require(msg.sender == address(allocationManager), OnlyAllocationManager()); + _; + } + /** * * INITIALIZING FUNCTIONS @@ -59,34 +61,33 @@ contract DelegationManager is */ /** - * @dev Initializes the immutable addresses of the strategy mananger and slasher. + * @dev Initializes the immutable addresses of the strategy mananger, eigenpod manager, and allocation manager. */ constructor( + IAVSDirectory _avsDirectory, IStrategyManager _strategyManager, - ISlasher _slasher, - IEigenPodManager _eigenPodManager - ) DelegationManagerStorage(_strategyManager, _slasher, _eigenPodManager) { + IEigenPodManager _eigenPodManager, + IAllocationManager _allocationManager, + IPauserRegistry _pauserRegistry, + IPermissionController _permissionController, + uint32 _MIN_WITHDRAWAL_DELAY + ) + DelegationManagerStorage( + _avsDirectory, + _strategyManager, + _eigenPodManager, + _allocationManager, + _MIN_WITHDRAWAL_DELAY + ) + Pausable(_pauserRegistry) + PermissionControllerMixin(_permissionController) + { _disableInitializers(); - ORIGINAL_CHAIN_ID = block.chainid; } - /** - * @dev Initializes the addresses of the initial owner, pauser registry, and paused status. - * minWithdrawalDelayBlocks is set only once here - */ - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 initialPausedStatus, - uint256 _minWithdrawalDelayBlocks, - IStrategy[] calldata _strategies, - uint256[] calldata _withdrawalDelayBlocks - ) external initializer { - _initializePauser(_pauserRegistry, initialPausedStatus); - _DOMAIN_SEPARATOR = _calculateDomainSeparator(); + function initialize(address initialOwner, uint256 initialPausedStatus) external initializer { + _setPausedStatus(initialPausedStatus); _transferOwnership(initialOwner); - _setMinWithdrawalDelayBlocks(_minWithdrawalDelayBlocks); - _setStrategyWithdrawalDelayBlocks(_strategies, _withdrawalDelayBlocks); } /** @@ -97,29 +98,32 @@ contract DelegationManager is /// @inheritdoc IDelegationManager function registerAsOperator( - OperatorDetails calldata registeringOperatorDetails, + address initDelegationApprover, + uint32 allocationDelay, string calldata metadataURI ) external { - require(!isDelegated(msg.sender), "DelegationManager.registerAsOperator: caller is already actively delegated"); - _setOperatorDetails(msg.sender, registeringOperatorDetails); - SignatureWithExpiry memory emptySignatureAndExpiry; + require(!isDelegated(msg.sender), ActivelyDelegated()); + + allocationManager.setAllocationDelay(msg.sender, allocationDelay); + _setDelegationApprover(msg.sender, initDelegationApprover); + // delegate from the operator to themselves - _delegate(msg.sender, msg.sender, emptySignatureAndExpiry, bytes32(0)); - // emit events - emit OperatorRegistered(msg.sender, registeringOperatorDetails); + _delegate(msg.sender, msg.sender); + + emit OperatorRegistered(msg.sender, initDelegationApprover); emit OperatorMetadataURIUpdated(msg.sender, metadataURI); } /// @inheritdoc IDelegationManager - function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external { - require(isOperator(msg.sender), "DelegationManager.modifyOperatorDetails: caller must be an operator"); - _setOperatorDetails(msg.sender, newOperatorDetails); + function modifyOperatorDetails(address operator, address newDelegationApprover) external checkCanCall(operator) { + require(isOperator(operator), OperatorNotRegistered()); + _setDelegationApprover(operator, newDelegationApprover); } /// @inheritdoc IDelegationManager - function updateOperatorMetadataURI(string calldata metadataURI) external { - require(isOperator(msg.sender), "DelegationManager.updateOperatorMetadataURI: caller must be an operator"); - emit OperatorMetadataURIUpdated(msg.sender, metadataURI); + function updateOperatorMetadataURI(address operator, string calldata metadataURI) external checkCanCall(operator) { + require(isOperator(operator), OperatorNotRegistered()); + emit OperatorMetadataURIUpdated(operator, metadataURI); } /// @inheritdoc IDelegationManager @@ -128,128 +132,113 @@ contract DelegationManager is SignatureWithExpiry memory approverSignatureAndExpiry, bytes32 approverSalt ) external { - require(!isDelegated(msg.sender), "DelegationManager.delegateTo: staker is already actively delegated"); - require(isOperator(operator), "DelegationManager.delegateTo: operator is not registered in EigenLayer"); - // go through the internal delegation flow, checking the `approverSignatureAndExpiry` if applicable - _delegate(msg.sender, operator, approverSignatureAndExpiry, approverSalt); - } + require(!isDelegated(msg.sender), ActivelyDelegated()); + require(isOperator(operator), OperatorNotRegistered()); - /// @inheritdoc IDelegationManager - function delegateToBySignature( - address staker, - address operator, - SignatureWithExpiry memory stakerSignatureAndExpiry, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external { - // check the signature expiry - require( - stakerSignatureAndExpiry.expiry >= block.timestamp, - "DelegationManager.delegateToBySignature: staker signature expired" - ); - require(!isDelegated(staker), "DelegationManager.delegateToBySignature: staker is already actively delegated"); - require( - isOperator(operator), "DelegationManager.delegateToBySignature: operator is not registered in EigenLayer" - ); + // Checking the `approverSignatureAndExpiry` if applicable + address approver = _operatorDetails[operator].delegationApprover; + if (approver != address(0)) { + // check that the salt hasn't been used previously, then mark the salt as spent + require(!delegationApproverSaltIsSpent[approver][approverSalt], SaltSpent()); + // actually check that the signature is valid + _checkIsValidSignatureNow({ + signer: approver, + signableDigest: calculateDelegationApprovalDigestHash( + msg.sender, operator, approver, approverSalt, approverSignatureAndExpiry.expiry + ), + signature: approverSignatureAndExpiry.signature, + expiry: approverSignatureAndExpiry.expiry + }); - // calculate the digest hash, then increment `staker`'s nonce - uint256 currentStakerNonce = stakerNonce[staker]; - bytes32 stakerDigestHash = - calculateStakerDelegationDigestHash(staker, currentStakerNonce, operator, stakerSignatureAndExpiry.expiry); - unchecked { - stakerNonce[staker] = currentStakerNonce + 1; + delegationApproverSaltIsSpent[approver][approverSalt] = true; } - // actually check that the signature is valid - EIP1271SignatureUtils.checkSignature_EIP1271(staker, stakerDigestHash, stakerSignatureAndExpiry.signature); - - // go through the internal delegation flow, checking the `approverSignatureAndExpiry` if applicable - _delegate(staker, operator, approverSignatureAndExpiry, approverSalt); + // Delegate msg.sender to the operator + _delegate(msg.sender, operator); } /// @inheritdoc IDelegationManager - function undelegate(address staker) - external - onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) - returns (bytes32[] memory withdrawalRoots) - { - require(isDelegated(staker), "DelegationManager.undelegate: staker must be delegated to undelegate"); - require(!isOperator(staker), "DelegationManager.undelegate: operators cannot be undelegated"); - require(staker != address(0), "DelegationManager.undelegate: cannot undelegate zero address"); + function undelegate( + address staker + ) external onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) returns (bytes32[] memory withdrawalRoots) { + require(isDelegated(staker), NotActivelyDelegated()); + require(!isOperator(staker), OperatorsCannotUndelegate()); + require(staker != address(0), InputAddressZero()); address operator = delegatedTo[staker]; require( - msg.sender == staker || msg.sender == operator + msg.sender == staker || _checkCanCall(operator) || msg.sender == _operatorDetails[operator].delegationApprover, - "DelegationManager.undelegate: caller cannot undelegate staker" + CallerCannotUndelegate() ); - // Gather strategies and shares to remove from staker/operator during undelegation + // Gather strategies and shares from the staker. Calculate depositedShares to remove from operator during undelegation // Undelegation removes ALL currently-active strategies and shares - (IStrategy[] memory strategies, uint256[] memory shares) = getDelegatableShares(staker); + (IStrategy[] memory strategies, uint256[] memory depositedShares) = getDepositedShares(staker); - // emit an event if this action was not initiated by the staker themselves + // Undelegate the staker + delegatedTo[staker] = address(0); + emit StakerUndelegated(staker, operator); + // Emit an event if this action was not initiated by the staker themselves if (msg.sender != staker) { emit StakerForceUndelegated(staker, operator); } - // undelegate the staker - emit StakerUndelegated(staker, operator); - delegatedTo[staker] = address(0); - - // if no delegatable shares, return an empty array, and don't queue a withdrawal + // if no deposited shares, return an empty array, and don't queue a withdrawal if (strategies.length == 0) { - withdrawalRoots = new bytes32[](0); - } else { - withdrawalRoots = new bytes32[](strategies.length); - for (uint256 i = 0; i < strategies.length; i++) { - IStrategy[] memory singleStrategy = new IStrategy[](1); - uint256[] memory singleShare = new uint256[](1); - singleStrategy[0] = strategies[i]; - singleShare[0] = shares[i]; - - withdrawalRoots[i] = _removeSharesAndQueueWithdrawal({ - staker: staker, - operator: operator, - withdrawer: staker, - strategies: singleStrategy, - shares: singleShare - }); - } + return withdrawalRoots; + } + + withdrawalRoots = new bytes32[](strategies.length); + uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies); + + for (uint256 i = 0; i < strategies.length; i++) { + IStrategy[] memory singleStrategy = new IStrategy[](1); + uint256[] memory singleDepositShares = new uint256[](1); + uint256[] memory singleSlashingFactor = new uint256[](1); + singleStrategy[0] = strategies[i]; + singleDepositShares[0] = depositedShares[i]; + singleSlashingFactor[0] = slashingFactors[i]; + + // Remove shares from staker's strategies and place strategies/shares in queue. + // The operator's delegated shares are also reduced. + withdrawalRoots[i] = _removeSharesAndQueueWithdrawal({ + staker: staker, + operator: operator, + strategies: singleStrategy, + depositSharesToWithdraw: singleDepositShares, + slashingFactors: singleSlashingFactor + }); } return withdrawalRoots; } /// @inheritdoc IDelegationManager - function queueWithdrawals(QueuedWithdrawalParams[] calldata queuedWithdrawalParams) - external - onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) - returns (bytes32[] memory) - { - bytes32[] memory withdrawalRoots = new bytes32[](queuedWithdrawalParams.length); + function queueWithdrawals( + QueuedWithdrawalParams[] calldata params + ) external onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) returns (bytes32[] memory) { + bytes32[] memory withdrawalRoots = new bytes32[](params.length); address operator = delegatedTo[msg.sender]; - for (uint256 i = 0; i < queuedWithdrawalParams.length; i++) { - require( - queuedWithdrawalParams[i].strategies.length == queuedWithdrawalParams[i].shares.length, - "DelegationManager.queueWithdrawal: input length mismatch" - ); - require( - queuedWithdrawalParams[i].withdrawer == msg.sender, - "DelegationManager.queueWithdrawal: withdrawer must be staker" - ); + for (uint256 i = 0; i < params.length; i++) { + require(params[i].strategies.length == params[i].depositShares.length, InputArrayLengthMismatch()); + require(params[i].withdrawer == msg.sender, WithdrawerNotStaker()); + + uint256[] memory slashingFactors = _getSlashingFactors(msg.sender, operator, params[i].strategies); // Remove shares from staker's strategies and place strategies/shares in queue. // If the staker is delegated to an operator, the operator's delegated shares are also reduced - // NOTE: This will fail if the staker doesn't have the shares implied by the input parameters + // NOTE: This will fail if the staker doesn't have the shares implied by the input parameters. + // The view function getWithdrawableShares() can be used to check what shares are available for withdrawal. withdrawalRoots[i] = _removeSharesAndQueueWithdrawal({ staker: msg.sender, operator: operator, - withdrawer: queuedWithdrawalParams[i].withdrawer, - strategies: queuedWithdrawalParams[i].strategies, - shares: queuedWithdrawalParams[i].shares + strategies: params[i].strategies, + depositSharesToWithdraw: params[i].depositShares, + slashingFactors: slashingFactors }); } + return withdrawalRoots; } @@ -257,71 +246,136 @@ contract DelegationManager is function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, - uint256 middlewareTimesIndex, bool receiveAsTokens ) external onlyWhenNotPaused(PAUSED_EXIT_WITHDRAWAL_QUEUE) nonReentrant { - _completeQueuedWithdrawal(withdrawal, tokens, middlewareTimesIndex, receiveAsTokens); + _completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); } /// @inheritdoc IDelegationManager function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, bool[] calldata receiveAsTokens ) external onlyWhenNotPaused(PAUSED_EXIT_WITHDRAWAL_QUEUE) nonReentrant { - for (uint256 i = 0; i < withdrawals.length; ++i) { - _completeQueuedWithdrawal(withdrawals[i], tokens[i], middlewareTimesIndexes[i], receiveAsTokens[i]); + uint256 n = withdrawals.length; + for (uint256 i; i < n; ++i) { + _completeQueuedWithdrawal(withdrawals[i], tokens[i], receiveAsTokens[i]); } } /// @inheritdoc IDelegationManager - function increaseDelegatedShares( - address staker, - IStrategy strategy, - uint256 shares - ) external onlyStrategyManagerOrEigenPodManager { - // if the staker is delegated to an operator - if (isDelegated(staker)) { - address operator = delegatedTo[staker]; + function completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) external onlyWhenNotPaused(PAUSED_EXIT_WITHDRAWAL_QUEUE) nonReentrant { + EnumerableSet.Bytes32Set storage withdrawalRoots = _stakerQueuedWithdrawalRoots[msg.sender]; + uint256 length = withdrawalRoots.length(); + numToComplete = numToComplete > length ? length : numToComplete; + + // Read withdrawals to complete. We use 2 seperate loops here because the second + // loop will remove elements by index from `withdrawalRoots`. + Withdrawal[] memory withdrawals = new Withdrawal[](numToComplete); + for (uint256 i; i < withdrawals.length; ++i) { + withdrawals[i] = queuedWithdrawals[withdrawalRoots.at(i)]; + } - // add strategy shares to delegate's shares - _increaseOperatorShares({operator: operator, staker: staker, strategy: strategy, shares: shares}); + for (uint256 i; i < withdrawals.length; ++i) { + _completeQueuedWithdrawal(withdrawals[i], tokens[i], receiveAsTokens[i]); } } /// @inheritdoc IDelegationManager - function decreaseDelegatedShares( + function increaseDelegatedShares( address staker, IStrategy strategy, - uint256 shares + uint256 prevDepositShares, + uint256 addedShares ) external onlyStrategyManagerOrEigenPodManager { - // if the staker is delegated to an operator - if (isDelegated(staker)) { - address operator = delegatedTo[staker]; + address operator = delegatedTo[staker]; + uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, strategy); + uint256 slashingFactor = _getSlashingFactor(staker, strategy, maxMagnitude); - // forgefmt: disable-next-item - // subtract strategy shares from delegate's shares - _decreaseOperatorShares({ - operator: operator, - staker: staker, - strategy: strategy, - shares: shares - }); - } + // Increase the staker's deposit scaling factor and delegate shares to the operator + _increaseDelegation({ + operator: operator, + staker: staker, + strategy: strategy, + prevDepositShares: prevDepositShares, + addedShares: addedShares, + slashingFactor: slashingFactor + }); } /// @inheritdoc IDelegationManager - function setMinWithdrawalDelayBlocks(uint256 newMinWithdrawalDelayBlocks) external onlyOwner { - _setMinWithdrawalDelayBlocks(newMinWithdrawalDelayBlocks); + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 prevBeaconChainSlashingFactor, + uint256 wadSlashed + ) external onlyEigenPodManager { + if (!isDelegated(staker)) { + return; + } + + address operator = delegatedTo[staker]; + + // Calculate the previous slashing factor. This mirrors the calculation done + // in _getSlashingFactor + uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, beaconChainETHStrategy); + uint256 prevSlashingFactor = maxMagnitude.mulWad(prevBeaconChainSlashingFactor); + + // Calculate the shares to remove from the operator by calculating the previously-withdrawable + // shares and applying slashing + DepositScalingFactor memory dsf = _depositScalingFactor[staker][beaconChainETHStrategy]; + uint256 sharesToRemove = dsf.calcWithdrawable({ + depositShares: curDepositShares, + slashingFactor: prevSlashingFactor + }).mulWad(wadSlashed); + + // Decrease the operator's shares + _decreaseDelegation({ + operator: operator, + staker: staker, + strategy: beaconChainETHStrategy, + sharesToDecrease: sharesToRemove + }); } /// @inheritdoc IDelegationManager - function setStrategyWithdrawalDelayBlocks( - IStrategy[] calldata strategies, - uint256[] calldata withdrawalDelayBlocks - ) external onlyOwner { - _setStrategyWithdrawalDelayBlocks(strategies, withdrawalDelayBlocks); + function burnOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external onlyAllocationManager { + /// forgefmt: disable-next-item + uint256 sharesToDecrement = SlashingLib.calcSlashedAmount({ + operatorShares: operatorShares[operator][strategy], + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + + // While `sharesToDecrement` describes the amount we should directly remove from the operator's delegated + // shares, `sharesToBurn` also includes any shares that have been queued for withdrawal and are still + // slashable given the withdrawal delay. + uint256 sharesToBurn = + sharesToDecrement + _getSlashedSharesInQueue(operator, strategy, prevMaxMagnitude, newMaxMagnitude); + + // Remove shares from operator + _decreaseDelegation({ + operator: operator, + staker: address(0), // we treat this as a decrease for the zero address staker + strategy: strategy, + sharesToDecrease: sharesToDecrement + }); + + /// TODO: implement EPM.burnShares interface. Likely requires more complex interface than just shares + /// so not adding a burnShares method in IShareManager + if (strategy != beaconChainETHStrategy) { + strategyManager.burnShares(strategy, sharesToBurn); + emit OperatorSharesBurned(operator, strategy, sharesToBurn); + } } /** @@ -333,27 +387,17 @@ contract DelegationManager is /** * @notice Sets operator parameters in the `_operatorDetails` mapping. * @param operator The account registered as an operator updating their operatorDetails - * @param newOperatorDetails The new parameters for the operator + * @param newDelegationApprover The new parameters for the operator */ - function _setOperatorDetails(address operator, OperatorDetails calldata newOperatorDetails) internal { - require( - newOperatorDetails.stakerOptOutWindowBlocks <= MAX_STAKER_OPT_OUT_WINDOW_BLOCKS, - "DelegationManager._setOperatorDetails: stakerOptOutWindowBlocks cannot be > MAX_STAKER_OPT_OUT_WINDOW_BLOCKS" - ); - require( - newOperatorDetails.stakerOptOutWindowBlocks >= _operatorDetails[operator].stakerOptOutWindowBlocks, - "DelegationManager._setOperatorDetails: stakerOptOutWindowBlocks cannot be decreased" - ); - _operatorDetails[operator] = newOperatorDetails; - emit OperatorDetailsModified(msg.sender, newOperatorDetails); + function _setDelegationApprover(address operator, address newDelegationApprover) internal { + _operatorDetails[operator].delegationApprover = newDelegationApprover; + emit DelegationApproverUpdated(operator, newDelegationApprover); } /** * @notice Delegates *from* a `staker` *to* an `operator`. * @param staker The address to delegate *from* -- this address is delegating control of its own assets. * @param operator The address to delegate *to* -- this address is being given power to place the `staker`'s assets at risk on services - * @param approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param approverSalt Is a salt used to help guarantee signature uniqueness. Each salt can only be used once by a given approver. * @dev Assumes the following is checked before calling this function: * 1) the `staker` is not already delegated to an operator * 2) the `operator` has indeed registered as an operator in EigenLayer @@ -361,248 +405,243 @@ contract DelegationManager is * 1) if applicable, that the approver signature is valid and non-expired * 2) new delegations are not paused (PAUSED_NEW_DELEGATION) */ - function _delegate( - address staker, - address operator, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) internal onlyWhenNotPaused(PAUSED_NEW_DELEGATION) { - // fetch the operator's `delegationApprover` address and store it in memory in case we need to use it multiple times - address _delegationApprover = _operatorDetails[operator].delegationApprover; - /** - * Check the `_delegationApprover`'s signature, if applicable. - * If the `_delegationApprover` is the zero address, then the operator allows all stakers to delegate to them and this verification is skipped. - * If the `_delegationApprover` or the `operator` themselves is the caller, then approval is assumed and signature verification is skipped as well. - */ - if (_delegationApprover != address(0) && msg.sender != _delegationApprover && msg.sender != operator) { - // check the signature expiry - require( - approverSignatureAndExpiry.expiry >= block.timestamp, - "DelegationManager._delegate: approver signature expired" - ); - // check that the salt hasn't been used previously, then mark the salt as spent - require( - !delegationApproverSaltIsSpent[_delegationApprover][approverSalt], - "DelegationManager._delegate: approverSalt already spent" - ); - delegationApproverSaltIsSpent[_delegationApprover][approverSalt] = true; - - // forgefmt: disable-next-item - // calculate the digest hash - bytes32 approverDigestHash = calculateDelegationApprovalDigestHash( - staker, - operator, - _delegationApprover, - approverSalt, - approverSignatureAndExpiry.expiry - ); - - // forgefmt: disable-next-item - // actually check that the signature is valid - EIP1271SignatureUtils.checkSignature_EIP1271( - _delegationApprover, - approverDigestHash, - approverSignatureAndExpiry.signature - ); - } - + function _delegate(address staker, address operator) internal onlyWhenNotPaused(PAUSED_NEW_DELEGATION) { // record the delegation relation between the staker and operator, and emit an event delegatedTo[staker] = operator; emit StakerDelegated(staker, operator); - (IStrategy[] memory strategies, uint256[] memory shares) = getDelegatableShares(staker); + // read staker's deposited shares and strategies to add to operator's shares + // and also update the staker depositScalingFactor for each strategy + (IStrategy[] memory strategies, uint256[] memory depositedShares) = getDepositedShares(staker); + uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies); - for (uint256 i = 0; i < strategies.length;) { + for (uint256 i = 0; i < strategies.length; ++i) { // forgefmt: disable-next-item - _increaseOperatorShares({ + _increaseDelegation({ operator: operator, staker: staker, - strategy: strategies[i], - shares: shares[i] + strategy: strategies[i], + prevDepositShares: uint256(0), + addedShares: depositedShares[i], + slashingFactor: slashingFactors[i] }); - - unchecked { - ++i; - } } } /** - * @dev commented-out param (middlewareTimesIndex) is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array - * This param is intended to be passed on to the Slasher contract, but is unused in the M2 release of these contracts, and is thus commented-out. + * @dev This function completes a queued withdrawal for a staker. + * This will apply any slashing that has occurred since the the withdrawal was queued by multiplying the withdrawal's + * scaledShares by the operator's maxMagnitude for each strategy. This ensures that any slashing that has occurred + * during the period the withdrawal was queued until its completable timestamp is applied to the withdrawal amount. + * If receiveAsTokens is true, then these shares will be withdrawn as tokens. + * If receiveAsTokens is false, then they will be redeposited according to the current operator the staker is delegated to, + * and added back to the operator's delegatedShares. */ function _completeQueuedWithdrawal( - Withdrawal calldata withdrawal, + Withdrawal memory withdrawal, IERC20[] calldata tokens, - uint256, /*middlewareTimesIndex*/ bool receiveAsTokens ) internal { + require(tokens.length == withdrawal.strategies.length, InputArrayLengthMismatch()); + require(msg.sender == withdrawal.withdrawer, WithdrawerNotCaller()); bytes32 withdrawalRoot = calculateWithdrawalRoot(withdrawal); + require(pendingWithdrawals[withdrawalRoot], WithdrawalNotQueued()); + + uint256[] memory prevSlashingFactors; + { + uint32 completableBlock = withdrawal.startBlock + MIN_WITHDRAWAL_DELAY_BLOCKS; + require(completableBlock <= uint32(block.number), WithdrawalDelayNotElapsed()); + + // Given the max magnitudes of the operator the staker was originally delegated to, calculate + // the slashing factors for each of the withdrawal's strategies. + prevSlashingFactors = _getSlashingFactorsAtBlock({ + staker: withdrawal.staker, + operator: withdrawal.delegatedTo, + strategies: withdrawal.strategies, + blockNumber: completableBlock + }); + } - require( - pendingWithdrawals[withdrawalRoot], "DelegationManager._completeQueuedWithdrawal: action is not in queue" - ); + // Given the max magnitudes of the operator the staker is now delegated to, calculate the current + // slashing factors to apply to each withdrawal if it is received as shares. + address newOperator = delegatedTo[withdrawal.staker]; + uint256[] memory newSlashingFactors = _getSlashingFactors(withdrawal.staker, newOperator, withdrawal.strategies); - require( - withdrawal.startBlock + minWithdrawalDelayBlocks <= block.number, - "DelegationManager._completeQueuedWithdrawal: minWithdrawalDelayBlocks period has not yet passed" - ); + for (uint256 i = 0; i < withdrawal.strategies.length; i++) { + IShareManager shareManager = _getShareManager(withdrawal.strategies[i]); - require( - msg.sender == withdrawal.withdrawer, - "DelegationManager._completeQueuedWithdrawal: only withdrawer can complete action" - ); - - if (receiveAsTokens) { - require( - tokens.length == withdrawal.strategies.length, - "DelegationManager._completeQueuedWithdrawal: input length mismatch" - ); - } - - // Remove `withdrawalRoot` from pending roots - delete pendingWithdrawals[withdrawalRoot]; + // Calculate how much slashing to apply, as well as shares to withdraw + uint256 sharesToWithdraw = SlashingLib.scaleForCompleteWithdrawal({ + scaledShares: withdrawal.scaledShares[i], + slashingFactor: prevSlashingFactors[i] + }); - if (receiveAsTokens) { - // Finalize action by converting shares to tokens for each strategy, or - // by re-awarding shares in each strategy. - for (uint256 i = 0; i < withdrawal.strategies.length;) { - require( - withdrawal.startBlock + strategyWithdrawalDelayBlocks[withdrawal.strategies[i]] <= block.number, - "DelegationManager._completeQueuedWithdrawal: withdrawalDelayBlocks period has not yet passed for this strategy" - ); + if (receiveAsTokens) { + // Withdraws `shares` in `strategy` to `withdrawer`. If the shares are virtual beaconChainETH shares, + // then a call is ultimately forwarded to the `staker`s EigenPod; otherwise a call is ultimately forwarded + // to the `strategy` with info on the `token`. + shareManager.withdrawSharesAsTokens({ + staker: withdrawal.staker, + strategy: withdrawal.strategies[i], + token: tokens[i], + shares: sharesToWithdraw + }); + } else { + // Award shares back in StrategyManager/EigenPodManager. + (uint256 prevDepositShares, uint256 addedShares) = shareManager.addShares({ + staker: withdrawal.staker, + strategy: withdrawal.strategies[i], + token: tokens[i], + shares: sharesToWithdraw + }); - _withdrawSharesAsTokens({ + // Update the staker's deposit scaling factor and delegate shares to their operator + _increaseDelegation({ + operator: newOperator, staker: withdrawal.staker, - withdrawer: msg.sender, strategy: withdrawal.strategies[i], - shares: withdrawal.shares[i], - token: tokens[i] + prevDepositShares: prevDepositShares, + addedShares: addedShares, + slashingFactor: newSlashingFactors[i] }); - unchecked { - ++i; - } - } - } else { - // Award shares back in StrategyManager/EigenPodManager. - // If withdrawer is delegated, increase the shares delegated to the operator. - address currentOperator = delegatedTo[msg.sender]; - for (uint256 i = 0; i < withdrawal.strategies.length;) { - require( - withdrawal.startBlock + strategyWithdrawalDelayBlocks[withdrawal.strategies[i]] <= block.number, - "DelegationManager._completeQueuedWithdrawal: withdrawalDelayBlocks period has not yet passed for this strategy" - ); - - /** - * When awarding podOwnerShares in EigenPodManager, we need to be sure to only give them back to the original podOwner. - * Other strategy shares can + will be awarded to the withdrawer. - */ - if (withdrawal.strategies[i] == beaconChainETHStrategy) { - address staker = withdrawal.staker; - /** - * Update shares amount depending upon the returned value. - * The return value will be lower than the input value in the case where the staker has an existing share deficit - */ - uint256 increaseInDelegateableShares = - eigenPodManager.addShares({podOwner: staker, shares: withdrawal.shares[i]}); - address podOwnerOperator = delegatedTo[staker]; - // Similar to `isDelegated` logic - if (podOwnerOperator != address(0)) { - _increaseOperatorShares({ - operator: podOwnerOperator, - // the 'staker' here is the address receiving new shares - staker: staker, - strategy: withdrawal.strategies[i], - shares: increaseInDelegateableShares - }); - } - } else { - strategyManager.addShares(msg.sender, tokens[i], withdrawal.strategies[i], withdrawal.shares[i]); - // Similar to `isDelegated` logic - if (currentOperator != address(0)) { - _increaseOperatorShares({ - operator: currentOperator, - // the 'staker' here is the address receiving new shares - staker: msg.sender, - strategy: withdrawal.strategies[i], - shares: withdrawal.shares[i] - }); - } - } - unchecked { - ++i; - } } } - emit WithdrawalCompleted(withdrawalRoot); + _stakerQueuedWithdrawalRoots[withdrawal.staker].remove(withdrawalRoot); + + delete queuedWithdrawals[withdrawalRoot]; + delete pendingWithdrawals[withdrawalRoot]; + + emit SlashingWithdrawalCompleted(withdrawalRoot); } - // @notice Increases `operator`s delegated shares in `strategy` by `shares` and emits an `OperatorSharesIncreased` event - function _increaseOperatorShares(address operator, address staker, IStrategy strategy, uint256 shares) internal { - operatorShares[operator][strategy] += shares; - emit OperatorSharesIncreased(operator, staker, strategy, shares); + /** + * @notice Increases `operator`s depositedShares in `strategy` based on staker's addedDepositShares + * and updates the staker's depositScalingFactor for the strategy. + * @param operator The operator to increase the delegated delegatedShares for + * @param staker The staker to increase the depositScalingFactor for + * @param strategy The strategy to increase the delegated delegatedShares and the depositScalingFactor for + * @param prevDepositShares The number of delegated deposit shares the staker had in the strategy prior to the increase + * @param addedShares The shares added to the staker in the StrategyManager/EigenPodManager + * @param slashingFactor The current slashing factor for the staker/operator/strategy + */ + function _increaseDelegation( + address operator, + address staker, + IStrategy strategy, + uint256 prevDepositShares, + uint256 addedShares, + uint256 slashingFactor + ) internal { + // Ensure that the operator has not been fully slashed for a strategy + // and that the staker has not been fully slashed if it is the beaconChainStrategy + require(slashingFactor != 0, FullySlashed()); + + // Update the staker's depositScalingFactor. This only results in an update + // if the slashing factor has changed for this strategy. + DepositScalingFactor storage dsf = _depositScalingFactor[staker][strategy]; + dsf.update(prevDepositShares, addedShares, slashingFactor); + emit DepositScalingFactorUpdated(staker, strategy, dsf.scalingFactor()); + + // If the staker is delegated to an operator, update the operator's shares + if (isDelegated(staker)) { + operatorShares[operator][strategy] += addedShares; + emit OperatorSharesIncreased(operator, staker, strategy, addedShares); + } } - // @notice Decreases `operator`s delegated shares in `strategy` by `shares` and emits an `OperatorSharesDecreased` event - function _decreaseOperatorShares(address operator, address staker, IStrategy strategy, uint256 shares) internal { - // This will revert on underflow, so no check needed - operatorShares[operator][strategy] -= shares; - emit OperatorSharesDecreased(operator, staker, strategy, shares); + /** + * @notice Decreases `operator`s shares in `strategy` based on staker's removed shares + * @param operator The operator to decrease the delegated delegated shares for + * @param staker The staker to decrease the delegated delegated shares for + * @param strategy The strategy to decrease the delegated delegated shares for + * @param sharesToDecrease The shares to remove from the operator's delegated shares + */ + function _decreaseDelegation( + address operator, + address staker, + IStrategy strategy, + uint256 sharesToDecrease + ) internal { + // Decrement operator shares + operatorShares[operator][strategy] -= sharesToDecrease; + emit OperatorSharesDecreased(operator, staker, strategy, sharesToDecrease); } /** - * @notice Removes `shares` in `strategies` from `staker` who is currently delegated to `operator` and queues a withdrawal to the `withdrawer`. + * @notice Removes `sharesToWithdraw` in `strategies` from `staker` who is currently delegated to `operator` and queues a withdrawal to the `withdrawer`. + * @param staker The staker queuing a withdrawal + * @param operator The operator the staker is delegated to + * @param strategies The strategies to queue a withdrawal for + * @param depositSharesToWithdraw The amount of deposit shares the staker wishes to withdraw, must be less than staker's depositShares in storage + * @param slashingFactors The corresponding slashing factor for the staker/operator for each strategy + * + * @dev The amount withdrawable by the staker may not actually be the same as the depositShares that are in storage in the StrategyManager/EigenPodManager. + * This is a result of any slashing that has occurred during the time the staker has been delegated to an operator. So the proportional amount that is withdrawn + * out of the amount withdrawable for the staker has to also be decremented from the staker's deposit shares. + * So the amount of depositShares withdrawn out has to be proportionally scaled down depending on the slashing that has occurred. + * Ex. Suppose as a staker, I have 100 depositShares for a strategy thats sitting in the StrategyManager in the `stakerDepositShares` mapping but I actually have been slashed 50% + * and my real withdrawable amount is 50 shares. + * Now when I go to withdraw 40 depositShares, I'm proportionally withdrawing 40% of my withdrawable shares. We calculate below the actual shares withdrawn via the `toShares()` function to + * get 20 shares to queue withdraw. The end state is that I have 60 depositShares and 30 withdrawable shares now, this still accurately reflects a 50% slashing that has occurred on my existing stake. + * @dev depositSharesToWithdraw are converted to sharesToWithdraw using the `toShares` library function. sharesToWithdraw are then divided by the current maxMagnitude of the operator (at queue time) + * and this value is stored in the Withdrawal struct as `scaledShares. + * Upon completion the `scaledShares` are then multiplied by the maxMagnitude of the operator at completion time. This is how we factor in any slashing events + * that occurred during the withdrawal delay period. Shares in a withdrawal are no longer slashable once the withdrawal is completable. * @dev If the `operator` is indeed an operator, then the operator's delegated shares in the `strategies` are also decreased appropriately. - * @dev If `withdrawer` is not the same address as `staker`, then thirdPartyTransfersForbidden[strategy] must be set to false in the StrategyManager. */ function _removeSharesAndQueueWithdrawal( address staker, address operator, - address withdrawer, IStrategy[] memory strategies, - uint256[] memory shares + uint256[] memory depositSharesToWithdraw, + uint256[] memory slashingFactors ) internal returns (bytes32) { - require( - staker != address(0), "DelegationManager._removeSharesAndQueueWithdrawal: staker cannot be zero address" - ); - require(strategies.length != 0, "DelegationManager._removeSharesAndQueueWithdrawal: strategies cannot be empty"); + require(staker != address(0), InputAddressZero()); + require(strategies.length != 0, InputArrayLengthZero()); + + uint256[] memory scaledShares = new uint256[](strategies.length); + uint256[] memory sharesToWithdraw = new uint256[](strategies.length); // Remove shares from staker and operator // Each of these operations fail if we attempt to remove more shares than exist - for (uint256 i = 0; i < strategies.length;) { - // Similar to `isDelegated` logic + for (uint256 i = 0; i < strategies.length; ++i) { + IShareManager shareManager = _getShareManager(strategies[i]); + DepositScalingFactor memory dsf = _depositScalingFactor[staker][strategies[i]]; + + // Check withdrawing deposit shares amount doesn't exceed balance + require( + depositSharesToWithdraw[i] <= shareManager.stakerDepositShares(staker, strategies[i]), + WithdrawalExceedsMax() + ); + + // Calculate how many shares can be withdrawn after factoring in slashing + sharesToWithdraw[i] = dsf.calcWithdrawable(depositSharesToWithdraw[i], slashingFactors[i]); + + // Apply slashing. If the staker or operator has been fully slashed, this will return 0 + scaledShares[i] = SlashingLib.scaleForQueueWithdrawal({ + sharesToWithdraw: sharesToWithdraw[i], + slashingFactor: slashingFactors[i] + }); + + // Remove delegated shares from the operator if (operator != address(0)) { + // Staker was delegated and remains slashable during the withdrawal delay period + // Cumulative withdrawn scaled shares are updated for the strategy, this is for accounting + // purposes for burning shares if slashed + _addQueuedSlashableShares(operator, strategies[i], scaledShares[i]); + // forgefmt: disable-next-item - _decreaseOperatorShares({ - operator: operator, - staker: staker, - strategy: strategies[i], - shares: shares[i] + _decreaseDelegation({ + operator: operator, + staker: staker, + strategy: strategies[i], + sharesToDecrease: sharesToWithdraw[i] }); } - // Remove active shares from EigenPodManager/StrategyManager - if (strategies[i] == beaconChainETHStrategy) { - /** - * This call will revert if it would reduce the Staker's virtual beacon chain ETH shares below zero. - * This behavior prevents a Staker from queuing a withdrawal which improperly removes excessive - * shares from the operator to whom the staker is delegated. - * It will also revert if the share amount being withdrawn is not a whole Gwei amount. - */ - eigenPodManager.removeShares(staker, shares[i]); - } else { - require( - staker == withdrawer || !strategyManager.thirdPartyTransfersForbidden(strategies[i]), - "DelegationManager._removeSharesAndQueueWithdrawal: withdrawer must be same address as staker if thirdPartyTransfersForbidden are set" - ); - // this call will revert if `shares[i]` exceeds the Staker's current shares in `strategies[i]` - strategyManager.removeShares(staker, strategies[i], shares[i]); - } - - unchecked { - ++i; - } + // Remove deposit shares from EigenPodManager/StrategyManager + shareManager.removeDepositShares(staker, strategies[i], depositSharesToWithdraw[i]); } // Create queue entry and increment withdrawal nonce @@ -612,79 +651,126 @@ contract DelegationManager is Withdrawal memory withdrawal = Withdrawal({ staker: staker, delegatedTo: operator, - withdrawer: withdrawer, + withdrawer: staker, nonce: nonce, startBlock: uint32(block.number), strategies: strategies, - shares: shares + scaledShares: scaledShares }); bytes32 withdrawalRoot = calculateWithdrawalRoot(withdrawal); - // Place withdrawal in queue pendingWithdrawals[withdrawalRoot] = true; + queuedWithdrawals[withdrawalRoot] = withdrawal; + _stakerQueuedWithdrawalRoots[staker].add(withdrawalRoot); - emit WithdrawalQueued(withdrawalRoot, withdrawal); + emit SlashingWithdrawalQueued(withdrawalRoot, withdrawal, sharesToWithdraw); return withdrawalRoot; } - /** - * @notice Withdraws `shares` in `strategy` to `withdrawer`. If the shares are virtual beaconChainETH shares, then a call is ultimately forwarded to the - * `staker`s EigenPod; otherwise a call is ultimately forwarded to the `strategy` with info on the `token`. - */ - function _withdrawSharesAsTokens( + /// @dev Calculate the amount of slashing to apply to the staker's shares + function _getSlashingFactor( address staker, - address withdrawer, IStrategy strategy, - uint256 shares, - IERC20 token - ) internal { + uint64 operatorMaxMagnitude + ) internal view returns (uint256) { if (strategy == beaconChainETHStrategy) { - eigenPodManager.withdrawSharesAsTokens({podOwner: staker, destination: withdrawer, shares: shares}); - } else { - strategyManager.withdrawSharesAsTokens(withdrawer, strategy, shares, token); + uint64 beaconChainSlashingFactor = eigenPodManager.beaconChainSlashingFactor(staker); + return operatorMaxMagnitude.mulWad(beaconChainSlashingFactor); } + + return operatorMaxMagnitude; } - function _setMinWithdrawalDelayBlocks(uint256 _minWithdrawalDelayBlocks) internal { - require( - _minWithdrawalDelayBlocks <= MAX_WITHDRAWAL_DELAY_BLOCKS, - "DelegationManager._setMinWithdrawalDelayBlocks: _minWithdrawalDelayBlocks cannot be > MAX_WITHDRAWAL_DELAY_BLOCKS" - ); - emit MinWithdrawalDelayBlocksSet(minWithdrawalDelayBlocks, _minWithdrawalDelayBlocks); - minWithdrawalDelayBlocks = _minWithdrawalDelayBlocks; + /// @dev Calculate the amount of slashing to apply to the staker's shares across multiple strategies + function _getSlashingFactors( + address staker, + address operator, + IStrategy[] memory strategies + ) internal view returns (uint256[] memory) { + uint256[] memory slashingFactors = new uint256[](strategies.length); + uint64[] memory maxMagnitudes = allocationManager.getMaxMagnitudes(operator, strategies); + + for (uint256 i = 0; i < strategies.length; i++) { + slashingFactors[i] = _getSlashingFactor(staker, strategies[i], maxMagnitudes[i]); + } + + return slashingFactors; + } + + /// @dev Calculate the amount of slashing to apply to the staker's shares across multiple strategies + /// Note: specifically checks the operator's magnitude at a prior block, used for completing withdrawals + function _getSlashingFactorsAtBlock( + address staker, + address operator, + IStrategy[] memory strategies, + uint32 blockNumber + ) internal view returns (uint256[] memory) { + uint256[] memory slashingFactors = new uint256[](strategies.length); + uint64[] memory maxMagnitudes = allocationManager.getMaxMagnitudesAtBlock({ + operator: operator, + strategies: strategies, + blockNumber: blockNumber + }); + + for (uint256 i = 0; i < strategies.length; i++) { + slashingFactors[i] = _getSlashingFactor(staker, strategies[i], maxMagnitudes[i]); + } + + return slashingFactors; } /** - * @notice Sets the withdrawal delay blocks for each strategy in `_strategies` to `_withdrawalDelayBlocks`. - * gets called when initializing contract or by calling `setStrategyWithdrawalDelayBlocks` + * @dev Calculate amount of slashable shares that would be slashed from the queued withdrawals from an operator for a strategy + * given the previous maxMagnitude and the new maxMagnitude. + * Note: To get the total amount of slashable shares in the queue withdrawable, set newMaxMagnitude to 0 and prevMaxMagnitude + * is the current maxMagnitude of the operator. */ - function _setStrategyWithdrawalDelayBlocks( - IStrategy[] calldata _strategies, - uint256[] calldata _withdrawalDelayBlocks - ) internal { - require( - _strategies.length == _withdrawalDelayBlocks.length, - "DelegationManager._setStrategyWithdrawalDelayBlocks: input length mismatch" - ); - uint256 numStrats = _strategies.length; - for (uint256 i = 0; i < numStrats; ++i) { - IStrategy strategy = _strategies[i]; - uint256 prevStrategyWithdrawalDelayBlocks = strategyWithdrawalDelayBlocks[strategy]; - uint256 newStrategyWithdrawalDelayBlocks = _withdrawalDelayBlocks[i]; - require( - newStrategyWithdrawalDelayBlocks <= MAX_WITHDRAWAL_DELAY_BLOCKS, - "DelegationManager._setStrategyWithdrawalDelayBlocks: _withdrawalDelayBlocks cannot be > MAX_WITHDRAWAL_DELAY_BLOCKS" - ); + function _getSlashedSharesInQueue( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) internal view returns (uint256) { + // Fetch the cumulative scaled shares sitting in the withdrawal queue both now and before + // the withdrawal delay. + uint256 curCumulativeScaledShares = _cumulativeScaledSharesHistory[operator][strategy].latest(); + uint256 prevCumulativeScaledShares = _cumulativeScaledSharesHistory[operator][strategy].upperLookup({ + key: uint32(block.number) - MIN_WITHDRAWAL_DELAY_BLOCKS + }); - // set the new withdrawal delay blocks - strategyWithdrawalDelayBlocks[strategy] = newStrategyWithdrawalDelayBlocks; - emit StrategyWithdrawalDelayBlocksSet( - strategy, prevStrategyWithdrawalDelayBlocks, newStrategyWithdrawalDelayBlocks - ); + // The difference between these values represents the number of scaled shares that entered the + // withdrawal queue less than `MIN_WITHDRAWAL_DELAY_BLOCKS` ago. These shares are still slashable, + // so we use them to calculate the number of slashable shares in the withdrawal queue. + uint256 slashableScaledShares = curCumulativeScaledShares - prevCumulativeScaledShares; + + return SlashingLib.scaleForBurning({ + scaledShares: slashableScaledShares, + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + } + + /// @dev Add to the cumulative withdrawn scaled shares from an operator for a given strategy + function _addQueuedSlashableShares(address operator, IStrategy strategy, uint256 scaledShares) internal { + if (strategy != beaconChainETHStrategy) { + uint256 currCumulativeScaledShares = _cumulativeScaledSharesHistory[operator][strategy].latest(); + _cumulativeScaledSharesHistory[operator][strategy].push({ + key: uint32(block.number), + value: currCumulativeScaledShares + scaledShares + }); } } + /// @dev Depending on the strategy used, determine which ShareManager contract to make external calls to + function _getShareManager( + IStrategy strategy + ) internal view returns (IShareManager) { + return strategy == beaconChainETHStrategy + ? IShareManager(address(eigenPodManager)) + : IShareManager(address(strategyManager)); + } + /** * * VIEW FUNCTIONS @@ -692,37 +778,29 @@ contract DelegationManager is */ /// @inheritdoc IDelegationManager - function domainSeparator() public view returns (bytes32) { - if (block.chainid == ORIGINAL_CHAIN_ID) { - return _DOMAIN_SEPARATOR; - } else { - return _calculateDomainSeparator(); - } - } - - /// @inheritdoc IDelegationManager - function isDelegated(address staker) public view returns (bool) { + function isDelegated( + address staker + ) public view returns (bool) { return (delegatedTo[staker] != address(0)); } /// @inheritdoc IDelegationManager - function isOperator(address operator) public view returns (bool) { + function isOperator( + address operator + ) public view returns (bool) { return operator != address(0) && delegatedTo[operator] == operator; } /// @inheritdoc IDelegationManager - function operatorDetails(address operator) external view returns (OperatorDetails memory) { - return _operatorDetails[operator]; - } - - /// @inheritdoc IDelegationManager - function delegationApprover(address operator) external view returns (address) { + function delegationApprover( + address operator + ) external view returns (address) { return _operatorDetails[operator].delegationApprover; } /// @inheritdoc IDelegationManager - function stakerOptOutWindowBlocks(address operator) external view returns (uint256) { - return _operatorDetails[operator].stakerOptOutWindowBlocks; + function depositScalingFactor(address staker, IStrategy strategy) public view returns (uint256) { + return _depositScalingFactor[staker][strategy].scalingFactor(); } /// @inheritdoc IDelegationManager @@ -738,116 +816,138 @@ contract DelegationManager is } /// @inheritdoc IDelegationManager - function getDelegatableShares(address staker) public view returns (IStrategy[] memory, uint256[] memory) { - // Get currently active shares and strategies for `staker` - int256 podShares = eigenPodManager.podOwnerShares(staker); - (IStrategy[] memory strategyManagerStrats, uint256[] memory strategyManagerShares) = - strategyManager.getDeposits(staker); - - // Has no shares in EigenPodManager, but potentially some in StrategyManager - if (podShares <= 0) { - return (strategyManagerStrats, strategyManagerShares); - } - - IStrategy[] memory strategies; - uint256[] memory shares; - - if (strategyManagerStrats.length == 0) { - // Has shares in EigenPodManager, but not in StrategyManager - strategies = new IStrategy[](1); - shares = new uint256[](1); - strategies[0] = beaconChainETHStrategy; - shares[0] = uint256(podShares); - } else { - // Has shares in both - - // 1. Allocate return arrays - strategies = new IStrategy[](strategyManagerStrats.length + 1); - shares = new uint256[](strategies.length); - - // 2. Place StrategyManager strats/shares in return arrays - for (uint256 i = 0; i < strategyManagerStrats.length;) { - strategies[i] = strategyManagerStrats[i]; - shares[i] = strategyManagerShares[i]; - - unchecked { - ++i; - } - } - - // 3. Place EigenPodManager strat/shares in return arrays - strategies[strategies.length - 1] = beaconChainETHStrategy; - shares[strategies.length - 1] = uint256(podShares); + function getOperatorsShares( + address[] memory operators, + IStrategy[] memory strategies + ) public view returns (uint256[][] memory) { + uint256[][] memory shares = new uint256[][](operators.length); + for (uint256 i = 0; i < operators.length; ++i) { + shares[i] = getOperatorShares(operators[i], strategies); } + return shares; + } - return (strategies, shares); + /// @inheritdoc IDelegationManager + function getSlashableSharesInQueue(address operator, IStrategy strategy) public view returns (uint256) { + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategy; + uint64 maxMagnitude = allocationManager.getMaxMagnitudes(operator, strategies)[0]; + // Return amount of shares slashed if all remaining magnitude were to be slashed + return _getSlashedSharesInQueue({ + operator: operator, + strategy: strategy, + prevMaxMagnitude: maxMagnitude, + newMaxMagnitude: 0 + }); } /// @inheritdoc IDelegationManager - function getWithdrawalDelay(IStrategy[] calldata strategies) public view returns (uint256) { - uint256 withdrawalDelay = minWithdrawalDelayBlocks; + function getWithdrawableShares( + address staker, + IStrategy[] memory strategies + ) public view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares) { + withdrawableShares = new uint256[](strategies.length); + depositShares = new uint256[](strategies.length); + + // Get the slashing factors for the staker/operator/strategies + address operator = delegatedTo[staker]; + uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies); + for (uint256 i = 0; i < strategies.length; ++i) { - uint256 currWithdrawalDelay = strategyWithdrawalDelayBlocks[strategies[i]]; - if (currWithdrawalDelay > withdrawalDelay) { - withdrawalDelay = currWithdrawalDelay; - } + IShareManager shareManager = _getShareManager(strategies[i]); + depositShares[i] = shareManager.stakerDepositShares(staker, strategies[i]); + + // Calculate the withdrawable shares based on the slashing factor + DepositScalingFactor memory dsf = _depositScalingFactor[staker][strategies[i]]; + withdrawableShares[i] = dsf.calcWithdrawable(depositShares[i], slashingFactors[i]); } - return withdrawalDelay; + + return (withdrawableShares, depositShares); } /// @inheritdoc IDelegationManager - function calculateWithdrawalRoot(Withdrawal memory withdrawal) public pure returns (bytes32) { - return keccak256(abi.encode(withdrawal)); + function getDepositedShares( + address staker + ) public view returns (IStrategy[] memory, uint256[] memory) { + // Get a list of the staker's deposited strategies/shares in the strategy manager + (IStrategy[] memory tokenStrategies, uint256[] memory tokenDeposits) = strategyManager.getDeposits(staker); + + // If the staker has no beacon chain ETH shares, return any shares from the strategy manager + uint256 podOwnerShares = eigenPodManager.stakerDepositShares(staker, beaconChainETHStrategy); + if (podOwnerShares == 0) { + return (tokenStrategies, tokenDeposits); + } + + // Allocate extra space for beaconChainETHStrategy and shares + IStrategy[] memory strategies = new IStrategy[](tokenStrategies.length + 1); + uint256[] memory shares = new uint256[](tokenStrategies.length + 1); + + strategies[tokenStrategies.length] = beaconChainETHStrategy; + shares[tokenStrategies.length] = podOwnerShares; + + // Copy any strategy manager shares to complete array + for (uint256 i = 0; i < tokenStrategies.length; i++) { + strategies[i] = tokenStrategies[i]; + shares[i] = tokenDeposits[i]; + } + + return (strategies, shares); } /// @inheritdoc IDelegationManager - function calculateCurrentStakerDelegationDigestHash( - address staker, - address operator, - uint256 expiry - ) external view returns (bytes32) { - // fetch the staker's current nonce - uint256 currentStakerNonce = stakerNonce[staker]; - // calculate the digest hash - return calculateStakerDelegationDigestHash(staker, currentStakerNonce, operator, expiry); + function getQueuedWithdrawals( + address staker + ) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares) { + bytes32[] memory withdrawalRoots = _stakerQueuedWithdrawalRoots[staker].values(); + + uint256 totalQueued = withdrawalRoots.length; + withdrawals = new Withdrawal[](totalQueued); + shares = new uint256[][](totalQueued); + + address operator = delegatedTo[staker]; + + for (uint256 i; i < totalQueued; ++i) { + withdrawals[i] = queuedWithdrawals[withdrawalRoots[i]]; + shares[i] = new uint256[](withdrawals[i].strategies.length); + + uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, withdrawals[i].strategies); + + for (uint256 j; j < withdrawals[i].strategies.length; ++j) { + shares[i][j] = SlashingLib.scaleForCompleteWithdrawal({ + scaledShares: withdrawals[i].scaledShares[j], + slashingFactor: slashingFactors[i] + }); + } + } } /// @inheritdoc IDelegationManager - function calculateStakerDelegationDigestHash( - address staker, - uint256 _stakerNonce, - address operator, - uint256 expiry - ) public view returns (bytes32) { - // calculate the struct hash - bytes32 stakerStructHash = - keccak256(abi.encode(STAKER_DELEGATION_TYPEHASH, staker, operator, _stakerNonce, expiry)); - // calculate the digest hash - bytes32 stakerDigestHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator(), stakerStructHash)); - return stakerDigestHash; + function calculateWithdrawalRoot( + Withdrawal memory withdrawal + ) public pure returns (bytes32) { + return keccak256(abi.encode(withdrawal)); } /// @inheritdoc IDelegationManager function calculateDelegationApprovalDigestHash( address staker, address operator, - address _delegationApprover, + address approver, bytes32 approverSalt, uint256 expiry ) public view returns (bytes32) { - // calculate the struct hash - bytes32 approverStructHash = keccak256( - abi.encode(DELEGATION_APPROVAL_TYPEHASH, _delegationApprover, staker, operator, approverSalt, expiry) + /// forgefmt: disable-next-item + return _calculateSignableDigest( + keccak256( + abi.encode( + DELEGATION_APPROVAL_TYPEHASH, + approver, + staker, + operator, + approverSalt, + expiry + ) + ) ); - // calculate the digest hash - bytes32 approverDigestHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator(), approverStructHash)); - return approverDigestHash; - } - - /** - * @dev Recalculates the domain separator when the chainid changes due to a fork. - */ - function _calculateDomainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this))); } } diff --git a/src/contracts/core/DelegationManagerStorage.sol b/src/contracts/core/DelegationManagerStorage.sol index 00fc5b4ac..d9066f85a 100644 --- a/src/contracts/core/DelegationManagerStorage.sol +++ b/src/contracts/core/DelegationManagerStorage.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; -import "../interfaces/IStrategyManager.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import "../libraries/SlashingLib.sol"; import "../interfaces/IDelegationManager.sol"; -import "../interfaces/ISlasher.sol"; +import "../interfaces/IAVSDirectory.sol"; import "../interfaces/IEigenPodManager.sol"; +import "../interfaces/IAllocationManager.sol"; + +import {Snapshots} from "../libraries/Snapshots.sol"; /** * @title Storage variables for the `DelegationManager` contract. @@ -13,99 +18,123 @@ import "../interfaces/IEigenPodManager.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract DelegationManagerStorage is IDelegationManager { - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + using Snapshots for Snapshots.DefaultZeroHistory; - /// @notice The EIP-712 typehash for the `StakerDelegation` struct used by the contract - bytes32 public constant STAKER_DELEGATION_TYPEHASH = - keccak256("StakerDelegation(address staker,address operator,uint256 nonce,uint256 expiry)"); + // Constants /// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract bytes32 public constant DELEGATION_APPROVAL_TYPEHASH = keccak256( "DelegationApproval(address delegationApprover,address staker,address operator,bytes32 salt,uint256 expiry)" ); - /** - * @notice Original EIP-712 Domain separator for this contract. - * @dev The domain separator may change in the event of a fork that modifies the ChainID. - * Use the getter function `domainSeparator` to get the current domain separator for this contract. - */ - bytes32 internal _DOMAIN_SEPARATOR; + /// @dev Index for flag that pauses new delegations when set + uint8 internal constant PAUSED_NEW_DELEGATION = 0; + + /// @dev Index for flag that pauses queuing new withdrawals when set. + uint8 internal constant PAUSED_ENTER_WITHDRAWAL_QUEUE = 1; + + /// @dev Index for flag that pauses completing existing withdrawals when set. + uint8 internal constant PAUSED_EXIT_WITHDRAWAL_QUEUE = 2; + + /// @notice Canonical, virtual beacon chain ETH strategy + IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + + // Immutables + + /// @notice The AVSDirectory contract for EigenLayer + IAVSDirectory public immutable avsDirectory; + + // TODO: Switch these to ShareManagers, but this breaks a lot of tests /// @notice The StrategyManager contract for EigenLayer IStrategyManager public immutable strategyManager; - /// @notice The Slasher contract for EigenLayer - ISlasher public immutable slasher; - /// @notice The EigenPodManager contract for EigenLayer IEigenPodManager public immutable eigenPodManager; - // the number of 12-second blocks in 30 days (60 * 60 * 24 * 30 / 12 = 216,000) - uint256 public constant MAX_WITHDRAWAL_DELAY_BLOCKS = 216_000; + /// @notice The AllocationManager contract for EigenLayer + IAllocationManager public immutable allocationManager; + + /// @notice Minimum withdrawal delay in blocks until a queued withdrawal can be completed. + uint32 public immutable MIN_WITHDRAWAL_DELAY_BLOCKS; + + // Mutatables + + /// @dev Do not remove, deprecated storage. + bytes32 internal __deprecated_DOMAIN_SEPARATOR; /** - * @notice returns the total number of shares in `strategy` that are delegated to `operator`. - * @notice Mapping: operator => strategy => total number of shares in the strategy delegated to the operator. + * @notice Returns the total number of shares owned by an `operator` for a given `strategy`. + * * @dev By design, the following invariant should hold for each Strategy: - * (operator's shares in delegation manager) = sum (shares above zero of all stakers delegated to operator) - * = sum (delegateable shares of all stakers delegated to the operator) + * + * (operator's delegatedShares in delegation manager) = sum (delegatedShares above zero of all stakers delegated to operator) + * = sum (delegateable delegatedShares of all stakers delegated to the operator) */ - mapping(address => mapping(IStrategy => uint256)) public operatorShares; + mapping(address operator => mapping(IStrategy strategy => uint256 shares)) public operatorShares; - /** - * @notice Mapping: operator => OperatorDetails struct - * @dev This struct is internal with an external getter so we can return an `OperatorDetails memory` object - */ - mapping(address => OperatorDetails) internal _operatorDetails; + /// @notice Returns the operator details for a given `operator`. + mapping(address operator => OperatorDetails) internal _operatorDetails; - /** - * @notice Mapping: staker => operator whom the staker is currently delegated to. - * @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator. - */ - mapping(address => address) public delegatedTo; + /// @notice Returns the `operator` a `staker` is delgated to, address(0) if not delegated. + mapping(address staker => address operator) public delegatedTo; - /// @notice Mapping: staker => number of signed messages (used in `delegateToBySignature`) from the staker that this contract has already checked. - mapping(address => uint256) public stakerNonce; + /// @notice Do not remove, deprecated storage. + mapping(address staker => uint256 nonce) private __deprecated_stakerNonce; - /** - * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover. - * @dev Salts are used in the `delegateTo` and `delegateToBySignature` functions. Note that these functions only process the delegationApprover's - * signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`. - */ - mapping(address => mapping(bytes32 => bool)) public delegationApproverSaltIsSpent; + /// @notice Returns whether `delegationApprover` has already used the given `salt`. + mapping(address delegationApprover => mapping(bytes32 salt => bool spent)) public delegationApproverSaltIsSpent; - /** - * @notice Global minimum withdrawal delay for all strategy withdrawals. - * In a prior Goerli release, we only had a global min withdrawal delay across all strategies. - * In addition, we now also configure withdrawal delays on a per-strategy basis. - * To withdraw from a strategy, max(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) number of blocks must have passed. - * See mapping strategyWithdrawalDelayBlocks below for per-strategy withdrawal delays. - */ - uint256 public minWithdrawalDelayBlocks; + /// @dev Do not remove, deprecated storage. + uint256 private __deprecated_minWithdrawalDelayBlocks; - /// @notice Mapping: hash of withdrawal inputs, aka 'withdrawalRoot' => whether the withdrawal is pending - mapping(bytes32 => bool) public pendingWithdrawals; + /// @dev Returns whether a withdrawal is pending for a given `withdrawalRoot`. + /// @dev This variable will be deprecated in the future, values should only be read or deleted. + mapping(bytes32 withdrawalRoot => bool pending) public pendingWithdrawals; - /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. + /// @notice Returns the total number of withdrawals that have been queued for a given `staker`. /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes. - mapping(address => uint256) public cumulativeWithdrawalsQueued; + mapping(address staker => uint256 totalQueued) public cumulativeWithdrawalsQueued; - /// @notice Deprecated from an old Goerli release + /// @dev Do not remove, deprecated storage. /// See conversation here: https://github.com/Layr-Labs/eigenlayer-contracts/pull/365/files#r1417525270 address private __deprecated_stakeRegistry; - /** - * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). - */ - mapping(IStrategy => uint256) public strategyWithdrawalDelayBlocks; - - constructor(IStrategyManager _strategyManager, ISlasher _slasher, IEigenPodManager _eigenPodManager) { + /// @dev Do not remove, deprecated storage. + mapping(IStrategy strategy => uint256 delayBlocks) private __deprecated_strategyWithdrawalDelayBlocks; + + /// @notice Returns the scaling factor applied to a `staker` for a given `strategy` + mapping(address staker => mapping(IStrategy strategy => DepositScalingFactor)) internal _depositScalingFactor; + + /// @notice Returns a list of queued withdrawals for a given `staker`. + /// @dev Entrys are removed when the withdrawal is completed. + /// @dev This variable only reflects withdrawals that were made after the slashing release. + mapping(address staker => EnumerableSet.Bytes32Set withdrawalRoots) internal _stakerQueuedWithdrawalRoots; + + /// @notice Returns the details of a queued withdrawal for a given `staker` and `withdrawalRoot`. + /// @dev This variable only reflects withdrawals that were made after the slashing release. + mapping(bytes32 withdrawalRoot => Withdrawal withdrawal) public queuedWithdrawals; + + /// @notice Contains history of the total cumulative staker withdrawals for an operator and a given strategy. + /// Used to calculate burned StrategyManager shares when an operator is slashed. + /// @dev Stores scaledShares instead of total withdrawn shares to track current slashable shares, dependent on the maxMagnitude + mapping(address operator => mapping(IStrategy strategy => Snapshots.DefaultZeroHistory)) internal + _cumulativeScaledSharesHistory; + + // Construction + + constructor( + IAVSDirectory _avsDirectory, + IStrategyManager _strategyManager, + IEigenPodManager _eigenPodManager, + IAllocationManager _allocationManager, + uint32 _MIN_WITHDRAWAL_DELAY_BLOCKS + ) { + avsDirectory = _avsDirectory; strategyManager = _strategyManager; eigenPodManager = _eigenPodManager; - slasher = _slasher; + allocationManager = _allocationManager; + MIN_WITHDRAWAL_DELAY_BLOCKS = _MIN_WITHDRAWAL_DELAY_BLOCKS; } /** @@ -113,5 +142,5 @@ abstract contract DelegationManagerStorage is IDelegationManager { * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[39] private __gap; + uint256[35] private __gap; } diff --git a/src/contracts/core/RewardsCoordinator.sol b/src/contracts/core/RewardsCoordinator.sol index 1bc73c99b..a6ccde585 100644 --- a/src/contracts/core/RewardsCoordinator.sol +++ b/src/contracts/core/RewardsCoordinator.sol @@ -1,13 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + import "../libraries/Merkle.sol"; import "../permissions/Pausable.sol"; import "./RewardsCoordinatorStorage.sol"; +import "../mixins/PermissionControllerMixin.sol"; /** * @title RewardsCoordinator @@ -23,47 +25,18 @@ contract RewardsCoordinator is OwnableUpgradeable, Pausable, ReentrancyGuardUpgradeable, - RewardsCoordinatorStorage + RewardsCoordinatorStorage, + PermissionControllerMixin { using SafeERC20 for IERC20; - /// @notice The EIP-712 typehash for the contract's domain - bytes32 internal constant DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - /// @dev Chain ID at the time of contract deployment - uint256 internal immutable ORIGINAL_CHAIN_ID; - /// @notice The maximum rewards token amount for a single rewards submission, constrained by off-chain calculation - uint256 internal constant MAX_REWARDS_AMOUNT = 1e38 - 1; - - /// @dev Index for flag that pauses calling createAVSRewardsSubmission - uint8 internal constant PAUSED_AVS_REWARDS_SUBMISSION = 0; - /// @dev Index for flag that pauses calling createRewardsForAllSubmission - uint8 internal constant PAUSED_REWARDS_FOR_ALL_SUBMISSION = 1; - /// @dev Index for flag that pauses calling processClaim - uint8 internal constant PAUSED_PROCESS_CLAIM = 2; - /// @dev Index for flag that pauses submitRoots and disableRoot - uint8 internal constant PAUSED_SUBMIT_DISABLE_ROOTS = 3; - /// @dev Index for flag that pauses calling rewardAllStakersAndOperators - uint8 internal constant PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS = 4; - - /// @dev Salt for the earner leaf, meant to distinguish from tokenLeaf since they have the same sized data - uint8 internal constant EARNER_LEAF_SALT = 0; - /// @dev Salt for the token leaf, meant to distinguish from earnerLeaf since they have the same sized data - uint8 internal constant TOKEN_LEAF_SALT = 1; - - /// @notice Canonical, virtual beacon chain ETH strategy - IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - modifier onlyRewardsUpdater() { - require(msg.sender == rewardsUpdater, "RewardsCoordinator: caller is not the rewardsUpdater"); + require(msg.sender == rewardsUpdater, UnauthorizedCaller()); _; } modifier onlyRewardsForAllSubmitter() { - require( - isRewardsForAllSubmitter[msg.sender], - "RewardsCoordinator: caller is not a valid createRewardsForAllSubmission submitter" - ); + require(isRewardsForAllSubmitter[msg.sender], UnauthorizedCaller()); _; } @@ -71,24 +44,29 @@ contract RewardsCoordinator is constructor( IDelegationManager _delegationManager, IStrategyManager _strategyManager, + IAllocationManager _allocationManager, + IPauserRegistry _pauserRegistry, + IPermissionController _permissionController, uint32 _CALCULATION_INTERVAL_SECONDS, uint32 _MAX_REWARDS_DURATION, uint32 _MAX_RETROACTIVE_LENGTH, uint32 _MAX_FUTURE_LENGTH, - uint32 __GENESIS_REWARDS_TIMESTAMP + uint32 _GENESIS_REWARDS_TIMESTAMP ) RewardsCoordinatorStorage( _delegationManager, _strategyManager, + _allocationManager, _CALCULATION_INTERVAL_SECONDS, _MAX_REWARDS_DURATION, _MAX_RETROACTIVE_LENGTH, _MAX_FUTURE_LENGTH, - __GENESIS_REWARDS_TIMESTAMP + _GENESIS_REWARDS_TIMESTAMP ) + Pausable(_pauserRegistry) + PermissionControllerMixin(_permissionController) { _disableInitializers(); - ORIGINAL_CHAIN_ID = block.chainid; } /** @@ -97,14 +75,12 @@ contract RewardsCoordinator is */ function initialize( address initialOwner, - IPauserRegistry _pauserRegistry, uint256 initialPausedStatus, address _rewardsUpdater, uint32 _activationDelay, uint16 _globalCommissionBips ) external initializer { - _DOMAIN_SEPARATOR = _calculateDomainSeparator(); - _initializePauser(_pauserRegistry, initialPausedStatus); + _setPausedStatus(initialPausedStatus); _transferOwnership(initialOwner); _setRewardsUpdater(_rewardsUpdater); _setActivationDelay(_activationDelay); @@ -118,11 +94,10 @@ contract RewardsCoordinator is */ /// @inheritdoc IRewardsCoordinator - function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) - external - onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) - nonReentrant - { + function createAVSRewardsSubmission( + address avs, + RewardsSubmission[] calldata rewardsSubmissions + ) external onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) checkCanCall(avs) nonReentrant { for (uint256 i = 0; i < rewardsSubmissions.length; i++) { RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; uint256 nonce = submissionNonce[msg.sender]; @@ -139,12 +114,9 @@ contract RewardsCoordinator is } /// @inheritdoc IRewardsCoordinator - function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmissions) - external - onlyWhenNotPaused(PAUSED_REWARDS_FOR_ALL_SUBMISSION) - onlyRewardsForAllSubmitter - nonReentrant - { + function createRewardsForAllSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external onlyWhenNotPaused(PAUSED_REWARDS_FOR_ALL_SUBMISSION) onlyRewardsForAllSubmitter nonReentrant { for (uint256 i = 0; i < rewardsSubmissions.length; i++) { RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; uint256 nonce = submissionNonce[msg.sender]; @@ -161,12 +133,9 @@ contract RewardsCoordinator is } /// @inheritdoc IRewardsCoordinator - function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) - external - onlyWhenNotPaused(PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS) - onlyRewardsForAllSubmitter - nonReentrant - { + function createRewardsForAllEarners( + RewardsSubmission[] calldata rewardsSubmissions + ) external onlyWhenNotPaused(PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS) onlyRewardsForAllSubmitter nonReentrant { for (uint256 i = 0; i < rewardsSubmissions.length; i++) { RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; uint256 nonce = submissionNonce[msg.sender]; @@ -197,15 +166,12 @@ contract RewardsCoordinator is if (claimer == address(0)) { claimer = earner; } - require(msg.sender == claimer, "RewardsCoordinator.processClaim: caller is not valid claimer"); + require(msg.sender == claimer, UnauthorizedCaller()); for (uint256 i = 0; i < claim.tokenIndices.length; i++) { TokenTreeMerkleLeaf calldata tokenLeaf = claim.tokenLeaves[i]; uint256 currCumulativeClaimed = cumulativeClaimed[earner][tokenLeaf.token]; - require( - tokenLeaf.cumulativeEarnings > currCumulativeClaimed, - "RewardsCoordinator.processClaim: cumulativeEarnings must be gt than cumulativeClaimed" - ); + require(tokenLeaf.cumulativeEarnings > currCumulativeClaimed, EarningsNotGreaterThanClaimed()); // Calculate amount to claim and update cumulativeClaimed uint256 claimAmount = tokenLeaf.cumulativeEarnings - currCumulativeClaimed; @@ -222,13 +188,9 @@ contract RewardsCoordinator is uint32 rewardsCalculationEndTimestamp ) external onlyWhenNotPaused(PAUSED_SUBMIT_DISABLE_ROOTS) onlyRewardsUpdater { require( - rewardsCalculationEndTimestamp > currRewardsCalculationEndTimestamp, - "RewardsCoordinator.submitRoot: new root must be for newer calculated period" - ); - require( - rewardsCalculationEndTimestamp < block.timestamp, - "RewardsCoordinator.submitRoot: rewardsCalculationEndTimestamp cannot be in the future" + rewardsCalculationEndTimestamp > currRewardsCalculationEndTimestamp, NewRootMustBeForNewCalculatedPeriod() ); + require(rewardsCalculationEndTimestamp < block.timestamp, RewardsEndTimestampNotElapsed()); uint32 rootIndex = uint32(_distributionRoots.length); uint32 activatedAt = uint32(block.timestamp) + activationDelay; _distributionRoots.push( @@ -244,35 +206,52 @@ contract RewardsCoordinator is } /// @inheritdoc IRewardsCoordinator - function disableRoot(uint32 rootIndex) external onlyWhenNotPaused(PAUSED_SUBMIT_DISABLE_ROOTS) onlyRewardsUpdater { - require(rootIndex < _distributionRoots.length, "RewardsCoordinator.disableRoot: invalid rootIndex"); + function disableRoot( + uint32 rootIndex + ) external onlyWhenNotPaused(PAUSED_SUBMIT_DISABLE_ROOTS) onlyRewardsUpdater { + require(rootIndex < _distributionRoots.length, InvalidRootIndex()); DistributionRoot storage root = _distributionRoots[rootIndex]; - require(!root.disabled, "RewardsCoordinator.disableRoot: root already disabled"); - require(block.timestamp < root.activatedAt, "RewardsCoordinator.disableRoot: root already activated"); + require(!root.disabled, RootDisabled()); + require(block.timestamp < root.activatedAt, RootAlreadyActivated()); root.disabled = true; emit DistributionRootDisabled(rootIndex); } /// @inheritdoc IRewardsCoordinator - function setClaimerFor(address claimer) external { + function setClaimerFor( + address claimer + ) external { address earner = msg.sender; - address prevClaimer = claimerFor[earner]; - claimerFor[earner] = claimer; - emit ClaimerForSet(earner, prevClaimer, claimer); + _setClaimer(earner, claimer); + } + + /// @inheritdoc IRewardsCoordinator + function setClaimerFor(address earner, address claimer) external checkCanCall(earner) { + // Require that the earner is an operator or AVS + require( + delegationManager.isOperator(earner) || allocationManager.getOperatorSetCount(earner) > 0, InvalidEarner() + ); + _setClaimer(earner, claimer); } /// @inheritdoc IRewardsCoordinator - function setActivationDelay(uint32 _activationDelay) external onlyOwner { + function setActivationDelay( + uint32 _activationDelay + ) external onlyOwner { _setActivationDelay(_activationDelay); } /// @inheritdoc IRewardsCoordinator - function setGlobalOperatorCommission(uint16 _globalCommissionBips) external onlyOwner { + function setGlobalOperatorCommission( + uint16 _globalCommissionBips + ) external onlyOwner { _setGlobalOperatorCommission(_globalCommissionBips); } /// @inheritdoc IRewardsCoordinator - function setRewardsUpdater(address _rewardsUpdater) external onlyOwner { + function setRewardsUpdater( + address _rewardsUpdater + ) external onlyOwner { _setRewardsUpdater(_rewardsUpdater); } @@ -292,37 +271,21 @@ contract RewardsCoordinator is /** * @notice Validate a RewardsSubmission. Called from both `createAVSRewardsSubmission` and `createRewardsForAllSubmission` */ - function _validateRewardsSubmission(RewardsSubmission calldata rewardsSubmission) internal view { - require( - rewardsSubmission.strategiesAndMultipliers.length > 0, - "RewardsCoordinator._validateRewardsSubmission: no strategies set" - ); - require(rewardsSubmission.amount > 0, "RewardsCoordinator._validateRewardsSubmission: amount cannot be 0"); - require( - rewardsSubmission.amount <= MAX_REWARDS_AMOUNT, - "RewardsCoordinator._validateRewardsSubmission: amount too large" - ); - require( - rewardsSubmission.duration <= MAX_REWARDS_DURATION, - "RewardsCoordinator._validateRewardsSubmission: duration exceeds MAX_REWARDS_DURATION" - ); - require( - rewardsSubmission.duration % CALCULATION_INTERVAL_SECONDS == 0, - "RewardsCoordinator._validateRewardsSubmission: duration must be a multiple of CALCULATION_INTERVAL_SECONDS" - ); - require( - rewardsSubmission.startTimestamp % CALCULATION_INTERVAL_SECONDS == 0, - "RewardsCoordinator._validateRewardsSubmission: startTimestamp must be a multiple of CALCULATION_INTERVAL_SECONDS" - ); + function _validateRewardsSubmission( + RewardsSubmission calldata rewardsSubmission + ) internal view { + require(rewardsSubmission.strategiesAndMultipliers.length > 0, InputArrayLengthZero()); + require(rewardsSubmission.amount > 0, AmountIsZero()); + require(rewardsSubmission.amount <= MAX_REWARDS_AMOUNT, AmountExceedsMax()); + require(rewardsSubmission.duration <= MAX_REWARDS_DURATION, DurationExceedsMax()); + require(rewardsSubmission.duration % CALCULATION_INTERVAL_SECONDS == 0, InvalidDurationRemainder()); + require(rewardsSubmission.startTimestamp % CALCULATION_INTERVAL_SECONDS == 0, InvalidStartTimestampRemainder()); require( block.timestamp - MAX_RETROACTIVE_LENGTH <= rewardsSubmission.startTimestamp && GENESIS_REWARDS_TIMESTAMP <= rewardsSubmission.startTimestamp, - "RewardsCoordinator._validateRewardsSubmission: startTimestamp too far in the past" - ); - require( - rewardsSubmission.startTimestamp <= block.timestamp + MAX_FUTURE_LENGTH, - "RewardsCoordinator._validateRewardsSubmission: startTimestamp too far in the future" + StartTimestampTooFarInPast() ); + require(rewardsSubmission.startTimestamp <= block.timestamp + MAX_FUTURE_LENGTH, StartTimestampTooFarInFuture()); // Require rewardsSubmission is for whitelisted strategy or beaconChainETHStrategy address currAddress = address(0); @@ -330,27 +293,18 @@ contract RewardsCoordinator is IStrategy strategy = rewardsSubmission.strategiesAndMultipliers[i].strategy; require( strategyManager.strategyIsWhitelistedForDeposit(strategy) || strategy == beaconChainETHStrategy, - "RewardsCoordinator._validateRewardsSubmission: invalid strategy considered" - ); - require( - currAddress < address(strategy), - "RewardsCoordinator._validateRewardsSubmission: strategies must be in ascending order to handle duplicates" + StrategyNotWhitelisted() ); + require(currAddress < address(strategy), StrategiesNotInAscendingOrder()); currAddress = address(strategy); } } function _checkClaim(RewardsMerkleClaim calldata claim, DistributionRoot memory root) internal view { - require(!root.disabled, "RewardsCoordinator._checkClaim: root is disabled"); - require(block.timestamp >= root.activatedAt, "RewardsCoordinator._checkClaim: root not activated yet"); - require( - claim.tokenIndices.length == claim.tokenTreeProofs.length, - "RewardsCoordinator._checkClaim: tokenIndices and tokenProofs length mismatch" - ); - require( - claim.tokenTreeProofs.length == claim.tokenLeaves.length, - "RewardsCoordinator._checkClaim: tokenTreeProofs and leaves length mismatch" - ); + require(!root.disabled, RootDisabled()); + require(block.timestamp >= root.activatedAt, RootNotActivated()); + require(claim.tokenIndices.length == claim.tokenTreeProofs.length, InputArrayLengthMismatch()); + require(claim.tokenTreeProofs.length == claim.tokenLeaves.length, InputArrayLengthMismatch()); // Verify inclusion of earners leaf (earner, earnerTokenRoot) in the distribution root _verifyEarnerClaimProof({ @@ -386,10 +340,7 @@ contract RewardsCoordinator is ) internal pure { // Validate index size so that there aren't multiple valid indices for the given proof // index can't be greater than 2**(tokenProof/32) - require( - tokenLeafIndex < (1 << (tokenProof.length / 32)), - "RewardsCoordinator._verifyTokenClaim: invalid tokenLeafIndex" - ); + require(tokenLeafIndex < (1 << (tokenProof.length / 32)), InvalidTokenLeafIndex()); // Verify inclusion of token leaf bytes32 tokenLeafHash = calculateTokenLeafHash(tokenLeaf); @@ -400,7 +351,7 @@ contract RewardsCoordinator is proof: tokenProof, leaf: tokenLeafHash }), - "RewardsCoordinator._verifyTokenClaim: invalid token claim proof" + InvalidClaimProof() ); } @@ -421,10 +372,7 @@ contract RewardsCoordinator is ) internal pure { // Validate index size so that there aren't multiple valid indices for the given proof // index can't be greater than 2**(earnerProof/32) - require( - earnerLeafIndex < (1 << (earnerProof.length / 32)), - "RewardsCoordinator._verifyEarnerClaimProof: invalid earnerLeafIndex" - ); + require(earnerLeafIndex < (1 << (earnerProof.length / 32)), InvalidEarnerLeafIndex()); // Verify inclusion of earner leaf bytes32 earnerLeafHash = calculateEarnerLeafHash(earnerLeaf); // forgefmt: disable-next-item @@ -435,25 +383,37 @@ contract RewardsCoordinator is proof: earnerProof, leaf: earnerLeafHash }), - "RewardsCoordinator._verifyEarnerClaimProof: invalid earner claim proof" + InvalidClaimProof() ); } - function _setActivationDelay(uint32 _activationDelay) internal { + function _setActivationDelay( + uint32 _activationDelay + ) internal { emit ActivationDelaySet(activationDelay, _activationDelay); activationDelay = _activationDelay; } - function _setGlobalOperatorCommission(uint16 _globalCommissionBips) internal { + function _setGlobalOperatorCommission( + uint16 _globalCommissionBips + ) internal { emit GlobalCommissionBipsSet(globalOperatorCommissionBips, _globalCommissionBips); globalOperatorCommissionBips = _globalCommissionBips; } - function _setRewardsUpdater(address _rewardsUpdater) internal { + function _setRewardsUpdater( + address _rewardsUpdater + ) internal { emit RewardsUpdaterSet(rewardsUpdater, _rewardsUpdater); rewardsUpdater = _rewardsUpdater; } + function _setClaimer(address earner, address claimer) internal { + address prevClaimer = claimerFor[earner]; + claimerFor[earner] = claimer; + emit ClaimerForSet(earner, prevClaimer, claimer); + } + /** * * VIEW FUNCTIONS @@ -461,23 +421,32 @@ contract RewardsCoordinator is */ /// @inheritdoc IRewardsCoordinator - function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) public pure returns (bytes32) { + function calculateEarnerLeafHash( + EarnerTreeMerkleLeaf calldata leaf + ) public pure returns (bytes32) { return keccak256(abi.encodePacked(EARNER_LEAF_SALT, leaf.earner, leaf.earnerTokenRoot)); } /// @inheritdoc IRewardsCoordinator - function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) public pure returns (bytes32) { + function calculateTokenLeafHash( + TokenTreeMerkleLeaf calldata leaf + ) public pure returns (bytes32) { return keccak256(abi.encodePacked(TOKEN_LEAF_SALT, leaf.token, leaf.cumulativeEarnings)); } /// @inheritdoc IRewardsCoordinator - function checkClaim(RewardsMerkleClaim calldata claim) public view returns (bool) { + function checkClaim( + RewardsMerkleClaim calldata claim + ) public view returns (bool) { _checkClaim(claim, _distributionRoots[claim.rootIndex]); return true; } /// @inheritdoc IRewardsCoordinator - function operatorCommissionBips(address /* operator */, address /* avs */) external view returns (uint16) { + function operatorCommissionBips( + address, // operator + address // avs + ) external view returns (uint16) { return globalOperatorCommissionBips; } @@ -487,7 +456,9 @@ contract RewardsCoordinator is } /// @inheritdoc IRewardsCoordinator - function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory) { + function getDistributionRootAtIndex( + uint256 index + ) external view returns (DistributionRoot memory) { return _distributionRoots[index]; } @@ -509,28 +480,14 @@ contract RewardsCoordinator is } /// @inheritdoc IRewardsCoordinator - function getRootIndexFromHash(bytes32 rootHash) public view returns (uint32) { + function getRootIndexFromHash( + bytes32 rootHash + ) public view returns (uint32) { for (uint32 i = uint32(_distributionRoots.length); i > 0; i--) { if (_distributionRoots[i - 1].root == rootHash) { return i - 1; } } - revert("RewardsCoordinator.getRootIndexFromHash: root not found"); - } - - /// @inheritdoc IRewardsCoordinator - function domainSeparator() public view returns (bytes32) { - if (block.chainid == ORIGINAL_CHAIN_ID) { - return _DOMAIN_SEPARATOR; - } else { - return _calculateDomainSeparator(); - } - } - - /** - * @dev Recalculates the domain separator when the chainid changes due to a fork. - */ - function _calculateDomainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this))); + revert InvalidRoot(); } } diff --git a/src/contracts/core/RewardsCoordinatorStorage.sol b/src/contracts/core/RewardsCoordinatorStorage.sol index ca30e0f18..808597573 100644 --- a/src/contracts/core/RewardsCoordinatorStorage.sol +++ b/src/contracts/core/RewardsCoordinatorStorage.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; -import "../interfaces/IStrategyManager.sol"; -import "../interfaces/IDelegationManager.sol"; import "../interfaces/IRewardsCoordinator.sol"; +import "../interfaces/IDelegationManager.sol"; +import "../interfaces/IStrategyManager.sol"; +import "../interfaces/IAllocationManager.sol"; /** * @title Storage variables for the `RewardsCoordinator` contract. @@ -12,11 +13,40 @@ import "../interfaces/IRewardsCoordinator.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { - /** - * - * CONSTANTS AND IMMUTABLES - * - */ + // Constants + + /// @notice The maximum rewards token amount for a single rewards submission, constrained by off-chain calculation + uint256 internal constant MAX_REWARDS_AMOUNT = 1e38 - 1; + + /// @dev Index for flag that pauses calling createAVSRewardsSubmission + uint8 internal constant PAUSED_AVS_REWARDS_SUBMISSION = 0; + /// @dev Index for flag that pauses calling createRewardsForAllSubmission + uint8 internal constant PAUSED_REWARDS_FOR_ALL_SUBMISSION = 1; + /// @dev Index for flag that pauses calling processClaim + uint8 internal constant PAUSED_PROCESS_CLAIM = 2; + /// @dev Index for flag that pauses submitRoots and disableRoot + uint8 internal constant PAUSED_SUBMIT_DISABLE_ROOTS = 3; + /// @dev Index for flag that pauses calling rewardAllStakersAndOperators + uint8 internal constant PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS = 4; + + /// @dev Salt for the earner leaf, meant to distinguish from tokenLeaf since they have the same sized data + uint8 internal constant EARNER_LEAF_SALT = 0; + /// @dev Salt for the token leaf, meant to distinguish from earnerLeaf since they have the same sized data + uint8 internal constant TOKEN_LEAF_SALT = 1; + + /// @notice Canonical, virtual beacon chain ETH strategy + IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + + // Immtuables + + /// @notice The DelegationManager contract for EigenLayer + IDelegationManager public immutable delegationManager; + + /// @notice The StrategyManager contract for EigenLayer + IStrategyManager public immutable strategyManager; + + /// @notice The AllocationManager contract for EigenLayer + IAllocationManager public immutable allocationManager; /// @notice The interval in seconds at which the calculation for rewards distribution is done. /// @dev RewardsSubmission durations must be multiples of this interval. This is going to be configured to 1 week @@ -32,24 +62,10 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { /// @notice The cadence at which a snapshot is taken offchain for calculating rewards distributions uint32 internal constant SNAPSHOT_CADENCE = 1 days; - /// @notice The DelegationManager contract for EigenLayer - IDelegationManager public immutable delegationManager; + // Mutatables - /// @notice The StrategyManager contract for EigenLayer - IStrategyManager public immutable strategyManager; - - /** - * - * STORAGE - * - */ - - /** - * @notice Original EIP-712 Domain separator for this contract. - * @dev The domain separator may change in the event of a fork that modifies the ChainID. - * Use the getter function `domainSeparator` to get the current domain separator for this contract. - */ - bytes32 internal _DOMAIN_SEPARATOR; + /// @dev Do not remove, deprecated storage. + bytes32 internal __deprecated_DOMAIN_SEPARATOR; /** * @notice List of roots submited by the rewardsUpdater @@ -67,31 +83,34 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { /// @notice the commission for all operators across all avss uint16 public globalOperatorCommissionBips; - /// @notice Mapping: earner => the address of the entity who can call `processClaim` on behalf of the earner - mapping(address => address) public claimerFor; + /// @notice Returns the `claimer` for a given `earner`. + /// @dev The claimer is able to call `processClaim` on behalf of the `earner`. + mapping(address earner => address claimer) public claimerFor; - /// @notice Mapping: earner => token => total amount claimed - mapping(address => mapping(IERC20 => uint256)) public cumulativeClaimed; + /// @notice Returns the total claimed amount for an `earner` for a given `token`. + mapping(address earner => mapping(IERC20 token => uint256 totalClaimed)) public cumulativeClaimed; - /// @notice Used for unique rewardsSubmissionHashes per AVS and for RewardsForAllSubmitters and the tokenHopper - mapping(address => uint256) public submissionNonce; + /// @notice Returns the submission `nonce` for an `avs`. + mapping(address avs => uint256 nonce) public submissionNonce; - /// @notice Mapping: avs => avsRewardsSubmissionHash => bool to check if rewards submission hash has been submitted - mapping(address => mapping(bytes32 => bool)) public isAVSRewardsSubmissionHash; + /// @notice Returns whether a `hash` is a `valid` rewards submission hash for a given `avs`. + mapping(address avs => mapping(bytes32 hash => bool valid)) public isAVSRewardsSubmissionHash; - /// @notice Mapping: avs => rewardsSubmissionForAllHash => bool to check if rewards submission hash for all has been submitted - mapping(address => mapping(bytes32 => bool)) public isRewardsSubmissionForAllHash; + /// @notice Returns whether a `hash` is a `valid` rewards submission for all hash for a given `avs`. + mapping(address avs => mapping(bytes32 hash => bool valid)) public isRewardsSubmissionForAllHash; - /// @notice Mapping: address => bool to check if the address is permissioned to call createRewardsForAllSubmission - mapping(address => bool) public isRewardsForAllSubmitter; + /// @notice Returns whether a `submitter` is a `valid` rewards for all submitter. + mapping(address submitter => bool valid) public isRewardsForAllSubmitter; - /// @notice Mapping: avs => rewardsSubmissionForAllEarnersHash => bool to check - /// if rewards submission hash for all stakers and operators has been submitted - mapping(address => mapping(bytes32 => bool)) public isRewardsSubmissionForAllEarnersHash; + /// @notice Returns whether a `hash` is a `valid` rewards submission for all earners hash for a given `avs`. + mapping(address avs => mapping(bytes32 hash => bool valid)) public isRewardsSubmissionForAllEarnersHash; + + // Construction constructor( IDelegationManager _delegationManager, IStrategyManager _strategyManager, + IAllocationManager _allocationManager, uint32 _CALCULATION_INTERVAL_SECONDS, uint32 _MAX_REWARDS_DURATION, uint32 _MAX_RETROACTIVE_LENGTH, @@ -99,15 +118,12 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { uint32 _GENESIS_REWARDS_TIMESTAMP ) { require( - _GENESIS_REWARDS_TIMESTAMP % _CALCULATION_INTERVAL_SECONDS == 0, - "RewardsCoordinator: GENESIS_REWARDS_TIMESTAMP must be a multiple of CALCULATION_INTERVAL_SECONDS" - ); - require( - _CALCULATION_INTERVAL_SECONDS % SNAPSHOT_CADENCE == 0, - "RewardsCoordinator: CALCULATION_INTERVAL_SECONDS must be a multiple of SNAPSHOT_CADENCE" + _GENESIS_REWARDS_TIMESTAMP % _CALCULATION_INTERVAL_SECONDS == 0, InvalidGenesisRewardsTimestampRemainder() ); + require(_CALCULATION_INTERVAL_SECONDS % SNAPSHOT_CADENCE == 0, InvalidCalculationIntervalSecondsRemainder()); delegationManager = _delegationManager; strategyManager = _strategyManager; + allocationManager = _allocationManager; CALCULATION_INTERVAL_SECONDS = _CALCULATION_INTERVAL_SECONDS; MAX_REWARDS_DURATION = _MAX_REWARDS_DURATION; MAX_RETROACTIVE_LENGTH = _MAX_RETROACTIVE_LENGTH; diff --git a/src/contracts/core/Slasher.sol b/src/contracts/core/Slasher.sol deleted file mode 100644 index 9a05a560a..000000000 --- a/src/contracts/core/Slasher.sol +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../interfaces/ISlasher.sol"; -import "../interfaces/IDelegationManager.sol"; -import "../interfaces/IStrategyManager.sol"; -import "../permissions/Pausable.sol"; -import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; -import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; - -/** - * @notice This contract is not in use as of the Eigenlayer M2 release. - * - * Although many contracts reference it as an immutable variable, they do not - * interact with it and it is effectively dead code. The Slasher was originally - * deployed during Eigenlayer M1, but remained paused and unused for the duration - * of that release as well. - * - * Eventually, slashing design will be finalized and the Slasher will be finished - * and more fully incorporated into the core contracts. For now, you can ignore this - * file. If you really want to see what the deployed M1 version looks like, check - * out the `init-mainnet-deployment` branch under "releases". - * - * This contract is a stub that maintains its original interface for use in testing - * and deploy scripts. Otherwise, it does nothing. - */ -contract Slasher is Initializable, OwnableUpgradeable, ISlasher, Pausable { - constructor(IStrategyManager, IDelegationManager) {} - - function initialize(address, IPauserRegistry, uint256) external {} - - function optIntoSlashing(address) external {} - - function freezeOperator(address) external {} - - function resetFrozenStatus(address[] calldata) external {} - - function recordFirstStakeUpdate(address, uint32) external {} - - function recordStakeUpdate(address, uint32, uint32, uint256) external {} - - function recordLastStakeUpdateAndRevokeSlashingAbility(address, uint32) external {} - - function strategyManager() external view returns (IStrategyManager) {} - - function delegation() external view returns (IDelegationManager) {} - - function isFrozen(address) external view returns (bool) {} - - function canSlash(address, address) external view returns (bool) {} - - function contractCanSlashOperatorUntilBlock(address, address) external view returns (uint32) {} - - function latestUpdateBlock(address, address) external view returns (uint32) {} - - function getCorrectValueForInsertAfter(address, uint32) external view returns (uint256) {} - - function canWithdraw(address, uint32, uint256) external returns (bool) {} - - function operatorToMiddlewareTimes(address, uint256) external view returns (MiddlewareTimes memory) {} - - function middlewareTimesLength(address) external view returns (uint256) {} - - function getMiddlewareTimesIndexStalestUpdateBlock(address, uint32) external view returns (uint32) {} - - function getMiddlewareTimesIndexServeUntilBlock(address, uint32) external view returns (uint32) {} - - function operatorWhitelistedContractsLinkedListSize(address) external view returns (uint256) {} - - function operatorWhitelistedContractsLinkedListEntry( - address, - address - ) external view returns (bool, uint256, uint256) {} - - function whitelistedContractDetails(address, address) external view returns (MiddlewareDetails memory) {} -} diff --git a/src/contracts/core/StrategyManager.sol b/src/contracts/core/StrategyManager.sol index 4deeb4a97..eb8c545d6 100644 --- a/src/contracts/core/StrategyManager.sol +++ b/src/contracts/core/StrategyManager.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import "../mixins/SignatureUtils.sol"; import "../interfaces/IEigenPodManager.sol"; import "../permissions/Pausable.sol"; import "./StrategyManagerStorage.sol"; -import "../libraries/EIP1271SignatureUtils.sol"; /** * @title The primary entry- and exit-point for funds into and out of EigenLayer. @@ -24,48 +25,37 @@ contract StrategyManager is OwnableUpgradeable, ReentrancyGuardUpgradeable, Pausable, - StrategyManagerStorage + StrategyManagerStorage, + SignatureUtils { + using SlashingLib for *; using SafeERC20 for IERC20; - // index for flag that pauses deposits when set - uint8 internal constant PAUSED_DEPOSITS = 0; - - // chain id at the time of contract deployment - uint256 internal immutable ORIGINAL_CHAIN_ID; - modifier onlyStrategyWhitelister() { - require( - msg.sender == strategyWhitelister, "StrategyManager.onlyStrategyWhitelister: not the strategyWhitelister" - ); + require(msg.sender == strategyWhitelister, OnlyStrategyWhitelister()); _; } - modifier onlyStrategiesWhitelistedForDeposit(IStrategy strategy) { - require( - strategyIsWhitelistedForDeposit[strategy], - "StrategyManager.onlyStrategiesWhitelistedForDeposit: strategy not whitelisted" - ); + modifier onlyStrategiesWhitelistedForDeposit( + IStrategy strategy + ) { + require(strategyIsWhitelistedForDeposit[strategy], StrategyNotWhitelisted()); _; } modifier onlyDelegationManager() { - require(msg.sender == address(delegation), "StrategyManager.onlyDelegationManager: not the DelegationManager"); + require(msg.sender == address(delegation), OnlyDelegationManager()); _; } /** * @param _delegation The delegation contract of EigenLayer. - * @param _slasher The primary slashing contract of EigenLayer. - * @param _eigenPodManager The contract that keeps track of EigenPod stakes for restaking beacon chain ether. */ constructor( IDelegationManager _delegation, - IEigenPodManager _eigenPodManager, - ISlasher _slasher - ) StrategyManagerStorage(_delegation, _eigenPodManager, _slasher) { + IPauserRegistry _pauserRegistry + ) StrategyManagerStorage(_delegation) Pausable(_pauserRegistry) { _disableInitializers(); - ORIGINAL_CHAIN_ID = block.chainid; } // EXTERNAL FUNCTIONS @@ -73,19 +63,15 @@ contract StrategyManager is /** * @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set), * and transfers contract ownership to the specified `initialOwner`. - * @param _pauserRegistry Used for access control of pausing. * @param initialOwner Ownership of this contract is transferred to this address. * @param initialStrategyWhitelister The initial value of `strategyWhitelister` to set. - * @param initialPausedStatus The initial value of `_paused` to set. */ function initialize( address initialOwner, address initialStrategyWhitelister, - IPauserRegistry _pauserRegistry, uint256 initialPausedStatus ) external initializer { - _DOMAIN_SEPARATOR = _calculateDomainSeparator(); - _initializePauser(_pauserRegistry, initialPausedStatus); + _setPausedStatus(initialPausedStatus); _transferOwnership(initialOwner); _setStrategyWhitelister(initialStrategyWhitelister); } @@ -95,8 +81,8 @@ contract StrategyManager is IStrategy strategy, IERC20 token, uint256 amount - ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 shares) { - shares = _depositIntoStrategy(msg.sender, strategy, token, amount); + ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 depositedShares) { + depositedShares = _depositIntoStrategy(msg.sender, strategy, token, amount); } /// @inheritdoc IStrategyManager @@ -107,108 +93,90 @@ contract StrategyManager is address staker, uint256 expiry, bytes memory signature - ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 shares) { - require( - !thirdPartyTransfersForbidden[strategy], - "StrategyManager.depositIntoStrategyWithSignature: third transfers disabled" - ); - require(expiry >= block.timestamp, "StrategyManager.depositIntoStrategyWithSignature: signature expired"); - // calculate struct hash, then increment `staker`'s nonce + ) external onlyWhenNotPaused(PAUSED_DEPOSITS) nonReentrant returns (uint256 depositedShares) { + // Cache staker's nonce to avoid sloads. uint256 nonce = nonces[staker]; - bytes32 structHash = keccak256(abi.encode(DEPOSIT_TYPEHASH, staker, strategy, token, amount, nonce, expiry)); + // Assert that the signature is valid. + _checkIsValidSignatureNow({ + signer: staker, + signableDigest: calculateStrategyDepositDigestHash(staker, strategy, token, amount, nonce, expiry), + signature: signature, + expiry: expiry + }); + // Increment the nonce for the staker. unchecked { nonces[staker] = nonce + 1; } - - // calculate the digest hash - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", domainSeparator(), structHash)); - - /** - * check validity of signature: - * 1) if `staker` is an EOA, then `signature` must be a valid ECDSA signature from `staker`, - * indicating their intention for this action - * 2) if `staker` is a contract, then `signature` will be checked according to EIP-1271 - */ - EIP1271SignatureUtils.checkSignature_EIP1271(staker, digestHash, signature); - // deposit the tokens (from the `msg.sender`) and credit the new shares to the `staker` - shares = _depositIntoStrategy(staker, strategy, token, amount); + depositedShares = _depositIntoStrategy(staker, strategy, token, amount); } - /// @inheritdoc IStrategyManager - function removeShares(address staker, IStrategy strategy, uint256 shares) external onlyDelegationManager { - _removeShares(staker, strategy, shares); + /// @inheritdoc IShareManager + function removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) external onlyDelegationManager { + _removeDepositShares(staker, strategy, depositSharesToRemove); } - /// @inheritdoc IStrategyManager + /// @inheritdoc IShareManager function addShares( address staker, - IERC20 token, IStrategy strategy, + IERC20 token, uint256 shares - ) external onlyDelegationManager { - _addShares(staker, token, strategy, shares); + ) external onlyDelegationManager returns (uint256, uint256) { + return _addShares(staker, token, strategy, shares); } - /// @inheritdoc IStrategyManager + /// @inheritdoc IShareManager function withdrawSharesAsTokens( - address recipient, + address staker, IStrategy strategy, - uint256 shares, - IERC20 token + IERC20 token, + uint256 shares ) external onlyDelegationManager { - strategy.withdraw(recipient, token, shares); + strategy.withdraw(staker, token, shares); } /// @inheritdoc IStrategyManager - function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external onlyStrategyWhitelister { - _setThirdPartyTransfersForbidden(strategy, value); + function burnShares(IStrategy strategy, uint256 sharesToBurn) external onlyDelegationManager { + // burning shares is functionally the same as withdrawing but with different destination address + strategy.withdraw(DEFAULT_BURN_ADDRESS, strategy.underlyingToken(), sharesToBurn); } /// @inheritdoc IStrategyManager - function setStrategyWhitelister(address newStrategyWhitelister) external onlyOwner { + function setStrategyWhitelister( + address newStrategyWhitelister + ) external onlyOwner { _setStrategyWhitelister(newStrategyWhitelister); } /// @inheritdoc IStrategyManager function addStrategiesToDepositWhitelist( - IStrategy[] calldata strategiesToWhitelist, - bool[] calldata thirdPartyTransfersForbiddenValues + IStrategy[] calldata strategiesToWhitelist ) external onlyStrategyWhitelister { - require( - strategiesToWhitelist.length == thirdPartyTransfersForbiddenValues.length, - "StrategyManager.addStrategiesToDepositWhitelist: array lengths do not match" - ); uint256 strategiesToWhitelistLength = strategiesToWhitelist.length; - for (uint256 i = 0; i < strategiesToWhitelistLength;) { + for (uint256 i = 0; i < strategiesToWhitelistLength; ++i) { // change storage and emit event only if strategy is not already in whitelist if (!strategyIsWhitelistedForDeposit[strategiesToWhitelist[i]]) { strategyIsWhitelistedForDeposit[strategiesToWhitelist[i]] = true; emit StrategyAddedToDepositWhitelist(strategiesToWhitelist[i]); - _setThirdPartyTransfersForbidden(strategiesToWhitelist[i], thirdPartyTransfersForbiddenValues[i]); - } - unchecked { - ++i; } } } /// @inheritdoc IStrategyManager - function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) - external - onlyStrategyWhitelister - { + function removeStrategiesFromDepositWhitelist( + IStrategy[] calldata strategiesToRemoveFromWhitelist + ) external onlyStrategyWhitelister { uint256 strategiesToRemoveFromWhitelistLength = strategiesToRemoveFromWhitelist.length; - for (uint256 i = 0; i < strategiesToRemoveFromWhitelistLength;) { + for (uint256 i = 0; i < strategiesToRemoveFromWhitelistLength; ++i) { // change storage and emit event only if strategy is already in whitelist if (strategyIsWhitelistedForDeposit[strategiesToRemoveFromWhitelist[i]]) { strategyIsWhitelistedForDeposit[strategiesToRemoveFromWhitelist[i]] = false; emit StrategyRemovedFromDepositWhitelist(strategiesToRemoveFromWhitelist[i]); - // Set mapping value to default false value - _setThirdPartyTransfersForbidden(strategiesToRemoveFromWhitelist[i], false); - } - unchecked { - ++i; } } } @@ -222,27 +190,32 @@ contract StrategyManager is * @param strategy The Strategy in which the `staker` is receiving shares * @param shares The amount of shares to grant to the `staker` * @dev In particular, this function calls `delegation.increaseDelegatedShares(staker, strategy, shares)` to ensure that all - * delegated shares are tracked, increases the stored share amount in `stakerStrategyShares[staker][strategy]`, and adds `strategy` + * delegated shares are tracked, increases the stored share amount in `stakerDepositShares[staker][strategy]`, and adds `strategy` * to the `staker`'s list of strategies, if it is not in the list already. */ - function _addShares(address staker, IERC20 token, IStrategy strategy, uint256 shares) internal { + function _addShares( + address staker, + IERC20 token, + IStrategy strategy, + uint256 shares + ) internal returns (uint256, uint256) { // sanity checks on inputs - require(staker != address(0), "StrategyManager._addShares: staker cannot be zero address"); - require(shares != 0, "StrategyManager._addShares: shares should not be zero!"); - - // if they dont have existing shares of this strategy, add it to their strats - if (stakerStrategyShares[staker][strategy] == 0) { - require( - stakerStrategyList[staker].length < MAX_STAKER_STRATEGY_LIST_LENGTH, - "StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH" - ); + require(staker != address(0), StakerAddressZero()); + require(shares != 0, SharesAmountZero()); + + uint256 prevDepositShares = stakerDepositShares[staker][strategy]; + + // if they dont have prevDepositShares of this strategy, add it to their strats + if (prevDepositShares == 0) { + require(stakerStrategyList[staker].length < MAX_STAKER_STRATEGY_LIST_LENGTH, MaxStrategiesExceeded()); stakerStrategyList[staker].push(strategy); } - // add the returned shares to their existing shares for this strategy - stakerStrategyShares[staker][strategy] += shares; + // add the returned depositedShares to their existing shares for this strategy + stakerDepositShares[staker][strategy] = prevDepositShares + shares; emit Deposit(staker, token, strategy, shares); + return (prevDepositShares, shares); } /** @@ -267,40 +240,48 @@ contract StrategyManager is shares = strategy.deposit(token, amount); // add the returned shares to the staker's existing shares for this strategy - _addShares(staker, token, strategy, shares); + (uint256 prevDepositShares, uint256 addedShares) = _addShares(staker, token, strategy, shares); - // Increase shares delegated to operator, if needed - delegation.increaseDelegatedShares(staker, strategy, shares); + // Increase shares delegated to operator + delegation.increaseDelegatedShares({ + staker: staker, + strategy: strategy, + prevDepositShares: prevDepositShares, + addedShares: addedShares + }); return shares; } /** - * @notice Decreases the shares that `staker` holds in `strategy` by `shareAmount`. + * @notice Decreases the shares that `staker` holds in `strategy` by `depositSharesToRemove`. * @param staker The address to decrement shares from * @param strategy The strategy for which the `staker`'s shares are being decremented - * @param shareAmount The amount of shares to decrement + * @param depositSharesToRemove The amount of deposit shares to decrement * @dev If the amount of shares represents all of the staker`s shares in said strategy, * then the strategy is removed from stakerStrategyList[staker] and 'true' is returned. Otherwise 'false' is returned. */ - function _removeShares(address staker, IStrategy strategy, uint256 shareAmount) internal returns (bool) { + function _removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) internal returns (bool) { // sanity checks on inputs - require(shareAmount != 0, "StrategyManager._removeShares: shareAmount should not be zero!"); + require(depositSharesToRemove != 0, SharesAmountZero()); //check that the user has sufficient shares - uint256 userShares = stakerStrategyShares[staker][strategy]; + uint256 userDepositShares = stakerDepositShares[staker][strategy]; - require(shareAmount <= userShares, "StrategyManager._removeShares: shareAmount too high"); - //unchecked arithmetic since we just checked this above - unchecked { - userShares = userShares - shareAmount; - } + // This check technically shouldn't actually ever revert because depositSharesToRemove is already + // checked to not exceed max amount of shares when the withdrawal was queued in the DelegationManager + require(depositSharesToRemove <= userDepositShares, SharesAmountTooHigh()); + userDepositShares = userDepositShares - depositSharesToRemove; // subtract the shares from the staker's existing shares for this strategy - stakerStrategyShares[staker][strategy] = userShares; + stakerDepositShares[staker][strategy] = userDepositShares; // if no existing shares, remove the strategy from the staker's dynamic array of strategies - if (userShares == 0) { + if (userDepositShares == 0) { _removeStrategyFromStakerStrategyList(staker, strategy); // return true in the event that the strategy was removed from stakerStrategyList[staker] @@ -319,38 +300,26 @@ contract StrategyManager is //loop through all of the strategies, find the right one, then replace uint256 stratsLength = stakerStrategyList[staker].length; uint256 j = 0; - for (; j < stratsLength;) { + for (; j < stratsLength; ++j) { if (stakerStrategyList[staker][j] == strategy) { //replace the strategy with the last strategy in the list stakerStrategyList[staker][j] = stakerStrategyList[staker][stakerStrategyList[staker].length - 1]; break; } - unchecked { - ++j; - } } // if we didn't find the strategy, revert - require(j != stratsLength, "StrategyManager._removeStrategyFromStakerStrategyList: strategy not found"); + require(j != stratsLength, StrategyNotFound()); // pop off the last entry in the list of strategies stakerStrategyList[staker].pop(); } - /** - * @notice Internal function for modifying `thirdPartyTransfersForbidden`. - * Used inside of the `setThirdPartyTransfersForbidden` and `addStrategiesToDepositWhitelist` functions. - * @param strategy The strategy to set `thirdPartyTransfersForbidden` value to - * @param value bool value to set `thirdPartyTransfersForbidden` to - */ - function _setThirdPartyTransfersForbidden(IStrategy strategy, bool value) internal { - emit UpdatedThirdPartyTransfersForbidden(strategy, value); - thirdPartyTransfersForbidden[strategy] = value; - } - /** * @notice Internal function for modifying the `strategyWhitelister`. Used inside of the `setStrategyWhitelister` and `initialize` functions. * @param newStrategyWhitelister The new address for the `strategyWhitelister` to take. */ - function _setStrategyWhitelister(address newStrategyWhitelister) internal { + function _setStrategyWhitelister( + address newStrategyWhitelister + ) internal { emit StrategyWhitelisterChanged(strategyWhitelister, newStrategyWhitelister); strategyWhitelister = newStrategyWhitelister; } @@ -358,35 +327,53 @@ contract StrategyManager is // VIEW FUNCTIONS /// @inheritdoc IStrategyManager - function getDeposits(address staker) external view returns (IStrategy[] memory, uint256[] memory) { + function getDeposits( + address staker + ) external view returns (IStrategy[] memory, uint256[] memory) { uint256 strategiesLength = stakerStrategyList[staker].length; - uint256[] memory shares = new uint256[](strategiesLength); + uint256[] memory depositedShares = new uint256[](strategiesLength); - for (uint256 i = 0; i < strategiesLength;) { - shares[i] = stakerStrategyShares[staker][stakerStrategyList[staker][i]]; - unchecked { - ++i; - } + for (uint256 i = 0; i < strategiesLength; ++i) { + depositedShares[i] = stakerDepositShares[staker][stakerStrategyList[staker][i]]; } - return (stakerStrategyList[staker], shares); + return (stakerStrategyList[staker], depositedShares); } - /// @notice Simple getter function that returns `stakerStrategyList[staker].length`. - function stakerStrategyListLength(address staker) external view returns (uint256) { - return stakerStrategyList[staker].length; + function getStakerStrategyList( + address staker + ) external view returns (IStrategy[] memory) { + return stakerStrategyList[staker]; } /// @inheritdoc IStrategyManager - function domainSeparator() public view returns (bytes32) { - if (block.chainid == ORIGINAL_CHAIN_ID) { - return _DOMAIN_SEPARATOR; - } else { - return _calculateDomainSeparator(); - } + function stakerStrategyListLength( + address staker + ) external view returns (uint256) { + return stakerStrategyList[staker].length; } - // @notice Internal function for calculating the current domain separator of this contract - function _calculateDomainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this))); + /// @inheritdoc IStrategyManager + function calculateStrategyDepositDigestHash( + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount, + uint256 nonce, + uint256 expiry + ) public view returns (bytes32) { + /// forgefmt: disable-next-item + return _calculateSignableDigest( + keccak256( + abi.encode( + DEPOSIT_TYPEHASH, + staker, + strategy, + token, + amount, + nonce, + expiry + ) + ) + ); } } diff --git a/src/contracts/core/StrategyManagerStorage.sol b/src/contracts/core/StrategyManagerStorage.sol index 085b1dc9a..c02fd77b7 100644 --- a/src/contracts/core/StrategyManagerStorage.sol +++ b/src/contracts/core/StrategyManagerStorage.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IStrategyManager.sol"; import "../interfaces/IStrategy.sol"; import "../interfaces/IEigenPodManager.sol"; import "../interfaces/IDelegationManager.sol"; -import "../interfaces/ISlasher.sol"; +import "../interfaces/IAVSDirectory.sol"; /** * @title Storage variables for the `StrategyManager` contract. @@ -14,68 +14,70 @@ import "../interfaces/ISlasher.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract StrategyManagerStorage is IStrategyManager { - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + // Constants + /// @notice The EIP-712 typehash for the deposit struct used by the contract bytes32 public constant DEPOSIT_TYPEHASH = keccak256("Deposit(address staker,address strategy,address token,uint256 amount,uint256 nonce,uint256 expiry)"); + // maximum length of dynamic arrays in `stakerStrategyList` mapping, for sanity's sake uint8 internal constant MAX_STAKER_STRATEGY_LIST_LENGTH = 32; - // system contracts + // index for flag that pauses deposits when set + uint8 internal constant PAUSED_DEPOSITS = 0; + + /// @notice default address for burning slashed shares and transferring underlying tokens + address public constant DEFAULT_BURN_ADDRESS = 0x00000000000000000000000000000000DeaDBeef; + + // Immutables + IDelegationManager public immutable delegation; - IEigenPodManager public immutable eigenPodManager; - ISlasher public immutable slasher; - /** - * @notice Original EIP-712 Domain separator for this contract. - * @dev The domain separator may change in the event of a fork that modifies the ChainID. - * Use the getter function `domainSeparator` to get the current domain separator for this contract. - */ - bytes32 internal _DOMAIN_SEPARATOR; - // staker => number of signed deposit nonce (used in depositIntoStrategyWithSignature) - mapping(address => uint256) public nonces; - /// @notice Permissioned role, which can be changed by the contract owner. Has the ability to edit the strategy whitelist + // Mutatables + + /// @dev Do not remove, deprecated storage. + bytes32 internal __deprecated_DOMAIN_SEPARATOR; + + /// @notice Returns the signature `nonce` for each `signer`. + mapping(address signer => uint256 nonce) public nonces; + + /// @notice Returns the permissioned address that can whitelist strategies. address public strategyWhitelister; - /* - * Reserved space previously used by the deprecated storage variable `withdrawalDelayBlocks. - * This variable was migrated to the DelegationManager instead. - */ + + /// @dev Do not remove, deprecated storage. uint256 private __deprecated_withdrawalDelayBlocks; - /// @notice Mapping: staker => Strategy => number of shares which they currently hold - mapping(address => mapping(IStrategy => uint256)) public stakerStrategyShares; - /// @notice Mapping: staker => array of strategies in which they have nonzero shares - mapping(address => IStrategy[]) public stakerStrategyList; - /// @notice *Deprecated* mapping: hash of withdrawal inputs, aka 'withdrawalRoot' => whether the withdrawal is pending - /// @dev This mapping is preserved to allow the migration of withdrawals to the DelegationManager contract. - mapping(bytes32 => bool) private __deprecated_withdrawalRootPending; - /* - * Reserved space previously used by the deprecated mapping(address => uint256) numWithdrawalsQueued. - * This mapping tracked the cumulative number of queued withdrawals initiated by a staker. - * Withdrawals are now initiated in the DlegationManager, so the mapping has moved to that contract. - */ - mapping(address => uint256) private __deprecated_numWithdrawalsQueued; - /// @notice Mapping: strategy => whether or not stakers are allowed to deposit into it - mapping(IStrategy => bool) public strategyIsWhitelistedForDeposit; - /* - * Reserved space previously used by the deprecated mapping(address => uint256) beaconChainETHSharesToDecrementOnWithdrawal. - * This mapping tracked beaconChainETH "deficit" in cases where updates were made to shares retroactively. However, this construction was - * moved into the EigenPodManager contract itself. - */ - mapping(address => uint256) internal beaconChainETHSharesToDecrementOnWithdrawal; + + /// @notice Returns the number of deposited `shares` for a `staker` for a given `strategy`. + /// @dev All of these shares may not be withdrawable if the staker has delegated to an operator that has been slashed. + mapping(address staker => mapping(IStrategy strategy => uint256 shares)) public stakerDepositShares; + + /// @notice Returns a list of the `strategies` that a `staker` is currently staking in. + mapping(address staker => IStrategy[] strategies) public stakerStrategyList; + + /// @dev Do not remove, deprecated storage. + mapping(bytes32 withdrawalRoot => bool pending) private __deprecated_withdrawalRootPending; + + /// @dev Do not remove, deprecated storage. + mapping(address staker => uint256 totalQueued) private __deprecated_numWithdrawalsQueued; + + /// @notice Returns whether a `strategy` is `whitelisted` for deposits. + mapping(IStrategy strategy => bool whitelisted) public strategyIsWhitelistedForDeposit; + + /// @dev Do not remove, deprecated storage. + mapping(address avs => uint256 shares) private __deprecated_beaconChainETHSharesToDecrementOnWithdrawal; + + /// @dev Do not remove, deprecated storage. + mapping(IStrategy strategy => bool) private __deprecated_thirdPartyTransfersForbidden; + + // Construction /** - * @notice Mapping: strategy => whether or not stakers are allowed to transfer strategy shares to another address - * if true for a strategy, a user cannot depositIntoStrategyWithSignature into that strategy for another staker - * and also when performing queueWithdrawals, a staker can only withdraw to themselves + * @param _delegation The delegation contract of EigenLayer. */ - mapping(IStrategy => bool) public thirdPartyTransfersForbidden; - - constructor(IDelegationManager _delegation, IEigenPodManager _eigenPodManager, ISlasher _slasher) { + constructor( + IDelegationManager _delegation + ) { delegation = _delegation; - eigenPodManager = _eigenPodManager; - slasher = _slasher; } /** diff --git a/src/contracts/interfaces/IAVSDirectory.sol b/src/contracts/interfaces/IAVSDirectory.sol index 2c3f767d8..231ef2e9d 100644 --- a/src/contracts/interfaces/IAVSDirectory.sol +++ b/src/contracts/interfaces/IAVSDirectory.sol @@ -2,9 +2,38 @@ pragma solidity >=0.5.0; import "./ISignatureUtils.sol"; +import "./IPauserRegistry.sol"; +import "./IStrategy.sol"; + +interface IAVSDirectoryErrors { + /// Operator Status + + /// @dev Thrown when an operator does not exist in the DelegationManager + error OperatorNotRegisteredToEigenLayer(); + /// @dev Thrown when an operator is already registered to an AVS. + error OperatorNotRegisteredToAVS(); + /// @dev Thrown when `operator` is already registered to the AVS. + error OperatorAlreadyRegisteredToAVS(); -interface IAVSDirectory is ISignatureUtils { /// @notice Enum representing the status of an operator's registration with an AVS + /// @dev Thrown when an invalid AVS is provided. + error InvalidAVS(); + /// @dev Thrown when an invalid operator is provided. + error InvalidOperator(); + /// @dev Thrown when an invalid operator set is provided. + error InvalidOperatorSet(); + /// @dev Thrown when a strategy is already added to an operator set. + error StrategyAlreadyInOperatorSet(); + /// @dev Thrown when a strategy is not in an operator set. + error StrategyNotInOperatorSet(); + + /// @dev Thrown when attempting to spend a spent eip-712 salt. + error SaltSpent(); +} + +interface IAVSDirectoryTypes { + /// @notice Enum representing the registration status of an operator with an AVS. + /// @notice Only used by legacy M2 AVSs that have not integrated with operatorSets. enum OperatorAVSRegistrationStatus { UNREGISTERED, // Operator not registered to AVS REGISTERED // Operator registered to AVS @@ -12,51 +41,112 @@ interface IAVSDirectory is ISignatureUtils { } /** - * @notice Emitted when @param avs indicates that they are updating their MetadataURI string - * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing + * @notice Struct representing the registration status of an operator with an operator set. + * Keeps track of last deregistered timestamp for slashability concerns. + * @param registered whether the operator is registered with the operator set + * @param lastDeregisteredTimestamp the timestamp at which the operator was last deregistered */ - event AVSMetadataURIUpdated(address indexed avs, string metadataURI); + struct OperatorSetRegistrationStatus { + bool registered; + uint32 lastDeregisteredTimestamp; + } +} - /// @notice Emitted when an operator's registration status for an AVS is updated +interface IAVSDirectoryEvents is IAVSDirectoryTypes { + /** + * @notice Emitted when an operator's registration status with an AVS id udpated + * @notice Only used by legacy M2 AVSs that have not integrated with operatorSets. + */ event OperatorAVSRegistrationStatusUpdated( address indexed operator, address indexed avs, OperatorAVSRegistrationStatus status ); + /// @notice Emitted when an AVS updates their metadata URI (Uniform Resource Identifier). + /// @dev The URI is never stored; it is simply emitted through an event for off-chain indexing. + event AVSMetadataURIUpdated(address indexed avs, string metadataURI); + + /// @notice Emitted when an AVS migrates to using operator sets. + event AVSMigratedToOperatorSets(address indexed avs); + + /// @notice Emitted when an operator is migrated from M2 registration to operator sets. + event OperatorMigratedToOperatorSets(address indexed operator, address indexed avs, uint32[] operatorSetIds); +} + +interface IAVSDirectory is IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtils { /** - * @notice Called by the AVS's service manager contract to register an operator with the avs. - * @param operator The address of the operator to register. - * @param operatorSignature The signature, salt, and expiry of the operator's signature. + * + * EXTERNAL FUNCTIONS + * */ - function registerOperatorToAVS( - address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + + /** + * @dev Initializes the addresses of the initial owner and paused status. + */ + function initialize(address initialOwner, uint256 initialPausedStatus) external; + + /** + * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated. + * + * @param metadataURI The URI for metadata associated with an AVS. + * + * @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event. + */ + function updateAVSMetadataURI( + string calldata metadataURI ) external; /** - * @notice Called by an avs to deregister an operator with the avs. - * @param operator The address of the operator to deregister. + * @notice Called by an operator to cancel a salt that has been used to register with an AVS. + * + * @param salt A unique and single use value associated with the approver signature. + */ + function cancelSalt( + bytes32 salt + ) external; + + /** + * @notice Legacy function called by the AVS's service manager contract + * to register an operator with the AVS. NOTE: this function will be deprecated in a future release + * after the slashing release. New AVSs should use `registerForOperatorSets` instead. + * + * @param operator The address of the operator to register. + * @param operatorSignature The signature, salt, and expiry of the operator's signature. + * + * @dev msg.sender must be the AVS. + * @dev Only used by legacy M2 AVSs that have not integrated with operator sets. */ - function deregisterOperatorFromAVS(address operator) external; + function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external; /** - * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated. - * @param metadataURI The URI for metadata associated with an AVS - * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `AVSMetadataURIUpdated` event + * @notice Legacy function called by an AVS to deregister an operator from the AVS. + * NOTE: this function will be deprecated in a future release after the slashing release. + * New AVSs integrating should use `deregisterOperatorFromOperatorSets` instead. + * + * @param operator The address of the operator to deregister. + * + * @dev Only used by legacy M2 AVSs that have not integrated with operator sets. */ - function updateAVSMetadataURI(string calldata metadataURI) external; + function deregisterOperatorFromAVS( + address operator + ) external; /** - * @notice Returns whether or not the salt has already been used by the operator. - * @dev Salts is used in the `registerOperatorToAVS` function. + * + * VIEW FUNCTIONS + * */ function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool); /** - * @notice Calculates the digest hash to be signed by an operator to register with an AVS - * @param operator The account registering as an operator - * @param avs The address of the service manager contract for the AVS that the operator is registering to - * @param salt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid + * @notice Calculates the digest hash to be signed by an operator to register with an AVS. + * + * @param operator The account registering as an operator. + * @param avs The AVS the operator is registering with. + * @param salt A unique and single-use value associated with the approver's signature. + * @param expiry The time after which the approver's signature becomes invalid. */ function calculateOperatorAVSRegistrationDigestHash( address operator, @@ -65,21 +155,9 @@ interface IAVSDirectory is ISignatureUtils { uint256 expiry ) external view returns (bytes32); - /// @notice The EIP-712 typehash for the Registration struct used by the contract + /// @notice The EIP-712 typehash for the Registration struct used by the contract. function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32); - /** - * @notice Called by an operator to cancel a salt that has been used to register with an AVS. - * @param salt A unique and single use value associated with the approver signature. - */ - function cancelSalt(bytes32 salt) external; - - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. - */ - function domainSeparator() external view returns (bytes32); + /// @notice The EIP-712 typehash for the OperatorSetRegistration struct used by the contract. + function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32); } diff --git a/src/contracts/interfaces/IAVSRegistrar.sol b/src/contracts/interfaces/IAVSRegistrar.sol new file mode 100644 index 000000000..9cc7f32ff --- /dev/null +++ b/src/contracts/interfaces/IAVSRegistrar.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity >=0.5.0; + +interface IAVSRegistrar { + /** + * @notice Called by the AllocationManager when an operator wants to register + * for one or more operator sets. This method should revert if registration + * is unsuccessful. + * @param operator the registering operator + * @param operatorSetIds the list of operator set ids being registered for + * @param data arbitrary data the operator can provide as part of registration + */ + function registerOperator(address operator, uint32[] calldata operatorSetIds, bytes calldata data) external; + + /** + * @notice Called by the AllocationManager when an operator is deregistered from + * one or more operator sets. If this method reverts, it is ignored. + * @param operator the deregistering operator + * @param operatorSetIds the list of operator set ids being deregistered from + */ + function deregisterOperator(address operator, uint32[] calldata operatorSetIds) external; +} diff --git a/src/contracts/interfaces/IAllocationManager.sol b/src/contracts/interfaces/IAllocationManager.sol new file mode 100644 index 000000000..d4eb3a9c3 --- /dev/null +++ b/src/contracts/interfaces/IAllocationManager.sol @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity >=0.5.0; + +import {OperatorSet} from "../libraries/OperatorSetLib.sol"; +import "./IPauserRegistry.sol"; +import "./IStrategy.sol"; +import "./ISignatureUtils.sol"; +import "./IAVSRegistrar.sol"; + +interface IAllocationManagerErrors { + /// Input Validation + + /// @dev Thrown when `wadToSlash` is zero or greater than 1e18 + error InvalidWadToSlash(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + + /// Caller + + /// @dev Thrown when caller is not authorized to call a function. + error InvalidCaller(); + + /// Operator Status + + /// @dev Thrown when an invalid operator is provided. + error InvalidOperator(); + /// @dev Thrown when an operator's allocation delay has yet to be set. + error UninitializedAllocationDelay(); + /// @dev Thrown when trying to add an operator to a set they are already a member of + error AlreadyMemberOfSet(); + /// @dev Thrown when trying to slash/remove an operator from a set they are not a member of + error NotMemberOfSet(); + + /// Operator Set Status + + /// @dev Thrown when an invalid operator set is provided. + error InvalidOperatorSet(); + /// @dev Thrown when trying to add a strategy to an operator set that already contains it. + error StrategyAlreadyInOperatorSet(); + /// @dev Thrown when trying to remove a strategy from an operator set it is not a part of. + error StrategyNotInOperatorSet(); + + /// Modifying Allocations + + /// @dev Thrown when an operator attempts to set their allocation for an operatorSet to the same value + error SameMagnitude(); + /// @dev Thrown when an allocation is attempted for a given operator when they have pending allocations or deallocations. + error ModificationAlreadyPending(); + /// @dev Thrown when an allocation is attempted that exceeds a given operators total allocatable magnitude. + error InsufficientMagnitude(); +} + +interface IAllocationManagerTypes { + /** + * @notice Defines allocation information from a strategy to an operator set, for an operator + * @param currentMagnitude the current magnitude allocated from the strategy to the operator set + * @param pendingDiff a pending change in magnitude, if it exists (0 otherwise) + * @param effectBlock the block at which the pending magnitude diff will take effect + */ + struct Allocation { + uint64 currentMagnitude; + int128 pendingDiff; + uint32 effectBlock; + } + + /** + * @notice Struct containing allocation delay metadata for a given operator. + * @param delay Current allocation delay + * @param isSet Whether the operator has initially set an allocation delay. Note that this could be false but the + * block.number >= effectBlock in which we consider their delay to be configured and active. + * @param pendingDelay The delay that will take effect after `effectBlock` + * @param effectBlock The block number after which a pending delay will take effect + */ + struct AllocationDelayInfo { + uint32 delay; + bool isSet; + uint32 pendingDelay; + uint32 effectBlock; + } + + /** + * @notice Contains registration details for an operator pertaining to an operator set + * @param registered Whether the operator is currently registered for the operator set + * @param registeredUntil If the operator is not registered, how long until the operator is no longer + * slashable by the AVS. + */ + struct RegistrationStatus { + bool registered; + uint32 registeredUntil; + } + + /** + * @notice Contains allocation info for a specific strategy + * @param maxMagnitude the maximum magnitude that can be allocated between all operator sets + * @param encumberedMagnitude the currently-allocated magnitude for the strategy + */ + struct StrategyInfo { + uint64 maxMagnitude; + uint64 encumberedMagnitude; + } + + /** + * @notice Struct containing parameters to slashing + * @param operator the address to slash + * @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of + * @param wadToSlash the parts in 1e18 to slash, this will be proportional to the operator's + * slashable stake allocation for the operatorSet + * @param description the description of the slashing provided by the AVS for legibility + */ + struct SlashingParams { + address operator; + uint32 operatorSetId; + uint256 wadToSlash; + string description; + } + + /** + * @notice struct used to modify the allocation of slashable magnitude to an operator set + * @param operatorSet the operator set to modify the allocation for + * @param strategies the strategies to modify allocations for + * @param newMagnitudes the new magnitude to allocate for each strategy to this operator set + */ + struct AllocateParams { + OperatorSet operatorSet; + IStrategy[] strategies; + uint64[] newMagnitudes; + } + + /** + * @notice Parameters used to register for an AVS's operator sets + * @param avs the AVS being registered for + * @param operatorSetIds the operator sets within the AVS to register for + * @param data extra data to be passed to the AVS to complete registration + */ + struct RegisterParams { + address avs; + uint32[] operatorSetIds; + bytes data; + } + + /** + * @notice Parameters used to deregister from an AVS's operator sets + * @param operator the operator being deregistered + * @param avs the avs being deregistered from + * @param operatorSetIds the operator sets within the AVS being deregistered from + */ + struct DeregisterParams { + address operator; + address avs; + uint32[] operatorSetIds; + } + + /** + * @notice Parameters used by an AVS to create new operator sets + * @param operatorSetId the id of the operator set to create + * @param strategies the strategies to add as slashable to the operator set + */ + struct CreateSetParams { + uint32 operatorSetId; + IStrategy[] strategies; + } +} + +interface IAllocationManagerEvents is IAllocationManagerTypes { + /// @notice Emitted when operator updates their allocation delay. + event AllocationDelaySet(address operator, uint32 delay, uint32 effectBlock); + + /// @notice Emitted when an operator's magnitude is updated for a given operatorSet and strategy + event AllocationUpdated( + address operator, OperatorSet operatorSet, IStrategy strategy, uint64 magnitude, uint32 effectBlock + ); + + /// @notice Emitted when operator's encumbered magnitude is updated for a given strategy + event EncumberedMagnitudeUpdated(address operator, IStrategy strategy, uint64 encumberedMagnitude); + + /// @notice Emitted when an operator's max magnitude is updated for a given strategy + event MaxMagnitudeUpdated(address operator, IStrategy strategy, uint64 maxMagnitude); + + /// @notice Emitted when an operator is slashed by an operator set for a strategy + /// `wadSlashed` is the proportion of the operator's total delegated stake that was slashed + event OperatorSlashed( + address operator, OperatorSet operatorSet, IStrategy[] strategies, uint256[] wadSlashed, string description + ); + + /// @notice Emitted when an AVS configures the address that will handle registration/deregistration + event AVSRegistrarSet(address avs, IAVSRegistrar registrar); + + /// @notice Emitted when an AVS updates their metadata URI (Uniform Resource Identifier). + /// @dev The URI is never stored; it is simply emitted through an event for off-chain indexing. + event AVSMetadataURIUpdated(address indexed avs, string metadataURI); + + /// @notice Emitted when an operator set is created by an AVS. + event OperatorSetCreated(OperatorSet operatorSet); + + /// @notice Emitted when an operator is added to an operator set. + event OperatorAddedToOperatorSet(address indexed operator, OperatorSet operatorSet); + + /// @notice Emitted when an operator is removed from an operator set. + event OperatorRemovedFromOperatorSet(address indexed operator, OperatorSet operatorSet); + + /// @notice Emitted when a strategy is added to an operator set. + event StrategyAddedToOperatorSet(OperatorSet operatorSet, IStrategy strategy); + + /// @notice Emitted when a strategy is removed from an operator set. + event StrategyRemovedFromOperatorSet(OperatorSet operatorSet, IStrategy strategy); +} + +interface IAllocationManager is ISignatureUtils, IAllocationManagerErrors, IAllocationManagerEvents { + /** + * @dev Initializes the initial owner and paused status. + */ + function initialize(address initialOwner, uint256 initialPausedStatus) external; + + /** + * @notice Called by an AVS to slash an operator in a given operator set + */ + function slashOperator(address avs, SlashingParams calldata params) external; + + /** + * @notice Modifies the proportions of slashable stake allocated to an operator set from a list of strategies + * Note that deallocations remain slashable for DEALLOCATION_DELAY blocks therefore when they are cleared they may + * free up less allocatable magnitude than initially deallocated. + * @param operator the operator to modify allocations for + * @param params array of magnitude adjustments for one or more operator sets + * @dev Updates encumberedMagnitude for the updated strategies + * @dev msg.sender is used as operator + * @dev If an operator is unaware of a slash that occurs before the modification, the end + * result may be differ from expected + */ + function modifyAllocations(address operator, AllocateParams[] calldata params) external; + + /** + * @notice This function takes a list of strategies and for each strategy, removes from the deallocationQueue + * all clearable deallocations up to max `numToClear` number of deallocations, updating the encumberedMagnitude + * of the operator as needed. + * + * @param operator address to clear deallocations for + * @param strategies a list of strategies to clear deallocations for + * @param numToClear a list of number of pending deallocations to clear for each strategy + * + * @dev can be called permissionlessly by anyone + */ + function clearDeallocationQueue( + address operator, + IStrategy[] calldata strategies, + uint16[] calldata numToClear + ) external; + + /** + * @notice Allows an operator to register for one or more operator sets for an AVS. If the operator + * has any stake allocated to these operator sets, it immediately becomes slashable. + * @dev After registering within the ALM, this method calls `avs.registerOperator` to complete + * registration. This call MUST succeed in order for registration to be successful. + */ + function registerForOperatorSets(address operator, RegisterParams calldata params) external; + + /** + * @notice Allows an operator or AVS to deregister the operator from one or more of the AVS's operator sets. + * If the operator has any slashable stake allocated to the AVS, it remains slashable until the + * DEALLOCATION_DELAY has passed. + * @dev After deregistering within the ALM, this method calls `avs.deregisterOperator` to complete + * deregistration. If this call reverts, it is ignored. + */ + function deregisterFromOperatorSets( + DeregisterParams calldata params + ) external; + + /** + * @notice Called by the delegation manager OR an operator to set an operator's allocation delay. + * This is set when the operator first registers, and is the number of blocks between an operator + * allocating magnitude to an operator set, and the magnitude becoming slashable. + * @param operator The operator to set the delay on behalf of. + * @param delay the allocation delay in blocks + */ + function setAllocationDelay(address operator, uint32 delay) external; + + /** + * @notice Called by an AVS to configure the address that is called when an operator registers + * or is deregistered from the AVS's operator sets. If not set (or set to 0), defaults + * to the AVS's address. + * @param registrar the new registrar address + */ + function setAVSRegistrar(address avs, IAVSRegistrar registrar) external; + + /** + * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated. + * + * @param metadataURI The URI for metadata associated with an AVS. + * + * @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event. + */ + function updateAVSMetadataURI(address avs, string calldata metadataURI) external; + + /** + * @notice Allows an AVS to create new operator sets, defining strategies that the operator set uses + */ + function createOperatorSets(address avs, CreateSetParams[] calldata params) external; + + /** + * @notice Allows an AVS to add strategies to an operator set + * @dev Strategies MUST NOT already exist in the operator set + * @param avs the avs to set strategies for + * @param operatorSetId the operator set to add strategies to + * @param strategies the strategies to add + */ + function addStrategiesToOperatorSet(address avs, uint32 operatorSetId, IStrategy[] calldata strategies) external; + + /** + * @notice Allows an AVS to remove strategies from an operator set + * @dev Strategies MUST already exist in the operator set + * @param avs the avs to remove strategies for + * @param operatorSetId the operator set to remove strategies from + * @param strategies the strategies to remove + */ + function removeStrategiesFromOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external; + + /** + * + * VIEW FUNCTIONS + * + */ + + /** + * @notice Returns the number of operator sets for the AVS + * @param avs the AVS to query + */ + function getOperatorSetCount( + address avs + ) external view returns (uint256); + + /** + * @notice Returns the list of operator sets the operator has current or pending allocations/deallocations in + * @param operator the operator to query + * @return the list of operator sets the operator has current or pending allocations/deallocations in + */ + function getAllocatedSets( + address operator + ) external view returns (OperatorSet[] memory); + + /** + * @notice Returns the list of strategies an operator has current or pending allocations/deallocations from + * given a specific operator set. + * @param operator the operator to query + * @param operatorSet the operator set to query + * @return the list of strategies + */ + function getAllocatedStrategies( + address operator, + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory); + + /** + * @notice Returns the current/pending stake allocation an operator has from a strategy to an operator set + * @param operator the operator to query + * @param operatorSet the operator set to query + * @param strategy the strategy to query + * @return the current/pending stake allocation + */ + function getAllocation( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view returns (Allocation memory); + + /** + * @notice Returns the current/pending stake allocations for multiple operators from a strategy to an operator set + * @param operators the operators to query + * @param operatorSet the operator set to query + * @param strategy the strategy to query + * @return each operator's allocation + */ + function getAllocations( + address[] memory operators, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view returns (Allocation[] memory); + + /** + * @notice Given a strategy, returns a list of operator sets and corresponding stake allocations. + * @dev Note that this returns a list of ALL operator sets the operator has allocations in. This means + * some of the returned allocations may be zero. + * @param operator the operator to query + * @param strategy the strategy to query + * @return the list of all operator sets the operator has allocations for + * @return the corresponding list of allocations from the specific `strategy` + */ + function getStrategyAllocations( + address operator, + IStrategy strategy + ) external view returns (OperatorSet[] memory, Allocation[] memory); + + /** + * @notice For a strategy, get the amount of magnitude not currently allocated to any operator set + * @param operator the operator to query + * @param strategy the strategy to get allocatable magnitude for + * @return magnitude available to be allocated to an operator set + */ + function getAllocatableMagnitude(address operator, IStrategy strategy) external view returns (uint64); + + /** + * @notice Returns the maximum magnitude an operator can allocate for the given strategy + * @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime + * the operator is slashed. This value acts as a cap on the max magnitude of the operator. + * @param operator the operator to query + * @param strategy the strategy to get the max magnitude for + * @return the max magnitude for the strategy + */ + function getMaxMagnitude(address operator, IStrategy strategy) external view returns (uint64); + + /** + * @notice Returns the maximum magnitude an operator can allocate for the given strategies + * @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime + * the operator is slashed. This value acts as a cap on the max magnitude of the operator. + * @param operator the operator to query + * @param strategies the strategies to get the max magnitudes for + * @return the max magnitudes for each strategy + */ + function getMaxMagnitudes( + address operator, + IStrategy[] calldata strategies + ) external view returns (uint64[] memory); + + /** + * @notice Returns the maximum magnitudes each operator can allocate for the given strategy + * @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime + * the operator is slashed. This value acts as a cap on the max magnitude of the operator. + * @param operators the operators to query + * @param strategy the strategy to get the max magnitudes for + * @return the max magnitudes for each operator + */ + function getMaxMagnitudes( + address[] calldata operators, + IStrategy strategy + ) external view returns (uint64[] memory); + + /** + * @notice Returns the maximum magnitude an operator can allocate for the given strategies + * at a given block number + * @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime + * the operator is slashed. This value acts as a cap on the max magnitude of the operator. + * @param operator the operator to query + * @param strategies the strategies to get the max magnitudes for + * @param blockNumber the blockNumber at which to check the max magnitudes + * @return the max magnitudes for each strategy + */ + function getMaxMagnitudesAtBlock( + address operator, + IStrategy[] calldata strategies, + uint32 blockNumber + ) external view returns (uint64[] memory); + + /** + * @notice Returns the time in blocks between an operator allocating slashable magnitude + * and the magnitude becoming slashable. If the delay has not been set, `isSet` will be false. + * @dev The operator must have a configured delay before allocating magnitude + * @param operator The operator to query + * @return isSet Whether the operator has configured a delay + * @return delay The time in blocks between allocating magnitude and magnitude becoming slashable + */ + function getAllocationDelay( + address operator + ) external view returns (bool isSet, uint32 delay); + + /** + * @notice Returns a list of all operator sets the operator is registered for + * @param operator The operator address to query. + */ + function getRegisteredSets( + address operator + ) external view returns (OperatorSet[] memory operatorSets); + + /** + * @notice Returns whether the operator set exists + */ + function isOperatorSet( + OperatorSet memory operatorSet + ) external view returns (bool); + + /** + * @notice Returns all the operators registered to an operator set + * @param operatorSet The operatorSet to query. + */ + function getMembers( + OperatorSet memory operatorSet + ) external view returns (address[] memory operators); + + /** + * @notice Returns the number of operators registered to an operatorSet. + * @param operatorSet The operatorSet to get the member count for + */ + function getMemberCount( + OperatorSet memory operatorSet + ) external view returns (uint256); + + /** + * @notice Returns the address that handles registration/deregistration for the AVS + * If not set, defaults to the input address (`avs`) + */ + function getAVSRegistrar( + address avs + ) external view returns (IAVSRegistrar); + + /** + * @notice Returns an array of strategies in the operatorSet. + * @param operatorSet The operatorSet to query. + */ + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory strategies); + + /** + * @notice Returns the minimum amount of stake that will be slashable as of some future block, + * according to each operator's allocation from each strategy to the operator set. + * @dev This method queries actual delegated stakes in the DelegationManager and applies + * each operator's allocation to the stake to produce the slashable stake each allocation + * represents. + * @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude + * diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true + * minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number + * @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future, + * or the values returned from this method may not be accurate due to deallocations. + * @param operatorSet the operator set to query + * @param operators the list of operators whose slashable stakes will be returned + * @param strategies the strategies that each slashable stake corresponds to + * @param futureBlock the block at which to get allocation information. Should be a future block. + * @return slashableStake a list of slashable stakes, indexed by [operator][strategy] + */ + function getMinimumSlashableStake( + OperatorSet memory operatorSet, + address[] memory operators, + IStrategy[] memory strategies, + uint32 futureBlock + ) external view returns (uint256[][] memory slashableStake); +} diff --git a/src/contracts/interfaces/IBackingEigen.sol b/src/contracts/interfaces/IBackingEigen.sol index 2542d734a..c8e031bd6 100644 --- a/src/contracts/interfaces/IBackingEigen.sol +++ b/src/contracts/interfaces/IBackingEigen.sol @@ -26,7 +26,9 @@ interface IBackingEigen is IERC20 { /** * @notice An initializer function that sets initial values for the contract's state variables. */ - function initialize(address initialOwner) external; + function initialize( + address initialOwner + ) external; // @notice Allows the contract owner to modify an entry in the `isMinter` mapping. function setIsMinter(address minterAddress, bool newStatus) external; @@ -42,7 +44,9 @@ interface IBackingEigen is IERC20 { * * See {ERC20-_burn}. */ - function burn(uint256 amount) external; + function burn( + uint256 amount + ) external; /// @notice the address of the wrapped Eigen token EIGEN function EIGEN() external view returns (IERC20); diff --git a/src/contracts/interfaces/IDelegationFaucet.sol b/src/contracts/interfaces/IDelegationFaucet.sol index 8741208db..5642c1342 100644 --- a/src/contracts/interfaces/IDelegationFaucet.sol +++ b/src/contracts/interfaces/IDelegationFaucet.sol @@ -13,7 +13,9 @@ interface IDelegationFaucet { uint256 _depositAmount ) external; - function getStaker(address operator) external returns (address); + function getStaker( + address operator + ) external returns (address); function depositIntoStrategy( address staker, diff --git a/src/contracts/interfaces/IDelegationManager.sol b/src/contracts/interfaces/IDelegationManager.sol index 2fcb8d03d..80a971367 100644 --- a/src/contracts/interfaces/IDelegationManager.sol +++ b/src/contracts/interfaces/IDelegationManager.sol @@ -2,22 +2,73 @@ pragma solidity >=0.5.0; import "./IStrategy.sol"; +import "./IPauserRegistry.sol"; import "./ISignatureUtils.sol"; +import "../libraries/SlashingLib.sol"; + +interface IDelegationManagerErrors { + /// @dev Thrown when msg.sender is not allowed to call a function + error UnauthorizedCaller(); + /// @dev Thrown when msg.sender is not the EigenPodManager + error OnlyEigenPodManager(); + /// @dev Throw when msg.sender is not the AllocationManager + error OnlyAllocationManager(); + + /// Delegation Status + + /// @dev Thrown when an operator attempts to undelegate. + error OperatorsCannotUndelegate(); + /// @dev Thrown when an account is actively delegated. + error ActivelyDelegated(); + /// @dev Thrown when an account is not actively delegated. + error NotActivelyDelegated(); + /// @dev Thrown when `operator` is not a registered operator. + error OperatorNotRegistered(); + + /// Invalid Inputs + + /// @dev Thrown when attempting to execute an action that was not queued. + error WithdrawalNotQueued(); + /// @dev Thrown when caller cannot undelegate on behalf of a staker. + error CallerCannotUndelegate(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when input arrays length is zero. + error InputArrayLengthZero(); + /// @dev Thrown when caller is neither the StrategyManager or EigenPodManager contract. + error OnlyStrategyManagerOrEigenPodManager(); + + /// Slashing + + /// @dev Thrown when an operator has been fully slashed(maxMagnitude is 0) for a strategy. + /// or if the staker has had been natively slashed to the point of their beaconChainScalingFactor equalling 0. + error FullySlashed(); + + /// Signatures + + /// @dev Thrown when attempting to spend a spent eip-712 salt. + error SaltSpent(); + + /// Withdrawal Processing + + /// @dev Thrown when attempting to execute an action that was not queued. + error WithdrawalDoesNotExist(); + /// @dev Thrown when attempting to withdraw before delay has elapsed. + error WithdrawalDelayNotElapsed(); + /// @dev Thrown when provided delay exceeds maximum. + error WithdrawalDelayExeedsMax(); + /// @dev Thrown when a withdraw amount larger than max is attempted. + error WithdrawalExceedsMax(); + /// @dev Thrown when withdrawer is not the current caller. + error WithdrawerNotCaller(); + /// @dev Thrown when `withdrawer` is not staker. + error WithdrawerNotStaker(); +} -/** - * @title DelegationManager - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are - * - enabling anyone to register as an operator in EigenLayer - * - allowing operators to specify parameters related to stakers who delegate to them - * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time) - * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager) - */ -interface IDelegationManager is ISignatureUtils { +interface IDelegationManagerTypes { // @notice Struct used for storing information about a single operator who has registered with EigenLayer struct OperatorDetails { - /// @notice DEPRECATED -- this field is no longer used, payments are handled in PaymentCoordinator.sol + /// @notice DEPRECATED -- this field is no longer used, payments are handled in RewardsCoordinator.sol address __deprecated_earningsReceiver; /** * @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling "forced undelegations". @@ -27,30 +78,8 @@ interface IDelegationManager is ISignatureUtils { * 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it returns the correct EIP-1271 "magic value". */ address delegationApprover; - /** - * @notice A minimum delay -- measured in blocks -- enforced between: - * 1) the operator signalling their intent to register for a service, via calling `Slasher.optIntoSlashing` - * and - * 2) the operator completing registration for the service, via the service ultimately calling `Slasher.recordFirstStakeUpdate` - * @dev note that for a specific operator, this value *cannot decrease*, i.e. if the operator wishes to modify their OperatorDetails, - * then they are only allowed to either increase this value or keep it the same. - */ - uint32 stakerOptOutWindowBlocks; - } - - /** - * @notice Abstract struct used in calculating an EIP712 signature for a staker to approve that they (the staker themselves) delegate to a specific operator. - * @dev Used in computing the `STAKER_DELEGATION_TYPEHASH` and as a reference in the computation of the stakerDigestHash in the `delegateToBySignature` function. - */ - struct StakerDelegation { - // the staker who is delegating - address staker; - // the operator being delegated to - address operator; - // the staker's nonce - uint256 nonce; - // the expiration timestamp (UTC) of the signature - uint256 expiry; + /// @notice DEPRECATED -- this field is no longer used. An analogous field is the `allocationDelay` stored in the AllocationManager + uint32 __deprecated_stakerOptOutWindowBlocks; } /** @@ -82,28 +111,36 @@ interface IDelegationManager is ISignatureUtils { address withdrawer; // Nonce used to guarantee that otherwise identical withdrawals have unique hashes uint256 nonce; - // Block number when the Withdrawal was created + // Blocknumber when the Withdrawal was created. uint32 startBlock; // Array of strategies that the Withdrawal contains IStrategy[] strategies; - // Array containing the amount of shares in each Strategy in the `strategies` array - uint256[] shares; + // Array containing the amount of staker's scaledShares for withdrawal in each Strategy in the `strategies` array + // Note that these scaledShares need to be multiplied by the operator's maxMagnitude and beaconChainScalingFactor at completion to include + // slashing occurring during the queue withdrawal delay. This is because scaledShares = sharesToWithdraw / (maxMagnitude * beaconChainScalingFactor) + // at queue time. beaconChainScalingFactor is simply equal to 1 if the strategy is not the beaconChainStrategy. + // To account for slashing, we later multiply scaledShares * maxMagnitude * beaconChainScalingFactor at the earliest possible completion time + // to get the withdrawn shares after applying slashing during the delay period. + uint256[] scaledShares; } struct QueuedWithdrawalParams { // Array of strategies that the QueuedWithdrawal contains IStrategy[] strategies; - // Array containing the amount of shares in each Strategy in the `strategies` array - uint256[] shares; + // Array containing the amount of depositShares for withdrawal in each Strategy in the `strategies` array + // Note that the actual shares received on completing withdrawal may be less than the depositShares if slashing occurred + uint256[] depositShares; // The address of the withdrawer address withdrawer; } +} - // @notice Emitted when a new operator registers in EigenLayer and provides their OperatorDetails. - event OperatorRegistered(address indexed operator, OperatorDetails operatorDetails); +interface IDelegationManagerEvents is IDelegationManagerTypes { + // @notice Emitted when a new operator registers in EigenLayer and provides their delegation approver. + event OperatorRegistered(address indexed operator, address delegationApprover); - /// @notice Emitted when an operator updates their OperatorDetails to @param newOperatorDetails - event OperatorDetailsModified(address indexed operator, OperatorDetails newOperatorDetails); + /// @notice Emitted when an operator updates their delegation approver + event DelegationApproverUpdated(address indexed operator, address newDelegationApprover); /** * @notice Emitted when @param operator indicates that they are updating their MetadataURI string @@ -117,6 +154,9 @@ interface IDelegationManager is ISignatureUtils { /// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta in the operator's shares. event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares); + /// @notice Emitted whenever an operator's shares are burned for a given strategy + event OperatorSharesBurned(address indexed operator, IStrategy strategy, uint256 shares); + /// @notice Emitted when @param staker delegates to @param operator. event StakerDelegated(address indexed staker, address indexed operator); @@ -126,25 +166,42 @@ interface IDelegationManager is ISignatureUtils { /// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself event StakerForceUndelegated(address indexed staker, address indexed operator); + /// @notice Emitted when a staker's depositScalingFactor is updated + event DepositScalingFactorUpdated(address staker, IStrategy strategy, uint256 newDepositScalingFactor); + /** * @notice Emitted when a new withdrawal is queued. * @param withdrawalRoot Is the hash of the `withdrawal`. * @param withdrawal Is the withdrawal itself. + * @param sharesToWithdraw Is an array of the expected shares that were queued for withdrawal corresponding to the strategies in the `withdrawal`. */ - event WithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal); + event SlashingWithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal, uint256[] sharesToWithdraw); /// @notice Emitted when a queued withdrawal is completed - event WithdrawalCompleted(bytes32 withdrawalRoot); - - /// @notice Emitted when the `minWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. - event MinWithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue); + event SlashingWithdrawalCompleted(bytes32 withdrawalRoot); +} - /// @notice Emitted when the `strategyWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. - event StrategyWithdrawalDelayBlocksSet(IStrategy strategy, uint256 previousValue, uint256 newValue); +/** + * @title DelegationManager + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are + * - enabling anyone to register as an operator in EigenLayer + * - allowing operators to specify parameters related to stakers who delegate to them + * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time) + * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager) + */ +interface IDelegationManager is ISignatureUtils, IDelegationManagerErrors, IDelegationManagerEvents { + /** + * @dev Initializes the initial owner and paused status. + */ + function initialize(address initialOwner, uint256 initialPausedStatus) external; /** * @notice Registers the caller as an operator in EigenLayer. - * @param registeringOperatorDetails is the `OperatorDetails` for the operator. + * @param initDelegationApprover is an address that, if set, must provide a signature when stakers delegate + * to an operator. + * @param allocationDelay The delay before allocations take effect. * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator. * * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself". @@ -152,37 +209,38 @@ interface IDelegationManager is ISignatureUtils { * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event */ function registerAsOperator( - OperatorDetails calldata registeringOperatorDetails, + address initDelegationApprover, + uint32 allocationDelay, string calldata metadataURI ) external; /** - * @notice Updates an operator's stored `OperatorDetails`. - * @param newOperatorDetails is the updated `OperatorDetails` for the operator, to replace their current OperatorDetails`. + * @notice Updates an operator's stored `delegationApprover`. + * @param operator is the operator to update the delegationApprover for + * @param newDelegationApprover is the new delegationApprover for the operator * * @dev The caller must have previously registered as an operator in EigenLayer. */ - function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external; + function modifyOperatorDetails(address operator, address newDelegationApprover) external; /** * @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated. + * @param operator The operator to update metadata for * @param metadataURI The URI for metadata associated with an operator * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event */ - function updateOperatorMetadataURI(string calldata metadataURI) external; + function updateOperatorMetadataURI(address operator, string calldata metadataURI) external; /** * @notice Caller delegates their stake to an operator. * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer. * @param approverSignatureAndExpiry Verifies the operator approves of this delegation * @param approverSalt A unique single use value tied to an individual signature. - * @dev The approverSignatureAndExpiry is used in the event that: - * 1) the operator's `delegationApprover` address is set to a non-zero value. - * AND - * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator - * or their delegationApprover is the `msg.sender`, then approval is assumed. + * @dev The approverSignatureAndExpiry is used in the event that the operator's `delegationApprover` address is set to a non-zero value. * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input * in this case to save on complexity + gas costs + * @dev If the staker delegating has shares in a strategy that the operator was slashed 100% for (the operator's maxMagnitude = 0), + * then delegation is blocked and will revert. */ function delegateTo( address operator, @@ -191,63 +249,55 @@ interface IDelegationManager is ISignatureUtils { ) external; /** - * @notice Caller delegates a staker's stake to an operator with valid signatures from both parties. - * @param staker The account delegating stake to an `operator` account - * @param operator The account (`staker`) is delegating its assets to for use in serving applications built on EigenLayer. - * @param stakerSignatureAndExpiry Signed data from the staker authorizing delegating stake to an operator - * @param approverSignatureAndExpiry is a parameter that will be used for verifying that the operator approves of this delegation action in the event that: - * @param approverSalt Is a salt used to help guarantee signature uniqueness. Each salt can only be used once by a given approver. - * - * @dev If `staker` is an EOA, then `stakerSignature` is verified to be a valid ECDSA stakerSignature from `staker`, indicating their intention for this action. - * @dev If `staker` is a contract, then `stakerSignature` will be checked according to EIP-1271. - * @dev the operator's `delegationApprover` address is set to a non-zero value. - * @dev neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator or their delegationApprover - * is the `msg.sender`, then approval is assumed. - * @dev This function will revert if the current `block.timestamp` is equal to or exceeds the expiry - * @dev In the case that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input - * in this case to save on complexity + gas costs - */ - function delegateToBySignature( - address staker, - address operator, - SignatureWithExpiry memory stakerSignatureAndExpiry, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external; - - /** - * @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the "undelegation limbo" mode of the EigenPodManager - * and queues a withdrawal of all of the staker's shares in the StrategyManager (to the staker), if necessary. + * @notice Undelegates the staker from the operator who they are delegated to. + * Queues withdrawals of all of the staker's withdrawable shares in the StrategyManager (to the staker) and/or EigenPodManager, if necessary. * @param staker The account to be undelegated. - * @return withdrawalRoot The root of the newly queued withdrawal, if a withdrawal was queued. Otherwise just bytes32(0). + * @return withdrawalRoots The roots of the newly queued withdrawals, if a withdrawal was queued. Otherwise just bytes32(0). * * @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves. * @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover" * @dev Reverts if the `staker` is already undelegated. */ - function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot); + function undelegate( + address staker + ) external returns (bytes32[] memory withdrawalRoots); /** - * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed + * @notice Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from * their operator. * - * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay. + * All withdrawn shares/strategies are placed in a queue and can be withdrawn after a delay. Withdrawals + * are still subject to slashing during the delay period so the amount withdrawn on completion may actually be less + * than what was queued if slashing has occurred in that period. + * + * @dev To view what the staker is able to queue withdraw, see `getWithdrawableShares()` + */ + function queueWithdrawals( + QueuedWithdrawalParams[] calldata params + ) external returns (bytes32[] memory); + + /** + * @notice Used to complete the all queued withdrawals. + * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer` + * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array. + * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean. + * @param numToComplete The number of withdrawals to complete. This must be less than or equal to the number of queued withdrawals. + * @dev See `completeQueuedWithdrawal` for relevant dev tags */ - function queueWithdrawals(QueuedWithdrawalParams[] calldata queuedWithdrawalParams) - external - returns (bytes32[] memory); + function completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) external; /** - * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer` - * @param withdrawal The Withdrawal to complete. + * @notice Used to complete the lastest queued withdrawal. + * @param withdrawal The withdrawal to complete. * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array. - * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused) - * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array - * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves + * @param receiveAsTokens If true, the shares calculated to be withdrawn will be withdrawn from the specified strategies themselves * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies * will simply be transferred to the caller directly. - * @dev middlewareTimesIndex is unused, but will be used in the Slasher eventually * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in * any other strategies, which will be transferred to the withdrawer. @@ -255,181 +305,201 @@ interface IDelegationManager is ISignatureUtils { function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, - uint256 middlewareTimesIndex, bool receiveAsTokens ) external; /** - * @notice Array-ified version of `completeQueuedWithdrawal`. + * @notice Used to complete the all queued withdrawals. * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer` - * @param withdrawals The Withdrawals to complete. + * @param withdrawals Array of Withdrawals to complete. See `completeQueuedWithdrawal` for the usage of a single Withdrawal. * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array. - * @param middlewareTimesIndexes One index to reference per Withdrawal. See `completeQueuedWithdrawal` for the usage of a single index. * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean. * @dev See `completeQueuedWithdrawal` for relevant dev tags */ function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, bool[] calldata receiveAsTokens ) external; /** - * @notice Increases a staker's delegated share balance in a strategy. + * @notice Increases a staker's delegated share balance in a strategy. Note that before adding to operator shares, + * the delegated delegatedShares. The staker's depositScalingFactor is updated here. * @param staker The address to increase the delegated shares for their operator. * @param strategy The strategy in which to increase the delegated shares. - * @param shares The number of shares to increase. + * @param prevDepositShares The number of deposit shares the staker already had in the strategy. This is the shares amount stored in the + * StrategyManager/EigenPodManager for the staker's shares. + * @param addedShares The number of shares added to the staker's shares in the strategy * - * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. + * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated delegatedShares in `strategy`. + * Otherwise does nothing. + * @dev If the operator was slashed 100% for the strategy (the operator's maxMagnitude = 0), then increasing delegated shares is blocked and will revert. * @dev Callable only by the StrategyManager or EigenPodManager. */ - function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; + function increaseDelegatedShares( + address staker, + IStrategy strategy, + uint256 prevDepositShares, + uint256 addedShares + ) external; /** - * @notice Decreases a staker's delegated share balance in a strategy. - * @param staker The address to increase the delegated shares for their operator. - * @param strategy The strategy in which to decrease the delegated shares. - * @param shares The number of shares to decrease. - * - * @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing. - * @dev Callable only by the StrategyManager or EigenPodManager. + * @notice If the staker is delegated, decreases its operator's shares in response to + * a decrease in balance in the beaconChainETHStrategy + * @param staker the staker whose operator's balance will be decreased + * @param curDepositShares the current deposit shares held by the staker + * @param prevBeaconChainSlashingFactor the amount of beacon chain slashing experienced before the balance decrease + * @param wadSlashed the additional slashing experienced by the staker + * @dev Note: `wadSlashed` and `prevBeaconChainSlashingFactor` are assumed to ALWAYS be < 1 WAD. + * These invariants are maintained in the EigenPodManager. */ - function decreaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 prevBeaconChainSlashingFactor, + uint256 wadSlashed + ) external; /** - * @notice Owner-only function for modifying the value of the `minWithdrawalDelayBlocks` variable. - * @param newMinWithdrawalDelayBlocks new value of `minWithdrawalDelayBlocks`. + * @notice Decreases the operators shares in storage after a slash and burns the corresponding Strategy shares + * by calling into the StrategyManager or EigenPodManager to burn the shares. + * @param operator The operator to decrease shares for + * @param strategy The strategy to decrease shares for + * @param prevMaxMagnitude the previous maxMagnitude of the operator + * @param newMaxMagnitude the new maxMagnitude of the operator + * @dev Callable only by the AllocationManager + * @dev Note: Assumes `prevMaxMagnitude <= newMaxMagnitude`. This invariant is maintained in + * the AllocationManager. */ - function setMinWithdrawalDelayBlocks(uint256 newMinWithdrawalDelayBlocks) external; + function burnOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external; /** - * @notice Called by owner to set the minimum withdrawal delay blocks for each passed in strategy - * Note that the min number of blocks to complete a withdrawal of a strategy is - * MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) - * @param strategies The strategies to set the minimum withdrawal delay blocks for - * @param withdrawalDelayBlocks The minimum withdrawal delay blocks to set for each strategy + * + * VIEW FUNCTIONS + * */ - function setStrategyWithdrawalDelayBlocks(IStrategy[] calldata strategies, uint256[] calldata withdrawalDelayBlocks) external; /** * @notice returns the address of the operator that `staker` is delegated to. * @notice Mapping: staker => operator whom the staker is currently delegated to. * @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator. */ - function delegatedTo(address staker) external view returns (address); + function delegatedTo( + address staker + ) external view returns (address); /** - * @notice Returns the OperatorDetails struct associated with an `operator`. + * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover. + * @dev Salts are used in the `delegateTo` function. Note that this function only processes the delegationApprover's + * signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`. */ - function operatorDetails(address operator) external view returns (OperatorDetails memory); + function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool); - /** - * @notice Returns the delegationApprover account for an operator - */ - function delegationApprover(address operator) external view returns (address); + /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. + /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes. + function cumulativeWithdrawalsQueued( + address staker + ) external view returns (uint256); /** - * @notice Returns the stakerOptOutWindowBlocks for an operator + * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. */ - function stakerOptOutWindowBlocks(address operator) external view returns (uint256); + function isDelegated( + address staker + ) external view returns (bool); /** - * @notice Given array of strategies, returns array of shares for the operator + * @notice Returns true is an operator has previously registered for delegation. */ - function getOperatorShares( - address operator, - IStrategy[] memory strategies - ) external view returns (uint256[] memory); + function isOperator( + address operator + ) external view returns (bool); /** - * @notice Given a list of strategies, return the minimum number of blocks that must pass to withdraw - * from all the inputted strategies. Return value is >= minWithdrawalDelayBlocks as this is the global min withdrawal delay. - * @param strategies The strategies to check withdrawal delays for + * @notice Returns the delegationApprover account for an operator */ - function getWithdrawalDelay(IStrategy[] calldata strategies) external view returns (uint256); + function delegationApprover( + address operator + ) external view returns (address); /** - * @notice returns the total number of shares in `strategy` that are delegated to `operator`. - * @notice Mapping: operator => strategy => total number of shares in the strategy delegated to the operator. - * @dev By design, the following invariant should hold for each Strategy: - * (operator's shares in delegation manager) = sum (shares above zero of all stakers delegated to operator) - * = sum (delegateable shares of all stakers delegated to the operator) + * @notice Returns the shares that an operator has delegated to them in a set of strategies + * @param operator the operator to get shares for + * @param strategies the strategies to get shares for */ - function operatorShares(address operator, IStrategy strategy) external view returns (uint256); - + function getOperatorShares( + address operator, + IStrategy[] memory strategies + ) external view returns (uint256[] memory); /** - * @notice Returns the number of actively-delegatable shares a staker has across all strategies. - * @dev Returns two empty arrays in the case that the Staker has no actively-delegateable shares. + * @notice Returns the shares that a set of operators have delegated to them in a set of strategies + * @param operators the operators to get shares for + * @param strategies the strategies to get shares for */ - function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory); + function getOperatorsShares( + address[] memory operators, + IStrategy[] memory strategies + ) external view returns (uint256[][] memory); /** - * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. + * @notice Returns amount of withdrawable shares from an operator for a strategy that is still in the queue + * and therefore slashable. Note that the *actual* slashable amount could be less than this value as this doesn't account + * for amounts that have already been slashed. This assumes that none of the shares have been slashed. + * @param operator the operator to get shares for + * @param strategy the strategy to get shares for + * @return the amount of shares that are slashable in the withdrawal queue for an operator and a strategy */ - function isDelegated(address staker) external view returns (bool); + function getSlashableSharesInQueue(address operator, IStrategy strategy) external view returns (uint256); /** - * @notice Returns true is an operator has previously registered for delegation. + * @notice Given a staker and a set of strategies, return the shares they can queue for withdrawal and the + * corresponding depositShares. + * This value depends on which operator the staker is delegated to. + * The shares amount returned is the actual amount of Strategy shares the staker would receive (subject + * to each strategy's underlying shares to token ratio). */ - function isOperator(address operator) external view returns (bool); - - /// @notice Mapping: staker => number of signed delegation nonces (used in `delegateToBySignature`) from the staker that the contract has already checked - function stakerNonce(address staker) external view returns (uint256); + function getWithdrawableShares( + address staker, + IStrategy[] memory strategies + ) external view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares); /** - * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover. - * @dev Salts are used in the `delegateTo` and `delegateToBySignature` functions. Note that these functions only process the delegationApprover's - * signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`. + * @notice Returns the number of shares in storage for a staker and all their strategies */ - function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool); + function getDepositedShares( + address staker + ) external view returns (IStrategy[] memory, uint256[] memory); /** - * @notice Minimum delay enforced by this contract for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). - * Note that strategies each have a separate withdrawal delay, which can be greater than this value. So the minimum number of blocks that must pass - * to withdraw a strategy is MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) + * @notice Returns the scaling factor applied to a staker's deposits for a given strategy */ - function minWithdrawalDelayBlocks() external view returns (uint256); + function depositScalingFactor(address staker, IStrategy strategy) external view returns (uint256); /** - * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). + * @notice Returns the minimum withdrawal delay in blocks to pass for withdrawals queued to be completable. + * Also applies to legacy withdrawals so any withdrawals not completed prior to the slashing upgrade will be subject + * to this longer delay. */ - function strategyWithdrawalDelayBlocks(IStrategy strategy) external view returns (uint256); + function MIN_WITHDRAWAL_DELAY_BLOCKS() external view returns (uint32); - /// @notice return address of the beaconChainETHStrategy - function beaconChainETHStrategy() external view returns (IStrategy); - - /** - * @notice Calculates the digestHash for a `staker` to sign to delegate to an `operator` - * @param staker The signing staker - * @param operator The operator who is being delegated to - * @param expiry The desired expiry time of the staker's signature - */ - function calculateCurrentStakerDelegationDigestHash( - address staker, - address operator, - uint256 expiry - ) external view returns (bytes32); + /// @notice Returns a list of pending queued withdrawals for a `staker`, and the `shares` to be withdrawn. + function getQueuedWithdrawals( + address staker + ) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares); - /** - * @notice Calculates the digest hash to be signed and used in the `delegateToBySignature` function - * @param staker The signing staker - * @param _stakerNonce The nonce of the staker. In practice we use the staker's current nonce, stored at `stakerNonce[staker]` - * @param operator The operator who is being delegated to - * @param expiry The desired expiry time of the staker's signature - */ - function calculateStakerDelegationDigestHash( - address staker, - uint256 _stakerNonce, - address operator, - uint256 expiry - ) external view returns (bytes32); + /// @notice Returns the keccak256 hash of `withdrawal`. + function calculateWithdrawalRoot( + Withdrawal memory withdrawal + ) external pure returns (bytes32); /** - * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` and `delegateToBySignature` functions. + * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` function. * @param staker The account delegating their stake * @param operator The account receiving delegated stake * @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general) @@ -444,28 +514,9 @@ interface IDelegationManager is ISignatureUtils { uint256 expiry ) external view returns (bytes32); - /// @notice The EIP-712 typehash for the contract's domain - function DOMAIN_TYPEHASH() external view returns (bytes32); - - /// @notice The EIP-712 typehash for the StakerDelegation struct used by the contract - function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32); + /// @notice return address of the beaconChainETHStrategy + function beaconChainETHStrategy() external view returns (IStrategy); /// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32); - - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. - */ - function domainSeparator() external view returns (bytes32); - - /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. - /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes. - function cumulativeWithdrawalsQueued(address staker) external view returns (uint256); - - /// @notice Returns the keccak256 hash of `withdrawal`. - function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32); } diff --git a/src/contracts/interfaces/IEigen.sol b/src/contracts/interfaces/IEigen.sol index 1809902d4..0de79374b 100644 --- a/src/contracts/interfaces/IEigen.sol +++ b/src/contracts/interfaces/IEigen.sol @@ -31,18 +31,16 @@ interface IEigen is IERC20 { /** * @notice This function allows bEIGEN holders to wrap their tokens into Eigen */ - function wrap(uint256 amount) external; + function wrap( + uint256 amount + ) external; /** * @notice This function allows Eigen holders to unwrap their tokens into bEIGEN */ - function unwrap(uint256 amount) external; - - // @notice Burns EIGEN tokens held by the EIGEN token address itself - function burnExtraTokens() external; - - /// @notice the address of the backing Eigen token bEIGEN - function bEIGEN() external view returns (IERC20); + function unwrap( + uint256 amount + ) external; /** * @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based diff --git a/src/contracts/interfaces/IEigenPod.sol b/src/contracts/interfaces/IEigenPod.sol index be96da52c..ec4f524b4 100644 --- a/src/contracts/interfaces/IEigenPod.sol +++ b/src/contracts/interfaces/IEigenPod.sol @@ -1,23 +1,76 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + import "../libraries/BeaconChainProofs.sol"; import "./IEigenPodManager.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -/** - * @title The implementation contract used for restaking beacon chain ETH on EigenLayer - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose - * to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts - */ -interface IEigenPod { - /** - * - * STRUCTS / ENUMS - * - */ +interface IEigenPodErrors { + /// @dev Thrown when msg.sender is not the EPM. + error OnlyEigenPodManager(); + /// @dev Thrown when msg.sender is not the pod owner. + error OnlyEigenPodOwner(); + /// @dev Thrown when msg.sender is not owner or the proof submitter. + error OnlyEigenPodOwnerOrProofSubmitter(); + /// @dev Thrown when attempting an action that is currently paused. + error CurrentlyPaused(); + + /// Invalid Inputs + + /// @dev Thrown when an address of zero is provided. + error InputAddressZero(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when `validatorPubKey` length is not equal to 48-bytes. + error InvalidPubKeyLength(); + /// @dev Thrown when provided timestamp is out of range. + error TimestampOutOfRange(); + + /// Checkpoints + + /// @dev Thrown when no active checkpoints are found. + error NoActiveCheckpoint(); + /// @dev Thrown if an uncompleted checkpoint exists. + error CheckpointAlreadyActive(); + /// @dev Thrown if there's not a balance available to checkpoint. + error NoBalanceToCheckpoint(); + /// @dev Thrown when attempting to create a checkpoint twice within a given block. + error CannotCheckpointTwiceInSingleBlock(); + + /// Withdrawing + + /// @dev Thrown when amount exceeds `restakedExecutionLayerGwei`. + error InsufficientWithdrawableBalance(); + /// @dev Thrown when provided `amountGwei` is not a multiple of gwei. + error AmountMustBeMultipleOfGwei(); + + /// Validator Status + + /// @dev Thrown when a validator's withdrawal credentials have already been verified. + error CredentialsAlreadyVerified(); + /// @dev Thrown if the provided proof is not valid for this EigenPod. + error WithdrawalCredentialsNotForEigenPod(); + /// @dev Thrown when a validator is not in the ACTIVE status in the pod. + error ValidatorNotActiveInPod(); + /// @dev Thrown when validator is not active yet on the beacon chain. + error ValidatorInactiveOnBeaconChain(); + /// @dev Thrown if a validator is exiting the beacon chain. + error ValidatorIsExitingBeaconChain(); + /// @dev Thrown when a validator has not been slashed on the beacon chain. + error ValidatorNotSlashedOnBeaconChain(); + + /// Misc + + /// @dev Thrown when an invalid block root is returned by the EIP-4788 oracle. + error InvalidEIP4788Response(); + /// @dev Thrown when attempting to send an invalid amount to the beacon deposit contract. + error MsgValueNot32ETH(); + /// @dev Thrown when provided `beaconTimestamp` is too far in the past. + error BeaconTimestampTooFarInPast(); +} + +interface IEigenPodTypes { enum VALIDATOR_STATUS { INACTIVE, // doesnt exist ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod @@ -40,15 +93,12 @@ interface IEigenPod { bytes32 beaconBlockRoot; uint24 proofsRemaining; uint64 podBalanceGwei; - int128 balanceDeltasGwei; + int64 balanceDeltasGwei; + uint64 prevBeaconBalanceGwei; } +} - /** - * - * EVENTS - * - */ - +interface IEigenPodEvents is IEigenPodTypes { /// @notice Emitted when an ETH validator stakes via this eigenPod event EigenPodStaked(bytes pubkey); @@ -81,15 +131,20 @@ interface IEigenPod { /// @notice Emitted when a validaor is proven to have 0 balance at a given checkpoint event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex); +} - /** - * - * EXTERNAL STATE-CHANGING METHODS - * - */ - +/** + * @title The implementation contract used for restaking beacon chain ETH on EigenLayer + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose + * to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts + */ +interface IEigenPod is IEigenPodErrors, IEigenPodEvents { /// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager - function initialize(address owner) external; + function initialize( + address owner + ) external; /// @notice Called by EigenPodManager when the owner wants to create another ETH validator. function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable; @@ -97,7 +152,7 @@ interface IEigenPod { /** * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain. - * @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `withdrawableRestakedExecutionLayerGwei` exceeds the + * @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `restakedExecutionLayerGwei` exceeds the * `amountWei` input (when converted to GWEI). * @dev Reverts if `amountWei` is not a whole Gwei amount */ @@ -115,7 +170,9 @@ interface IEigenPod { * @param revertIfNoBalance Forces a revert if the pod ETH balance is 0. This allows the pod owner * to prevent accidentally starting a checkpoint that will not increase their shares */ - function startCheckpoint(bool revertIfNoBalance) external; + function startCheckpoint( + bool revertIfNoBalance + ) external; /** * @dev Progress the current checkpoint towards completion by submitting one or more validator @@ -200,7 +257,9 @@ interface IEigenPod { /// only address that can call these methods. /// @param newProofSubmitter The new proof submitter address. If set to 0, only the /// pod owner will be able to call `startCheckpoint` and `verifyWithdrawalCredentials` - function setProofSubmitter(address newProofSubmitter) external; + function setProofSubmitter( + address newProofSubmitter + ) external; /** * @@ -224,16 +283,24 @@ interface IEigenPod { function podOwner() external view returns (address); /// @notice Returns the validatorInfo struct for the provided pubkeyHash - function validatorPubkeyHashToInfo(bytes32 validatorPubkeyHash) external view returns (ValidatorInfo memory); + function validatorPubkeyHashToInfo( + bytes32 validatorPubkeyHash + ) external view returns (ValidatorInfo memory); /// @notice Returns the validatorInfo struct for the provided pubkey - function validatorPubkeyToInfo(bytes calldata validatorPubkey) external view returns (ValidatorInfo memory); + function validatorPubkeyToInfo( + bytes calldata validatorPubkey + ) external view returns (ValidatorInfo memory); /// @notice This returns the status of a given validator - function validatorStatus(bytes32 pubkeyHash) external view returns (VALIDATOR_STATUS); + function validatorStatus( + bytes32 pubkeyHash + ) external view returns (VALIDATOR_STATUS); /// @notice This returns the status of a given validator pubkey - function validatorStatus(bytes calldata validatorPubkey) external view returns (VALIDATOR_STATUS); + function validatorStatus( + bytes calldata validatorPubkey + ) external view returns (VALIDATOR_STATUS); /// @notice Number of validators with proven withdrawal credentials, who do not have proven full withdrawals function activeValidatorCount() external view returns (uint256); @@ -275,11 +342,15 @@ interface IEigenPod { /// - The final partial withdrawal for an exited validator will be likely be included in this mapping. /// i.e. if a validator was last checkpointed at 32.1 ETH before exiting, the next checkpoint will calculate their /// "exited" amount to be 32.1 ETH rather than 32 ETH. - function checkpointBalanceExitedGwei(uint64) external view returns (uint64); + function checkpointBalanceExitedGwei( + uint64 + ) external view returns (uint64); /// @notice Query the 4788 oracle to get the parent block root of the slot with the given `timestamp` /// @param timestamp of the block for which the parent block root will be returned. MUST correspond /// to an existing slot within the last 24 hours. If the slot at `timestamp` was skipped, this method /// will revert. - function getParentBlockRoot(uint64 timestamp) external view returns (bytes32); + function getParentBlockRoot( + uint64 timestamp + ) external view returns (bytes32); } diff --git a/src/contracts/interfaces/IEigenPodManager.sol b/src/contracts/interfaces/IEigenPodManager.sol index cbe253382..dfc46219b 100644 --- a/src/contracts/interfaces/IEigenPodManager.sol +++ b/src/contracts/interfaces/IEigenPodManager.sol @@ -5,16 +5,29 @@ import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; import "./IETHPOSDeposit.sol"; import "./IStrategyManager.sol"; import "./IEigenPod.sol"; +import "./IShareManager.sol"; import "./IPausable.sol"; -import "./ISlasher.sol"; import "./IStrategy.sol"; -/** - * @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - */ -interface IEigenPodManager is IPausable { +interface IEigenPodManagerErrors { + /// @dev Thrown when caller is not a EigenPod. + error OnlyEigenPod(); + /// @dev Thrown when caller is not DelegationManager. + error OnlyDelegationManager(); + /// @dev Thrown when caller already has an EigenPod. + error EigenPodAlreadyExists(); + /// @dev Thrown when shares is not a multiple of gwei. + error SharesNotMultipleOfGwei(); + /// @dev Thrown when shares would result in a negative integer. + error SharesNegative(); + /// @dev Thrown when the strategy is not the beaconChainETH strategy. + error InvalidStrategy(); + /// @dev Thrown when the pods shares are negative and a beacon chain balance update is attempted. + /// The podOwner should complete legacy withdrawal first. + error LegacyWithdrawalsNotCompleted(); +} + +interface IEigenPodManagerEvents { /// @notice Emitted to notify the deployment of an EigenPod event PodDeployed(address indexed eigenPod, address indexed podOwner); @@ -37,6 +50,38 @@ interface IEigenPodManager is IPausable { bytes32 withdrawalRoot ); + /// @notice Emitted when a staker's beaconChainSlashingFactor is updated + event BeaconChainSlashingFactorDecreased(address staker, uint256 wadSlashed, uint64 newBeaconChainSlashingFactor); +} + +interface IEigenPodManagerTypes { + /** + * @notice The amount of beacon chain slashing experienced by a pod owner as a proportion of WAD + * @param isSet whether the slashingFactor has ever been updated. Used to distinguish between + * a value of "0" and an uninitialized value. + * @param slashingFactor the proportion of the pod owner's balance that has been decreased due to + * slashing or other beacon chain balance decreases. + * @dev NOTE: if !isSet, `slashingFactor` should be treated as WAD. `slashingFactor` is monotonically + * decreasing and can hit 0 if fully slashed. + */ + struct BeaconChainSlashingFactor { + bool isSet; + uint64 slashingFactor; + } +} + +/** + * @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + */ +interface IEigenPodManager is + IEigenPodManagerErrors, + IEigenPodManagerEvents, + IEigenPodManagerTypes, + IShareManager, + IPausable +{ /** * @notice Creates an EigenPod for the sender. * @dev Function will revert if the `msg.sender` already has an EigenPod. @@ -57,17 +102,26 @@ interface IEigenPodManager is IPausable { * @notice Changes the `podOwner`'s shares by `sharesDelta` and performs a call to the DelegationManager * to ensure that delegated shares are also tracked correctly * @param podOwner is the pod owner whose balance is being updated. - * @param sharesDelta is the change in podOwner's beaconChainETHStrategy shares + * @param prevRestakedBalanceWei is the total amount restaked through the pod before the balance update + * @param balanceDeltaWei is the amount the balance changed * @dev Callable only by the podOwner's EigenPod contract. * @dev Reverts if `sharesDelta` is not a whole Gwei amount */ - function recordBeaconChainETHBalanceUpdate(address podOwner, int256 sharesDelta) external; + function recordBeaconChainETHBalanceUpdate( + address podOwner, + uint256 prevRestakedBalanceWei, + int256 balanceDeltaWei + ) external; /// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed. - function ownerToPod(address podOwner) external view returns (IEigenPod); + function ownerToPod( + address podOwner + ) external view returns (IEigenPod); /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not). - function getPod(address podOwner) external view returns (IEigenPod); + function getPod( + address podOwner + ) external view returns (IEigenPod); /// @notice The ETH2 Deposit Contract function ethPOS() external view returns (IETHPOSDeposit); @@ -78,11 +132,10 @@ interface IEigenPodManager is IPausable { /// @notice EigenLayer's StrategyManager contract function strategyManager() external view returns (IStrategyManager); - /// @notice EigenLayer's Slasher contract - function slasher() external view returns (ISlasher); - /// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise. - function hasPod(address podOwner) external view returns (bool); + function hasPod( + address podOwner + ) external view returns (bool); /// @notice Returns the number of EigenPods that have been created function numPods() external view returns (uint256); @@ -95,34 +148,18 @@ interface IEigenPodManager is IPausable { * Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We can think of this * as the withdrawal "paying off the deficit". */ - function podOwnerShares(address podOwner) external view returns (int256); + function podOwnerDepositShares( + address podOwner + ) external view returns (int256); /// @notice returns canonical, virtual beaconChainETH strategy function beaconChainETHStrategy() external view returns (IStrategy); /** - * @notice Used by the DelegationManager to remove a pod owner's shares while they're in the withdrawal queue. - * Simply decreases the `podOwner`'s shares by `shares`, down to a minimum of zero. - * @dev This function reverts if it would result in `podOwnerShares[podOwner]` being less than zero, i.e. it is forbidden for this function to - * result in the `podOwner` incurring a "share deficit". This behavior prevents a Staker from queuing a withdrawal which improperly removes excessive - * shares from the operator to whom the staker is delegated. - * @dev Reverts if `shares` is not a whole Gwei amount - */ - function removeShares(address podOwner, uint256 shares) external; - - /** - * @notice Increases the `podOwner`'s shares by `shares`, paying off deficit if possible. - * Used by the DelegationManager to award a pod owner shares on exiting the withdrawal queue - * @dev Returns the number of shares added to `podOwnerShares[podOwner]` above zero, which will be less than the `shares` input - * in the event that the podOwner has an existing shares deficit (i.e. `podOwnerShares[podOwner]` starts below zero) - * @dev Reverts if `shares` is not a whole Gwei amount - */ - function addShares(address podOwner, uint256 shares) external returns (uint256); - - /** - * @notice Used by the DelegationManager to complete a withdrawal, sending tokens to some destination address - * @dev Prioritizes decreasing the podOwner's share deficit, if they have one - * @dev Reverts if `shares` is not a whole Gwei amount + * @notice Returns the historical sum of proportional balance decreases a pod owner has experienced when + * updating their pod's balance. */ - function withdrawSharesAsTokens(address podOwner, address destination, uint256 shares) external; + function beaconChainSlashingFactor( + address staker + ) external view returns (uint64); } diff --git a/src/contracts/interfaces/IPausable.sol b/src/contracts/interfaces/IPausable.sol index 061712653..d152df371 100644 --- a/src/contracts/interfaces/IPausable.sol +++ b/src/contracts/interfaces/IPausable.sol @@ -20,8 +20,16 @@ import "../interfaces/IPauserRegistry.sol"; * indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused */ interface IPausable { - /// @notice Emitted when the `pauserRegistry` is set to `newPauserRegistry`. - event PauserRegistrySet(IPauserRegistry pauserRegistry, IPauserRegistry newPauserRegistry); + /// @dev Thrown when caller is not pauser. + error OnlyPauser(); + /// @dev Thrown when caller is not unpauser. + error OnlyUnpauser(); + /// @dev Thrown when currently paused. + error CurrentlyPaused(); + /// @dev Thrown when invalid `newPausedStatus` is provided. + error InvalidNewPausedStatus(); + /// @dev Thrown when a null address input is provided. + error InputAddressZero(); /// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`. event Paused(address indexed account, uint256 newPausedStatus); @@ -38,7 +46,9 @@ interface IPausable { * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once. * @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0. */ - function pause(uint256 newPausedStatus) external; + function pause( + uint256 newPausedStatus + ) external; /** * @notice Alias for `pause(type(uint256).max)`. @@ -51,14 +61,15 @@ interface IPausable { * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once. * @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1. */ - function unpause(uint256 newPausedStatus) external; + function unpause( + uint256 newPausedStatus + ) external; /// @notice Returns the current paused status as a uint256. function paused() external view returns (uint256); /// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise - function paused(uint8 index) external view returns (bool); - - /// @notice Allows the unpauser to set a new pauser registry - function setPauserRegistry(IPauserRegistry newPauserRegistry) external; + function paused( + uint8 index + ) external view returns (bool); } diff --git a/src/contracts/interfaces/IPauserRegistry.sol b/src/contracts/interfaces/IPauserRegistry.sol index cd0b95546..e20fd77a7 100644 --- a/src/contracts/interfaces/IPauserRegistry.sol +++ b/src/contracts/interfaces/IPauserRegistry.sol @@ -7,12 +7,17 @@ pragma solidity >=0.5.0; * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface IPauserRegistry { + error OnlyUnpauser(); + error InputAddressZero(); + event PauserStatusChanged(address pauser, bool canPause); event UnpauserChanged(address previousUnpauser, address newUnpauser); /// @notice Mapping of addresses to whether they hold the pauser role. - function isPauser(address pauser) external view returns (bool); + function isPauser( + address pauser + ) external view returns (bool); /// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses. function unpauser() external view returns (address); diff --git a/src/contracts/interfaces/IPermissionController.sol b/src/contracts/interfaces/IPermissionController.sol new file mode 100644 index 000000000..5d4be806d --- /dev/null +++ b/src/contracts/interfaces/IPermissionController.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +interface IPermissionControllerErrors { + /// @notice Thrown when the caller is not the admin + error NotAdmin(); + /// @notice Thrown when the admin to remove is not an admin + error AdminNotSet(); + /// @notice Thrown when an appointee is already set for the account's function + error AppointeeAlreadySet(); + /// @notice Thrown when an appointee is not set for the account's function + error AppointeeNotSet(); + /// @notice Thrown when the account attempts to remove the only admin + error CannotHaveZeroAdmins(); + /// @notice Thrown when an admin is already set + error AdminAlreadySet(); + /// @notice Thrown when an admin is not pending + error AdminNotPending(); + /// @notice Thrown when an admin is already pending + error AdminAlreadyPending(); +} + +interface IPermissionControllerEvents { + /// @notice Emitted when an appointee is set + event AppointeeSet(address indexed account, address indexed appointee, address target, bytes4 selector); + + /// @notice Emitted when an appointee is revoked + event AppointeeRemoved(address indexed account, address indexed appointee, address target, bytes4 selector); + + /// @notice Emitted when an admin is set as pending for an account + event PendingAdminAdded(address indexed account, address admin); + + /// @notice Emitted when an admin is removed as pending for an account + event PendingAdminRemoved(address indexed account, address admin); + + /// @notice Emitted when an admin is set for a given account + event AdminSet(address indexed account, address admin); + + /// @notice Emitted when an admin is removed for a given account + event AdminRemoved(address indexed account, address admin); +} + +interface IPermissionController is IPermissionControllerErrors, IPermissionControllerEvents { + /** + * @notice Sets a pending admin of an account + * @param account to set pending admin for + * @param admin to set + * @dev Multiple admins can be set for an account + */ + function addPendingAdmin(address account, address admin) external; + + /** + * @notice Removes a pending admin of an account + * @param account to remove pending admin for + * @param admin to remove + * @dev Only the admin of the account can remove a pending admin + */ + function removePendingAdmin(address account, address admin) external; + + /** + * @notice Accepts the admin role of an account + * @param account to accept admin for + * @dev Only a pending admin for the account can become an admin + */ + function acceptAdmin( + address account + ) external; + + /** + * @notice Remove an admin of an account + * @param account to remove admin for + * @param admin to remove + * @dev Only the admin of the account can remove an admin + * @dev Reverts when an admin is removed such that no admins are remaining + */ + function removeAdmin(address account, address admin) external; + + /** + * @notice Set an appointee for a given account + * @param account to set appointee for + * @param appointee to set + * @param target to set appointee for + * @param selector to set appointee for + * @dev Only the admin of the account can set an appointee + */ + function setAppointee(address account, address appointee, address target, bytes4 selector) external; + + /** + * Removes an appointee for a given account + * @param account to remove appointee for + * @param appointee to remove + * @param target to remove appointee for + * @param selector to remove appointee for + * @dev Only the admin of the account can remove an appointee + */ + function removeAppointee(address account, address appointee, address target, bytes4 selector) external; + + /** + * @notice Checks if the given caller is an admin of the account + * @dev If the account has no admin, the caller is checked to be the account itself + */ + function isAdmin(address account, address caller) external view returns (bool); + + /** + * @notice Checks if the `pendingAdmin` is a pending admin of the `account` + */ + function isPendingAdmin(address account, address pendingAdmin) external view returns (bool); + + /** + * @notice Get the admins of an account + * @param account The account to get the admin of + * @dev If the account has no admin, the account itself is returned + */ + function getAdmins( + address account + ) external view returns (address[] memory); + + /** + * @notice Get the pending admins of an account + * @param account The account to get the pending admin of + */ + function getPendingAdmins( + address account + ) external view returns (address[] memory); + + /** + * @notice Checks if the given caller has permissions to call the fucntion + * @param account to check + * @param caller to check permission for + * @param target to check permission for + * @param selector to check permission for + * @dev Returns `true` if the admin OR the appointee is the caller + */ + function canCall(address account, address caller, address target, bytes4 selector) external returns (bool); + + /** + * @notice Gets the list of permissions of an appointee for a given account + * @param account to get appointee permissions for + * @param appointee to get permissions + */ + function getAppointeePermissions( + address account, + address appointee + ) external returns (address[] memory, bytes4[] memory); + + /** + * @notice Returns the list of appointees for a given account and function + * @param account to get appointees for + * @param target to get appointees for + * @param selector to get appointees for + * @dev Does NOT include admin as an appointee, even though it can call + */ + function getAppointees(address account, address target, bytes4 selector) external returns (address[] memory); +} diff --git a/src/contracts/interfaces/IRewardsCoordinator.sol b/src/contracts/interfaces/IRewardsCoordinator.sol index 933758618..785afc851 100644 --- a/src/contracts/interfaces/IRewardsCoordinator.sol +++ b/src/contracts/interfaces/IRewardsCoordinator.sol @@ -1,20 +1,78 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./IPauserRegistry.sol"; import "./IStrategy.sol"; -/** - * @title Interface for the `IRewardsCoordinator` contract. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice Allows AVSs to make "Rewards Submissions", which get distributed amongst the AVSs' confirmed - * Operators and the Stakers delegated to those Operators. - * Calculations are performed based on the completed RewardsSubmission, with the results posted in - * a Merkle root against which Stakers & Operators can make claims. - */ -interface IRewardsCoordinator { - /// STRUCTS /// +interface IRewardsCoordinatorErrors { + /// @dev Thrown when msg.sender is not allowed to call a function + error UnauthorizedCaller(); + /// @dev Thrown when a earner not an AVS or Operator + error InvalidEarner(); + + /// Invalid Inputs + + /// @dev Thrown when an invalid root is provided. + error InvalidRoot(); + /// @dev Thrown when an invalid root index is provided. + error InvalidRootIndex(); + /// @dev Thrown when input arrays length is zero. + error InputArrayLengthZero(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when provided root is not for new calculated period. + error NewRootMustBeForNewCalculatedPeriod(); + /// @dev Thrown when rewards end timestamp has not elapsed. + error RewardsEndTimestampNotElapsed(); + + /// Rewards Submissions + + /// @dev Thrown when input `amount` is zero. + error AmountIsZero(); + /// @dev Thrown when input `amount` exceeds maximum. + error AmountExceedsMax(); + /// @dev Thrown when input `duration` exceeds maximum. + error DurationExceedsMax(); + /// @dev Thrown when input `duration` is not evenly divisble by CALCULATION_INTERVAL_SECONDS. + error InvalidDurationRemainder(); + /// @dev Thrown when GENESIS_REWARDS_TIMESTAMP is not evenly divisble by CALCULATION_INTERVAL_SECONDS. + error InvalidGenesisRewardsTimestampRemainder(); + /// @dev Thrown when CALCULATION_INTERVAL_SECONDS is not evenly divisble by SNAPSHOT_CADENCE. + error InvalidCalculationIntervalSecondsRemainder(); + /// @dev Thrown when `startTimestamp` is not evenly divisble by CALCULATION_INTERVAL_SECONDS. + error InvalidStartTimestampRemainder(); + /// @dev Thrown when `startTimestamp` is too far in the future. + error StartTimestampTooFarInFuture(); + /// @dev Thrown when `startTimestamp` is too far in the past. + error StartTimestampTooFarInPast(); + /// @dev Thrown when an attempt to use a non-whitelisted strategy is made. + error StrategyNotWhitelisted(); + /// @dev Thrown when `strategies` is not sorted in ascending order. + error StrategiesNotInAscendingOrder(); + + /// Claims + + /// @dev Thrown when an invalid earner claim proof is provided. + error InvalidClaimProof(); + /// @dev Thrown when an invalid token leaf index is provided. + error InvalidTokenLeafIndex(); + /// @dev Thrown when an invalid earner leaf index is provided. + error InvalidEarnerLeafIndex(); + /// @dev Thrown when cummulative earnings are not greater than cummulative claimed. + error EarningsNotGreaterThanClaimed(); + + /// Reward Root Checks + + /// @dev Thrown if a root has already been disabled. + error RootDisabled(); + /// @dev Thrown if a root has not been activated yet. + error RootNotActivated(); + /// @dev Thrown if a root has already been activated. + error RootAlreadyActivated(); +} + +interface IRewardsCoordinatorTypes { /** * @notice A linear combination of strategies and multipliers for AVSs to weigh * EigenLayer strategies. @@ -126,9 +184,9 @@ interface IRewardsCoordinator { bytes[] tokenTreeProofs; TokenTreeMerkleLeaf[] tokenLeaves; } +} - /// EVENTS /// - +interface IRewardsCoordinatorEvents is IRewardsCoordinatorTypes { /// @notice emitted when an AVS creates a valid RewardsSubmission event AVSRewardsSubmissionCreated( address indexed avs, @@ -136,6 +194,7 @@ interface IRewardsCoordinator { bytes32 indexed rewardsSubmissionHash, RewardsSubmission rewardsSubmission ); + /// @notice emitted when a valid RewardsSubmission is created for all stakers by a valid submitter event RewardsSubmissionForAllCreated( address indexed submitter, @@ -143,6 +202,7 @@ interface IRewardsCoordinator { bytes32 indexed rewardsSubmissionHash, RewardsSubmission rewardsSubmission ); + /// @notice emitted when a valid RewardsSubmission is created when rewardAllStakersAndOperators is called event RewardsSubmissionForAllEarnersCreated( address indexed tokenHopper, @@ -150,14 +210,20 @@ interface IRewardsCoordinator { bytes32 indexed rewardsSubmissionHash, RewardsSubmission rewardsSubmission ); + /// @notice rewardsUpdater is responsible for submiting DistributionRoots, only owner can set rewardsUpdater event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater); + event RewardsForAllSubmitterSet( address indexed rewardsForAllSubmitter, bool indexed oldValue, bool indexed newValue ); + event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay); + event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips); + event ClaimerForSet(address indexed earner, address indexed oldClaimer, address indexed claimer); + /// @notice rootIndex is the specific array index of the newly created root in the storage array event DistributionRootSubmitted( uint32 indexed rootIndex, @@ -165,7 +231,9 @@ interface IRewardsCoordinator { uint32 indexed rewardsCalculationEndTimestamp, uint32 activatedAt ); + event DistributionRootDisabled(uint32 indexed rootIndex); + /// @notice root is one of the submitted distribution roots that was claimed against event RewardsClaimed( bytes32 root, @@ -175,84 +243,29 @@ interface IRewardsCoordinator { IERC20 token, uint256 claimedAmount ); +} +/** + * @title Interface for the `IRewardsCoordinator` contract. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice Allows AVSs to make "Rewards Submissions", which get distributed amongst the AVSs' confirmed + * Operators and the Stakers delegated to those Operators. + * Calculations are performed based on the completed RewardsSubmission, with the results posted in + * a Merkle root against which Stakers & Operators can make claims. + */ +interface IRewardsCoordinator is IRewardsCoordinatorErrors, IRewardsCoordinatorEvents { /** - * - * VIEW FUNCTIONS - * - */ - - /// @notice The address of the entity that can update the contract with new merkle roots - function rewardsUpdater() external view returns (address); - - /** - * @notice The interval in seconds at which the calculation for a RewardsSubmission distribution is done. - * @dev Rewards Submission durations must be multiples of this interval. - */ - function CALCULATION_INTERVAL_SECONDS() external view returns (uint32); - - /// @notice The maximum amount of time (seconds) that a RewardsSubmission can span over - function MAX_REWARDS_DURATION() external view returns (uint32); - - /// @notice max amount of time (seconds) that a submission can start in the past - function MAX_RETROACTIVE_LENGTH() external view returns (uint32); - - /// @notice max amount of time (seconds) that a submission can start in the future - function MAX_FUTURE_LENGTH() external view returns (uint32); - - /// @notice absolute min timestamp (seconds) that a submission can start at - function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32); - - /// @notice Delay in timestamp (seconds) before a posted root can be claimed against - function activationDelay() external view returns (uint32); - - /// @notice Mapping: earner => the address of the entity who can call `processClaim` on behalf of the earner - function claimerFor(address earner) external view returns (address); - - /// @notice Mapping: claimer => token => total amount claimed - function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256); - - /// @notice the commission for all operators across all avss - function globalOperatorCommissionBips() external view returns (uint16); - - /// @notice the commission for a specific operator for a specific avs - /// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release - function operatorCommissionBips(address operator, address avs) external view returns (uint16); - - /// @notice return the hash of the earner's leaf - function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) external pure returns (bytes32); - - /// @notice returns the hash of the earner's token leaf - function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) external pure returns (bytes32); - - /// @notice returns 'true' if the claim would currently pass the check in `processClaims` - /// but will revert if not valid - function checkClaim(RewardsMerkleClaim calldata claim) external view returns (bool); - - /// @notice The timestamp until which RewardsSubmissions have been calculated - function currRewardsCalculationEndTimestamp() external view returns (uint32); - - /// @notice returns the number of distribution roots posted - function getDistributionRootsLength() external view returns (uint256); - - /// @notice returns the distributionRoot at the specified index - function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory); - - /// @notice returns the current distributionRoot - function getCurrentDistributionRoot() external view returns (DistributionRoot memory); - - /// @notice loop through the distribution roots from reverse and get latest root that is not disabled and activated - /// i.e. a root that can be claimed against - function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory); - - /// @notice loop through distribution roots from reverse and return index from hash - function getRootIndexFromHash(bytes32 rootHash) external view returns (uint32); - - /** - * - * EXTERNAL FUNCTIONS - * + * @dev Initializes the addresses of the initial owner, rewardsUpdater, and + * configures the initial paused status, activationDelay, and globalOperatorCommissionBips. */ + function initialize( + address initialOwner, + uint256 initialPausedStatus, + address _rewardsUpdater, + uint32 _activationDelay, + uint16 _globalCommissionBips + ) external; /** * @notice Creates a new rewards submission on behalf of an AVS, to be split amongst the @@ -265,15 +278,17 @@ interface IRewardsCoordinator { * @dev This function will revert if the `rewardsSubmission` is malformed, * e.g. if the `strategies` and `weights` arrays are of non-equal lengths */ - function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external; + function createAVSRewardsSubmission(address avs, RewardsSubmission[] calldata rewardsSubmissions) external; /** * @notice similar to `createAVSRewardsSubmission` except the rewards are split amongst *all* stakers * rather than just those delegated to operators who are registered to a single avs and is * a permissioned call based on isRewardsForAllSubmitter mapping. - * @param rewardsSubmission The rewards submission being created + * @param rewardsSubmissions The rewards submissions being created */ - function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmission) external; + function createRewardsForAllSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external; /** * @notice Creates a new rewards submission for all earners across all AVSs. @@ -282,7 +297,9 @@ interface IRewardsCoordinator { * by the token hopper contract from the Eigen Foundation * @param rewardsSubmissions The rewards submissions being created */ - function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) external; + function createRewardsForAllEarners( + RewardsSubmission[] calldata rewardsSubmissions + ) external; /** * @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]). @@ -310,35 +327,54 @@ interface IRewardsCoordinator { * @notice allow the rewardsUpdater to disable/cancel a pending root submission in case of an error * @param rootIndex The index of the root to be disabled */ - function disableRoot(uint32 rootIndex) external; + function disableRoot( + uint32 rootIndex + ) external; /** - * @notice Sets the address of the entity that can call `processClaim` on behalf of the earner (msg.sender) + * @notice Sets the address of the entity that can call `processClaim` on ehalf of an earner * @param claimer The address of the entity that can call `processClaim` on behalf of the earner - * @dev Only callable by the `earner` + * @dev Assumes msg.sender is the earner */ - function setClaimerFor(address claimer) external; + function setClaimerFor( + address claimer + ) external; + + /** + * @notice Sets the address of the entity that can call `processClaim` on behalf of an earner + * @param earner The address to set the claimer for + * @param claimer The address of the entity that can call `processClaim` on behalf of the earner + * @dev Only callable by operators or AVSs. We define an AVS that has created at least one + * operatorSet in the `AllocationManager` + */ + function setClaimerFor(address earner, address claimer) external; /** * @notice Sets the delay in timestamp before a posted root can be claimed against * @dev Only callable by the contract owner * @param _activationDelay The new value for activationDelay */ - function setActivationDelay(uint32 _activationDelay) external; + function setActivationDelay( + uint32 _activationDelay + ) external; /** * @notice Sets the global commission for all operators across all avss - * @param _globalCommissionBips The commission for all operators across all avss * @dev Only callable by the contract owner + * @param _globalCommissionBips The commission for all operators across all avss */ - function setGlobalOperatorCommission(uint16 _globalCommissionBips) external; + function setGlobalOperatorCommission( + uint16 _globalCommissionBips + ) external; /** * @notice Sets the permissioned `rewardsUpdater` address which can post new roots * @dev Only callable by the contract owner * @param _rewardsUpdater The address of the new rewardsUpdater */ - function setRewardsUpdater(address _rewardsUpdater) external; + function setRewardsUpdater( + address _rewardsUpdater + ) external; /** * @notice Sets the permissioned `rewardsForAllSubmitter` address which can submit createRewardsForAllSubmission @@ -349,11 +385,86 @@ interface IRewardsCoordinator { function setRewardsForAllSubmitter(address _submitter, bool _newValue) external; /** - * @notice Getter function for the current EIP-712 domain separator for this contract. * - * @dev The domain separator will change in the event of a fork that changes the ChainID. - * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. - * for more detailed information please read EIP-712. + * VIEW FUNCTIONS + * */ - function domainSeparator() external view returns (bytes32); + + /// @notice Delay in timestamp (seconds) before a posted root can be claimed against + function activationDelay() external view returns (uint32); + + /// @notice The timestamp until which RewardsSubmissions have been calculated + function currRewardsCalculationEndTimestamp() external view returns (uint32); + + /// @notice Mapping: earner => the address of the entity who can call `processClaim` on behalf of the earner + function claimerFor( + address earner + ) external view returns (address); + + /// @notice Mapping: claimer => token => total amount claimed + function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256); + + /// @notice the commission for all operators across all avss + function globalOperatorCommissionBips() external view returns (uint16); + + /// @notice return the hash of the earner's leaf + function calculateEarnerLeafHash( + EarnerTreeMerkleLeaf calldata leaf + ) external pure returns (bytes32); + + /// @notice returns the hash of the earner's token leaf + function calculateTokenLeafHash( + TokenTreeMerkleLeaf calldata leaf + ) external pure returns (bytes32); + + /// @notice returns 'true' if the claim would currently pass the check in `processClaims` + /// but will revert if not valid + function checkClaim( + RewardsMerkleClaim calldata claim + ) external view returns (bool); + + /// @notice the commission for a specific operator for a specific avs + /// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release + function operatorCommissionBips(address operator, address avs) external view returns (uint16); + + /// @notice returns the number of distribution roots posted + function getDistributionRootsLength() external view returns (uint256); + + /// @notice returns the distributionRoot at the specified index + function getDistributionRootAtIndex( + uint256 index + ) external view returns (DistributionRoot memory); + + /// @notice returns the current distributionRoot + function getCurrentDistributionRoot() external view returns (DistributionRoot memory); + + /// @notice loop through the distribution roots from reverse and get latest root that is not disabled and activated + /// i.e. a root that can be claimed against + function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory); + + /// @notice loop through distribution roots from reverse and return index from hash + function getRootIndexFromHash( + bytes32 rootHash + ) external view returns (uint32); + + /// @notice The address of the entity that can update the contract with new merkle roots + function rewardsUpdater() external view returns (address); + + /** + * @notice The interval in seconds at which the calculation for a RewardsSubmission distribution is done. + * @dev Rewards Submission durations must be multiples of this interval. + */ + function CALCULATION_INTERVAL_SECONDS() external view returns (uint32); + + /// @notice The maximum amount of time (seconds) that a RewardsSubmission can span over + function MAX_REWARDS_DURATION() external view returns (uint32); + + /// @notice max amount of time (seconds) that a submission can start in the past + function MAX_RETROACTIVE_LENGTH() external view returns (uint32); + + /// @notice max amount of time (seconds) that a submission can start in the future + function MAX_FUTURE_LENGTH() external view returns (uint32); + + /// @notice absolute min timestamp (seconds) that a submission can start at + function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32); } diff --git a/src/contracts/interfaces/IShareManager.sol b/src/contracts/interfaces/IShareManager.sol new file mode 100644 index 000000000..aaf5d6854 --- /dev/null +++ b/src/contracts/interfaces/IShareManager.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../libraries/SlashingLib.sol"; +import "./IStrategy.sol"; + +/** + * @title Interface for a `IShareManager` contract. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice This contract is used by the DelegationManager as a unified interface to interact with the EigenPodManager and StrategyManager + */ +interface IShareManager { + /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue + /// @dev strategy must be beaconChainETH when talking to the EigenPodManager + function removeDepositShares(address staker, IStrategy strategy, uint256 depositSharesToRemove) external; + + /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue + /// @dev strategy must be beaconChainETH when talking to the EigenPodManager + /// @dev token is not validated when talking to the EigenPodManager + /// @return existingDepositShares the shares the staker had before any were added + /// @return addedShares the new shares added to the staker's balance + function addShares( + address staker, + IStrategy strategy, + IERC20 token, + uint256 shares + ) external returns (uint256, uint256); + + /// @notice Used by the DelegationManager to convert withdrawn descaled shares to tokens and send them to a staker + /// @dev strategy must be beaconChainETH when talking to the EigenPodManager + /// @dev token is not validated when talking to the EigenPodManager + function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external; + + /// @notice Returns the current shares of `user` in `strategy` + /// @dev strategy must be beaconChainETH when talking to the EigenPodManager + /// @dev returns 0 if the user has negative shares + function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares); +} diff --git a/src/contracts/interfaces/ISignatureUtils.sol b/src/contracts/interfaces/ISignatureUtils.sol index 158b325d1..9e1ac2b45 100644 --- a/src/contracts/interfaces/ISignatureUtils.sol +++ b/src/contracts/interfaces/ISignatureUtils.sol @@ -7,6 +7,9 @@ pragma solidity >=0.5.0; * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service */ interface ISignatureUtils { + error InvalidSignature(); + error SignatureExpired(); + // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management. struct SignatureWithExpiry { // the signature itself, formatted as a single bytes object diff --git a/src/contracts/interfaces/ISlasher.sol b/src/contracts/interfaces/ISlasher.sol index f2b4952be..1cd77b996 100644 --- a/src/contracts/interfaces/ISlasher.sol +++ b/src/contracts/interfaces/ISlasher.sol @@ -55,7 +55,9 @@ interface ISlasher { * @notice Gives the `contractAddress` permission to slash the funds of the caller. * @dev Typically, this function must be called prior to registering for a middleware. */ - function optIntoSlashing(address contractAddress) external; + function optIntoSlashing( + address contractAddress + ) external; /** * @notice Used for 'slashing' a certain operator. @@ -63,13 +65,17 @@ interface ISlasher { * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop. * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `optIntoSlashing`. */ - function freezeOperator(address toBeFrozen) external; + function freezeOperator( + address toBeFrozen + ) external; /** * @notice Removes the 'frozen' status from each of the `frozenAddresses` * @dev Callable only by the contract owner (i.e. governance). */ - function resetFrozenStatus(address[] calldata frozenAddresses) external; + function resetFrozenStatus( + address[] calldata frozenAddresses + ) external; /** * @notice this function is a called by middlewares during an operator's registration to make sure the operator's stake at registration @@ -121,7 +127,9 @@ interface ISlasher { * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated * to an operator who has their status set to frozen. Otherwise returns 'false'. */ - function isFrozen(address staker) external view returns (bool); + function isFrozen( + address staker + ) external view returns (bool); /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`. function canSlash(address toBeSlashed, address slashingContract) external view returns (bool); @@ -171,7 +179,9 @@ interface ISlasher { ) external view returns (MiddlewareTimes memory); /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length` - function middlewareTimesLength(address operator) external view returns (uint256); + function middlewareTimesLength( + address operator + ) external view returns (uint256); /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`. function getMiddlewareTimesIndexStalestUpdateBlock(address operator, uint32 index) external view returns (uint32); @@ -180,7 +190,9 @@ interface ISlasher { function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns (uint32); /// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`. - function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256); + function operatorWhitelistedContractsLinkedListSize( + address operator + ) external view returns (uint256); /// @notice Getter function for fetching a single node in the operator's linked list (`_operatorToWhitelistedContractsByUpdate[operator]`). function operatorWhitelistedContractsLinkedListEntry( diff --git a/src/contracts/interfaces/ISocketUpdater.sol b/src/contracts/interfaces/ISocketUpdater.sol index df95d4ab0..921b1a46b 100644 --- a/src/contracts/interfaces/ISocketUpdater.sol +++ b/src/contracts/interfaces/ISocketUpdater.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Interface for an `ISocketUpdater` where operators can update their sockets. @@ -16,5 +16,7 @@ interface ISocketUpdater { * @notice Updates the socket of the msg.sender given they are a registered operator * @param socket is the new socket of the operator */ - function updateSocket(string memory socket) external; + function updateSocket( + string memory socket + ) external; } diff --git a/src/contracts/interfaces/IStrategy.sol b/src/contracts/interfaces/IStrategy.sol index e7a6f684d..3052cba1c 100644 --- a/src/contracts/interfaces/IStrategy.sol +++ b/src/contracts/interfaces/IStrategy.sol @@ -2,14 +2,29 @@ pragma solidity >=0.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../libraries/SlashingLib.sol"; -/** - * @title Minimal interface for an `Strategy` contract. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice Custom `Strategy` implementations may expand extensively on this interface. - */ -interface IStrategy { +interface IStrategyErrors { + /// @dev Thrown when called by an account that is not strategy manager. + error OnlyStrategyManager(); + /// @dev Thrown when new shares value is zero. + error NewSharesZero(); + /// @dev Thrown when total shares exceeds max. + error TotalSharesExceedsMax(); + /// @dev Thrown when amount shares is greater than total shares. + error WithdrawalAmountExceedsTotalDeposits(); + /// @dev Thrown when attempting an action with a token that is not accepted. + error OnlyUnderlyingToken(); + + /// StrategyBaseWithTVLLimits + + /// @dev Thrown when `maxPerDeposit` exceeds max. + error MaxPerDepositExceedsMax(); + /// @dev Thrown when balance exceeds max total deposits. + error BalanceExceedsMaxTotalDeposits(); +} + +interface IStrategyEvents { /** * @notice Used to emit an event for the exchange rate between 1 share and underlying token in a strategy contract * @param rate is the exchange rate in wad 18 decimals @@ -24,7 +39,15 @@ interface IStrategy { * @param decimals are the decimals of the ERC20 token in the strategy */ event StrategyTokenSet(IERC20 token, uint8 decimals); +} +/** + * @title Minimal interface for an `Strategy` contract. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice Custom `Strategy` implementations may expand extensively on this interface. + */ +interface IStrategy is IStrategyErrors, IStrategyEvents { /** * @notice Used to deposit tokens into this Strategy * @param token is the ERC20 token being deposited @@ -52,7 +75,9 @@ interface IStrategy { * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function sharesToUnderlying(uint256 amountShares) external returns (uint256); + function sharesToUnderlying( + uint256 amountShares + ) external returns (uint256); /** * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy. @@ -61,19 +86,25 @@ interface IStrategy { * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function underlyingToShares(uint256 amountUnderlying) external returns (uint256); + function underlyingToShares( + uint256 amountUnderlying + ) external returns (uint256); /** * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications */ - function userUnderlying(address user) external returns (uint256); + function userUnderlying( + address user + ) external returns (uint256); /** * @notice convenience function for fetching the current total shares of `user` in this strategy, by * querying the `strategyManager` contract */ - function shares(address user) external view returns (uint256); + function shares( + address user + ) external view returns (uint256); /** * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy. @@ -82,7 +113,9 @@ interface IStrategy { * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256); + function sharesToUnderlyingView( + uint256 amountShares + ) external view returns (uint256); /** * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy. @@ -91,13 +124,17 @@ interface IStrategy { * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256); + function underlyingToSharesView( + uint256 amountUnderlying + ) external view returns (uint256); /** * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications */ - function userUnderlyingView(address user) external view returns (uint256); + function userUnderlyingView( + address user + ) external view returns (uint256); /// @notice The underlying token for shares in this Strategy function underlyingToken() external view returns (IERC20); diff --git a/src/contracts/interfaces/IStrategyFactory.sol b/src/contracts/interfaces/IStrategyFactory.sol index 85dab8cd0..137659cc3 100644 --- a/src/contracts/interfaces/IStrategyFactory.sol +++ b/src/contracts/interfaces/IStrategyFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -12,6 +12,13 @@ import "./IStrategy.sol"; * @dev This may not be compatible with non-standard ERC20 tokens. Caution is warranted. */ interface IStrategyFactory { + /// @dev Thrown when attempting to deploy a strategy for a blacklisted token. + error BlacklistedToken(); + /// @dev Thrown when attempting to deploy a strategy that already exists. + error StrategyAlreadyExists(); + /// @dev Thrown when attempting to blacklist a token that is already blacklisted + error AlreadyBlacklisted(); + event TokenBlacklisted(IERC20 token); /// @notice Upgradeable beacon which new Strategies deployed by this contract point to @@ -24,7 +31,9 @@ interface IStrategyFactory { /// though deployNewStrategy does whitelist by default. /// These strategies MIGHT not be the only strategy for the underlying token /// as additional strategies can be whitelisted by the owner of the factory. - function deployedStrategies(IERC20 token) external view returns (IStrategy); + function deployedStrategies( + IERC20 token + ) external view returns (IStrategy); /** * @notice Deploy a new strategyBeacon contract for the ERC20 token. @@ -33,25 +42,23 @@ interface IStrategyFactory { * $dev Immense caution is warranted for non-standard ERC20 tokens, particularly "reentrant" tokens * like those that conform to ERC777. */ - function deployNewStrategy(IERC20 token) external returns (IStrategy newStrategy); + function deployNewStrategy( + IERC20 token + ) external returns (IStrategy newStrategy); /** * @notice Owner-only function to pass through a call to `StrategyManager.addStrategiesToDepositWhitelist` */ function whitelistStrategies( - IStrategy[] calldata strategiesToWhitelist, - bool[] calldata thirdPartyTransfersForbiddenValues + IStrategy[] calldata strategiesToWhitelist ) external; - /** - * @notice Owner-only function to pass through a call to `StrategyManager.setThirdPartyTransfersForbidden` - */ - function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external; - /** * @notice Owner-only function to pass through a call to `StrategyManager.removeStrategiesFromDepositWhitelist` */ - function removeStrategiesFromWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external; + function removeStrategiesFromWhitelist( + IStrategy[] calldata strategiesToRemoveFromWhitelist + ) external; /// @notice Emitted when the `strategyBeacon` is changed event StrategyBeaconModified(IBeacon previousBeacon, IBeacon newBeacon); diff --git a/src/contracts/interfaces/IStrategyManager.sol b/src/contracts/interfaces/IStrategyManager.sol index 784bb1c46..da5d0a813 100644 --- a/src/contracts/interfaces/IStrategyManager.sol +++ b/src/contracts/interfaces/IStrategyManager.sol @@ -2,17 +2,32 @@ pragma solidity >=0.5.0; import "./IStrategy.sol"; -import "./ISlasher.sol"; +import "./IShareManager.sol"; import "./IDelegationManager.sol"; import "./IEigenPodManager.sol"; -/** - * @title Interface for the primary entrypoint for funds into EigenLayer. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice See the `StrategyManager` contract itself for implementation details. - */ -interface IStrategyManager { +interface IStrategyManagerErrors { + /// @dev Thrown when total strategies deployed exceeds max. + error MaxStrategiesExceeded(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when call attempted from address that's not delegation manager. + error OnlyDelegationManager(); + /// @dev Thrown when call attempted from address that's not strategy whitelister. + error OnlyStrategyWhitelister(); + /// @dev Thrown when provided `shares` amount is too high. + error SharesAmountTooHigh(); + /// @dev Thrown when provided `shares` amount is zero. + error SharesAmountZero(); + /// @dev Thrown when provided `staker` address is null. + error StakerAddressZero(); + /// @dev Thrown when provided `strategy` not found. + error StrategyNotFound(); + /// @dev Thrown when attempting to deposit to a non-whitelisted strategy. + error StrategyNotWhitelisted(); +} + +interface IStrategyManagerEvents { /** * @notice Emitted when a new deposit occurs on behalf of `staker`. * @param staker Is the staker who is depositing funds into EigenLayer. @@ -22,9 +37,6 @@ interface IStrategyManager { */ event Deposit(address staker, IERC20 token, IStrategy strategy, uint256 shares); - /// @notice Emitted when `thirdPartyTransfersForbidden` is updated for a strategy and value by the owner - event UpdatedThirdPartyTransfersForbidden(IStrategy strategy, bool value); - /// @notice Emitted when the `strategyWhitelister` is changed event StrategyWhitelisterChanged(address previousAddress, address newAddress); @@ -33,6 +45,27 @@ interface IStrategyManager { /// @notice Emitted when a strategy is removed from the approved list of strategies for deposit event StrategyRemovedFromDepositWhitelist(IStrategy strategy); +} + +/** + * @title Interface for the primary entrypoint for funds into EigenLayer. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice See the `StrategyManager` contract itself for implementation details. + */ +interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IShareManager { + /** + * @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set), + * and transfers contract ownership to the specified `initialOwner`. + * @param initialOwner Ownership of this contract is transferred to this address. + * @param initialStrategyWhitelister The initial value of `strategyWhitelister` to set. + * @param initialPausedStatus The initial value of `_paused` to set. + */ + function initialize( + address initialOwner, + address initialStrategyWhitelister, + uint256 initialPausedStatus + ) external; /** * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender` @@ -64,7 +97,6 @@ interface IStrategyManager { * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf. * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those * targeting stakers who may be attempting to undelegate. - * @dev Cannot be called if thirdPartyTransfersForbidden is set to true for this strategy * * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead to attack vectors * where the token balance and corresponding strategy shares are not in sync upon reentrancy @@ -78,83 +110,84 @@ interface IStrategyManager { bytes memory signature ) external returns (uint256 shares); - /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue - function removeShares(address staker, IStrategy strategy, uint256 shares) external; - - /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue - function addShares(address staker, IERC20 token, IStrategy strategy, uint256 shares) external; - - /// @notice Used by the DelegationManager to convert withdrawn shares to tokens and send them to a recipient - function withdrawSharesAsTokens(address recipient, IStrategy strategy, uint256 shares, IERC20 token) external; - - /// @notice Returns the current shares of `user` in `strategy` - function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares); - /** - * @notice Get all details on the staker's deposits and corresponding shares - * @param staker The staker of interest, whose deposits this function will fetch - * @return (staker's strategies, shares in these strategies) + * @notice Burns Strategy shares for the given strategy by calling into the strategy to transfer to the default burn address. + * @param strategy The strategy to burn shares in. + * @param sharesToBurn The amount of shares to burn. + * @dev This function is only called by the DelegationManager when an operator is slashed. */ - function getDeposits(address staker) external view returns (IStrategy[] memory, uint256[] memory); + function burnShares(IStrategy strategy, uint256 sharesToBurn) external; - /// @notice Simple getter function that returns `stakerStrategyList[staker].length`. - function stakerStrategyListLength(address staker) external view returns (uint256); + /** + * @notice Owner-only function to change the `strategyWhitelister` address. + * @param newStrategyWhitelister new address for the `strategyWhitelister`. + */ + function setStrategyWhitelister( + address newStrategyWhitelister + ) external; /** * @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already) - * @param thirdPartyTransfersForbiddenValues bool values to set `thirdPartyTransfersForbidden` to for each strategy */ function addStrategiesToDepositWhitelist( - IStrategy[] calldata strategiesToWhitelist, - bool[] calldata thirdPartyTransfersForbiddenValues + IStrategy[] calldata strategiesToWhitelist ) external; /** * @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into * @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it) */ - function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external; + function removeStrategiesFromDepositWhitelist( + IStrategy[] calldata strategiesToRemoveFromWhitelist + ) external; + + /// @notice Returns bool for whether or not `strategy` is whitelisted for deposit + function strategyIsWhitelistedForDeposit( + IStrategy strategy + ) external view returns (bool); /** - * If true for a strategy, a user cannot depositIntoStrategyWithSignature into that strategy for another staker - * and also when performing DelegationManager.queueWithdrawals, a staker can only withdraw to themselves. - * Defaulted to false for all existing strategies. - * @param strategy The strategy to set `thirdPartyTransfersForbidden` value to - * @param value bool value to set `thirdPartyTransfersForbidden` to + * @notice Get all details on the staker's deposits and corresponding shares + * @return (staker's strategies, shares in these strategies) */ - function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external; + function getDeposits( + address staker + ) external view returns (IStrategy[] memory, uint256[] memory); - /// @notice Returns the single, central Delegation contract of EigenLayer - function delegation() external view returns (IDelegationManager); + function getStakerStrategyList( + address staker + ) external view returns (IStrategy[] memory); - /// @notice Returns the single, central Slasher contract of EigenLayer - function slasher() external view returns (ISlasher); + /// @notice Simple getter function that returns `stakerStrategyList[staker].length`. + function stakerStrategyListLength( + address staker + ) external view returns (uint256); - /// @notice Returns the EigenPodManager contract of EigenLayer - function eigenPodManager() external view returns (IEigenPodManager); + /// @notice Returns the current shares of `user` in `strategy` + function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 shares); + + /// @notice Returns the single, central Delegation contract of EigenLayer + function delegation() external view returns (IDelegationManager); /// @notice Returns the address of the `strategyWhitelister` function strategyWhitelister() external view returns (address); - /// @notice Returns bool for whether or not `strategy` is whitelisted for deposit - function strategyIsWhitelistedForDeposit(IStrategy strategy) external view returns (bool); - - /** - * @notice Owner-only function to change the `strategyWhitelister` address. - * @param newStrategyWhitelister new address for the `strategyWhitelister`. - */ - function setStrategyWhitelister(address newStrategyWhitelister) external; - /** - * @notice Returns bool for whether or not `strategy` enables credit transfers. i.e enabling - * depositIntoStrategyWithSignature calls or queueing withdrawals to a different address than the staker. + * @param staker The address of the staker. + * @param strategy The strategy to deposit into. + * @param token The token to deposit. + * @param amount The amount of `token` to deposit. + * @param nonce The nonce of the staker. + * @param expiry The expiry of the signature. + * @return The EIP-712 signable digest hash. */ - function thirdPartyTransfersForbidden(IStrategy strategy) external view returns (bool); - - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * @dev The domain separator will change in the event of a fork that changes the ChainID. - */ - function domainSeparator() external view returns (bytes32); + function calculateStrategyDepositDigestHash( + address staker, + IStrategy strategy, + IERC20 token, + uint256 amount, + uint256 nonce, + uint256 expiry + ) external view returns (bytes32); } diff --git a/src/contracts/interfaces/IWhitelister.sol b/src/contracts/interfaces/IWhitelister.sol index da68992c8..b68f50eec 100644 --- a/src/contracts/interfaces/IWhitelister.sol +++ b/src/contracts/interfaces/IWhitelister.sol @@ -11,9 +11,13 @@ import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; interface IWhitelister { - function whitelist(address operator) external; + function whitelist( + address operator + ) external; - function getStaker(address operator) external returns (address); + function getStaker( + address operator + ) external returns (address); function depositIntoStrategy( address staker, @@ -24,12 +28,12 @@ interface IWhitelister { function queueWithdrawal( address staker, - IDelegationManager.QueuedWithdrawalParams[] calldata queuedWithdrawalParams + IDelegationManagerTypes.QueuedWithdrawalParams[] calldata queuedWithdrawalParams ) external returns (bytes memory); function completeQueuedWithdrawal( address staker, - IDelegationManager.Withdrawal calldata queuedWithdrawal, + IDelegationManagerTypes.Withdrawal calldata queuedWithdrawal, IERC20[] calldata tokens, uint256 middlewareTimesIndex, bool receiveAsTokens diff --git a/src/contracts/libraries/BeaconChainProofs.sol b/src/contracts/libraries/BeaconChainProofs.sol index 9d0caa8d9..7e176653b 100644 --- a/src/contracts/libraries/BeaconChainProofs.sol +++ b/src/contracts/libraries/BeaconChainProofs.sol @@ -10,6 +10,13 @@ import "../libraries/Endian.sol"; //BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader //BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate library BeaconChainProofs { + /// @dev Thrown when a proof is invalid. + error InvalidProof(); + /// @dev Thrown when a proof with an invalid length is provided. + error InvalidProofLength(); + /// @dev Thrown when a validator fields length is invalid. + error InvalidValidatorFieldsLength(); + /// @notice Heights of various merkle trees in the beacon chain /// - beaconBlockRoot /// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT @@ -99,10 +106,7 @@ library BeaconChainProofs { /// @param beaconBlockRoot merkle root of the beacon block /// @param proof the beacon state root and merkle proof of its inclusion under `beaconBlockRoot` function verifyStateRoot(bytes32 beaconBlockRoot, StateRootProof calldata proof) internal view { - require( - proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT), - "BeaconChainProofs.verifyStateRoot: Proof has incorrect length" - ); + require(proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT), InvalidProofLength()); /// This merkle proof verifies the `beaconStateRoot` under the `beaconBlockRoot` /// - beaconBlockRoot @@ -115,7 +119,7 @@ library BeaconChainProofs { leaf: proof.beaconStateRoot, index: STATE_ROOT_INDEX }), - "BeaconChainProofs.verifyStateRoot: Invalid state root merkle proof" + InvalidProof() ); } @@ -135,16 +139,13 @@ library BeaconChainProofs { bytes calldata validatorFieldsProof, uint40 validatorIndex ) internal view { - require( - validatorFields.length == VALIDATOR_FIELDS_LENGTH, - "BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length" - ); + require(validatorFields.length == VALIDATOR_FIELDS_LENGTH, InvalidValidatorFieldsLength()); /// Note: the reason we use `VALIDATOR_TREE_HEIGHT + 1` here is because the merklization process for /// this container includes hashing the root of the validator tree with the length of the validator list require( validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_TREE_HEIGHT), - "BeaconChainProofs.verifyValidatorFields: Proof has incorrect length" + InvalidProofLength() ); // Merkleize `validatorFields` to get the leaf to prove @@ -165,7 +166,7 @@ library BeaconChainProofs { leaf: validatorRoot, index: index }), - "BeaconChainProofs.verifyValidatorFields: Invalid merkle proof" + InvalidProof() ); } @@ -187,7 +188,7 @@ library BeaconChainProofs { function verifyBalanceContainer(bytes32 beaconBlockRoot, BalanceContainerProof calldata proof) internal view { require( proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + BEACON_STATE_TREE_HEIGHT), - "BeaconChainProofs.verifyBalanceContainer: Proof has incorrect length" + InvalidProofLength() ); /// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees: @@ -205,7 +206,7 @@ library BeaconChainProofs { leaf: proof.balanceContainerRoot, index: index }), - "BeaconChainProofs.verifyBalanceContainer: invalid balance container proof" + InvalidProof() ); } @@ -221,10 +222,7 @@ library BeaconChainProofs { ) internal view returns (uint64 validatorBalanceGwei) { /// Note: the reason we use `BALANCE_TREE_HEIGHT + 1` here is because the merklization process for /// this container includes hashing the root of the balances tree with the length of the balances list - require( - proof.proof.length == 32 * (BALANCE_TREE_HEIGHT + 1), - "BeaconChainProofs.verifyValidatorBalance: Proof has incorrect length" - ); + require(proof.proof.length == 32 * (BALANCE_TREE_HEIGHT + 1), InvalidProofLength()); /// When merkleized, beacon chain balances are combined into groups of 4 called a `balanceRoot`. The merkle /// proof here verifies that this validator's `balanceRoot` is included in the `balanceContainerRoot` @@ -240,7 +238,7 @@ library BeaconChainProofs { leaf: proof.balanceRoot, index: balanceIndex }), - "BeaconChainProofs.verifyValidatorBalance: Invalid merkle proof" + InvalidProof() ); /// Extract the individual validator's balance from the `balanceRoot` @@ -274,32 +272,44 @@ library BeaconChainProofs { /// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator) /// @dev Retrieves a validator's pubkey hash - function getPubkeyHash(bytes32[] memory validatorFields) internal pure returns (bytes32) { + function getPubkeyHash( + bytes32[] memory validatorFields + ) internal pure returns (bytes32) { return validatorFields[VALIDATOR_PUBKEY_INDEX]; } /// @dev Retrieves a validator's withdrawal credentials - function getWithdrawalCredentials(bytes32[] memory validatorFields) internal pure returns (bytes32) { + function getWithdrawalCredentials( + bytes32[] memory validatorFields + ) internal pure returns (bytes32) { return validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX]; } /// @dev Retrieves a validator's effective balance (in gwei) - function getEffectiveBalanceGwei(bytes32[] memory validatorFields) internal pure returns (uint64) { + function getEffectiveBalanceGwei( + bytes32[] memory validatorFields + ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_BALANCE_INDEX]); } /// @dev Retrieves a validator's activation epoch - function getActivationEpoch(bytes32[] memory validatorFields) internal pure returns (uint64) { + function getActivationEpoch( + bytes32[] memory validatorFields + ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_ACTIVATION_EPOCH_INDEX]); } /// @dev Retrieves true IFF a validator is marked slashed - function isValidatorSlashed(bytes32[] memory validatorFields) internal pure returns (bool) { + function isValidatorSlashed( + bytes32[] memory validatorFields + ) internal pure returns (bool) { return validatorFields[VALIDATOR_SLASHED_INDEX] != 0; } /// @dev Retrieves a validator's exit epoch - function getExitEpoch(bytes32[] memory validatorFields) internal pure returns (uint64) { + function getExitEpoch( + bytes32[] memory validatorFields + ) internal pure returns (uint64) { return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_EXIT_EPOCH_INDEX]); } } diff --git a/src/contracts/libraries/BytesLib.sol b/src/contracts/libraries/BytesLib.sol index a019da303..b20ef5992 100644 --- a/src/contracts/libraries/BytesLib.sol +++ b/src/contracts/libraries/BytesLib.sol @@ -9,6 +9,9 @@ pragma solidity >=0.8.0 <0.9.0; library BytesLib { + error Overflow(); + error OutOfBounds(); + function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; @@ -211,8 +214,8 @@ library BytesLib { } function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { - require(_length + 31 >= _length, "slice_overflow"); - require(_bytes.length >= _start + _length, "slice_outOfBounds"); + require(_length + 31 >= _length, Overflow()); + require(_bytes.length >= _start + _length, OutOfBounds()); bytes memory tempBytes; @@ -270,7 +273,7 @@ library BytesLib { } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { - require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); + require(_bytes.length >= _start + 20, OutOfBounds()); address tempAddress; assembly { @@ -281,7 +284,7 @@ library BytesLib { } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { - require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); + require(_bytes.length >= _start + 1, OutOfBounds()); uint8 tempUint; assembly { @@ -292,7 +295,7 @@ library BytesLib { } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { - require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); + require(_bytes.length >= _start + 2, OutOfBounds()); uint16 tempUint; assembly { @@ -303,7 +306,7 @@ library BytesLib { } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { - require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); + require(_bytes.length >= _start + 4, OutOfBounds()); uint32 tempUint; assembly { @@ -314,7 +317,7 @@ library BytesLib { } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { - require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); + require(_bytes.length >= _start + 8, OutOfBounds()); uint64 tempUint; assembly { @@ -325,7 +328,7 @@ library BytesLib { } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { - require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); + require(_bytes.length >= _start + 12, OutOfBounds()); uint96 tempUint; assembly { @@ -336,7 +339,7 @@ library BytesLib { } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { - require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); + require(_bytes.length >= _start + 16, OutOfBounds()); uint128 tempUint; assembly { @@ -347,7 +350,7 @@ library BytesLib { } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { - require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); + require(_bytes.length >= _start + 32, OutOfBounds()); uint256 tempUint; assembly { @@ -358,7 +361,7 @@ library BytesLib { } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { - require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); + require(_bytes.length >= _start + 32, OutOfBounds()); bytes32 tempBytes32; assembly { diff --git a/src/contracts/libraries/EIP1271SignatureUtils.sol b/src/contracts/libraries/EIP1271SignatureUtils.sol deleted file mode 100644 index a4452f91e..000000000 --- a/src/contracts/libraries/EIP1271SignatureUtils.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/interfaces/IERC1271.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -/** - * @title Library of utilities for making EIP1271-compliant signature checks. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - */ -library EIP1271SignatureUtils { - // bytes4(keccak256("isValidSignature(bytes32,bytes)") - bytes4 internal constant EIP1271_MAGICVALUE = 0x1626ba7e; - - /** - * @notice Checks @param signature is a valid signature of @param digestHash from @param signer. - * If the `signer` contains no code -- i.e. it is not (yet, at least) a contract address, then checks using standard ECDSA logic - * Otherwise, passes on the signature to the signer to verify the signature and checks that it returns the `EIP1271_MAGICVALUE`. - */ - function checkSignature_EIP1271(address signer, bytes32 digestHash, bytes memory signature) internal view { - /** - * check validity of signature: - * 1) if `signer` is an EOA, then `signature` must be a valid ECDSA signature from `signer`, - * indicating their intention for this action - * 2) if `signer` is a contract, then `signature` must will be checked according to EIP-1271 - */ - if (Address.isContract(signer)) { - require( - IERC1271(signer).isValidSignature(digestHash, signature) == EIP1271_MAGICVALUE, - "EIP1271SignatureUtils.checkSignature_EIP1271: ERC1271 signature verification failed" - ); - } else { - require( - ECDSA.recover(digestHash, signature) == signer, - "EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer" - ); - } - } -} diff --git a/src/contracts/libraries/Endian.sol b/src/contracts/libraries/Endian.sol index f9799bb9e..56233cda2 100644 --- a/src/contracts/libraries/Endian.sol +++ b/src/contracts/libraries/Endian.sol @@ -9,7 +9,9 @@ library Endian { * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits) * through a right-shift/shr operation. */ - function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) { + function fromLittleEndianUint64( + bytes32 lenum + ) internal pure returns (uint64 n) { // the number needs to be stored in little-endian encoding (ie in bytes 0-8) n = uint64(uint256(lenum >> 192)); // forgefmt: disable-next-item diff --git a/src/contracts/libraries/Merkle.sol b/src/contracts/libraries/Merkle.sol index 5b7635423..071dcb8d9 100644 --- a/src/contracts/libraries/Merkle.sol +++ b/src/contracts/libraries/Merkle.sol @@ -18,6 +18,8 @@ pragma solidity ^0.8.0; * against this attack out of the box. */ library Merkle { + error InvalidProofLength(); + /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt @@ -51,7 +53,7 @@ library Merkle { bytes32 leaf, uint256 index ) internal pure returns (bytes32) { - require(proof.length % 32 == 0, "Merkle.processInclusionProofKeccak: proof length should be a multiple of 32"); + require(proof.length % 32 == 0, InvalidProofLength()); bytes32 computedHash = leaf; for (uint256 i = 32; i <= proof.length; i += 32) { if (index % 2 == 0) { @@ -107,10 +109,7 @@ library Merkle { bytes32 leaf, uint256 index ) internal view returns (bytes32) { - require( - proof.length != 0 && proof.length % 32 == 0, - "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32" - ); + require(proof.length != 0 && proof.length % 32 == 0, InvalidProofLength()); bytes32[1] memory computedHash = [leaf]; for (uint256 i = 32; i <= proof.length; i += 32) { if (index % 2 == 0) { @@ -140,7 +139,9 @@ library Merkle { * @return The computed Merkle root of the tree. * @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will merkleize the inputs incorrectly. */ - function merkleizeSha256(bytes32[] memory leaves) internal pure returns (bytes32) { + function merkleizeSha256( + bytes32[] memory leaves + ) internal pure returns (bytes32) { //there are half as many nodes in the layer above the leaves uint256 numNodesInLayer = leaves.length / 2; //create a layer to store the internal nodes diff --git a/src/contracts/libraries/OperatorSetLib.sol b/src/contracts/libraries/OperatorSetLib.sol new file mode 100644 index 000000000..5b43359e3 --- /dev/null +++ b/src/contracts/libraries/OperatorSetLib.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +struct OperatorSet { + address avs; + uint32 id; +} + +library OperatorSetLib { + function key( + OperatorSet memory os + ) internal pure returns (bytes32) { + return bytes32(abi.encodePacked(os.avs, uint96(os.id))); + } + + function decode( + bytes32 _key + ) internal pure returns (OperatorSet memory) { + /// forgefmt: disable-next-item + return OperatorSet({ + avs: address(uint160(uint256(_key) >> 96)), + id: uint32(uint256(_key) & type(uint96).max) + }); + } +} diff --git a/src/contracts/libraries/SlashingLib.sol b/src/contracts/libraries/SlashingLib.sol new file mode 100644 index 000000000..7236a9604 --- /dev/null +++ b/src/contracts/libraries/SlashingLib.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/utils/math/Math.sol"; +import "@openzeppelin-upgrades/contracts/utils/math/SafeCastUpgradeable.sol"; + +/// @dev the stakerScalingFactor and operatorMagnitude have initial default values to 1e18 as "1" +/// to preserve precision with uint256 math. We use `WAD` where these variables are used +/// and divide to represent as 1 +uint64 constant WAD = 1e18; + +/* + * There are 2 types of shares: + * 1. depositShares + * - These can be converted to an amount of tokens given a strategy + * - by calling `sharesToUnderlying` on the strategy address (they're already tokens + * in the case of EigenPods) + * - These live in the storage of EPM and SM strategies + * 2. shares + * - For a staker, this is the amount of shares that they can withdraw + * - For an operator, this is the sum of its staker's withdrawable shares + * + * Note that `withdrawal.scaledShares` is scaled for the beaconChainETHStrategy to divide by the beaconChainScalingFactor upon queueing + * and multiply by the beaconChainScalingFactor upon withdrawal + */ +struct DepositScalingFactor { + uint256 _scalingFactor; +} + +using SlashingLib for DepositScalingFactor global; + +// TODO: validate order of operations everywhere +library SlashingLib { + using Math for uint256; + using SlashingLib for uint256; + using SafeCastUpgradeable for uint256; + + // WAD MATH + + function mulWad(uint256 x, uint256 y) internal pure returns (uint256) { + return x.mulDiv(y, WAD); + } + + function divWad(uint256 x, uint256 y) internal pure returns (uint256) { + return x.mulDiv(WAD, y); + } + + /** + * @notice Used explicitly for calculating slashed magnitude, we want to ensure even in the + * situation where an operator is slashed several times and precision has been lost over time, + * an incoming slashing request isn't rounded down to 0 and an operator is able to avoid slashing penalties. + */ + function mulWadRoundUp(uint256 x, uint256 y) internal pure returns (uint256) { + return x.mulDiv(y, WAD, Math.Rounding.Up); + } + + /** + * @notice Used as part of calculating wadSlashed in the EPM to ensure that we don't overslash + */ + function divWadRoundUp(uint256 x, uint256 y) internal pure returns (uint256) { + return x.mulDiv(WAD, y, Math.Rounding.Up); + } + + // GETTERS + + function scalingFactor( + DepositScalingFactor memory dsf + ) internal pure returns (uint256) { + return dsf._scalingFactor == 0 ? WAD : dsf._scalingFactor; + } + + function scaleForQueueWithdrawal( + uint256 sharesToWithdraw, + uint256 slashingFactor + ) internal pure returns (uint256) { + if (slashingFactor == 0) { + return 0; + } + + return sharesToWithdraw.divWad(slashingFactor); + } + + function scaleForCompleteWithdrawal(uint256 scaledShares, uint256 slashingFactor) internal pure returns (uint256) { + return scaledShares.mulWad(slashingFactor); + } + + /** + * @notice Scales shares according to the difference in an operator's magnitude before and + * after being slashed. This is used to calculate the number of slashable shares in the + * withdrawal queue. + * NOTE: max magnitude is guaranteed to only ever decrease. + */ + function scaleForBurning( + uint256 scaledShares, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) internal pure returns (uint256) { + return scaledShares.mulWad(prevMaxMagnitude - newMaxMagnitude); + } + + function update( + DepositScalingFactor storage dsf, + uint256 prevDepositShares, + uint256 addedShares, + uint256 slashingFactor + ) internal { + // If this is the staker's first deposit, set the scaling factor to + // the inverse of slashingFactor + if (prevDepositShares == 0) { + dsf._scalingFactor = uint256(WAD).divWad(slashingFactor); + return; + } + + /** + * Base Equations: + * (1) newShares = currentShares + addedShares + * (2) newDepositShares = prevDepositShares + addedShares + * (3) newShares = newDepositShares * newDepositScalingFactor * slashingFactor + * + * Plugging (1) into (3): + * (4) newDepositShares * newDepositScalingFactor * slashingFactor = currentShares + addedShares + * + * Solving for newDepositScalingFactor + * (5) newDepositScalingFactor = (currentShares + addedShares) / (newDepositShares * slashingFactor) + * + * Plugging in (2) into (5): + * (7) newDepositScalingFactor = (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor) + * Note that magnitudes must be divided by WAD for precision. Thus, + * + * (8) newDepositScalingFactor = WAD * (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor / WAD) + * (9) newDepositScalingFactor = (currentShares + addedShares) * WAD / (prevDepositShares + addedShares) * WAD / slashingFactor + */ + + // Step 1: Calculate Numerator + uint256 currentShares = dsf.calcWithdrawable(prevDepositShares, slashingFactor); + + // Step 2: Compute currentShares + addedShares + uint256 newShares = currentShares + addedShares; + + // Step 3: Calculate newDepositScalingFactor + /// forgefmt: disable-next-item + uint256 newDepositScalingFactor = newShares + .divWad(prevDepositShares + addedShares) + .divWad(slashingFactor); + + dsf._scalingFactor = newDepositScalingFactor; + } + + // CONVERSION + + function calcWithdrawable( + DepositScalingFactor memory dsf, + uint256 depositShares, + uint256 slashingFactor + ) internal pure returns (uint256) { + /// forgefmt: disable-next-item + return depositShares + .mulWad(dsf.scalingFactor()) + .mulWad(slashingFactor); + } + + function calcSlashedAmount( + uint256 operatorShares, + uint256 prevMaxMagnitude, + uint256 newMaxMagnitude + ) internal pure returns (uint256) { + // round up mulDiv so we don't overslash + return operatorShares - operatorShares.mulDiv(newMaxMagnitude, prevMaxMagnitude, Math.Rounding.Up); + } +} diff --git a/src/contracts/libraries/Snapshots.sol b/src/contracts/libraries/Snapshots.sol new file mode 100644 index 000000000..839aec0d4 --- /dev/null +++ b/src/contracts/libraries/Snapshots.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@openzeppelin-upgrades/contracts/utils/math/MathUpgradeable.sol"; + +import "./SlashingLib.sol"; + +/** + * @title Library for handling snapshots as part of allocating and slashing. + * @notice This library is using OpenZeppelin's CheckpointsUpgradeable library (v4.9.0) + * and removes structs and functions that are unessential. + * Interfaces and structs are renamed for clarity and usage. + * Some additional functions have also been added for convenience. + * @dev This library defines the `DefaultWadHistory` and `DefaultZeroHistory` struct, for snapshotting values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of snapshots define a variable type `Snapshots.DefaultWadHistory` or `Snapshots.DefaultZeroHistory` in your contract, + * and store a new snapshot for the current transaction block using the {push} function. If there is no history yet, the value is either WAD or 0, + * depending on the type of History struct used. This is implemented because for the AllocationManager we want the + * the default value to be WAD(1e18) but when used in the DelegationManager we want the default value to be 0. + * + * _Available since v4.5._ + */ +library Snapshots { + struct DefaultWadHistory { + Snapshot[] _snapshots; + } + + struct DefaultZeroHistory { + Snapshot[] _snapshots; + } + + struct Snapshot { + uint32 _key; + uint224 _value; + } + + error InvalidSnapshotOrdering(); + + /** + * @dev Pushes a (`key`, `value`) pair into a DefaultWadHistory so that it is stored as the snapshot. + */ + function push(DefaultWadHistory storage self, uint32 key, uint64 value) internal { + _insert(self._snapshots, key, value); + } + + /** + * @dev Pushes a (`key`, `value`) pair into a DefaultZeroHistory so that it is stored as the snapshot. + * `value` is cast to uint224. Responsibility for the safety of this operation falls outside of this library. + */ + function push(DefaultZeroHistory storage self, uint32 key, uint256 value) internal { + _insert(self._snapshots, key, uint224(value)); + } + + /** + * @dev Return default value of WAD if there are no snapshots for DefaultWadHistory. + * This is used for looking up maxMagnitudes in the AllocationManager. + */ + function upperLookup(DefaultWadHistory storage self, uint32 key) internal view returns (uint64) { + return uint64(_upperLookup(self._snapshots, key, WAD)); + } + + /** + * @dev Return default value of 0 if there are no snapshots for DefaultZeroHistory. + * This is used for looking up cumulative scaled shares in the DelegationManager. + */ + function upperLookup(DefaultZeroHistory storage self, uint32 key) internal view returns (uint256) { + return _upperLookup(self._snapshots, key, 0); + } + + /** + * @dev Returns the value in the most recent snapshot, or WAD if there are no snapshots. + */ + function latest( + DefaultWadHistory storage self + ) internal view returns (uint64) { + return uint64(_latest(self._snapshots, WAD)); + } + + /** + * @dev Returns the value in the most recent snapshot, or 0 if there are no snapshots. + */ + function latest( + DefaultZeroHistory storage self + ) internal view returns (uint256) { + return uint256(_latest(self._snapshots, 0)); + } + + /** + * @dev Returns the number of snapshots. + */ + function length( + DefaultWadHistory storage self + ) internal view returns (uint256) { + return self._snapshots.length; + } + + /** + * @dev Returns the number of snapshots. + */ + function length( + DefaultZeroHistory storage self + ) internal view returns (uint256) { + return self._snapshots.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of snapshots, either by inserting a new snapshot, + * or by updating the last one. + */ + function _insert(Snapshot[] storage self, uint32 key, uint224 value) private { + uint256 pos = self.length; + + if (pos > 0) { + // Validate that inserted keys are always >= the previous key + Snapshot memory last = _unsafeAccess(self, pos - 1); + require(last._key <= key, InvalidSnapshotOrdering()); + + // Update existing snapshot if `key` matches + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + return; + } + } + + // `key` was not in the list; push as a new entry + self.push(Snapshot({_key: key, _value: value})); + } + + /** + * @dev Returns the value in the last (most recent) snapshot with key lower or equal than the search key, or `defaultValue` if there is none. + */ + function _upperLookup( + Snapshot[] storage snapshots, + uint32 key, + uint224 defaultValue + ) private view returns (uint224) { + uint256 len = snapshots.length; + uint256 pos = _upperBinaryLookup(snapshots, key, 0, len); + return pos == 0 ? defaultValue : _unsafeAccess(snapshots, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent snapshot, or `defaultValue` if there are no snapshots. + */ + function _latest(Snapshot[] storage snapshots, uint224 defaultValue) private view returns (uint224) { + uint256 pos = snapshots.length; + return pos == 0 ? defaultValue : _unsafeAccess(snapshots, pos - 1)._value; + } + + /** + * @dev Return the index of the last (most recent) snapshot with key lower or equal than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Snapshot[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = MathUpgradeable.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess(Snapshot[] storage self, uint256 pos) private pure returns (Snapshot storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/src/contracts/libraries/StructuredLinkedList.sol b/src/contracts/libraries/StructuredLinkedList.sol deleted file mode 100644 index 29410656f..000000000 --- a/src/contracts/libraries/StructuredLinkedList.sol +++ /dev/null @@ -1,258 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.12; - -/** - * @title StructuredLinkedList - * @author Vittorio Minacori (https://github.com/vittominacori) - * @dev An utility library for using sorted linked list data structures in your Solidity project. - * @notice Adapted from https://github.com/vittominacori/solidity-linked-list/blob/master/contracts/StructuredLinkedList.sol - */ -library StructuredLinkedList { - uint256 private constant _NULL = 0; - uint256 private constant _HEAD = 0; - - bool private constant _PREV = false; - bool private constant _NEXT = true; - - struct List { - uint256 size; - mapping(uint256 => mapping(bool => uint256)) list; - } - - /** - * @dev Checks if the list exists - * @param self stored linked list from contract - * @return bool true if list exists, false otherwise - */ - function listExists(List storage self) internal view returns (bool) { - // if the head nodes previous or next pointers both point to itself, then there are no items in the list - if (self.list[_HEAD][_PREV] != _HEAD || self.list[_HEAD][_NEXT] != _HEAD) { - return true; - } else { - return false; - } - } - - /** - * @dev Checks if the node exists - * @param self stored linked list from contract - * @param _node a node to search for - * @return bool true if node exists, false otherwise - */ - function nodeExists(List storage self, uint256 _node) internal view returns (bool) { - if (self.list[_node][_PREV] == _HEAD && self.list[_node][_NEXT] == _HEAD) { - if (self.list[_HEAD][_NEXT] == _node) { - return true; - } else { - return false; - } - } else { - return true; - } - } - - /** - * @dev Returns the number of elements in the list - * @param self stored linked list from contract - * @return uint256 - */ - function sizeOf(List storage self) internal view returns (uint256) { - return self.size; - } - - /** - * @dev Gets the head of the list - * @param self stored linked list from contract - * @return uint256 the head of the list - */ - function getHead(List storage self) internal view returns (uint256) { - return self.list[_HEAD][_NEXT]; - } - - /** - * @dev Returns the links of a node as a tuple - * @param self stored linked list from contract - * @param _node id of the node to get - * @return bool, uint256, uint256 true if node exists or false otherwise, previous node, next node - */ - function getNode(List storage self, uint256 _node) internal view returns (bool, uint256, uint256) { - if (!nodeExists(self, _node)) { - return (false, 0, 0); - } else { - return (true, self.list[_node][_PREV], self.list[_node][_NEXT]); - } - } - - /** - * @dev Returns the link of a node `_node` in direction `_direction`. - * @param self stored linked list from contract - * @param _node id of the node to step from - * @param _direction direction to step in - * @return bool, uint256 true if node exists or false otherwise, node in _direction - */ - function getAdjacent(List storage self, uint256 _node, bool _direction) internal view returns (bool, uint256) { - if (!nodeExists(self, _node)) { - return (false, 0); - } else { - uint256 adjacent = self.list[_node][_direction]; - return (adjacent != _HEAD, adjacent); - } - } - - /** - * @dev Returns the link of a node `_node` in direction `_NEXT`. - * @param self stored linked list from contract - * @param _node id of the node to step from - * @return bool, uint256 true if node exists or false otherwise, next node - */ - function getNextNode(List storage self, uint256 _node) internal view returns (bool, uint256) { - return getAdjacent(self, _node, _NEXT); - } - - /** - * @dev Returns the link of a node `_node` in direction `_PREV`. - * @param self stored linked list from contract - * @param _node id of the node to step from - * @return bool, uint256 true if node exists or false otherwise, previous node - */ - function getPreviousNode(List storage self, uint256 _node) internal view returns (bool, uint256) { - return getAdjacent(self, _node, _PREV); - } - - /** - * @dev Insert node `_new` beside existing node `_node` in direction `_NEXT`. - * @param self stored linked list from contract - * @param _node existing node - * @param _new new node to insert - * @return bool true if success, false otherwise - */ - function insertAfter(List storage self, uint256 _node, uint256 _new) internal returns (bool) { - return _insert(self, _node, _new, _NEXT); - } - - /** - * @dev Insert node `_new` beside existing node `_node` in direction `_PREV`. - * @param self stored linked list from contract - * @param _node existing node - * @param _new new node to insert - * @return bool true if success, false otherwise - */ - function insertBefore(List storage self, uint256 _node, uint256 _new) internal returns (bool) { - return _insert(self, _node, _new, _PREV); - } - - /** - * @dev Removes an entry from the linked list - * @param self stored linked list from contract - * @param _node node to remove from the list - * @return uint256 the removed node - */ - function remove(List storage self, uint256 _node) internal returns (uint256) { - if ((_node == _NULL) || (!nodeExists(self, _node))) { - return 0; - } - _createLink(self, self.list[_node][_PREV], self.list[_node][_NEXT], _NEXT); - delete self.list[_node][_PREV]; - delete self.list[_node][_NEXT]; - - self.size -= 1; // NOT: SafeMath library should be used here to decrement. - - return _node; - } - - /** - * @dev Pushes an entry to the head of the linked list - * @param self stored linked list from contract - * @param _node new entry to push to the head - * @return bool true if success, false otherwise - */ - function pushFront(List storage self, uint256 _node) internal returns (bool) { - return _push(self, _node, _NEXT); - } - - /** - * @dev Pushes an entry to the tail of the linked list - * @param self stored linked list from contract - * @param _node new entry to push to the tail - * @return bool true if success, false otherwise - */ - function pushBack(List storage self, uint256 _node) internal returns (bool) { - return _push(self, _node, _PREV); - } - - /** - * @dev Pops the first entry from the head of the linked list - * @param self stored linked list from contract - * @return uint256 the removed node - */ - function popFront(List storage self) internal returns (uint256) { - return _pop(self, _NEXT); - } - - /** - * @dev Pops the first entry from the tail of the linked list - * @param self stored linked list from contract - * @return uint256 the removed node - */ - function popBack(List storage self) internal returns (uint256) { - return _pop(self, _PREV); - } - - /** - * @dev Pushes an entry to the head of the linked list - * @param self stored linked list from contract - * @param _node new entry to push to the head - * @param _direction push to the head (_NEXT) or tail (_PREV) - * @return bool true if success, false otherwise - */ - function _push(List storage self, uint256 _node, bool _direction) private returns (bool) { - return _insert(self, _HEAD, _node, _direction); - } - - /** - * @dev Pops the first entry from the linked list - * @param self stored linked list from contract - * @param _direction pop from the head (_NEXT) or the tail (_PREV) - * @return uint256 the removed node - */ - function _pop(List storage self, bool _direction) private returns (uint256) { - uint256 adj; - (, adj) = getAdjacent(self, _HEAD, _direction); - return remove(self, adj); - } - - /** - * @dev Insert node `_new` beside existing node `_node` in direction `_direction`. - * @param self stored linked list from contract - * @param _node existing node - * @param _new new node to insert - * @param _direction direction to insert node in - * @return bool true if success, false otherwise - */ - function _insert(List storage self, uint256 _node, uint256 _new, bool _direction) private returns (bool) { - if (!nodeExists(self, _new) && nodeExists(self, _node)) { - uint256 c = self.list[_node][_direction]; - _createLink(self, _node, _new, _direction); - _createLink(self, _new, c, _direction); - - self.size += 1; // NOT: SafeMath library should be used here to increment. - - return true; - } - - return false; - } - - /** - * @dev Creates a bidirectional link between two nodes on direction `_direction` - * @param self stored linked list from contract - * @param _node existing node - * @param _link node to link to in the _direction - * @param _direction direction to insert node in - */ - function _createLink(List storage self, uint256 _node, uint256 _link, bool _direction) private { - self.list[_link][!_direction] = _node; - self.list[_node][_direction] = _link; - } -} diff --git a/src/contracts/mixins/PermissionControllerMixin.sol b/src/contracts/mixins/PermissionControllerMixin.sol new file mode 100644 index 000000000..88fceff91 --- /dev/null +++ b/src/contracts/mixins/PermissionControllerMixin.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "../interfaces/IPermissionController.sol"; + +abstract contract PermissionControllerMixin { + /// @dev Thrown when the caller is not allowed to call a function on behalf of an account. + error InvalidPermissions(); + + /// @notice Pointer to the permission controller contract. + IPermissionController public immutable permissionController; + + constructor( + IPermissionController _permissionController + ) { + permissionController = _permissionController; + } + + /// @notice Checks if the caller (msg.sender) can call on behalf of an account. + modifier checkCanCall( + address account + ) { + require(_checkCanCall(account), InvalidPermissions()); + _; + } + + /** + * @notice Checks if the caller is allowed to call a function on behalf of an account. + * @param account the account to check + * @dev `msg.sender` is the caller to check that can call the function on behalf of `account`. + * @dev Returns a bool, instead of reverting + */ + function _checkCanCall( + address account + ) internal returns (bool) { + return permissionController.canCall(account, msg.sender, address(this), msg.sig); + } +} diff --git a/src/contracts/mixins/SignatureUtils.sol b/src/contracts/mixins/SignatureUtils.sol new file mode 100644 index 000000000..79a5e932a --- /dev/null +++ b/src/contracts/mixins/SignatureUtils.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; + +import "../interfaces/ISignatureUtils.sol"; + +/// @title SignatureUtils +/// @notice A mixin to provide EIP-712 signature validation utilities. +/// @dev Domain name is hardcoded to "EigenLayer". +abstract contract SignatureUtils is ISignatureUtils { + using SignatureCheckerUpgradeable for address; + + /// CONSTANTS + + /// @notice The EIP-712 typehash for the contract's domain. + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + + /// @dev Returns the original chain ID from the time the contract was deployed. + uint256 internal immutable _INITIAL_CHAIN_ID; + + /// @dev Returns the original domain separator from the time the contract was deployed. + bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR; + + /// CONSTRUCTION + + constructor() { + _INITIAL_CHAIN_ID = block.chainid; + _INITIAL_DOMAIN_SEPARATOR = _calculateDomainSeparator(); + } + + /// EXTERNAL FUNCTIONS + + /** + * @notice Returns the current EIP-712 domain separator for this contract. + * + * @dev The domain separator will change in the event of a fork that changes the ChainID. + * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision. + * for more detailed information please read EIP-712. + * @dev Use `_calculateDomainSeparator` rather than using this function. + */ + function domainSeparator() external view virtual returns (bytes32) { + return _calculateDomainSeparator(); + } + + /// INTERNAL HELPERS + + /// @dev Helper for calculating the contract's current domain separator. + function _calculateDomainSeparator() internal view returns (bytes32) { + /// forgefmt: disable-next-item + return block.chainid == _INITIAL_CHAIN_ID ? + // If the chain ID is the same, return the original domain separator. + _INITIAL_DOMAIN_SEPARATOR : + // If the chain ID is different, return the new domain separator. + keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes("EigenLayer")), + block.chainid, + address(this) + ) + ); + } + + /// @dev Helper for creating valid EIP-712 signable digests. + function _calculateSignableDigest( + bytes32 hash + ) internal view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", _calculateDomainSeparator(), hash)); + } + + /// @dev Helper for checking if a signature is valid, reverts if not valid. + function _checkIsValidSignatureNow( + address signer, + bytes32 signableDigest, + bytes memory signature, + uint256 expiry + ) internal view { + require(expiry >= block.timestamp, SignatureExpired()); + require(signer.isValidSignatureNow(signableDigest, signature), InvalidSignature()); + } +} diff --git a/src/contracts/permissions/Pausable.sol b/src/contracts/permissions/Pausable.sol index 52883e888..d8d9685b2 100644 --- a/src/contracts/permissions/Pausable.sol +++ b/src/contracts/permissions/Pausable.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IPausable.sol"; @@ -20,110 +19,106 @@ import "../interfaces/IPausable.sol"; * @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3` * indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused */ -contract Pausable is IPausable { +abstract contract Pausable is IPausable { + /// Constants + + uint256 internal constant _UNPAUSE_ALL = 0; + + uint256 internal constant _PAUSE_ALL = type(uint256).max; + /// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing). - IPauserRegistry public pauserRegistry; + IPauserRegistry public immutable pauserRegistry; - /// @dev whether or not the contract is currently paused + /// Storage + + /// @dev Do not remove, deprecated storage. + IPauserRegistry private __deprecated_pauserRegistry; + + /// @dev Returns a bitmap representing the paused status of the contract. uint256 private _paused; - uint256 internal constant UNPAUSE_ALL = 0; - uint256 internal constant PAUSE_ALL = type(uint256).max; + /// Modifiers - /// @notice + /// @dev Thrown if the caller is not a valid pauser according to the pauser registry. modifier onlyPauser() { - require(pauserRegistry.isPauser(msg.sender), "msg.sender is not permissioned as pauser"); + require(pauserRegistry.isPauser(msg.sender), OnlyPauser()); _; } + /// @dev Thrown if the caller is not a valid unpauser according to the pauser registry. modifier onlyUnpauser() { - require(msg.sender == pauserRegistry.unpauser(), "msg.sender is not permissioned as unpauser"); + require(msg.sender == pauserRegistry.unpauser(), OnlyUnpauser()); _; } - /// @notice Throws if the contract is paused, i.e. if any of the bits in `_paused` is flipped to 1. + /// @dev Thrown if the contract is paused, i.e. if any of the bits in `_paused` is flipped to 1. modifier whenNotPaused() { - require(_paused == 0, "Pausable: contract is paused"); + require(_paused == 0, CurrentlyPaused()); _; } - /// @notice Throws if the `indexed`th bit of `_paused` is 1, i.e. if the `index`th pause switch is flipped. - modifier onlyWhenNotPaused(uint8 index) { - require(!paused(index), "Pausable: index is paused"); + /// @dev Thrown if the `indexed`th bit of `_paused` is 1, i.e. if the `index`th pause switch is flipped. + modifier onlyWhenNotPaused( + uint8 index + ) { + require(!paused(index), CurrentlyPaused()); _; } - /// @notice One-time function for setting the `pauserRegistry` and initializing the value of `_paused`. - function _initializePauser(IPauserRegistry _pauserRegistry, uint256 initPausedStatus) internal { - require( - address(pauserRegistry) == address(0) && address(_pauserRegistry) != address(0), - "Pausable._initializePauser: _initializePauser() can only be called once" - ); - _paused = initPausedStatus; - emit Paused(msg.sender, initPausedStatus); - _setPauserRegistry(_pauserRegistry); + /// Construction + + constructor( + IPauserRegistry _pauserRegistry + ) { + require(address(_pauserRegistry) != address(0), InputAddressZero()); + pauserRegistry = _pauserRegistry; } - /** - * @notice This function is used to pause an EigenLayer contract's functionality. - * It is permissioned to the `pauser` address, which is expected to be a low threshold multisig. - * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once. - * @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0. - */ - function pause(uint256 newPausedStatus) external onlyPauser { + /// @inheritdoc IPausable + function pause( + uint256 newPausedStatus + ) external onlyPauser { + uint256 currentPausedStatus = _paused; // verify that the `newPausedStatus` does not *unflip* any bits (i.e. doesn't unpause anything, all 1 bits remain) - require((_paused & newPausedStatus) == _paused, "Pausable.pause: invalid attempt to unpause functionality"); - _paused = newPausedStatus; - emit Paused(msg.sender, newPausedStatus); + require((currentPausedStatus & newPausedStatus) == currentPausedStatus, InvalidNewPausedStatus()); + _setPausedStatus(newPausedStatus); } - /** - * @notice Alias for `pause(type(uint256).max)`. - */ + /// @inheritdoc IPausable function pauseAll() external onlyPauser { - _paused = type(uint256).max; - emit Paused(msg.sender, type(uint256).max); + _setPausedStatus(_PAUSE_ALL); } - /** - * @notice This function is used to unpause an EigenLayer contract's functionality. - * It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract. - * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once. - * @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1. - */ - function unpause(uint256 newPausedStatus) external onlyUnpauser { + /// @inheritdoc IPausable + function unpause( + uint256 newPausedStatus + ) external onlyUnpauser { + uint256 currentPausedStatus = _paused; // verify that the `newPausedStatus` does not *flip* any bits (i.e. doesn't pause anything, all 0 bits remain) - require( - ((~_paused) & (~newPausedStatus)) == (~_paused), "Pausable.unpause: invalid attempt to pause functionality" - ); + require(((~currentPausedStatus) & (~newPausedStatus)) == (~currentPausedStatus), InvalidNewPausedStatus()); _paused = newPausedStatus; emit Unpaused(msg.sender, newPausedStatus); } - /// @notice Returns the current paused status as a uint256. + /// @inheritdoc IPausable function paused() public view virtual returns (uint256) { return _paused; } - /// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise - function paused(uint8 index) public view virtual returns (bool) { + /// @inheritdoc IPausable + function paused( + uint8 index + ) public view virtual returns (bool) { uint256 mask = 1 << index; return ((_paused & mask) == mask); } - /// @notice Allows the unpauser to set a new pauser registry - function setPauserRegistry(IPauserRegistry newPauserRegistry) external onlyUnpauser { - _setPauserRegistry(newPauserRegistry); - } - - /// internal function for setting pauser registry - function _setPauserRegistry(IPauserRegistry newPauserRegistry) internal { - require( - address(newPauserRegistry) != address(0), - "Pausable._setPauserRegistry: newPauserRegistry cannot be the zero address" - ); - emit PauserRegistrySet(pauserRegistry, newPauserRegistry); - pauserRegistry = newPauserRegistry; + /// @dev Internal helper for setting the paused status, and emitting the corresponding event. + function _setPausedStatus( + uint256 pausedStatus + ) internal { + _paused = pausedStatus; + emit Paused(msg.sender, pausedStatus); } /** diff --git a/src/contracts/permissions/PauserRegistry.sol b/src/contracts/permissions/PauserRegistry.sol index 1058784ec..cc86944af 100644 --- a/src/contracts/permissions/PauserRegistry.sol +++ b/src/contracts/permissions/PauserRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IPauserRegistry.sol"; @@ -16,7 +16,7 @@ contract PauserRegistry is IPauserRegistry { address public unpauser; modifier onlyUnpauser() { - require(msg.sender == unpauser, "msg.sender is not permissioned as unpauser"); + require(msg.sender == unpauser, OnlyUnpauser()); _; } @@ -35,18 +35,22 @@ contract PauserRegistry is IPauserRegistry { } /// @notice Sets new unpauser - only callable by unpauser, as the unpauser is expected to be kept more secure, e.g. being a multisig with a higher threshold - function setUnpauser(address newUnpauser) external onlyUnpauser { + function setUnpauser( + address newUnpauser + ) external onlyUnpauser { _setUnpauser(newUnpauser); } function _setIsPauser(address pauser, bool canPause) internal { - require(pauser != address(0), "PauserRegistry._setPauser: zero address input"); + require(pauser != address(0), InputAddressZero()); isPauser[pauser] = canPause; emit PauserStatusChanged(pauser, canPause); } - function _setUnpauser(address newUnpauser) internal { - require(newUnpauser != address(0), "PauserRegistry._setUnpauser: zero address input"); + function _setUnpauser( + address newUnpauser + ) internal { + require(newUnpauser != address(0), InputAddressZero()); emit UnpauserChanged(unpauser, newUnpauser); unpauser = newUnpauser; } diff --git a/src/contracts/permissions/PermissionController.sol b/src/contracts/permissions/PermissionController.sol new file mode 100644 index 000000000..c927c05f7 --- /dev/null +++ b/src/contracts/permissions/PermissionController.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import "./PermissionControllerStorage.sol"; + +contract PermissionController is Initializable, PermissionControllerStorage { + using EnumerableSet for *; + + modifier onlyAdmin( + address account + ) { + require(isAdmin(account, msg.sender), NotAdmin()); + _; + } + + /** + * + * INITIALIZING FUNCTIONS + * + */ + constructor() { + _disableInitializers(); + } + + function initialize() external initializer {} + + /** + * + * EXTERNAL FUNCTIONS + * + */ + + /// @inheritdoc IPermissionController + function addPendingAdmin(address account, address admin) external onlyAdmin(account) { + AccountPermissions storage permissions = _permissions[account]; + + // Revert if the admin is already set + require(!permissions.admins.contains(admin), AdminAlreadySet()); + + // Add the admin to the account's pending admins + // If the admin is already pending, the add will fail + require(permissions.pendingAdmins.add(admin), AdminAlreadyPending()); + + emit PendingAdminAdded(account, admin); + } + + /// @inheritdoc IPermissionController + function removePendingAdmin(address account, address admin) external onlyAdmin(account) { + EnumerableSet.AddressSet storage pendingAdmins = _permissions[account].pendingAdmins; + + // Remove the admin from the account's pending admins + // Revert if the admin is not pending + require(pendingAdmins.remove(admin), AdminNotPending()); + + emit PendingAdminRemoved(account, admin); + } + + /// @inheritdoc IPermissionController + function acceptAdmin( + address account + ) external { + AccountPermissions storage permissions = _permissions[account]; + + // Remove the admin from the pending list + // Revert if the admin is not pending + require(permissions.pendingAdmins.remove(msg.sender), AdminNotPending()); + + // Add the admin to the account's admins + // Not wrapped in a require since it must be the case the admin is not one + permissions.admins.add(msg.sender); + + emit AdminSet(account, msg.sender); + } + + /// @inheritdoc IPermissionController + function removeAdmin(address account, address admin) external onlyAdmin(account) { + EnumerableSet.AddressSet storage admins = _permissions[account].admins; + + require(admins.length() > 1, CannotHaveZeroAdmins()); + + // Remove the admin from the account's admins + // If the admin is not set, the remove will fail + require(admins.remove(admin), AdminNotSet()); + + emit AdminRemoved(account, admin); + } + + /// @inheritdoc IPermissionController + function setAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external onlyAdmin(account) { + AccountPermissions storage permissions = _permissions[account]; + + bytes32 targetSelector = _encodeTargetSelector(target, selector); + require(!permissions.appointeePermissions[appointee].contains(targetSelector), AppointeeAlreadySet()); + + // Add the appointee to the account's permissions + permissions.appointeePermissions[appointee].add(targetSelector); + permissions.permissionAppointees[targetSelector].add(appointee); + + emit AppointeeSet(account, appointee, target, selector); + } + + /// @inheritdoc IPermissionController + function removeAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external onlyAdmin(account) { + AccountPermissions storage permissions = _permissions[account]; + + bytes32 targetSelector = _encodeTargetSelector(target, selector); + require(permissions.appointeePermissions[appointee].contains(targetSelector), AppointeeNotSet()); + + // Remove the appointee from the account's permissions + permissions.appointeePermissions[appointee].remove(targetSelector); + permissions.permissionAppointees[targetSelector].remove(appointee); + + emit AppointeeRemoved(account, appointee, target, selector); + } + + /** + * + * INTERNAL FUNCTIONS + * + */ + + /// @dev Encodes the target and selector into a single bytes32 values + /// @dev Encoded Format: [160 bits target][32 bits selector][64 bits padding], + function _encodeTargetSelector(address target, bytes4 selector) internal pure returns (bytes32) { + // Reserve 96 bits for the target + uint256 shiftedTarget = uint256(uint160(target)) << 96; + // Reserve 32 bits for the selector + uint256 shiftedSelector = uint256(uint32(selector)) << 64; + // Combine the target and selector + return bytes32(shiftedTarget | shiftedSelector); + } + + /// @dev Decodes the target and selector from a single bytes32 value + /// @dev Encoded Format: [160 bits target][32 bits selector][64 bits padding], + function _decodeTargetSelector( + bytes32 targetSelector + ) internal pure returns (address, bytes4) { + // The target is in the upper 160 bits of the targetSelector + address target = address(uint160(uint256(targetSelector) >> 96)); + // The selector is in the lower 32 bits after the padding is removed + bytes4 selector = bytes4(uint32(uint256(targetSelector) >> 64)); + + return (target, selector); + } + + /** + * + * VIEW FUNCTIONS + * + */ + + /// @inheritdoc IPermissionController + function isAdmin(address account, address caller) public view returns (bool) { + if (_permissions[account].admins.length() == 0) { + // If the account does not have an admin, the caller must be the account + return account == caller; + } else { + // If the account has an admin, the caller must be an admin + return _permissions[account].admins.contains(caller); + } + } + + /// @inheritdoc IPermissionController + function isPendingAdmin(address account, address pendingAdmin) external view returns (bool) { + return _permissions[account].pendingAdmins.contains(pendingAdmin); + } + + /// @inheritdoc IPermissionController + function getAdmins( + address account + ) external view returns (address[] memory) { + if (_permissions[account].admins.length() == 0) { + address[] memory admin = new address[](1); + admin[0] = account; + return admin; + } else { + return _permissions[account].admins.values(); + } + } + + /// @inheritdoc IPermissionController + function getPendingAdmins( + address account + ) external view returns (address[] memory) { + return _permissions[account].pendingAdmins.values(); + } + + /// @inheritdoc IPermissionController + function canCall(address account, address caller, address target, bytes4 selector) external view returns (bool) { + return isAdmin(account, caller) + || _permissions[account].appointeePermissions[caller].contains(_encodeTargetSelector(target, selector)); + } + + /// @inheritdoc IPermissionController + function getAppointeePermissions( + address account, + address appointee + ) external view returns (address[] memory, bytes4[] memory) { + EnumerableSet.Bytes32Set storage appointeePermissions = _permissions[account].appointeePermissions[appointee]; + + uint256 length = appointeePermissions.length(); + + address[] memory targets = new address[](length); + bytes4[] memory selectors = new bytes4[](length); + + for (uint256 i = 0; i < length; i++) { + (address target, bytes4 selector) = _decodeTargetSelector(appointeePermissions.at(i)); + targets[i] = target; + selectors[i] = selector; + } + + return (targets, selectors); + } + + /// @inheritdoc IPermissionController + function getAppointees(address account, address target, bytes4 selector) external view returns (address[] memory) { + bytes32 targetSelector = _encodeTargetSelector(target, selector); + return _permissions[account].permissionAppointees[targetSelector].values(); + } +} diff --git a/src/contracts/permissions/PermissionControllerStorage.sol b/src/contracts/permissions/PermissionControllerStorage.sol new file mode 100644 index 000000000..771987c78 --- /dev/null +++ b/src/contracts/permissions/PermissionControllerStorage.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import "../interfaces/IPermissionController.sol"; + +abstract contract PermissionControllerStorage is IPermissionController { + using EnumerableSet for EnumerableSet.Bytes32Set; + using EnumerableSet for EnumerableSet.AddressSet; + + struct AccountPermissions { + /// @notice The pending admins of the account + EnumerableSet.AddressSet pendingAdmins; + /// @notice The admins of the account + EnumerableSet.AddressSet admins; + /// @notice Mapping from an appointee to the list of encoded target & selectors + mapping(address appointee => EnumerableSet.Bytes32Set) appointeePermissions; + /// @notice Mapping from encoded target & selector to the list of appointees + mapping(bytes32 targetSelector => EnumerableSet.AddressSet) permissionAppointees; + } + + /// @notice Mapping from an account to its permission + mapping(address account => AccountPermissions) internal _permissions; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} diff --git a/src/contracts/pods/EigenPod.sol b/src/contracts/pods/EigenPod.sol index d98ef59f3..f69981cec 100644 --- a/src/contracts/pods/EigenPod.sol +++ b/src/contracts/pods/EigenPod.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; @@ -61,22 +61,19 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC /// @notice Callable only by the EigenPodManager modifier onlyEigenPodManager() { - require(msg.sender == address(eigenPodManager), "EigenPod.onlyEigenPodManager: not eigenPodManager"); + require(msg.sender == address(eigenPodManager), OnlyEigenPodManager()); _; } /// @notice Callable only by the pod's owner modifier onlyEigenPodOwner() { - require(msg.sender == podOwner, "EigenPod.onlyEigenPodOwner: not podOwner"); + require(msg.sender == podOwner, OnlyEigenPodOwner()); _; } /// @notice Callable only by the pod's owner or proof submitter modifier onlyOwnerOrProofSubmitter() { - require( - msg.sender == podOwner || msg.sender == proofSubmitter, - "EigenPod.onlyOwnerOrProofSubmitter: caller is not pod owner or proof submitter" - ); + require(msg.sender == podOwner || msg.sender == proofSubmitter, OnlyEigenPodOwnerOrProofSubmitter()); _; } @@ -85,11 +82,10 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC * is necessary for enabling pausing all EigenPods at the same time (due to EigenPods being Beacon Proxies). * Modifier throws if the `indexed`th bit of `_paused` in the EigenPodManager is 1, i.e. if the `index`th pause switch is flipped. */ - modifier onlyWhenNotPaused(uint8 index) { - require( - !IPausable(address(eigenPodManager)).paused(index), - "EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager" - ); + modifier onlyWhenNotPaused( + uint8 index + ) { + require(!IPausable(address(eigenPodManager)).paused(index), CurrentlyPaused()); _; } @@ -106,8 +102,10 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC } /// @notice Used to initialize the pointers to addresses crucial to the pod's functionality. Called on construction by the EigenPodManager. - function initialize(address _podOwner) external initializer { - require(_podOwner != address(0), "EigenPod.initialize: podOwner cannot be zero address"); + function initialize( + address _podOwner + ) external initializer { + require(_podOwner != address(0), InputAddressZero()); podOwner = _podOwner; } @@ -134,11 +132,9 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC * @param revertIfNoBalance Forces a revert if the pod ETH balance is 0. This allows the pod owner * to prevent accidentally starting a checkpoint that will not increase their shares */ - function startCheckpoint(bool revertIfNoBalance) - external - onlyOwnerOrProofSubmitter - onlyWhenNotPaused(PAUSED_START_CHECKPOINT) - { + function startCheckpoint( + bool revertIfNoBalance + ) external onlyOwnerOrProofSubmitter onlyWhenNotPaused(PAUSED_START_CHECKPOINT) { _startCheckpoint(revertIfNoBalance); } @@ -157,10 +153,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC BeaconChainProofs.BalanceProof[] calldata proofs ) external onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS) { uint64 checkpointTimestamp = currentCheckpointTimestamp; - require( - checkpointTimestamp != 0, - "EigenPod.verifyCheckpointProofs: must have active checkpoint to perform checkpoint proof" - ); + require(checkpointTimestamp != 0, NoActiveCheckpoint()); Checkpoint memory checkpoint = _currentCheckpoint; @@ -196,7 +189,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC // If the proof shows the validator has a balance of 0, they are marked `WITHDRAWN`. // The assumption is that if this is the case, any withdrawn ETH was already in // the pod when `startCheckpoint` was originally called. - (int128 balanceDeltaGwei, uint64 exitedBalanceGwei) = _verifyCheckpointProof({ + (uint64 prevBalanceGwei, int64 balanceDeltaGwei, uint64 exitedBalanceGwei) = _verifyCheckpointProof({ validatorInfo: validatorInfo, checkpointTimestamp: checkpointTimestamp, balanceContainerRoot: balanceContainerProof.balanceContainerRoot, @@ -204,6 +197,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC }); checkpoint.proofsRemaining--; + checkpoint.prevBeaconBalanceGwei += prevBalanceGwei; checkpoint.balanceDeltasGwei += balanceDeltaGwei; exitedBalancesGwei += exitedBalanceGwei; @@ -241,16 +235,13 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC require( (validatorIndices.length == validatorFieldsProofs.length) && (validatorFieldsProofs.length == validatorFields.length), - "EigenPod.verifyWithdrawalCredentials: validatorIndices and proofs must be same length" + InputArrayLengthMismatch() ); // Calling this method using a `beaconTimestamp` <= `currentCheckpointTimestamp` would allow // a newly-verified validator to be submitted to `verifyCheckpointProofs`, making progress // on an existing checkpoint. - require( - beaconTimestamp > currentCheckpointTimestamp, - "EigenPod.verifyWithdrawalCredentials: specified timestamp is too far in past" - ); + require(beaconTimestamp > currentCheckpointTimestamp, BeaconTimestampTooFarInPast()); // Verify passed-in `beaconStateRoot` against the beacon block root // forgefmt: disable-next-item @@ -271,7 +262,11 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC } // Update the EigenPodManager on this pod's new balance - eigenPodManager.recordBeaconChainETHBalanceUpdate(podOwner, int256(totalAmountToBeRestakedWei)); + eigenPodManager.recordBeaconChainETHBalanceUpdate({ + podOwner: podOwner, + prevRestakedBalanceWei: 0, // only used for checkpoint balance updates + balanceDeltaWei: int256(totalAmountToBeRestakedWei) + }); } /** @@ -329,19 +324,13 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC // that have initiated exits, we know that if we're seeing a proof where the validator // is slashed that it MUST be newer than the `verifyWithdrawalCredentials` proof // (regardless of the relationship between `beaconTimestamp` and `lastCheckpointedAt`). - require( - beaconTimestamp > validatorInfo.lastCheckpointedAt, - "EigenPod.verifyStaleBalance: proof is older than last checkpoint" - ); + require(beaconTimestamp > validatorInfo.lastCheckpointedAt, BeaconTimestampTooFarInPast()); // Validator must be checkpoint-able - require(validatorInfo.status == VALIDATOR_STATUS.ACTIVE, "EigenPod.verifyStaleBalance: validator is not active"); + require(validatorInfo.status == VALIDATOR_STATUS.ACTIVE, ValidatorNotActiveInPod()); // Validator must be slashed on the beacon chain - require( - proof.validatorFields.isValidatorSlashed(), - "EigenPod.verifyStaleBalance: validator must be slashed to be marked stale" - ); + require(proof.validatorFields.isValidatorSlashed(), ValidatorNotSlashedOnBeaconChain()); // Verify passed-in `beaconStateRoot` against the beacon block root // forgefmt: disable-next-item @@ -368,10 +357,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC uint256[] memory amountsToWithdraw, address recipient ) external onlyEigenPodOwner onlyWhenNotPaused(PAUSED_NON_PROOF_WITHDRAWALS) { - require( - tokenList.length == amountsToWithdraw.length, - "EigenPod.recoverTokens: tokenList and amountsToWithdraw must be same length" - ); + require(tokenList.length == amountsToWithdraw.length, InputArrayLengthMismatch()); for (uint256 i = 0; i < tokenList.length; i++) { tokenList[i].safeTransfer(recipient, amountsToWithdraw[i]); } @@ -384,7 +370,9 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC /// only address that can call these methods. /// @param newProofSubmitter The new proof submitter address. If set to 0, only the /// pod owner will be able to call `startCheckpoint` and `verifyWithdrawalCredentials` - function setProofSubmitter(address newProofSubmitter) external onlyEigenPodOwner { + function setProofSubmitter( + address newProofSubmitter + ) external onlyEigenPodOwner { emit ProofSubmitterUpdated(proofSubmitter, newProofSubmitter); proofSubmitter = newProofSubmitter; } @@ -396,7 +384,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC bytes32 depositDataRoot ) external payable onlyEigenPodManager { // stake on ethpos - require(msg.value == 32 ether, "EigenPod.stake: must initially stake for any validator with 32 ether"); + require(msg.value == 32 ether, MsgValueNot32ETH()); ethPOS.deposit{value: 32 ether}(pubkey, _podWithdrawalCredentials(), signature, depositDataRoot); emit EigenPodStaked(pubkey); } @@ -404,21 +392,15 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC /** * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain. - * @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `withdrawableRestakedExecutionLayerGwei` exceeds the + * @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `restakedExecutionLayerGwei` exceeds the * `amountWei` input (when converted to GWEI). * @dev Reverts if `amountWei` is not a whole Gwei amount */ function withdrawRestakedBeaconChainETH(address recipient, uint256 amountWei) external onlyEigenPodManager { - require( - amountWei % GWEI_TO_WEI == 0, - "EigenPod.withdrawRestakedBeaconChainETH: amountWei must be a whole Gwei amount" - ); + require(amountWei % GWEI_TO_WEI == 0, AmountMustBeMultipleOfGwei()); uint64 amountGwei = uint64(amountWei / GWEI_TO_WEI); - require( - amountGwei <= withdrawableRestakedExecutionLayerGwei, - "EigenPod.withdrawRestakedBeaconChainETH: amountGwei exceeds withdrawableRestakedExecutionLayerGwei" - ); - withdrawableRestakedExecutionLayerGwei -= amountGwei; + require(amountGwei <= restakedExecutionLayerGwei, InsufficientWithdrawableBalance()); + restakedExecutionLayerGwei -= amountGwei; emit RestakedBeaconChainETHWithdrawn(recipient, amountWei); // transfer ETH from pod to `recipient` directly Address.sendValue(payable(recipient), amountWei); @@ -446,10 +428,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC ValidatorInfo memory validatorInfo = _validatorPubkeyHashToInfo[pubkeyHash]; // Withdrawal credential proofs should only be processed for "INACTIVE" validators - require( - validatorInfo.status == VALIDATOR_STATUS.INACTIVE, - "EigenPod._verifyWithdrawalCredentials: validator must be inactive to prove withdrawal credentials" - ); + require(validatorInfo.status == VALIDATOR_STATUS.INACTIVE, CredentialsAlreadyVerified()); // Validator should be active on the beacon chain, or in the process of activating. // This implies the validator has reached the minimum effective balance required @@ -465,8 +444,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC // to temporarily decrease, then be restored later. This would effectively prevent these // shares from being slashable on EigenLayer for a short period of time. require( - validatorFields.getActivationEpoch() != BeaconChainProofs.FAR_FUTURE_EPOCH, - "EigenPod._verifyWithdrawalCredentials: validator must be in the process of activating" + validatorFields.getActivationEpoch() != BeaconChainProofs.FAR_FUTURE_EPOCH, ValidatorInactiveOnBeaconChain() ); // Validator should not already be in the process of exiting. This is an important property @@ -491,15 +469,12 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC // 1 + MAX_SEED_LOOKAHEAD + MIN_VALIDATOR_WITHDRAWABILITY_DELAY == 261 epochs (8352 slots). // // (See https://eth2book.info/capella/part3/helper/mutators/#initiate_validator_exit) - require( - validatorFields.getExitEpoch() == BeaconChainProofs.FAR_FUTURE_EPOCH, - "EigenPod._verifyWithdrawalCredentials: validator must not be exiting" - ); + require(validatorFields.getExitEpoch() == BeaconChainProofs.FAR_FUTURE_EPOCH, ValidatorIsExitingBeaconChain()); // Ensure the validator's withdrawal credentials are pointed at this pod require( validatorFields.getWithdrawalCredentials() == bytes32(_podWithdrawalCredentials()), - "EigenPod._verifyWithdrawalCredentials: proof is not for this EigenPod" + WithdrawalCredentialsNotForEigenPod() ); // Get the validator's effective balance. Note that this method uses effective balance, while @@ -531,6 +506,11 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC status: VALIDATOR_STATUS.ACTIVE }); + // Add the validator's balance to the checkpoint's previous beacon balance + // Note that even if this checkpoint is not active, the next one will include + // the validator's restaked balance during the checkpoint process + _currentCheckpoint.prevBeaconBalanceGwei += restakedBalanceGwei; + emit ValidatorRestaked(validatorIndex); emit ValidatorBalanceUpdated(validatorIndex, lastCheckpointedAt, restakedBalanceGwei); return restakedBalanceGwei * GWEI_TO_WEI; @@ -541,11 +521,11 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC uint64 checkpointTimestamp, bytes32 balanceContainerRoot, BeaconChainProofs.BalanceProof calldata proof - ) internal returns (int128 balanceDeltaGwei, uint64 exitedBalanceGwei) { + ) internal returns (uint64 prevBalanceGwei, int64 balanceDeltaGwei, uint64 exitedBalanceGwei) { uint40 validatorIndex = uint40(validatorInfo.validatorIndex); // Verify validator balance against `balanceContainerRoot` - uint64 prevBalanceGwei = validatorInfo.restakedBalanceGwei; + prevBalanceGwei = validatorInfo.restakedBalanceGwei; uint64 newBalanceGwei = BeaconChainProofs.verifyValidatorBalance({ balanceContainerRoot: balanceContainerRoot, validatorIndex: validatorIndex, @@ -554,12 +534,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC // Calculate change in the validator's balance since the last proof if (newBalanceGwei != prevBalanceGwei) { - // forgefmt: disable-next-item - balanceDeltaGwei = _calcBalanceDelta({ - newAmountGwei: newBalanceGwei, - previousAmountGwei: prevBalanceGwei - }); - + balanceDeltaGwei = int64(newBalanceGwei) - int64(prevBalanceGwei); emit ValidatorBalanceUpdated(validatorIndex, checkpointTimestamp, newBalanceGwei); } @@ -572,12 +547,12 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC validatorInfo.status = VALIDATOR_STATUS.WITHDRAWN; // If we reach this point, `balanceDeltaGwei` should always be negative, // so this should be a safe conversion - exitedBalanceGwei = uint64(uint128(-balanceDeltaGwei)); + exitedBalanceGwei = uint64(-balanceDeltaGwei); emit ValidatorWithdrawn(checkpointTimestamp, validatorIndex); } - return (balanceDeltaGwei, exitedBalanceGwei); + return (prevBalanceGwei, balanceDeltaGwei, exitedBalanceGwei); } /** @@ -593,36 +568,32 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC * @param revertIfNoBalance If the available ETH balance for checkpointing is 0 and this is * true, this method will revert */ - function _startCheckpoint(bool revertIfNoBalance) internal { - require( - currentCheckpointTimestamp == 0, - "EigenPod._startCheckpoint: must finish previous checkpoint before starting another" - ); + function _startCheckpoint( + bool revertIfNoBalance + ) internal { + require(currentCheckpointTimestamp == 0, CheckpointAlreadyActive()); // Prevent a checkpoint being completable twice in the same block. This prevents an edge case // where the second checkpoint would not be completable. // // This is because the validators checkpointed in the first checkpoint would have a `lastCheckpointedAt` // value equal to the second checkpoint, causing their proofs to get skipped in `verifyCheckpointProofs` - require( - lastCheckpointTimestamp != uint64(block.timestamp), - "EigenPod._startCheckpoint: cannot checkpoint twice in one block" - ); + require(lastCheckpointTimestamp != uint64(block.timestamp), CannotCheckpointTwiceInSingleBlock()); // Snapshot pod balance at the start of the checkpoint, subtracting pod balance that has // previously been credited with shares. Once the checkpoint is finalized, `podBalanceGwei` // will be added to the total validator balance delta and credited as shares. // - // Note: On finalization, `podBalanceGwei` is added to `withdrawableRestakedExecutionLayerGwei` + // Note: On finalization, `podBalanceGwei` is added to `restakedExecutionLayerGwei` // to denote that it has been credited with shares. Because this value is denominated in gwei, // `podBalanceGwei` is also converted to a gwei amount here. This means that any sub-gwei amounts // sent to the pod are not credited with shares and are therefore not withdrawable. // This can be addressed by topping up a pod's balance to a value divisible by 1 gwei. - uint64 podBalanceGwei = uint64(address(this).balance / GWEI_TO_WEI) - withdrawableRestakedExecutionLayerGwei; + uint64 podBalanceGwei = uint64(address(this).balance / GWEI_TO_WEI) - restakedExecutionLayerGwei; // If the caller doesn't want a "0 balance" checkpoint, revert if (revertIfNoBalance && podBalanceGwei == 0) { - revert("EigenPod._startCheckpoint: no balance available to checkpoint"); + revert NoBalanceToCheckpoint(); } // Create checkpoint using the previous block's root for proofs, and the current @@ -632,7 +603,8 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC beaconBlockRoot: getParentBlockRoot(uint64(block.timestamp)), proofsRemaining: uint24(activeValidatorCount), podBalanceGwei: podBalanceGwei, - balanceDeltasGwei: 0 + balanceDeltasGwei: 0, + prevBeaconBalanceGwei: 0 }); // Place checkpoint in storage. If `proofsRemaining` is 0, the checkpoint @@ -647,30 +619,46 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC * @dev Finish progress on a checkpoint and store it in state. * @dev If the checkpoint has no proofs remaining, it is finalized: * - a share delta is calculated and sent to the `EigenPodManager` - * - the checkpointed `podBalanceGwei` is added to `withdrawableRestakedExecutionLayerGwei` + * - the checkpointed `podBalanceGwei` is added to `restakedExecutionLayerGwei` * - `lastCheckpointTimestamp` is updated * - `_currentCheckpoint` and `currentCheckpointTimestamp` are deleted */ - function _updateCheckpoint(Checkpoint memory checkpoint) internal { - if (checkpoint.proofsRemaining == 0) { - int256 totalShareDeltaWei = - (int128(uint128(checkpoint.podBalanceGwei)) + checkpoint.balanceDeltasGwei) * int256(GWEI_TO_WEI); - - // Add any native ETH in the pod to `withdrawableRestakedExecutionLayerGwei` - // ... this amount can be withdrawn via the `DelegationManager` withdrawal queue - withdrawableRestakedExecutionLayerGwei += checkpoint.podBalanceGwei; - - // Finalize the checkpoint - lastCheckpointTimestamp = currentCheckpointTimestamp; - delete currentCheckpointTimestamp; - delete _currentCheckpoint; - - // Update pod owner's shares - eigenPodManager.recordBeaconChainETHBalanceUpdate(podOwner, totalShareDeltaWei); - emit CheckpointFinalized(lastCheckpointTimestamp, totalShareDeltaWei); - } else { + function _updateCheckpoint( + Checkpoint memory checkpoint + ) internal { + if (checkpoint.proofsRemaining != 0) { _currentCheckpoint = checkpoint; + return; } + + // Calculate the previous total restaked balance and change in restaked balance + // Note: due to how these values are calculated, a negative `balanceDeltaGwei` + // should NEVER be greater in magnitude than `prevRestakedBalanceGwei` + uint64 prevRestakedBalanceGwei = restakedExecutionLayerGwei + checkpoint.prevBeaconBalanceGwei; + int64 balanceDeltaGwei = int64(checkpoint.podBalanceGwei) + checkpoint.balanceDeltasGwei; + + // And native ETH when the checkpoint was started is now considered restaked. + // Add it to `restakedExecutionLayerGwei`, which allows it to be withdrawn via + // the `DelegationManager` withdrawal queue. + restakedExecutionLayerGwei += checkpoint.podBalanceGwei; + + // Finalize the checkpoint by resetting `currentCheckpointTimestamp`. + // Note: `_currentCheckpoint` is not deleted, as it is overwritten + // when a new checkpoint is started + lastCheckpointTimestamp = currentCheckpointTimestamp; + delete currentCheckpointTimestamp; + + // Convert shares and delta to wei + uint256 prevRestakedBalanceWei = prevRestakedBalanceGwei * GWEI_TO_WEI; + int256 balanceDeltaWei = balanceDeltaGwei * int256(GWEI_TO_WEI); + + // Update pod owner's shares + emit CheckpointFinalized(lastCheckpointTimestamp, balanceDeltaWei); + eigenPodManager.recordBeaconChainETHBalanceUpdate({ + podOwner: podOwner, + prevRestakedBalanceWei: prevRestakedBalanceWei, + balanceDeltaWei: balanceDeltaWei + }); } function _podWithdrawalCredentials() internal view returns (bytes memory) { @@ -678,38 +666,48 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC } ///@notice Calculates the pubkey hash of a validator's pubkey as per SSZ spec - function _calculateValidatorPubkeyHash(bytes memory validatorPubkey) internal pure returns (bytes32) { - require(validatorPubkey.length == 48, "EigenPod._calculateValidatorPubkeyHash must be a 48-byte BLS public key"); + function _calculateValidatorPubkeyHash( + bytes memory validatorPubkey + ) internal pure returns (bytes32) { + require(validatorPubkey.length == 48, InvalidPubKeyLength()); return sha256(abi.encodePacked(validatorPubkey, bytes16(0))); } - /// @dev Calculates the delta between two Gwei amounts and returns as an int256 - function _calcBalanceDelta(uint64 newAmountGwei, uint64 previousAmountGwei) internal pure returns (int128) { - return int128(uint128(newAmountGwei)) - int128(uint128(previousAmountGwei)); - } - /** * * VIEW FUNCTIONS * */ + /// @inheritdoc IEigenPod + function withdrawableRestakedExecutionLayerGwei() external view returns (uint64) { + return restakedExecutionLayerGwei; + } + /// @notice Returns the validatorInfo for a given validatorPubkeyHash - function validatorPubkeyHashToInfo(bytes32 validatorPubkeyHash) external view returns (ValidatorInfo memory) { + function validatorPubkeyHashToInfo( + bytes32 validatorPubkeyHash + ) external view returns (ValidatorInfo memory) { return _validatorPubkeyHashToInfo[validatorPubkeyHash]; } /// @notice Returns the validatorInfo for a given validatorPubkey - function validatorPubkeyToInfo(bytes calldata validatorPubkey) external view returns (ValidatorInfo memory) { + function validatorPubkeyToInfo( + bytes calldata validatorPubkey + ) external view returns (ValidatorInfo memory) { return _validatorPubkeyHashToInfo[_calculateValidatorPubkeyHash(validatorPubkey)]; } - function validatorStatus(bytes32 pubkeyHash) external view returns (VALIDATOR_STATUS) { + function validatorStatus( + bytes32 pubkeyHash + ) external view returns (VALIDATOR_STATUS) { return _validatorPubkeyHashToInfo[pubkeyHash].status; } /// @notice Returns the validator status for a given validatorPubkey - function validatorStatus(bytes calldata validatorPubkey) external view returns (VALIDATOR_STATUS) { + function validatorStatus( + bytes calldata validatorPubkey + ) external view returns (VALIDATOR_STATUS) { bytes32 validatorPubkeyHash = _calculateValidatorPubkeyHash(validatorPubkey); return _validatorPubkeyHashToInfo[validatorPubkeyHash].status; } @@ -723,15 +721,14 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC /// @param timestamp of the block for which the parent block root will be returned. MUST correspond /// to an existing slot within the last 24 hours. If the slot at `timestamp` was skipped, this method /// will revert. - function getParentBlockRoot(uint64 timestamp) public view returns (bytes32) { - require( - block.timestamp - timestamp < BEACON_ROOTS_HISTORY_BUFFER_LENGTH * 12, - "EigenPod.getParentBlockRoot: timestamp out of range" - ); + function getParentBlockRoot( + uint64 timestamp + ) public view returns (bytes32) { + require(block.timestamp - timestamp < BEACON_ROOTS_HISTORY_BUFFER_LENGTH * 12, TimestampOutOfRange()); (bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(abi.encode(timestamp)); - require(success && result.length > 0, "EigenPod.getParentBlockRoot: invalid block root returned"); + require(success && result.length > 0, InvalidEIP4788Response()); return abi.decode(result, (bytes32)); } } diff --git a/src/contracts/pods/EigenPodManager.sol b/src/contracts/pods/EigenPodManager.sol index 300f36de0..418cdd003 100644 --- a/src/contracts/pods/EigenPodManager.sol +++ b/src/contracts/pods/EigenPodManager.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/Create2.sol"; import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; +import "../libraries/SlashingLib.sol"; import "../permissions/Pausable.sol"; import "./EigenPodPausingConstants.sol"; import "./EigenPodManagerStorage.sol"; @@ -28,15 +29,17 @@ contract EigenPodManager is EigenPodManagerStorage, ReentrancyGuardUpgradeable { - modifier onlyEigenPod(address podOwner) { - require(address(ownerToPod[podOwner]) == msg.sender, "EigenPodManager.onlyEigenPod: not a pod"); + using SlashingLib for *; + + modifier onlyEigenPod( + address podOwner + ) { + require(address(ownerToPod[podOwner]) == msg.sender, OnlyEigenPod()); _; } modifier onlyDelegationManager() { - require( - msg.sender == address(delegationManager), "EigenPodManager.onlyDelegationManager: not the DelegationManager" - ); + require(msg.sender == address(delegationManager), OnlyDelegationManager()); _; } @@ -44,41 +47,30 @@ contract EigenPodManager is IETHPOSDeposit _ethPOS, IBeacon _eigenPodBeacon, IStrategyManager _strategyManager, - ISlasher _slasher, - IDelegationManager _delegationManager - ) EigenPodManagerStorage(_ethPOS, _eigenPodBeacon, _strategyManager, _slasher, _delegationManager) { + IDelegationManager _delegationManager, + IPauserRegistry _pauserRegistry + ) + EigenPodManagerStorage(_ethPOS, _eigenPodBeacon, _strategyManager, _delegationManager) + Pausable(_pauserRegistry) + { _disableInitializers(); } - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 _initPausedStatus - ) external initializer { + function initialize(address initialOwner, uint256 _initPausedStatus) external initializer { _transferOwnership(initialOwner); - _initializePauser(_pauserRegistry, _initPausedStatus); + _setPausedStatus(_initPausedStatus); } - /** - * @notice Creates an EigenPod for the sender. - * @dev Function will revert if the `msg.sender` already has an EigenPod. - * @dev Returns EigenPod address - */ + /// @inheritdoc IEigenPodManager function createPod() external onlyWhenNotPaused(PAUSED_NEW_EIGENPODS) returns (address) { - require(!hasPod(msg.sender), "EigenPodManager.createPod: Sender already has a pod"); + require(!hasPod(msg.sender), EigenPodAlreadyExists()); // deploy a pod if the sender doesn't have one already IEigenPod pod = _deployPod(); return address(pod); } - /** - * @notice Stakes for a new beacon chain validator on the sender's EigenPod. - * Also creates an EigenPod for the sender if they don't have one already. - * @param pubkey The 48 bytes public key of the beacon chain validator. - * @param signature The validator's signature of the deposit data. - * @param depositDataRoot The root/hash of the deposit data for the validator's deposit. - */ + /// @inheritdoc IEigenPodManager function stake( bytes calldata pubkey, bytes calldata signature, @@ -92,100 +84,90 @@ contract EigenPodManager is pod.stake{value: msg.value}(pubkey, signature, depositDataRoot); } - /** - * @notice Changes the `podOwner`'s shares by `sharesDelta` and performs a call to the DelegationManager - * to ensure that delegated shares are also tracked correctly - * @param podOwner is the pod owner whose balance is being updated. - * @param sharesDelta is the change in podOwner's beaconChainETHStrategy shares - * @dev Callable only by the podOwner's EigenPod contract. - * @dev Reverts if `sharesDelta` is not a whole Gwei amount - */ + /// @inheritdoc IEigenPodManager function recordBeaconChainETHBalanceUpdate( address podOwner, - int256 sharesDelta + uint256 prevRestakedBalanceWei, + int256 balanceDeltaWei ) external onlyEigenPod(podOwner) nonReentrant { - require( - podOwner != address(0), "EigenPodManager.recordBeaconChainETHBalanceUpdate: podOwner cannot be zero address" - ); - require( - sharesDelta % int256(GWEI_TO_WEI) == 0, - "EigenPodManager.recordBeaconChainETHBalanceUpdate: sharesDelta must be a whole Gwei amount" - ); - int256 currentPodOwnerShares = podOwnerShares[podOwner]; - int256 updatedPodOwnerShares = currentPodOwnerShares + sharesDelta; - podOwnerShares[podOwner] = updatedPodOwnerShares; - - // inform the DelegationManager of the change in delegateable shares - int256 changeInDelegatableShares = _calculateChangeInDelegatableShares({ - sharesBefore: currentPodOwnerShares, - sharesAfter: updatedPodOwnerShares - }); - // skip making a call to the DelegationManager if there is no change in delegateable shares - if (changeInDelegatableShares != 0) { - if (changeInDelegatableShares < 0) { - delegationManager.decreaseDelegatedShares({ - staker: podOwner, - strategy: beaconChainETHStrategy, - shares: uint256(-changeInDelegatableShares) - }); - } else { - delegationManager.increaseDelegatedShares({ - staker: podOwner, - strategy: beaconChainETHStrategy, - shares: uint256(changeInDelegatableShares) - }); - } + require(podOwner != address(0), InputAddressZero()); + require(balanceDeltaWei % int256(GWEI_TO_WEI) == 0, SharesNotMultipleOfGwei()); + // Negative shares only exist in certain cases where, prior to the slashing release, negative balance + // deltas were reported after a pod owner queued a withdrawal for all their shares. + // + // The new system treats negative balance deltas differently, decreasing the pod owner's slashing factor + // proportional to the decrease. This check was added to ensure the new system does not need to handle + // negative shares - instead, stakers will need to go complete any existing withdrawals before their pod + // can process a balance update. + require(podOwnerDepositShares[podOwner] >= 0, LegacyWithdrawalsNotCompleted()); + + // Shares are only added to the pod owner's balance when `balanceDeltaWei` >= 0. When a pod reports + // a negative balance delta, the pod owner's beacon chain slashing factor is decreased, devaluing + // their shares. + if (balanceDeltaWei >= 0) { + (uint256 prevDepositShares, uint256 addedShares) = _addShares(podOwner, uint256(balanceDeltaWei)); + + // Update operator shares + delegationManager.increaseDelegatedShares({ + staker: podOwner, + strategy: beaconChainETHStrategy, + prevDepositShares: prevDepositShares, + addedShares: addedShares + }); + } else { + (uint256 curDepositShares, uint64 prevBeaconSlashingFactor, uint256 wadSlashed) = _reduceSlashingFactor({ + podOwner: podOwner, + prevRestakedBalanceWei: prevRestakedBalanceWei, + balanceDecreasedWei: uint256(-balanceDeltaWei) + }); + + // Update operator shares + delegationManager.decreaseDelegatedShares({ + staker: podOwner, + curDepositShares: curDepositShares, + prevBeaconChainSlashingFactor: prevBeaconSlashingFactor, + wadSlashed: wadSlashed + }); } - emit PodSharesUpdated(podOwner, sharesDelta); - emit NewTotalShares(podOwner, updatedPodOwnerShares); } /** - * @notice Used by the DelegationManager to remove a pod owner's shares while they're in the withdrawal queue. + * @notice Used by the DelegationManager to remove a pod owner's deposit shares when they enter the withdrawal queue. * Simply decreases the `podOwner`'s shares by `shares`, down to a minimum of zero. - * @dev This function reverts if it would result in `podOwnerShares[podOwner]` being less than zero, i.e. it is forbidden for this function to + * @dev This function reverts if it would result in `podOwnerDepositShares[podOwner]` being less than zero, i.e. it is forbidden for this function to * result in the `podOwner` incurring a "share deficit". This behavior prevents a Staker from queuing a withdrawal which improperly removes excessive * shares from the operator to whom the staker is delegated. - * @dev Reverts if `shares` is not a whole Gwei amount * @dev The delegation manager validates that the podOwner is not address(0) */ - function removeShares(address podOwner, uint256 shares) external onlyDelegationManager { - require(int256(shares) >= 0, "EigenPodManager.removeShares: shares cannot be negative"); - require(shares % GWEI_TO_WEI == 0, "EigenPodManager.removeShares: shares must be a whole Gwei amount"); - int256 updatedPodOwnerShares = podOwnerShares[podOwner] - int256(shares); - require( - updatedPodOwnerShares >= 0, - "EigenPodManager.removeShares: cannot result in pod owner having negative shares" - ); - podOwnerShares[podOwner] = updatedPodOwnerShares; + function removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) external onlyDelegationManager { + require(strategy == beaconChainETHStrategy, InvalidStrategy()); + int256 updatedShares = podOwnerDepositShares[staker] - int256(depositSharesToRemove); + require(updatedShares >= 0, SharesNegative()); + podOwnerDepositShares[staker] = updatedShares; - emit NewTotalShares(podOwner, updatedPodOwnerShares); + emit NewTotalShares(staker, updatedShares); } /** * @notice Increases the `podOwner`'s shares by `shares`, paying off deficit if possible. * Used by the DelegationManager to award a pod owner shares on exiting the withdrawal queue - * @dev Returns the number of shares added to `podOwnerShares[podOwner]` above zero, which will be less than the `shares` input - * in the event that the podOwner has an existing shares deficit (i.e. `podOwnerShares[podOwner]` starts below zero) * @dev Reverts if `shares` is not a whole Gwei amount + * @return existingDepositShares the pod owner's shares prior to any additions. Returns 0 if negative + * @return addedShares the number of shares added to the staker's balance above 0. This means that if, + * after shares are added, the staker's balance is non-positive, this will return 0. */ - function addShares(address podOwner, uint256 shares) external onlyDelegationManager returns (uint256) { - require(podOwner != address(0), "EigenPodManager.addShares: podOwner cannot be zero address"); - require(int256(shares) >= 0, "EigenPodManager.addShares: shares cannot be negative"); - require(shares % GWEI_TO_WEI == 0, "EigenPodManager.addShares: shares must be a whole Gwei amount"); - int256 currentPodOwnerShares = podOwnerShares[podOwner]; - int256 updatedPodOwnerShares = currentPodOwnerShares + int256(shares); - podOwnerShares[podOwner] = updatedPodOwnerShares; - - emit PodSharesUpdated(podOwner, int256(shares)); - emit NewTotalShares(podOwner, updatedPodOwnerShares); - - return uint256( - _calculateChangeInDelegatableShares({ - sharesBefore: currentPodOwnerShares, - sharesAfter: updatedPodOwnerShares - }) - ); + function addShares( + address staker, + IStrategy strategy, + IERC20, + uint256 shares + ) external onlyDelegationManager returns (uint256, uint256) { + require(strategy == beaconChainETHStrategy, InvalidStrategy()); + return _addShares(staker, shares); } /** @@ -193,40 +175,51 @@ contract EigenPodManager is * @dev Prioritizes decreasing the podOwner's share deficit, if they have one * @dev Reverts if `shares` is not a whole Gwei amount * @dev This function assumes that `removeShares` has already been called by the delegationManager, hence why - * we do not need to update the podOwnerShares if `currentPodOwnerShares` is positive + * we do not need to update the podOwnerDepositShares if `currentpodOwnerDepositShares` is positive */ function withdrawSharesAsTokens( - address podOwner, - address destination, + address staker, + IStrategy strategy, + IERC20, uint256 shares ) external onlyDelegationManager { - require(podOwner != address(0), "EigenPodManager.withdrawSharesAsTokens: podOwner cannot be zero address"); - require(destination != address(0), "EigenPodManager.withdrawSharesAsTokens: destination cannot be zero address"); - require(int256(shares) >= 0, "EigenPodManager.withdrawSharesAsTokens: shares cannot be negative"); - require(shares % GWEI_TO_WEI == 0, "EigenPodManager.withdrawSharesAsTokens: shares must be a whole Gwei amount"); - int256 currentPodOwnerShares = podOwnerShares[podOwner]; - - // if there is an existing shares deficit, prioritize decreasing the deficit first - if (currentPodOwnerShares < 0) { - uint256 currentShareDeficit = uint256(-currentPodOwnerShares); - - if (shares > currentShareDeficit) { - // get rid of the whole deficit if possible, and pass any remaining shares onto destination - podOwnerShares[podOwner] = 0; - shares -= currentShareDeficit; - emit PodSharesUpdated(podOwner, int256(currentShareDeficit)); - emit NewTotalShares(podOwner, 0); + require(strategy == beaconChainETHStrategy, InvalidStrategy()); + require(staker != address(0), InputAddressZero()); + require(int256(shares) > 0, SharesNegative()); + + int256 currentDepositShares = podOwnerDepositShares[staker]; + uint256 sharesToWithdraw = shares; + + // Negative shares only exist in certain cases where, prior to the slashing release, negative balance + // deltas were reported after a pod owner queued a withdrawal for all their shares. + // + // The new system treats negative balance deltas differently, decreasing the pod owner's slashing factor + // proportional to the decrease. This legacy codepath handles completion of withdrawals queued before + // the slashing release. + if (currentDepositShares < 0) { + uint256 currentDepositShareDeficit = uint256(-currentDepositShares); + uint256 depositSharesToAdd; + + if (shares > currentDepositShareDeficit) { + // Get rid of the whole deficit and withdraw any remaining shares + depositSharesToAdd = currentDepositShareDeficit; + sharesToWithdraw = shares - currentDepositShareDeficit; } else { - // otherwise get rid of as much deficit as possible, and return early, since there is nothing left over to forward on - int256 updatedPodOwnerShares = podOwnerShares[podOwner] + int256(shares); - podOwnerShares[podOwner] = updatedPodOwnerShares; - emit PodSharesUpdated(podOwner, int256(shares)); - emit NewTotalShares(podOwner, updatedPodOwnerShares); - return; + // Get rid of as much deficit as possible and don't withdraw any shares + depositSharesToAdd = shares; + sharesToWithdraw = 0; } + + int256 updatedShares = currentDepositShares + int256(depositSharesToAdd); + podOwnerDepositShares[staker] = updatedShares; + emit PodSharesUpdated(staker, int256(depositSharesToAdd)); + emit NewTotalShares(staker, updatedShares); + } + + // Withdraw ETH from EigenPod + if (sharesToWithdraw > 0) { + ownerToPod[staker].withdrawRestakedBeaconChainETH(staker, sharesToWithdraw); } - // Actually withdraw to the destination - ownerToPod[podOwner].withdrawRestakedBeaconChainETH(destination, shares); } // INTERNAL FUNCTIONS @@ -249,37 +242,70 @@ contract EigenPodManager is return pod; } - /** - * @notice Calculates the change in a pod owner's delegateable shares as a result of their beacon chain ETH shares changing - * from `sharesBefore` to `sharesAfter`. The key concept here is that negative/"deficit" shares are not delegateable. - */ - function _calculateChangeInDelegatableShares( - int256 sharesBefore, - int256 sharesAfter - ) internal pure returns (int256) { - if (sharesBefore <= 0) { - if (sharesAfter <= 0) { - // if the shares started negative and stayed negative, then there cannot have been an increase in delegateable shares - return 0; - } else { - // if the shares started negative and became positive, then the increase in delegateable shares is the ending share amount - return sharesAfter; - } - } else { - if (sharesAfter <= 0) { - // if the shares started positive and became negative, then the decrease in delegateable shares is the starting share amount - return (-sharesBefore); - } else { - // if the shares started positive and stayed positive, then the change in delegateable shares - // is the difference between starting and ending amounts - return (sharesAfter - sharesBefore); - } + /// @dev Adds the shares to the staker's balance, returning their current/added shares + /// NOTE: if the staker ends with a non-positive balance, this returns (0, 0) + /// @return prevDepositShares the shares the staker had before any were added + /// @return addedShares the shares added to the staker's balance + function _addShares(address staker, uint256 shares) internal returns (uint256, uint256) { + require(staker != address(0), InputAddressZero()); + require(int256(shares) >= 0, SharesNegative()); + + int256 sharesToAdd = int256(shares); + int256 prevDepositShares = podOwnerDepositShares[staker]; + int256 updatedDepositShares = prevDepositShares + sharesToAdd; + podOwnerDepositShares[staker] = updatedDepositShares; + + emit PodSharesUpdated(staker, sharesToAdd); + emit NewTotalShares(staker, updatedDepositShares); + + // If we haven't added enough shares to go positive, return (0, 0) + if (updatedDepositShares <= 0) { + return (0, 0); } + + return (prevDepositShares < 0 ? 0 : uint256(prevDepositShares), shares); + } + + /// @dev Calculates the proportion a pod owner's restaked balance has decreased, and + /// reduces their beacon slashing factor accordingly. + /// Note: `balanceDecreasedWei` is assumed to be less than `prevRestakedBalanceWei` + function _reduceSlashingFactor( + address podOwner, + uint256 prevRestakedBalanceWei, + uint256 balanceDecreasedWei + ) internal returns (uint256, uint64, uint256) { + // Apply negative balance delta to calculate the proportion of the original + // balance that remains. Note that underflow here should be impossible given + // the invariants pods use to calculate these values. + uint256 newRestakedBalanceWei = prevRestakedBalanceWei - balanceDecreasedWei; + uint256 proportionRemainingWad = newRestakedBalanceWei.divWadRoundUp(prevRestakedBalanceWei); + + // Note that underflow here should be impossible given + // `proportionRemainingWad` is guaranteed to be less than WAD. + uint256 wadSlashed = uint256(WAD) - proportionRemainingWad; + + // Update pod owner's beacon chain slashing factor. Note that `newBeaconSlashingFactor` + // should be less than `prevBeaconSlashingFactor` because `proportionRemainingWad` is + // guaranteed to be less than WAD. + uint64 prevBeaconSlashingFactor = beaconChainSlashingFactor(podOwner); + uint64 newBeaconSlashingFactor = uint64(prevBeaconSlashingFactor.mulWad(proportionRemainingWad)); + emit BeaconChainSlashingFactorDecreased(podOwner, wadSlashed, newBeaconSlashingFactor); + /// forgefmt: disable-next-item + _beaconChainSlashingFactor[podOwner] = BeaconChainSlashingFactor({ + slashingFactor: newBeaconSlashingFactor, + isSet: true + }); + + uint256 curDepositShares = uint256(podOwnerDepositShares[podOwner]); + return (curDepositShares, prevBeaconSlashingFactor, wadSlashed); } // VIEW FUNCTIONS - /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not). - function getPod(address podOwner) public view returns (IEigenPod) { + + /// @inheritdoc IEigenPodManager + function getPod( + address podOwner + ) public view returns (IEigenPod) { IEigenPod pod = ownerToPod[podOwner]; // if pod does not exist already, calculate what its address *will be* once it is deployed if (address(pod) == address(0)) { @@ -293,8 +319,26 @@ contract EigenPodManager is return pod; } - /// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise. - function hasPod(address podOwner) public view returns (bool) { + /// @inheritdoc IEigenPodManager + function hasPod( + address podOwner + ) public view returns (bool) { return address(ownerToPod[podOwner]) != address(0); } + + /// @notice Returns the current shares of `user` in `strategy` + /// @dev strategy must be beaconChainETHStrategy + /// @dev returns 0 if the user has negative shares + function stakerDepositShares(address user, IStrategy strategy) public view returns (uint256 depositShares) { + require(strategy == beaconChainETHStrategy, InvalidStrategy()); + return podOwnerDepositShares[user] < 0 ? 0 : uint256(podOwnerDepositShares[user]); + } + + /// @inheritdoc IEigenPodManager + function beaconChainSlashingFactor( + address podOwner + ) public view returns (uint64) { + BeaconChainSlashingFactor memory bsf = _beaconChainSlashingFactor[podOwner]; + return bsf.isSet ? bsf.slashingFactor : WAD; + } } diff --git a/src/contracts/pods/EigenPodManagerStorage.sol b/src/contracts/pods/EigenPodManagerStorage.sol index d85c0a178..bda301349 100644 --- a/src/contracts/pods/EigenPodManagerStorage.sol +++ b/src/contracts/pods/EigenPodManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; @@ -26,9 +26,6 @@ abstract contract EigenPodManagerStorage is IEigenPodManager { /// @notice EigenLayer's StrategyManager contract IStrategyManager public immutable strategyManager; - /// @notice EigenLayer's Slasher contract - ISlasher public immutable slasher; - /// @notice EigenLayer's DelegationManager contract IDelegationManager public immutable delegationManager; @@ -56,7 +53,7 @@ abstract contract EigenPodManagerStorage is IEigenPodManager { address internal __deprecated_beaconChainOracle; /// @notice Pod owner to deployed EigenPod address - mapping(address => IEigenPod) public ownerToPod; + mapping(address podOwner => IEigenPod) public ownerToPod; // BEGIN STORAGE VARIABLES ADDED AFTER FIRST TESTNET DEPLOYMENT -- DO NOT SUGGEST REORDERING TO CONVENTIONAL ORDER /// @notice The number of EigenPods that have been deployed @@ -68,28 +65,31 @@ abstract contract EigenPodManagerStorage is IEigenPodManager { // BEGIN STORAGE VARIABLES ADDED AFTER MAINNET DEPLOYMENT -- DO NOT SUGGEST REORDERING TO CONVENTIONAL ORDER /** - * @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy. - * @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can + * // TODO: Update this comment + * @notice Mapping from Pod owner owner to the number of deposit shares they have in the virtual beacon chain ETH strategy. + * @dev The deposit share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can * decrease between the pod owner queuing and completing a withdrawal. * When the pod owner's shares would otherwise increase, this "deficit" is decreased first _instead_. * Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We can think of this * as the withdrawal "paying off the deficit". */ - mapping(address => int256) public podOwnerShares; + mapping(address podOwner => int256 shares) public podOwnerDepositShares; uint64 internal __deprecated_denebForkTimestamp; + /// @notice Returns the slashing factor applied to the `staker` for the `beaconChainETHStrategy` + /// Note: this is specifically updated when the staker's beacon chain balance decreases + mapping(address staker => BeaconChainSlashingFactor) internal _beaconChainSlashingFactor; + constructor( IETHPOSDeposit _ethPOS, IBeacon _eigenPodBeacon, IStrategyManager _strategyManager, - ISlasher _slasher, IDelegationManager _delegationManager ) { ethPOS = _ethPOS; eigenPodBeacon = _eigenPodBeacon; strategyManager = _strategyManager; - slasher = _slasher; delegationManager = _delegationManager; } @@ -98,5 +98,5 @@ abstract contract EigenPodManagerStorage is IEigenPodManager { * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[44] private __gap; + uint256[43] private __gap; } diff --git a/src/contracts/pods/EigenPodPausingConstants.sol b/src/contracts/pods/EigenPodPausingConstants.sol index e731747a6..509fcade1 100644 --- a/src/contracts/pods/EigenPodPausingConstants.sol +++ b/src/contracts/pods/EigenPodPausingConstants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Constants shared between 'EigenPod' and 'EigenPodManager' contracts. diff --git a/src/contracts/pods/EigenPodStorage.sol b/src/contracts/pods/EigenPodStorage.sol index 43bd494b8..39fd5746e 100644 --- a/src/contracts/pods/EigenPodStorage.sol +++ b/src/contracts/pods/EigenPodStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IEigenPod.sol"; @@ -11,7 +11,7 @@ abstract contract EigenPodStorage is IEigenPod { uint64 internal __deprecated_mostRecentWithdrawalTimestamp; /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from the Beacon Chain but not from EigenLayer), - uint64 public withdrawableRestakedExecutionLayerGwei; + uint64 internal restakedExecutionLayerGwei; /// @notice DEPRECATED: previously used to track whether a pod had activated restaking bool internal __deprecated_hasRestaked; @@ -81,5 +81,5 @@ abstract contract EigenPodStorage is IEigenPod { * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[36] private __gap; + uint256[35] private __gap; } diff --git a/src/contracts/strategies/EigenStrategy.sol b/src/contracts/strategies/EigenStrategy.sol index aa5204dcb..f73bccf30 100644 --- a/src/contracts/strategies/EigenStrategy.sol +++ b/src/contracts/strategies/EigenStrategy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; // NOTE: Mainnet uses the OpenZeppelin v4.9.0 contracts, but this imports the 4.7.1 version. This will be changed after an upgrade. import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -35,11 +35,14 @@ contract EigenStrategy is StrategyBase { IEigen public EIGEN; /// @notice Since this contract is designed to be initializable, the constructor simply sets `strategyManager`, the only immutable variable. - constructor(IStrategyManager _strategyManager) StrategyBase(_strategyManager) {} + constructor( + IStrategyManager _strategyManager, + IPauserRegistry _pauserRegistry + ) StrategyBase(_strategyManager, _pauserRegistry) {} - function initialize(IEigen _EIGEN, IERC20 _bEIGEN, IPauserRegistry _pauserRegistry) public virtual initializer { + function initialize(IEigen _EIGEN, IERC20 _bEIGEN) public virtual initializer { EIGEN = _EIGEN; - _initializeStrategyBase(_bEIGEN, _pauserRegistry); + _initializeStrategyBase(_bEIGEN); } /** @@ -51,7 +54,7 @@ contract EigenStrategy is StrategyBase { * @param amount deposit amount */ function _beforeDeposit(IERC20 token, uint256 amount) internal virtual override { - require(token == underlyingToken || token == EIGEN, "EigenStrategy.deposit: Can only deposit bEIGEN or EIGEN"); + require(token == underlyingToken || token == EIGEN, OnlyUnderlyingToken()); if (token == EIGEN) { // unwrap EIGEN into bEIGEN assuming a 1-1 unwrapping amount @@ -71,7 +74,7 @@ contract EigenStrategy is StrategyBase { IERC20 token, uint256 /*amountShares*/ ) internal virtual override { - require(token == underlyingToken || token == EIGEN, "EigenStrategy.withdraw: Can only withdraw bEIGEN or EIGEN"); + require(token == underlyingToken || token == EIGEN, OnlyUnderlyingToken()); } /** diff --git a/src/contracts/strategies/StrategyBase.sol b/src/contracts/strategies/StrategyBase.sol index 616298a7f..555fe6a6e 100644 --- a/src/contracts/strategies/StrategyBase.sol +++ b/src/contracts/strategies/StrategyBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IStrategyManager.sol"; import "../permissions/Pausable.sol"; @@ -64,27 +64,28 @@ contract StrategyBase is Initializable, Pausable, IStrategy { /// @notice Simply checks that the `msg.sender` is the `strategyManager`, which is an address stored immutably at construction. modifier onlyStrategyManager() { - require(msg.sender == address(strategyManager), "StrategyBase.onlyStrategyManager"); + require(msg.sender == address(strategyManager), OnlyStrategyManager()); _; } /// @notice Since this contract is designed to be initializable, the constructor simply sets `strategyManager`, the only immutable variable. - constructor(IStrategyManager _strategyManager) { + constructor(IStrategyManager _strategyManager, IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { strategyManager = _strategyManager; _disableInitializers(); } - function initialize(IERC20 _underlyingToken, IPauserRegistry _pauserRegistry) public virtual initializer { - _initializeStrategyBase(_underlyingToken, _pauserRegistry); + function initialize( + IERC20 _underlyingToken + ) public virtual initializer { + _initializeStrategyBase(_underlyingToken); } /// @notice Sets the `underlyingToken` and `pauserRegistry` for the strategy. function _initializeStrategyBase( - IERC20 _underlyingToken, - IPauserRegistry _pauserRegistry + IERC20 _underlyingToken ) internal onlyInitializing { underlyingToken = _underlyingToken; - _initializePauser(_pauserRegistry, UNPAUSE_ALL); + _setPausedStatus(_UNPAUSE_ALL); emit StrategyTokenSet(underlyingToken, IERC20Metadata(address(_underlyingToken)).decimals()); } @@ -123,12 +124,11 @@ contract StrategyBase is Initializable, Pausable, IStrategy { newShares = (amount * virtualShareAmount) / virtualPriorTokenBalance; // extra check for correctness / against edge case where share rate can be massively inflated as a 'griefing' sort of attack - require(newShares != 0, "StrategyBase.deposit: newShares cannot be zero"); + require(newShares != 0, NewSharesZero()); // update total share amount to account for deposit totalShares = (priorTotalShares + newShares); - - require(totalShares <= MAX_TOTAL_SHARES, "StrategyBase.deposit: totalShares exceeds `MAX_TOTAL_SHARES`"); + require(totalShares <= MAX_TOTAL_SHARES, TotalSharesExceedsMax()); // emit exchange rate _emitExchangeRate(virtualTokenBalance, totalShares + SHARES_OFFSET); @@ -155,11 +155,7 @@ contract StrategyBase is Initializable, Pausable, IStrategy { // copy `totalShares` value to memory, prior to any change uint256 priorTotalShares = totalShares; - - require( - amountShares <= priorTotalShares, - "StrategyBase.withdraw: amountShares must be less than or equal to totalShares" - ); + require(amountShares <= priorTotalShares, WithdrawalAmountExceedsTotalDeposits()); /** * @notice calculation of amountToSend *mirrors* `sharesToUnderlying(amountShares)`, but is different since the `totalShares` has already @@ -184,16 +180,23 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @notice Called in the external `deposit` function, before any logic is executed. Expected to be overridden if strategies want such logic. * @param token The token being deposited */ - function _beforeDeposit(IERC20 token, uint256 /** amount **/) internal virtual { - require(token == underlyingToken, "StrategyBase.deposit: Can only deposit underlyingToken"); + function _beforeDeposit( + IERC20 token, + uint256 // amount + ) internal virtual { + require(token == underlyingToken, OnlyUnderlyingToken()); } /** * @notice Called in the external `withdraw` function, before any logic is executed. Expected to be overridden if strategies want such logic. * @param token The token being withdrawn */ - function _beforeWithdrawal(address /** recipient **/, IERC20 token, uint256 /** amountShares **/) internal virtual { - require(token == underlyingToken, "StrategyBase.withdraw: Can only withdraw the strategy token"); + function _beforeWithdrawal( + address, // recipient + IERC20 token, + uint256 // amountShares + ) internal virtual { + require(token == underlyingToken, OnlyUnderlyingToken()); } /** @@ -222,7 +225,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function sharesToUnderlyingView(uint256 amountShares) public view virtual override returns (uint256) { + function sharesToUnderlyingView( + uint256 amountShares + ) public view virtual override returns (uint256) { // account for virtual shares and balance uint256 virtualTotalShares = totalShares + SHARES_OFFSET; uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET; @@ -237,7 +242,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @return The amount of underlying tokens corresponding to the input `amountShares` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function sharesToUnderlying(uint256 amountShares) public view virtual override returns (uint256) { + function sharesToUnderlying( + uint256 amountShares + ) public view virtual override returns (uint256) { return sharesToUnderlyingView(amountShares); } @@ -248,7 +255,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function underlyingToSharesView(uint256 amountUnderlying) public view virtual returns (uint256) { + function underlyingToSharesView( + uint256 amountUnderlying + ) public view virtual returns (uint256) { // account for virtual shares and balance uint256 virtualTotalShares = totalShares + SHARES_OFFSET; uint256 virtualTokenBalance = _tokenBalance() + BALANCE_OFFSET; @@ -263,7 +272,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @return The amount of shares corresponding to the input `amountUnderlying` * @dev Implementation for these functions in particular may vary significantly for different strategies */ - function underlyingToShares(uint256 amountUnderlying) external view virtual returns (uint256) { + function underlyingToShares( + uint256 amountUnderlying + ) external view virtual returns (uint256) { return underlyingToSharesView(amountUnderlying); } @@ -271,7 +282,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications */ - function userUnderlyingView(address user) external view virtual returns (uint256) { + function userUnderlyingView( + address user + ) external view virtual returns (uint256) { return sharesToUnderlyingView(shares(user)); } @@ -279,7 +292,9 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications */ - function userUnderlying(address user) external virtual returns (uint256) { + function userUnderlying( + address user + ) external virtual returns (uint256) { return sharesToUnderlying(shares(user)); } @@ -287,8 +302,10 @@ contract StrategyBase is Initializable, Pausable, IStrategy { * @notice convenience function for fetching the current total shares of `user` in this strategy, by * querying the `strategyManager` contract */ - function shares(address user) public view virtual returns (uint256) { - return strategyManager.stakerStrategyShares(user, IStrategy(address(this))); + function shares( + address user + ) public view virtual returns (uint256) { + return strategyManager.stakerDepositShares(user, IStrategy(address(this))); } /// @notice Internal function used to fetch this contract's current balance of `underlyingToken`. diff --git a/src/contracts/strategies/StrategyBaseTVLLimits.sol b/src/contracts/strategies/StrategyBaseTVLLimits.sol index 63b76ff45..ac972822e 100644 --- a/src/contracts/strategies/StrategyBaseTVLLimits.sol +++ b/src/contracts/strategies/StrategyBaseTVLLimits.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./StrategyBase.sol"; @@ -24,16 +24,18 @@ contract StrategyBaseTVLLimits is StrategyBase { event MaxTotalDepositsUpdated(uint256 previousValue, uint256 newValue); // solhint-disable-next-line no-empty-blocks - constructor(IStrategyManager _strategyManager) StrategyBase(_strategyManager) {} + constructor( + IStrategyManager _strategyManager, + IPauserRegistry _pauserRegistry + ) StrategyBase(_strategyManager, _pauserRegistry) {} function initialize( uint256 _maxPerDeposit, uint256 _maxTotalDeposits, - IERC20 _underlyingToken, - IPauserRegistry _pauserRegistry + IERC20 _underlyingToken ) public virtual initializer { _setTVLLimits(_maxPerDeposit, _maxTotalDeposits); - _initializeStrategyBase(_underlyingToken, _pauserRegistry); + _initializeStrategyBase(_underlyingToken); } /** @@ -56,10 +58,7 @@ contract StrategyBaseTVLLimits is StrategyBase { function _setTVLLimits(uint256 newMaxPerDeposit, uint256 newMaxTotalDeposits) internal { emit MaxPerDepositUpdated(maxPerDeposit, newMaxPerDeposit); emit MaxTotalDepositsUpdated(maxTotalDeposits, newMaxTotalDeposits); - require( - newMaxPerDeposit <= newMaxTotalDeposits, - "StrategyBaseTVLLimits._setTVLLimits: maxPerDeposit exceeds maxTotalDeposits" - ); + require(newMaxPerDeposit <= newMaxTotalDeposits, MaxPerDepositExceedsMax()); maxPerDeposit = newMaxPerDeposit; maxTotalDeposits = newMaxTotalDeposits; } @@ -77,8 +76,8 @@ contract StrategyBaseTVLLimits is StrategyBase { * @param amount The amount of `token` being deposited */ function _beforeDeposit(IERC20 token, uint256 amount) internal virtual override { - require(amount <= maxPerDeposit, "StrategyBaseTVLLimits: max per deposit exceeded"); - require(_tokenBalance() <= maxTotalDeposits, "StrategyBaseTVLLimits: max deposits exceeded"); + require(amount <= maxPerDeposit, MaxPerDepositExceedsMax()); + require(_tokenBalance() <= maxTotalDeposits, BalanceExceedsMaxTotalDeposits()); super._beforeDeposit(token, amount); } diff --git a/src/contracts/strategies/StrategyFactory.sol b/src/contracts/strategies/StrategyFactory.sol index 7e9a468fb..f2d35d53f 100644 --- a/src/contracts/strategies/StrategyFactory.sol +++ b/src/contracts/strategies/StrategyFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; @@ -21,19 +21,18 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable IStrategyManager public immutable strategyManager; /// @notice Since this contract is designed to be initializable, the constructor simply sets the immutable variables. - constructor(IStrategyManager _strategyManager) { + constructor(IStrategyManager _strategyManager, IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { strategyManager = _strategyManager; _disableInitializers(); } function initialize( address _initialOwner, - IPauserRegistry _pauserRegistry, uint256 _initialPausedStatus, IBeacon _strategyBeacon ) public virtual initializer { _transferOwnership(_initialOwner); - _initializePauser(_pauserRegistry, _initialPausedStatus); + _setPausedStatus(_initialPausedStatus); _setStrategyBeacon(_strategyBeacon); } @@ -43,30 +42,22 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable * $dev Immense caution is warranted for non-standard ERC20 tokens, particularly "reentrant" tokens * like those that conform to ERC777. */ - function deployNewStrategy(IERC20 token) - external - onlyWhenNotPaused(PAUSED_NEW_STRATEGIES) - returns (IStrategy newStrategy) - { - require(!isBlacklisted[token], "StrategyFactory.deployNewStrategy: Token is blacklisted"); - require( - deployedStrategies[token] == IStrategy(address(0)), - "StrategyFactory.deployNewStrategy: Strategy already exists for token" - ); + function deployNewStrategy( + IERC20 token + ) external onlyWhenNotPaused(PAUSED_NEW_STRATEGIES) returns (IStrategy newStrategy) { + require(!isBlacklisted[token], BlacklistedToken()); + require(deployedStrategies[token] == IStrategy(address(0)), StrategyAlreadyExists()); IStrategy strategy = IStrategy( address( new BeaconProxy( - address(strategyBeacon), - abi.encodeWithSelector(StrategyBase.initialize.selector, token, pauserRegistry) + address(strategyBeacon), abi.encodeWithSelector(StrategyBase.initialize.selector, token) ) ) ); _setStrategyForToken(token, strategy); IStrategy[] memory strategiesToWhitelist = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); strategiesToWhitelist[0] = strategy; - thirdPartyTransfersForbiddenValues[0] = false; - strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist); return strategy; } @@ -74,12 +65,14 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable * @notice Owner-only function to prevent strategies from being created for given tokens. * @param tokens An array of token addresses to blacklist. */ - function blacklistTokens(IERC20[] calldata tokens) external onlyOwner { + function blacklistTokens( + IERC20[] calldata tokens + ) external onlyOwner { IStrategy[] memory strategiesToRemove = new IStrategy[](tokens.length); uint256 removeIdx = 0; for (uint256 i; i < tokens.length; ++i) { - require(!isBlacklisted[tokens[i]], "StrategyFactory.blacklistTokens: Cannot blacklist deployed strategy"); + require(!isBlacklisted[tokens[i]], AlreadyBlacklisted()); isBlacklisted[tokens[i]] = true; emit TokenBlacklisted(tokens[i]); @@ -107,23 +100,17 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable * @notice Owner-only function to pass through a call to `StrategyManager.addStrategiesToDepositWhitelist` */ function whitelistStrategies( - IStrategy[] calldata strategiesToWhitelist, - bool[] calldata thirdPartyTransfersForbiddenValues + IStrategy[] calldata strategiesToWhitelist ) external onlyOwner { - strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist, thirdPartyTransfersForbiddenValues); - } - - /** - * @notice Owner-only function to pass through a call to `StrategyManager.setThirdPartyTransfersForbidden` - */ - function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external onlyOwner { - strategyManager.setThirdPartyTransfersForbidden(strategy, value); + strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist); } /** * @notice Owner-only function to pass through a call to `StrategyManager.removeStrategiesFromDepositWhitelist` */ - function removeStrategiesFromWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external onlyOwner { + function removeStrategiesFromWhitelist( + IStrategy[] calldata strategiesToRemoveFromWhitelist + ) external onlyOwner { strategyManager.removeStrategiesFromDepositWhitelist(strategiesToRemoveFromWhitelist); } @@ -132,7 +119,9 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable emit StrategySetForToken(token, strategy); } - function _setStrategyBeacon(IBeacon _strategyBeacon) internal { + function _setStrategyBeacon( + IBeacon _strategyBeacon + ) internal { emit StrategyBeaconModified(strategyBeacon, _strategyBeacon); strategyBeacon = _strategyBeacon; } diff --git a/src/contracts/strategies/StrategyFactoryStorage.sol b/src/contracts/strategies/StrategyFactoryStorage.sol index f2eff77ca..c74cf7eb2 100644 --- a/src/contracts/strategies/StrategyFactoryStorage.sol +++ b/src/contracts/strategies/StrategyFactoryStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../interfaces/IStrategyFactory.sol"; diff --git a/src/contracts/token/BackingEigen.sol b/src/contracts/token/BackingEigen.sol index c8a97160d..a9fbc9f13 100644 --- a/src/contracts/token/BackingEigen.sol +++ b/src/contracts/token/BackingEigen.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; -import "@openzeppelin-v4.9.0/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-upgrades-v4.9.0/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; -import "@openzeppelin-upgrades-v4.9.0/contracts/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin-upgrades/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; +import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable { /// CONSTANTS & IMMUTABLES @@ -31,7 +31,9 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable { // @notice event emitted when the `isMinter` mapping is modified event IsMinterModified(address indexed minterAddress, bool newStatus); - constructor(IERC20 _EIGEN) { + constructor( + IERC20 _EIGEN + ) { EIGEN = _EIGEN; _disableInitializers(); } @@ -56,14 +58,18 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable { * * See {ERC20-_burn}. */ - function burn(uint256 amount) public virtual { + function burn( + uint256 amount + ) public virtual { _burn(_msgSender(), amount); } /** * @notice An initializer function that sets initial values for the contract's state variables. */ - function initialize(address initialOwner) public initializer { + function initialize( + address initialOwner + ) public initializer { __Ownable_init(); __ERC20_init("Backing Eigen", "bEIGEN"); _transferOwnership(initialOwner); @@ -79,7 +85,7 @@ contract BackingEigen is OwnableUpgradeable, ERC20VotesUpgradeable { // Mint the entire supply of EIGEN - this is a one-time event that // ensures bEIGEN fully backs EIGEN. - _mint(address(EIGEN), 1673646668284660000000000000); + _mint(address(EIGEN), 1_673_646_668_284_660_000_000_000_000); emit Backed(); } diff --git a/src/contracts/token/Eigen.sol b/src/contracts/token/Eigen.sol index fcd15cf15..d4fd35b9a 100644 --- a/src/contracts/token/Eigen.sol +++ b/src/contracts/token/Eigen.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; -import "@openzeppelin-v4.9.0/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin-upgrades-v4.9.0/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; -import "@openzeppelin-upgrades-v4.9.0/contracts/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin-upgrades/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; +import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable { /// CONSTANTS & IMMUTABLES @@ -32,7 +32,9 @@ contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable { /// @notice event emitted when the transfer restrictions disabled event TransferRestrictionsDisabled(); - constructor(IERC20 _bEIGEN) { + constructor( + IERC20 _bEIGEN + ) { bEIGEN = _bEIGEN; _disableInitializers(); } @@ -121,7 +123,9 @@ contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable { /** * @notice This function allows bEIGEN holders to wrap their tokens into Eigen */ - function wrap(uint256 amount) external { + function wrap( + uint256 amount + ) external { require(bEIGEN.transferFrom(msg.sender, address(this), amount), "Eigen.wrap: bEIGEN transfer failed"); _mint(msg.sender, amount); } @@ -129,7 +133,9 @@ contract Eigen is OwnableUpgradeable, ERC20VotesUpgradeable { /** * @notice This function allows Eigen holders to unwrap their tokens into bEIGEN */ - function unwrap(uint256 amount) external { + function unwrap( + uint256 amount + ) external { _burn(msg.sender, amount); require(bEIGEN.transfer(msg.sender, amount), "Eigen.unwrap: bEIGEN transfer failed"); } diff --git a/src/contracts/utils/UpgradeableSignatureCheckingUtils.sol b/src/contracts/utils/UpgradeableSignatureCheckingUtils.sol deleted file mode 100644 index ae6251361..000000000 --- a/src/contracts/utils/UpgradeableSignatureCheckingUtils.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; - -/** - * @title Abstract contract that implements minimal signature-related storage & functionality for upgradeable contracts. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - */ -abstract contract UpgradeableSignatureCheckingUtils is Initializable { - /// @notice The EIP-712 typehash for the contract's domain - bytes32 public constant DOMAIN_TYPEHASH = - keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - - // chain id at the time of contract deployment - uint256 internal immutable ORIGINAL_CHAIN_ID; - - /** - * @notice Original EIP-712 Domain separator for this contract. - * @dev The domain separator may change in the event of a fork that modifies the ChainID. - * Use the getter function `domainSeparator` to get the current domain separator for this contract. - */ - bytes32 internal _DOMAIN_SEPARATOR; - - // INITIALIZING FUNCTIONS - constructor() { - ORIGINAL_CHAIN_ID = block.chainid; - } - - function _initializeSignatureCheckingUtils() internal onlyInitializing { - _DOMAIN_SEPARATOR = _calculateDomainSeparator(); - } - - // VIEW FUNCTIONS - /** - * @notice Getter function for the current EIP-712 domain separator for this contract. - * @dev The domain separator will change in the event of a fork that changes the ChainID. - */ - function domainSeparator() public view returns (bytes32) { - if (block.chainid == ORIGINAL_CHAIN_ID) { - return _DOMAIN_SEPARATOR; - } else { - return _calculateDomainSeparator(); - } - } - - // @notice Internal function for calculating the current domain separator of this contract - function _calculateDomainSeparator() internal view returns (bytes32) { - return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("EigenLayer")), block.chainid, address(this))); - } -} diff --git a/src/test/Delegation.t.sol b/src/test/Delegation.t.sol deleted file mode 100644 index 3138039cd..000000000 --- a/src/test/Delegation.t.sol +++ /dev/null @@ -1,501 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/mocks/ERC1271WalletMock.sol"; -import "src/contracts/interfaces/ISignatureUtils.sol"; - -import "../test/EigenLayerTestHelper.t.sol"; - -contract DelegationTests is EigenLayerTestHelper { - uint256 public PRIVATE_KEY = 420; - - uint32 serveUntil = 100; - - address public registryCoordinator = address(uint160(uint256(keccak256("registryCoordinator")))); - uint8 defaultQuorumNumber = 0; - bytes32 defaultOperatorId = bytes32(uint256(0)); - - modifier fuzzedAmounts(uint256 ethAmount, uint256 eigenAmount) { - cheats.assume(ethAmount >= 0 && ethAmount <= 1e18); - cheats.assume(eigenAmount >= 0 && eigenAmount <= 1e18); - _; - } - - function setUp() public virtual override { - EigenLayerDeployer.setUp(); - } - - /// @notice testing if an operator can register to themselves. - function testSelfOperatorRegister() public { - _testRegisterAdditionalOperator(0); - } - - /// @notice testing if an operator can delegate to themselves. - /// @param sender is the address of the operator. - function testSelfOperatorDelegate(address sender) public { - cheats.assume(sender != address(0)); - cheats.assume(sender != address(eigenLayerProxyAdmin)); - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: sender, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(sender, operatorDetails); - } - - function testTwoSelfOperatorsRegister() public { - _testRegisterAdditionalOperator(0); - _testRegisterAdditionalOperator(1); - } - - /// @notice registers a fixed address as a delegate, delegates to it from a second address, - /// and checks that the delegate's voteWeights increase properly - /// @param operator is the operator being delegated to. - /// @param staker is the staker delegating stake to the operator. - function testDelegation( - address operator, - address staker, - uint96 ethAmount, - uint96 eigenAmount - ) public fuzzedAddress(operator) fuzzedAddress(staker) fuzzedAmounts(ethAmount, eigenAmount) { - cheats.assume(staker != operator); - // base strategy will revert if these amounts are too small on first deposit - cheats.assume(ethAmount >= 1); - cheats.assume(eigenAmount >= 2); - - // Set weights ahead of the helper function call - bytes memory quorumNumbers = new bytes(2); - quorumNumbers[0] = bytes1(uint8(0)); - quorumNumbers[0] = bytes1(uint8(1)); - _testDelegation(operator, staker, ethAmount, eigenAmount); - } - - /// @notice tests that a when an operator is delegated to, that delegation is properly accounted for. - function testDelegationReceived( - address _operator, - address staker, - uint64 ethAmount, - uint64 eigenAmount - ) public fuzzedAddress(_operator) fuzzedAddress(staker) fuzzedAmounts(ethAmount, eigenAmount) { - cheats.assume(staker != _operator); - cheats.assume(ethAmount >= 1); - cheats.assume(eigenAmount >= 2); - - // use storage to solve stack-too-deep - operator = _operator; - - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - if (!delegation.isOperator(operator)) { - _testRegisterAsOperator(operator, operatorDetails); - } - - uint256 amountBefore = delegation.operatorShares(operator, wethStrat); - - //making additional deposits to the strategies - assertTrue(!delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - _testDepositWeth(staker, ethAmount); - _testDepositEigen(staker, eigenAmount); - _testDelegateToOperator(staker, operator); - assertTrue(delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - - (/*IStrategy[] memory updatedStrategies*/, uint256[] memory updatedShares) = strategyManager.getDeposits(staker); - - { - IStrategy _strat = wethStrat; - // IStrategy _strat = strategyManager.stakerStrats(staker, 0); - assertTrue(address(_strat) != address(0), "stakerStrats not updated correctly"); - - assertTrue( - delegation.operatorShares(operator, _strat) - updatedShares[0] == amountBefore, - "ETH operatorShares not updated correctly" - ); - - cheats.startPrank(address(strategyManager)); - - IDelegationManager.OperatorDetails memory expectedOperatorDetails = delegation.operatorDetails(operator); - assertTrue( - keccak256(abi.encode(expectedOperatorDetails)) == keccak256(abi.encode(operatorDetails)), - "failed to set correct operator details" - ); - } - } - - /// @notice tests that a when an operator is undelegated from, that the staker is properly classified as undelegated. - function testUndelegation( - address operator, - address staker, - uint96 ethAmount, - uint96 eigenAmount - ) public fuzzedAddress(operator) fuzzedAddress(staker) fuzzedAmounts(ethAmount, eigenAmount) { - cheats.assume(staker != operator); - // base strategy will revert if these amounts are too small on first deposit - cheats.assume(ethAmount >= 1); - cheats.assume(eigenAmount >= 1); - _testDelegation(operator, staker, ethAmount, eigenAmount); - - (IStrategy[] memory strategyArray, uint256[] memory shareAmounts) = strategyManager.getDeposits(staker); - uint256[] memory strategyIndexes = new uint256[](strategyArray.length); - - // withdraw shares - _testQueueWithdrawal(staker, strategyIndexes, strategyArray, shareAmounts, staker /*withdrawer*/); - - cheats.startPrank(staker); - delegation.undelegate(staker); - cheats.stopPrank(); - - require(delegation.delegatedTo(staker) == address(0), "undelegation unsuccessful"); - } - - /// @notice tests delegation from a staker to operator via ECDSA signature. - function testDelegateToBySignature( - address operator, - uint96 ethAmount, - uint96 eigenAmount, - uint256 expiry - ) public fuzzedAddress(operator) { - address staker = cheats.addr(PRIVATE_KEY); - _registerOperatorAndDepositFromStaker(operator, staker, ethAmount, eigenAmount); - - uint256 nonceBefore = delegation.stakerNonce(staker); - - bytes32 structHash = keccak256( - abi.encode(delegation.STAKER_DELEGATION_TYPEHASH(), staker, operator, nonceBefore, expiry) - ); - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", delegation.domainSeparator(), structHash)); - - bytes memory signature; - { - (uint8 v, bytes32 r, bytes32 s) = cheats.sign(PRIVATE_KEY, digestHash); - signature = abi.encodePacked(r, s, v); - } - - if (expiry < block.timestamp) { - cheats.expectRevert("DelegationManager.delegateToBySignature: staker signature expired"); - } - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: expiry - }); - delegation.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, bytes32(0)); - if (expiry >= block.timestamp) { - assertTrue(delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - assertTrue(nonceBefore + 1 == delegation.stakerNonce(staker), "nonce not incremented correctly"); - assertTrue(delegation.delegatedTo(staker) == operator, "staker delegated to wrong operator"); - } - } - - /// @notice tries delegating using a signature and an EIP 1271 compliant wallet - function testDelegateToBySignature_WithContractWallet_Successfully( - address operator, - uint96 ethAmount, - uint96 eigenAmount - ) public fuzzedAddress(operator) { - address staker = cheats.addr(PRIVATE_KEY); - - // deploy ERC1271WalletMock for staker to use - cheats.startPrank(staker); - ERC1271WalletMock wallet = new ERC1271WalletMock(staker); - cheats.stopPrank(); - staker = address(wallet); - - _registerOperatorAndDepositFromStaker(operator, staker, ethAmount, eigenAmount); - - uint256 nonceBefore = delegation.stakerNonce(staker); - - bytes32 structHash = keccak256( - abi.encode(delegation.STAKER_DELEGATION_TYPEHASH(), staker, operator, nonceBefore, type(uint256).max) - ); - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", delegation.domainSeparator(), structHash)); - - bytes memory signature; - { - (uint8 v, bytes32 r, bytes32 s) = cheats.sign(PRIVATE_KEY, digestHash); - signature = abi.encodePacked(r, s, v); - } - - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: type(uint256).max - }); - delegation.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, bytes32(0)); - assertTrue(delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - assertTrue(nonceBefore + 1 == delegation.stakerNonce(staker), "nonce not incremented correctly"); - assertTrue(delegation.delegatedTo(staker) == operator, "staker delegated to wrong operator"); - } - - /// @notice tries delegating using a signature and an EIP 1271 compliant wallet, *but* providing a bad signature - function testDelegateToBySignature_WithContractWallet_BadSignature( - address operator, - uint96 ethAmount, - uint96 eigenAmount - ) public fuzzedAddress(operator) { - address staker = cheats.addr(PRIVATE_KEY); - - // deploy ERC1271WalletMock for staker to use - cheats.startPrank(staker); - ERC1271WalletMock wallet = new ERC1271WalletMock(staker); - cheats.stopPrank(); - staker = address(wallet); - - _registerOperatorAndDepositFromStaker(operator, staker, ethAmount, eigenAmount); - - uint256 nonceBefore = delegation.stakerNonce(staker); - - bytes32 structHash = keccak256( - abi.encode(delegation.STAKER_DELEGATION_TYPEHASH(), staker, operator, nonceBefore, type(uint256).max) - ); - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", delegation.domainSeparator(), structHash)); - - bytes memory signature; - { - (uint8 v, bytes32 r, bytes32 s) = cheats.sign(PRIVATE_KEY, digestHash); - // mess up the signature by flipping v's parity - v = (v == 27 ? 28 : 27); - signature = abi.encodePacked(r, s, v); - } - - cheats.expectRevert( - bytes("EIP1271SignatureUtils.checkSignature_EIP1271: ERC1271 signature verification failed") - ); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: type(uint256).max - }); - delegation.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, bytes32(0)); - } - - /// @notice tries delegating using a wallet that does not comply with EIP 1271 - function testDelegateToBySignature_WithContractWallet_NonconformingWallet( - address operator, - uint96 ethAmount, - uint96 eigenAmount, - uint8 v, - bytes32 r, - bytes32 s - ) public fuzzedAddress(operator) { - address staker = cheats.addr(PRIVATE_KEY); - - // deploy non ERC1271-compliant wallet for staker to use - cheats.startPrank(staker); - ERC1271MaliciousMock wallet = new ERC1271MaliciousMock(); - cheats.stopPrank(); - staker = address(wallet); - - _registerOperatorAndDepositFromStaker(operator, staker, ethAmount, eigenAmount); - - cheats.assume(staker != operator); - - bytes memory signature = abi.encodePacked(r, s, v); - - cheats.expectRevert(); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: type(uint256).max - }); - delegation.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, bytes32(0)); - } - - /// @notice tests delegation to EigenLayer via an ECDSA signatures with invalid signature - /// @param operator is the operator being delegated to. - function testDelegateToByInvalidSignature( - address operator, - uint96 ethAmount, - uint96 eigenAmount, - uint8 v, - bytes32 r, - bytes32 s - ) public fuzzedAddress(operator) fuzzedAmounts(ethAmount, eigenAmount) { - address staker = cheats.addr(PRIVATE_KEY); - _registerOperatorAndDepositFromStaker(operator, staker, ethAmount, eigenAmount); - - bytes memory signature = abi.encodePacked(r, s, v); - - cheats.expectRevert(); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: type(uint256).max - }); - delegation.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, bytes32(0)); - } - - /// @notice This function tests to ensure that a delegation contract - /// cannot be intitialized multiple times - function testCannotInitMultipleTimesDelegation() public cannotReinit { - //delegation has already been initialized in the Deployer test contract - delegation.initialize( - address(this), - eigenLayerPauserReg, - 0, - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ); - } - - /// @notice This function tests to ensure that a you can't register as a delegate multiple times - /// @param operator is the operator being delegated to. - function testRegisterAsOperatorMultipleTimes(address operator) public fuzzedAddress(operator) { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(operator, operatorDetails); - cheats.expectRevert(bytes("DelegationManager.registerAsOperator: caller is already actively delegated")); - _testRegisterAsOperator(operator, operatorDetails); - } - - /// @notice This function tests to ensure that a staker cannot delegate to an unregistered operator - /// @param delegate is the unregistered operator - function testDelegationToUnregisteredDelegate(address delegate) public fuzzedAddress(delegate) { - //deposit into 1 strategy for getOperatorAddress(1), who is delegating to the unregistered operator - _testDepositStrategies(getOperatorAddress(1), 1e18, 1); - _testDepositEigen(getOperatorAddress(1), 1e18); - - cheats.expectRevert(bytes("DelegationManager.delegateTo: operator is not registered in EigenLayer")); - cheats.startPrank(getOperatorAddress(1)); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; - delegation.delegateTo(delegate, signatureWithExpiry, bytes32(0)); - cheats.stopPrank(); - } - - /// @notice This function tests to ensure that a delegation contract - /// cannot be intitialized multiple times, test with different caller addresses - function testCannotInitMultipleTimesDelegation(address _attacker) public { - cheats.assume(_attacker != address(eigenLayerProxyAdmin)); - //delegation has already been initialized in the Deployer test contract - vm.prank(_attacker); - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - delegation.initialize( - _attacker, - eigenLayerPauserReg, - 0, - 0, // minWithdrawalDelayBLocks - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ); - } - - /// @notice This function tests to ensure that an address can only call registerAsOperator() once - function testCannotRegisterAsOperatorTwice( - address _operator, - address _dt - ) public fuzzedAddress(_operator) fuzzedAddress(_dt) { - vm.assume(_dt != address(0)); - vm.startPrank(_operator); - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: msg.sender, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - string memory emptyStringForMetadataURI; - delegation.registerAsOperator(operatorDetails, emptyStringForMetadataURI); - vm.expectRevert("DelegationManager.registerAsOperator: caller is already actively delegated"); - delegation.registerAsOperator(operatorDetails, emptyStringForMetadataURI); - cheats.stopPrank(); - } - - /// @notice this function checks that you can only delegate to an address that is already registered. - function testDelegateToInvalidOperator( - address _staker, - address _unregisteredoperator - ) public fuzzedAddress(_staker) { - vm.startPrank(_staker); - cheats.expectRevert(bytes("DelegationManager.delegateTo: operator is not registered in EigenLayer")); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; - delegation.delegateTo(_unregisteredoperator, signatureWithExpiry, bytes32(0)); - cheats.expectRevert(bytes("DelegationManager.delegateTo: operator is not registered in EigenLayer")); - delegation.delegateTo(_staker, signatureWithExpiry, bytes32(0)); - cheats.stopPrank(); - } - - function testUndelegate_SigP_Version(address _operator, address _staker, address _dt) public { - vm.assume(_operator != address(0)); - vm.assume(_staker != address(0)); - vm.assume(_operator != _staker); - vm.assume(_dt != address(0)); - vm.assume(_operator != address(eigenLayerProxyAdmin)); - vm.assume(_staker != address(eigenLayerProxyAdmin)); - - // setup delegation - vm.prank(_operator); - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: _dt, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - string memory emptyStringForMetadataURI; - delegation.registerAsOperator(operatorDetails, emptyStringForMetadataURI); - vm.prank(_staker); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; - delegation.delegateTo(_operator, signatureWithExpiry, bytes32(0)); - - // operators cannot undelegate from themselves - vm.prank(_operator); - cheats.expectRevert(bytes("DelegationManager.undelegate: operators cannot be undelegated")); - delegation.undelegate(_operator); - - // assert still delegated - assertTrue(delegation.isDelegated(_staker)); - assertTrue(delegation.isOperator(_operator)); - - // _staker *can* undelegate themselves - vm.prank(_staker); - delegation.undelegate(_staker); - - // assert undelegated - assertTrue(!delegation.isDelegated(_staker)); - assertTrue(delegation.isOperator(_operator)); - } - - function _testRegisterAdditionalOperator(uint256 index) internal { - address sender = getOperatorAddress(index); - - //register as both ETH and EIGEN operator - uint256 wethToDeposit = 1e18; - uint256 eigenToDeposit = 1e10; - _testDepositWeth(sender, wethToDeposit); - _testDepositEigen(sender, eigenToDeposit); - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: sender, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(sender, operatorDetails); - cheats.startPrank(sender); - - cheats.stopPrank(); - } - - // registers the operator if they are not already registered, and deposits "WETH" + "EIGEN" on behalf of the staker. - function _registerOperatorAndDepositFromStaker( - address operator, - address staker, - uint96 ethAmount, - uint96 eigenAmount - ) internal { - cheats.assume(staker != operator); - - // if first deposit amount to base strategy is too small, it will revert. ignore that case here. - cheats.assume(ethAmount >= 1 && ethAmount <= 1e18); - cheats.assume(eigenAmount >= 1 && eigenAmount <= 1e18); - - if (!delegation.isOperator(operator)) { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(operator, operatorDetails); - } - - //making additional deposits to the strategies - assertTrue(!delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - _testDepositWeth(staker, ethAmount); - _testDepositEigen(staker, eigenAmount); - } -} diff --git a/src/test/DelegationFaucet.t.sol b/src/test/DelegationFaucet.t.sol deleted file mode 100644 index c611b8669..000000000 --- a/src/test/DelegationFaucet.t.sol +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "script/whitelist/delegationFaucet/DelegationFaucet.sol"; -import "script/whitelist/ERC20PresetMinterPauser.sol"; - -import "src/test/EigenLayerTestHelper.t.sol"; - -contract DelegationFaucetTests is EigenLayerTestHelper { - // EigenLayer contracts - DelegationFaucet delegationFaucet; - - // M2 testing/mock contracts - ERC20PresetMinterPauser public stakeToken; - StrategyBase public stakeTokenStrat; - - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - uint256 public constant DEFAULT_AMOUNT = 100e18; - address owner = cheats.addr(1000); - - /// @notice Emitted when a queued withdrawal is completed - event WithdrawalCompleted(bytes32 withdrawalRoot); - - function setUp() public virtual override { - EigenLayerDeployer.setUp(); - - // Deploy ERC20 stakeToken, StrategyBase, and add StrategyBase to whitelist - stakeToken = new ERC20PresetMinterPauser("StakeToken", "STK"); - stakeTokenStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, stakeToken, eigenLayerPauserReg) - ) - ) - ); - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = stakeTokenStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - // Deploy DelegationFaucet, grant it admin/mint/pauser roles, etc. - delegationFaucet = new DelegationFaucet(strategyManager, delegation, stakeToken, stakeTokenStrat); - targetContract(address(delegationFaucet)); - stakeToken.grantRole(MINTER_ROLE, address(delegationFaucet)); - } - - /** - * @notice Assertions in test - * - Checks staker contract is deployed - * - Checks token supply before/after minting - * - Checks token balances are updated correctly for staker and strategy contracts - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - * @param _depositAmount is the amount of stakeToken to mint to the staker and deposit into the strategy - */ - function test_mintDepositAndDelegate_CheckBalancesAndDeploys(uint8 _operatorIndex, uint256 _depositAmount) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - // Passing 0 as amount param defaults the amount to DEFAULT_AMOUNT constant - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 supplyBefore = stakeToken.totalSupply(); - uint256 stratBalanceBefore = stakeToken.balanceOf(address(stakeTokenStrat)); - assertTrue( - !Address.isContract(stakerContract), - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker contract shouldn't be deployed" - ); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), _depositAmount); - assertTrue( - Address.isContract(stakerContract), - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker contract not deployed" - ); - uint256 supplyAfter = stakeToken.totalSupply(); - uint256 stratBalanceAfter = stakeToken.balanceOf(address(stakeTokenStrat)); - // Check token supply and balances - assertEq( - supplyAfter, - supplyBefore + _depositAmount, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: token supply not updated correctly" - ); - assertEq( - stratBalanceAfter, - stratBalanceBefore + _depositAmount, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: strategy balance not updated correctly" - ); - assertEq( - stakeToken.balanceOf(stakerContract), - 0, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker balance should be 0" - ); - } - - /** - * @notice Check the before/after values for strategy shares and operator shares - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - * @param _depositAmount is the amount of stakeToken to mint to the staker and deposit into the strategy - */ - function test_mintDepositAndDelegate_StrategyAndOperatorShares( - uint8 _operatorIndex, - uint256 _depositAmount - ) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), _depositAmount); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: operator shares not updated correctly" - ); - } - - /** - * @notice Invariant test the before/after values for strategy shares and operator shares from multiple runs - */ - /// forge-config: default.invariant.runs = 5 - /// forge-config: default.invariant.depth = 20 - function invariant_test_mintDepositAndDelegate_StrategyAndOperatorShares() public { - // Setup Operator - address operator = getOperatorAddress(0); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - cheats.prank(delegationFaucet.owner()); - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: operator shares not updated correctly" - ); - } - - /** - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - */ - function test_mintDepositAndDelegate_RevertsIf_UnregisteredOperator(uint8 _operatorIndex) public { - cheats.assume(_operatorIndex < 15); - address operator = getOperatorAddress(_operatorIndex); - // Unregistered operator should revert - cheats.expectRevert("DelegationFaucet: Operator not registered"); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - } - - function test_depositIntoStrategy_IncreaseShares(uint8 _operatorIndex, uint256 _depositAmount) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_IncreaseShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_IncreaseShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_IncreaseShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_IncreaseShares: operator shares not updated correctly" - ); - - // Deposit more into strategy - stakerSharesBefore = stakerSharesAfter; - operatorSharesBefore = operatorSharesAfter; - delegationFaucet.depositIntoStrategy(stakerContract, stakeTokenStrat, stakeToken, _depositAmount); - stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - - assertEq( - stakerSharesAfter, - stakerSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_IncreasesShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_IncreasesShares: operator shares not updated correctly" - ); - } - - function test_queueWithdrawal_StakeTokenWithdraw(uint8 _operatorIndex, uint256 _withdrawAmount) public { - cheats.assume(_operatorIndex < 15 && 0 < _withdrawAmount && _withdrawAmount < DEFAULT_AMOUNT); - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 nonceBefore = delegation.cumulativeWithdrawalsQueued(/*staker*/ stakerContract); - - // Queue withdrawal - ( - IDelegationManager.Withdrawal memory queuedWithdrawal, - , /*tokensArray is unused in this test*/ - /*withdrawalRoot is unused in this test*/ - ) = _setUpQueuedWithdrawalStructSingleStrat( - /*staker*/ stakerContract, - /*withdrawer*/ stakerContract, - stakeToken, - stakeTokenStrat, - _withdrawAmount - ); - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - - params[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: queuedWithdrawal.strategies, - shares: queuedWithdrawal.shares, - withdrawer: stakerContract - }); - - delegationFaucet.queueWithdrawal( - stakerContract, - params - ); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 nonceAfter = delegation.cumulativeWithdrawalsQueued(/*staker*/ stakerContract); - - assertEq( - operatorSharesBefore, - operatorSharesAfter + _withdrawAmount, - "test_queueWithdrawal_WithdrawStakeToken: operator shares not updated correctly" - ); - // Withdrawal queued, but not withdrawn as of yet - assertEq( - stakerSharesBefore, - stakerSharesAfter + _withdrawAmount, - "test_queueWithdrawal_WithdrawStakeToken: staker shares not updated correctly" - ); - assertEq( - nonceBefore, - nonceAfter - 1, - "test_queueWithdrawal_WithdrawStakeToken: staker withdrawal nonce not updated" - ); - } - - function test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse( - uint8 _operatorIndex, - uint256 _withdrawAmount - ) public { - test_queueWithdrawal_StakeTokenWithdraw(_operatorIndex, _withdrawAmount); - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - // assertion before values - uint256 sharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceBefore = stakeToken.balanceOf(address(stakerContract)); - - // Set completeQueuedWithdrawal params - IStrategy[] memory strategyArray = new IStrategy[](1); - IERC20[] memory tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - { - strategyArray[0] = stakeTokenStrat; - shareAmounts[0] = _withdrawAmount; - tokensArray[0] = stakeToken; - } - - IDelegationManager.Withdrawal memory queuedWithdrawal; - { - uint256 nonce = delegation.cumulativeWithdrawalsQueued(stakerContract); - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: stakerContract, - withdrawer: stakerContract, - nonce: (nonce - 1), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(stakerContract) - }); - } - cheats.expectEmit(true, true, true, true, address(delegation)); - emit WithdrawalCompleted(delegation.calculateWithdrawalRoot(queuedWithdrawal)); - uint256 middlewareTimesIndex = 0; - bool receiveAsTokens = false; - delegationFaucet.completeQueuedWithdrawal( - stakerContract, - queuedWithdrawal, - tokensArray, - middlewareTimesIndex, - receiveAsTokens - ); - // assertion after values - uint256 sharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceAfter = stakeToken.balanceOf(address(stakerContract)); - assertEq( - sharesBefore + _withdrawAmount, - sharesAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse: staker shares not updated correctly" - ); - assertEq( - balanceBefore, - balanceAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse: stakerContract balance not updated correctly" - ); - } - - function test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue( - uint8 _operatorIndex, - uint256 _withdrawAmount - ) public { - test_queueWithdrawal_StakeTokenWithdraw(_operatorIndex, _withdrawAmount); - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - // assertion before values - uint256 sharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceBefore = stakeToken.balanceOf(address(stakerContract)); - - // Set completeQueuedWithdrawal params - IStrategy[] memory strategyArray = new IStrategy[](1); - IERC20[] memory tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - { - strategyArray[0] = stakeTokenStrat; - shareAmounts[0] = _withdrawAmount; - tokensArray[0] = stakeToken; - } - - IDelegationManager.Withdrawal memory queuedWithdrawal; - { - uint256 nonce = delegation.cumulativeWithdrawalsQueued(stakerContract); - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: stakerContract, - withdrawer: stakerContract, - nonce: (nonce - 1), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(stakerContract) - }); - } - cheats.expectEmit(true, true, true, true, address(delegation)); - emit WithdrawalCompleted(delegation.calculateWithdrawalRoot(queuedWithdrawal)); - uint256 middlewareTimesIndex = 0; - bool receiveAsTokens = true; - delegationFaucet.completeQueuedWithdrawal( - stakerContract, - queuedWithdrawal, - tokensArray, - middlewareTimesIndex, - receiveAsTokens - ); - // assertion after values - uint256 sharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceAfter = stakeToken.balanceOf(address(stakerContract)); - assertEq( - sharesBefore, - sharesAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue: staker shares not updated correctly" - ); - assertEq( - balanceBefore + _withdrawAmount, - balanceAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue: stakerContract balance not updated correctly" - ); - } - - function test_transfer_TransfersERC20(uint8 _operatorIndex, address _to, uint256 _transferAmount) public { - cheats.assume(_operatorIndex < 15); - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - ERC20PresetMinterPauser mockToken = new ERC20PresetMinterPauser("MockToken", "MTK"); - mockToken.mint(stakerContract, _transferAmount); - - uint256 stakerBalanceBefore = mockToken.balanceOf(stakerContract); - uint256 toBalanceBefore = mockToken.balanceOf(_to); - delegationFaucet.transfer(stakerContract, address(mockToken), _to, _transferAmount); - uint256 stakerBalanceAfter = mockToken.balanceOf(stakerContract); - uint256 toBalanceAfter = mockToken.balanceOf(_to); - assertEq( - stakerBalanceBefore, - stakerBalanceAfter + _transferAmount, - "test_transfer_TransfersERC20: staker balance not updated correctly" - ); - assertEq( - toBalanceBefore + _transferAmount, - toBalanceAfter, - "test_transfer_TransfersERC20: to balance not updated correctly" - ); - } - - function _registerOperator(address _operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: _operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(_operator, operatorDetails); - } - - function _setUpQueuedWithdrawalStructSingleStrat( - address staker, - address withdrawer, - IERC20 token, - IStrategy strategy, - uint256 shareAmount - ) - internal - view - returns ( - IDelegationManager.Withdrawal memory queuedWithdrawal, - IERC20[] memory tokensArray, - bytes32 withdrawalRoot - ) - { - IStrategy[] memory strategyArray = new IStrategy[](1); - tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - strategyArray[0] = strategy; - tokensArray[0] = token; - shareAmounts[0] = shareAmount; - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: staker, - withdrawer: withdrawer, - nonce: delegation.cumulativeWithdrawalsQueued(staker), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(staker) - }); - // calculate the withdrawal root - withdrawalRoot = delegation.calculateWithdrawalRoot(queuedWithdrawal); - return (queuedWithdrawal, tokensArray, withdrawalRoot); - } -} diff --git a/src/test/DepositWithdraw.t.sol b/src/test/DepositWithdraw.t.sol deleted file mode 100644 index 8e87e245b..000000000 --- a/src/test/DepositWithdraw.t.sol +++ /dev/null @@ -1,503 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "./EigenLayerTestHelper.t.sol"; -import "../contracts/core/StrategyManagerStorage.sol"; -import "./mocks/ERC20_OneWeiFeeOnTransfer.sol"; - -contract DepositWithdrawTests is EigenLayerTestHelper { - uint256[] public emptyUintArray; - - /** - * @notice Verifies that it is possible to deposit WETH - * @param amountToDeposit Fuzzed input for amount of WETH to deposit - */ - function testWethDeposit(uint256 amountToDeposit) public returns (uint256 amountDeposited) { - // if first deposit amount to base strategy is too small, it will revert. ignore that case here. - cheats.assume(amountToDeposit >= 1); - cheats.assume(amountToDeposit <= 1e38 - 1); - return _testDepositWeth(getOperatorAddress(0), amountToDeposit); - } - - - /// @notice deploys 'numStratsToAdd' strategies using '_testAddStrategy' and then deposits '1e18' to each of them from 'getOperatorAddress(0)' - /// @param numStratsToAdd is the number of strategies being added and deposited into - function testDepositStrategies(uint8 numStratsToAdd) public { - _testDepositStrategies(getOperatorAddress(0), 1e18, numStratsToAdd); - } - - /// @notice Verifies that it is possible to deposit eigen. - /// @param eigenToDeposit is amount of eigen to deposit into the eigen strategy - function testDepositEigen(uint96 eigenToDeposit) public { - // sanity check for inputs; keeps fuzzed tests from failing - cheats.assume(eigenToDeposit < eigenTotalSupply); - // if first deposit amount to base strategy is too small, it will revert. ignore that case here. - cheats.assume(eigenToDeposit >= 1); - _testDepositEigen(getOperatorAddress(0), eigenToDeposit); - } - - /** - * @notice Tries to deposit an unsupported token into an `StrategyBase` contract by calling `strategyManager.depositIntoStrategy`. - * Verifies that reversion occurs correctly. - */ - function testDepositUnsupportedToken() public { - IERC20 token = new ERC20PresetFixedSupply( - "badToken", - "BADTOKEN", - 100, - address(this) - ); - token.approve(address(strategyManager), type(uint256).max); - - // whitelist the strategy for deposit - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = wethStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - cheats.expectRevert(bytes("StrategyBase.deposit: Can only deposit underlyingToken")); - strategyManager.depositIntoStrategy(wethStrat, token, 10); - } - - /** - * @notice Tries to deposit into an unsupported strategy by calling `strategyManager.depositIntoStrategy`. - * Verifies that reversion occurs correctly. - */ - function testDepositNonexistentStrategy(address nonexistentStrategy) public fuzzedAddress(nonexistentStrategy) { - // assume that the fuzzed address is not already a contract! - uint256 size; - assembly { - size := extcodesize(nonexistentStrategy) - } - cheats.assume(size == 0); - // check against calls from precompile addresses -- was getting fuzzy failures from this - cheats.assume(uint160(nonexistentStrategy) > 9); - - // harcoded input - uint256 testDepositAmount = 10; - - IERC20 token = new ERC20PresetFixedSupply( - "badToken", - "BADTOKEN", - 100, - address(this) - ); - token.approve(address(strategyManager), type(uint256).max); - - // whitelist the strategy for deposit - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = IStrategy(nonexistentStrategy); - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - cheats.expectRevert(); - strategyManager.depositIntoStrategy(IStrategy(nonexistentStrategy), token, testDepositAmount); - } - - /// @notice verify that trying to deposit an amount of zero will correctly revert - function testRevertOnZeroDeposit() public { - // whitelist the strategy for deposit - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = wethStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - cheats.expectRevert(bytes("StrategyBase.deposit: newShares cannot be zero")); - strategyManager.depositIntoStrategy(wethStrat, weth, 0); - } - - - /** - * @notice Modified from existing _createQueuedWithdrawal, skips delegation and deposit steps so that we can isolate the withdrawal step - * @notice Creates a queued withdrawal from `staker`, queues a withdrawal using - * `delegation.queueWithdrawal(strategyIndexes, strategyArray, tokensArray, shareAmounts, withdrawer)` - * @notice After initiating a queued withdrawal, this test checks that `delegation.canCompleteQueuedWithdrawal` immediately returns the correct - * response depending on whether `staker` is delegated or not. - * @param staker The address to initiate the queued withdrawal - * @param amountToDeposit The amount of WETH to deposit - */ - function _createOnlyQueuedWithdrawal( - address staker, - bool /*registerAsOperator*/, - uint256 amountToDeposit, - IStrategy[] memory strategyArray, - IERC20[] memory /*tokensArray*/, - uint256[] memory shareAmounts, - uint256[] memory /*strategyIndexes*/, - address withdrawer - ) - internal returns(bytes32 withdrawalRoot, IDelegationManager.Withdrawal memory queuedWithdrawal) - { - require(amountToDeposit >= shareAmounts[0], "_createQueuedWithdrawal: sanity check failed"); - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: staker, - withdrawer: withdrawer, - nonce: delegation.cumulativeWithdrawalsQueued(staker), - delegatedTo: delegation.delegatedTo(staker), - startBlock: uint32(block.number) - }); - - - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - - params[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategyArray, - shares: shareAmounts, - withdrawer: withdrawer - }); - - bytes32[] memory withdrawalRoots = new bytes32[](1); - - //queue the withdrawal - cheats.startPrank(staker); - withdrawalRoots = delegation.queueWithdrawals(params); - cheats.stopPrank(); - return (withdrawalRoots[0], queuedWithdrawal); - } - - - function testFrontrunFirstDepositor(/*uint256 depositAmount*/) public { - - //setup addresses - address attacker = address(100); - address user = address(200); - - //give 2 ether to attacker and user - weth.transfer(attacker,2 ether); - weth.transfer(user,2 ether); - - //attacker FRONTRUN: deposit 1 wei (receive 1 share) - StrategyManager _strategyManager = _whitelistStrategy(strategyManager, wethStrat); - - cheats.startPrank(attacker); - weth.approve(address(strategyManager), type(uint256).max); - _strategyManager.depositIntoStrategy(wethStrat, weth, 1 wei); - cheats.stopPrank(); - - //attacker FRONTRUN: transfer 1 ether into strategy directly to manipulate the value of shares - cheats.prank(attacker); - weth.transfer(address(wethStrat),1 ether); - - //user deposits 2 eth into strategy - only gets 1 share due to rounding - cheats.startPrank(user); - weth.approve(address(_strategyManager), type(uint256).max); - _strategyManager.depositIntoStrategy(wethStrat, weth, 2 ether); - cheats.stopPrank(); - - //attacker deposited 1 ether and 1 wei - received 1 share - //user deposited 2 ether - received X shares - //user has lost 0.5 ether? - (, uint256[] memory shares) = _strategyManager.getDeposits(attacker); - uint256 attackerValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); - require(attackerValueWeth >= (1), "attacker got zero shares"); - - (, shares) = _strategyManager.getDeposits(user); - uint256 userValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); - require(userValueWeth >= (1900000000000000000), "user has lost more than 0.1 eth from frontrunning"); - - uint256 attackerLossesWeth = (2 ether + 1 wei) - attackerValueWeth; - uint256 userLossesWeth = 2 ether - userValueWeth; - require(attackerLossesWeth > userLossesWeth, "griefing attack deals more damage than cost"); - } - - // fuzzed amounts user uint96's to be more realistic with amounts - function testFrontrunFirstDepositorFuzzed(uint96 firstDepositAmount, uint96 donationAmount, uint96 secondDepositAmount) public { - // want to only use nonzero amounts or else we'll get reverts - cheats.assume(firstDepositAmount != 0 && secondDepositAmount != 0); - - // setup addresses - address attacker = address(100); - address user = address(200); - - // attacker makes first deposit - _testDepositToStrategy(attacker, firstDepositAmount, weth, wethStrat); - - // transfer tokens into strategy directly to manipulate the value of shares - weth.transfer(address(wethStrat), donationAmount); - - // filter out calls that would revert for minting zero shares - cheats.assume(wethStrat.underlyingToShares(secondDepositAmount) != 0); - - // user makes 2nd deposit into strategy - gets diminished shares due to rounding - _testDepositToStrategy(user, secondDepositAmount, weth, wethStrat); - - // check for griefing - (, uint256[] memory shares) = strategyManager.getDeposits(attacker); - uint256 attackerValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); - (, shares) = strategyManager.getDeposits(user); - uint256 userValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); - - uint256 attackerCost = uint256(firstDepositAmount) + uint256(donationAmount); - require(attackerCost >= attackerValueWeth, "attacker gained value?"); - // uint256 attackerLossesWeth = attackerValueWeth > attackerCost ? 0 : (attackerCost - attackerValueWeth); - uint256 attackerLossesWeth = attackerCost - attackerValueWeth; - uint256 userLossesWeth = secondDepositAmount - userValueWeth; - - emit log_named_uint("attackerLossesWeth", attackerLossesWeth); - emit log_named_uint("userLossesWeth", userLossesWeth); - - // use '+1' here to account for rounding. given the attack will cost ETH in the form of gas, this is fine. - require(attackerLossesWeth + 1 >= userLossesWeth, "griefing attack deals more damage than cost"); - } - - - function testDepositTokenWithOneWeiFeeOnTransfer(address sender, uint64 amountToDeposit) public fuzzedAddress(sender) { - cheats.assume(amountToDeposit != 0); - - IERC20 underlyingToken; - - { - uint256 initSupply = 1e50; - address initOwner = address(this); - ERC20_OneWeiFeeOnTransfer oneWeiFeeOnTransferToken = new ERC20_OneWeiFeeOnTransfer(initSupply, initOwner); - underlyingToken = IERC20(address(oneWeiFeeOnTransferToken)); - } - - // need to transfer extra here because otherwise the `sender` won't have enough tokens - underlyingToken.transfer(sender, 1000); - - IStrategy oneWeiFeeOnTransferTokenStrategy = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) - ) - ) - ); - - // REMAINDER OF CODE ADAPTED FROM `_testDepositToStrategy` - // _testDepositToStrategy(sender, amountToDeposit, underlyingToken, oneWeiFeeOnTransferTokenStrategy); - - // whitelist the strategy for deposit, in case it wasn't before - { - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = oneWeiFeeOnTransferTokenStrategy; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - } - - uint256 operatorSharesBefore = strategyManager.stakerStrategyShares(sender, oneWeiFeeOnTransferTokenStrategy); - // check the expected output - uint256 expectedSharesOut = oneWeiFeeOnTransferTokenStrategy.underlyingToShares(amountToDeposit); - - underlyingToken.transfer(sender, amountToDeposit); - cheats.startPrank(sender); - underlyingToken.approve(address(strategyManager), type(uint256).max); - strategyManager.depositIntoStrategy(oneWeiFeeOnTransferTokenStrategy, underlyingToken, amountToDeposit); - - //check if depositor has never used this strat, that it is added correctly to stakerStrategyList array. - if (operatorSharesBefore == 0) { - // check that strategy is appropriately added to dynamic array of all of sender's strategies - assertTrue( - strategyManager.stakerStrategyList(sender, strategyManager.stakerStrategyListLength(sender) - 1) - == oneWeiFeeOnTransferTokenStrategy, - "_testDepositToStrategy: stakerStrategyList array updated incorrectly" - ); - } - - // check that the shares out match the expected amount out - // the actual transfer in will be lower by 1 wei than expected due to stETH's internal rounding - // to account for this we check approximate rather than strict equivalence here - { - uint256 actualSharesOut = strategyManager.stakerStrategyShares(sender, oneWeiFeeOnTransferTokenStrategy) - operatorSharesBefore; - require((actualSharesOut * 1000) / expectedSharesOut > 998, "too few shares"); - require((actualSharesOut * 1000) / expectedSharesOut < 1002, "too many shares"); - - // additional sanity check for deposit not increasing in value - require(oneWeiFeeOnTransferTokenStrategy.sharesToUnderlying(actualSharesOut) <= amountToDeposit, "value cannot have increased"); - } - cheats.stopPrank(); - } - - /// @notice Shadow-forks mainnet and tests depositing stETH tokens into a "StrategyBase" contract. - function testForkMainnetDepositSteth() public { - // hard-coded inputs - // address sender = address(this); - uint64 amountToDeposit = 1e12; - - // shadow-fork mainnet - try cheats.createFork("mainnet") returns (uint256 forkId) { - cheats.selectFork(forkId); - // If RPC_MAINNET ENV not set, default to this mainnet RPC endpoint - } catch { - cheats.createSelectFork("https://eth.llamarpc.com"); - } - - // cast mainnet stETH address to IERC20 interface - // IERC20 steth = IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); - IERC20 underlyingToken = IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); - - // deploy necessary contracts on the shadow-forked network - // deploy proxy admin for ability to upgrade proxy contracts - eigenLayerProxyAdmin = new ProxyAdmin(); - //deploy pauser registry - address[] memory pausers = new address[](1); - pausers[0] = pauser; - eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); - /** - * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are - * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. - */ - emptyContract = new EmptyContract(); - delegation = DelegationManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - strategyManager = StrategyManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - eigenPodManager = EigenPodManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - - ethPOSDeposit = new ETHPOSDepositMock(); - pod = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); - - eigenPodBeacon = new UpgradeableBeacon(address(pod)); - - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - DelegationManager delegationImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - StrategyManager strategyManagerImplementation = new StrategyManager(delegation, eigenPodManager, slasher); - Slasher slasherImplementation = new Slasher(strategyManager, delegation); - EigenPodManager eigenPodManagerImplementation = new EigenPodManager(ethPOSDeposit, eigenPodBeacon, strategyManager, slasher, delegation); - // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegation))), - address(delegationImplementation), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0 /*initialPausedStatus*/, - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation), - abi.encodeWithSelector( - StrategyManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0/*initialPausedStatus*/ - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0/*initialPausedStatus*/ - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation), - abi.encodeWithSelector( - EigenPodManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0/*initialPausedStatus*/ - ) - ); - - // cheat a bunch of ETH to this address - cheats.deal(address(this), 1e20); - // deposit a huge amount of ETH to get ample stETH - { - (bool success, bytes memory returnData) = address(underlyingToken).call{value: 1e20}(""); - require(success, "depositing stETH failed"); - returnData; - } - - // deploy StrategyBase contract implementation, then create upgradeable proxy that points to implementation and initialize it - baseStrategyImplementation = new StrategyBase(strategyManager); - IStrategy stethStrategy = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) - ) - ) - ); - - // REMAINDER OF CODE ADAPTED FROM `_testDepositToStrategy` - // _testDepositToStrategy(sender, amountToDeposit, underlyingToken, stethStrategy); - - // whitelist the strategy for deposit, in case it wasn't before - { - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = stethStrategy; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - } - - uint256 operatorSharesBefore = strategyManager.stakerStrategyShares(address(this), stethStrategy); - // check the expected output - uint256 expectedSharesOut = stethStrategy.underlyingToShares(amountToDeposit); - - underlyingToken.transfer(address(this), amountToDeposit); - cheats.startPrank(address(this)); - underlyingToken.approve(address(strategyManager), type(uint256).max); - strategyManager.depositIntoStrategy(stethStrategy, underlyingToken, amountToDeposit); - - //check if depositor has never used this strat, that it is added correctly to stakerStrategyList array. - if (operatorSharesBefore == 0) { - // check that strategy is appropriately added to dynamic array of all of sender's strategies - assertTrue( - strategyManager.stakerStrategyList(address(this), strategyManager.stakerStrategyListLength(address(this)) - 1) - == stethStrategy, - "_testDepositToStrategy: stakerStrategyList array updated incorrectly" - ); - } - - // check that the shares out match the expected amount out - // the actual transfer in will be lower by 1-2 wei than expected due to stETH's internal rounding - // to account for this we check approximate rather than strict equivalence here - { - uint256 actualSharesOut = strategyManager.stakerStrategyShares(address(this), stethStrategy) - operatorSharesBefore; - require(actualSharesOut >= expectedSharesOut, "too few shares"); - require((actualSharesOut * 1000) / expectedSharesOut < 1003, "too many shares"); - - // additional sanity check for deposit not increasing in value - require(stethStrategy.sharesToUnderlying(actualSharesOut) <= amountToDeposit, "value cannot have increased"); - // slippage check - require((stethStrategy.sharesToUnderlying(actualSharesOut) * 1e6) / amountToDeposit >= (1e6 - 1), "bad slippage on first deposit"); - } - cheats.stopPrank(); - } - - function _whitelistStrategy(StrategyManager _strategyManager, StrategyBase _strategyBase) internal returns(StrategyManager) { - // whitelist the strategy for deposit - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = IStrategy(_strategyBase); - _strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - return _strategyManager; - } -} diff --git a/src/test/DevnetLifecycle.t.sol b/src/test/DevnetLifecycle.t.sol new file mode 100644 index 000000000..5769b22c3 --- /dev/null +++ b/src/test/DevnetLifecycle.t.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +// Contracts +import "../../src/contracts/core/DelegationManager.sol"; +import "../../src/contracts/core/StrategyManager.sol"; +import "../../src/contracts/core/AVSDirectory.sol"; +import "../../src/contracts/core/AllocationManager.sol"; +import "../../src/contracts/strategies/StrategyBase.sol"; + +// Test +import "forge-std/Test.sol"; + +/// @notice Tests deployed contracts as part of the public devnet +/// Run with: forge test --mc Devnet_Lifecycle_Test --rpc-url $RPC_HOLESKY +contract Devnet_Lifecycle_Test is Test { + + // Contracts + DelegationManager public delegationManager; + StrategyManager public strategyManager; + AVSDirectory public avsDirectory; + AllocationManager public allocationManager; + StrategyBase public wethStrategy; + IERC20 public weth; + + Vm cheats = Vm(VM_ADDRESS); + + // Addresses + address public staker = address(0x1); + address public operator; + uint256 operatorPk = 420; + address public avs = address(0x3); + uint32 public operatorSetId = 1; + uint256 public wethAmount = 100 ether; + uint256 public wethShares = 100 ether; + OperatorSet public operatorSet; + + // Values + uint64 public magnitudeToSet = 1e18; + + function setUp() public { + // Set contracts + delegationManager = DelegationManager(0x3391eBafDD4b2e84Eeecf1711Ff9FC06EF9Ed182); + strategyManager = StrategyManager(0x70f8bC2Da145b434de66114ac539c9756eF64fb3); + avsDirectory = AVSDirectory(0xCa839541648D3e23137457b1Fd4A06bccEADD33a); + allocationManager = AllocationManager(0xAbD5Dd30CaEF8598d4EadFE7D45Fd582EDEade15); + wethStrategy = StrategyBase(0x4f812633943022fA97cb0881683aAf9f318D5Caa); + weth = IERC20(0x94373a4919B3240D86eA41593D5eBa789FEF3848); + + // Set operator + operator = cheats.addr(operatorPk); + operatorSet = OperatorSet({avs: avs, id: operatorSetId}); + } + + function _getOperatorSetArray() internal view returns (uint32[] memory) { + uint32[] memory operatorSets = new uint32[](1); + operatorSets[0] = operatorSetId; + return operatorSets; + } + + function _getOperatorSetsArray() internal view returns (OperatorSet[] memory) { + OperatorSet[] memory operatorSets = new OperatorSet[](1); + operatorSets[0] = OperatorSet({avs: avs, id: operatorSetId}); + return operatorSets; + } + + function test() public { + if (block.chainid == 17000) { + // Seed staker with WETH + StdCheats.deal(address(weth), address(staker), wethAmount); + _run_lifecycle(); + } + } + + function _run_lifecycle() internal { + // Staker <> Operator Relationship + _depositIntoStrategy(); + _registerOperator(); + _delegateToOperator(); + + // Operator <> AVS Relationship + _registerAVS(); + _registerOperatorToAVS(); + _setMagnitude(); + + // Slash operator + _slashOperator(); + + // Withdraw staker + _withdrawStaker(); + } + + function _depositIntoStrategy() internal { + // Approve WETH + cheats.startPrank(staker); + weth.approve(address(strategyManager), wethAmount); + + // Deposit WETH into strategy + strategyManager.depositIntoStrategy(wethStrategy, weth, wethAmount); + cheats.stopPrank(); + + // Check staker balance + assertEq(weth.balanceOf(staker), 0); + + // Check staker shares + assertEq(strategyManager.stakerDepositShares(staker, wethStrategy), wethAmount); + } + + function _registerOperator() internal { + // Register operator + string memory emptyStringForMetadataURI; + cheats.prank(operator); + delegationManager.registerAsOperator(address(0), 1, emptyStringForMetadataURI); + // Warp passed configuration delay + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + + // Validate storage + assertTrue(delegationManager.isOperator(operator)); + } + + function _delegateToOperator() internal { + // Delegate to operator + ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; + cheats.prank(staker); + delegationManager.delegateTo(operator, signatureWithExpiry, bytes32(0)); + + // Validate storage + assertTrue(delegationManager.isDelegated(staker)); + assertEq(delegationManager.delegatedTo(staker), operator); + + // Validate operator shares + assertEq(delegationManager.operatorShares(operator, wethStrategy), wethShares); + } + + function _registerAVS() internal { + cheats.startPrank(avs); + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = wethStrategy; + + IAllocationManagerTypes.CreateSetParams memory createSetParams = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: operatorSetId, + strategies: strategies + }); + + IAllocationManagerTypes.CreateSetParams[] memory array = new IAllocationManagerTypes.CreateSetParams[](1); + array[0] = createSetParams; + + allocationManager.createOperatorSets(avs, array); + cheats.stopPrank(); + } + + function _registerOperatorToAVS() public { + cheats.prank(operator); + + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = operatorSetId; + + allocationManager.registerForOperatorSets(operator, IAllocationManagerTypes.RegisterParams(avs, operatorSetIds, "")); + + assertEq(allocationManager.getMembers(OperatorSet(avs, operatorSetId))[0], operator); + } + + function _setMagnitude() public { + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = wethStrategy; + + uint64[] memory magnitudes = new uint64[](1); + magnitudes[0] = magnitudeToSet; + + IAllocationManagerTypes.AllocateParams[] memory allocations = new IAllocationManagerTypes.AllocateParams[](1); + allocations[0] = IAllocationManagerTypes.AllocateParams({ + operatorSet: operatorSet, + strategies: strategies, + newMagnitudes: magnitudes + }); + + cheats.prank(operator); + allocationManager.modifyAllocations(operator, allocations); + + // Assert storage + IAllocationManagerTypes.Allocation memory info = allocationManager.getAllocation(operator, operatorSet, wethStrategy); + assertEq(info.currentMagnitude, 0); + assertEq(info.pendingDiff, int128(uint128(magnitudeToSet))); + assertEq(info.effectBlock, block.number + 1); + + // Warp to effect block + cheats.roll(block.number + 1); + + // Check allocation + info = allocationManager.getAllocation(operator, operatorSet, wethStrategy); + assertEq(info.currentMagnitude, magnitudeToSet); + } + + function _slashOperator() public { + // Get slashing params + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = wethStrategy; + IAllocationManagerTypes.SlashingParams memory slashingParams = IAllocationManagerTypes.SlashingParams({ + operator: operator, + operatorSetId: 1, + wadToSlash: 5e17, + description: "test" + }); + + // Slash operator + cheats.prank(avs); + allocationManager.slashOperator(avs, slashingParams); + + // Assert storage + IAllocationManagerTypes.Allocation memory info = allocationManager.getAllocation(operator, operatorSet, wethStrategy); + assertEq(info.currentMagnitude, magnitudeToSet - 5e17); + } + + function _withdrawStaker() public { + // Generate queued withdrawal params + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = wethStrategy; + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategies); + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawals = new IDelegationManagerTypes.QueuedWithdrawalParams[](1); + queuedWithdrawals[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ + strategies: strategies, + depositShares: withdrawableShares, + withdrawer: staker + }); + + // Generate withdrawal params + uint256[] memory scaledShares = new uint256[](1); + scaledShares[0] = 100e18; + IDelegationManagerTypes.Withdrawal memory withdrawal = IDelegationManagerTypes.Withdrawal({ + staker: staker, + delegatedTo: operator, + withdrawer: staker, + nonce: delegationManager.cumulativeWithdrawalsQueued(staker), + startBlock: uint32(block.number), + strategies: strategies, + scaledShares: scaledShares + }); + // bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal); + // Generate complete withdrawal params + + cheats.startPrank(staker); + delegationManager.queueWithdrawals(queuedWithdrawals); + + // Roll passed withdrawal delay + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + + // Complete withdrawal + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = weth; + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + + // Assert tokens + assertEq(weth.balanceOf(staker), wethAmount / 2); + } +} \ No newline at end of file diff --git a/src/test/EigenLayerDeployer.t.sol b/src/test/EigenLayerDeployer.t.sol deleted file mode 100644 index 937ce98b4..000000000 --- a/src/test/EigenLayerDeployer.t.sol +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; -import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; -import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; - -import "../contracts/interfaces/IDelegationManager.sol"; -import "../contracts/core/DelegationManager.sol"; - -import "../contracts/interfaces/IETHPOSDeposit.sol"; - -import "../contracts/core/StrategyManager.sol"; -import "../contracts/strategies/StrategyBase.sol"; -import "../contracts/core/Slasher.sol"; - -import "../contracts/pods/EigenPod.sol"; -import "../contracts/pods/EigenPodManager.sol"; - -import "../contracts/permissions/PauserRegistry.sol"; - -import "./utils/Operators.sol"; - -import "./mocks/LiquidStakingToken.sol"; -import "./mocks/EmptyContract.sol"; -import "./mocks/ETHDepositMock.sol"; - -import "forge-std/Test.sol"; - -contract EigenLayerDeployer is Operators { - Vm cheats = Vm(VM_ADDRESS); - - // EigenLayer contracts - ProxyAdmin public eigenLayerProxyAdmin; - PauserRegistry public eigenLayerPauserReg; - - Slasher public slasher; - DelegationManager public delegation; - StrategyManager public strategyManager; - EigenPodManager public eigenPodManager; - IEigenPod public pod; - IETHPOSDeposit public ethPOSDeposit; - IBeacon public eigenPodBeacon; - - // testing/mock contracts - IERC20 public eigenToken; - IERC20 public weth; - StrategyBase public wethStrat; - StrategyBase public eigenStrat; - StrategyBase public baseStrategyImplementation; - EmptyContract public emptyContract; - - mapping(uint256 => IStrategy) public strategies; - - //from testing seed phrase - bytes32 priv_key_0 = 0x1234567812345678123456781234567812345678123456781234567812345678; - bytes32 priv_key_1 = 0x1234567812345678123456781234567812345698123456781234567812348976; - - //strategy indexes for undelegation (see commitUndelegation function) - uint256[] public strategyIndexes; - address[2] public stakers; - address sample_registrant = cheats.addr(436364636); - - address[] public slashingContracts; - - uint256 wethInitialSupply = 10e50; - uint256 public constant eigenTotalSupply = 1000e18; - uint256 nonce = 69; - uint256 public gasLimit = 750000; - IStrategy[] public initializeStrategiesToSetDelayBlocks; - uint256[] public initializeWithdrawalDelayBlocks; - uint256 minWithdrawalDelayBlocks = 0; - uint32 PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS = 7 days / 12 seconds; - uint256 REQUIRED_BALANCE_WEI = 32 ether; - uint64 MAX_PARTIAL_WTIHDRAWAL_AMOUNT_GWEI = 1 ether / 1e9; - uint64 GOERLI_GENESIS_TIME = 1616508000; - - address pauser; - address unpauser; - address theMultiSig = address(420); - address operator = address(0x4206904396bF2f8b173350ADdEc5007A52664293); //sk: e88d9d864d5d731226020c5d2f02b62a4ce2a4534a39c225d32d3db795f83319 - address acct_0 = cheats.addr(uint256(priv_key_0)); - address acct_1 = cheats.addr(uint256(priv_key_1)); - address _challenger = address(0x6966904396bF2f8b173350bCcec5007A52669873); - address public eigenLayerReputedMultisig = address(this); - - address eigenLayerProxyAdminAddress; - address eigenLayerPauserRegAddress; - address slasherAddress; - address delegationAddress; - address strategyManagerAddress; - address eigenPodManagerAddress; - address podAddress; - address eigenPodBeaconAddress; - address emptyContractAddress; - address operationsMultisig; - address executorMultisig; - - - // addresses excluded from fuzzing due to abnormal behavior. TODO: @Sidu28 define this better and give it a clearer name - mapping(address => bool) fuzzedAddressMapping; - - //ensures that a passed in address is not set to true in the fuzzedAddressMapping - modifier fuzzedAddress(address addr) virtual { - cheats.assume(fuzzedAddressMapping[addr] == false); - _; - } - - modifier cannotReinit() { - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - _; - } - - //performs basic deployment before each test - function setUp() public virtual { - try vm.envUint("CHAIN_ID") returns (uint256 chainId) { - if (chainId == 31337) { - _deployEigenLayerContractsLocal(); - } - // If CHAIN_ID ENV is not set, assume local deployment on 31337 - } catch { - _deployEigenLayerContractsLocal(); - } - - fuzzedAddressMapping[address(0)] = true; - fuzzedAddressMapping[address(eigenLayerProxyAdmin)] = true; - fuzzedAddressMapping[address(strategyManager)] = true; - fuzzedAddressMapping[address(eigenPodManager)] = true; - fuzzedAddressMapping[address(delegation)] = true; - fuzzedAddressMapping[address(slasher)] = true; - } - - function _deployEigenLayerContractsLocal() internal { - pauser = address(69); - unpauser = address(489); - // deploy proxy admin for ability to upgrade proxy contracts - eigenLayerProxyAdmin = new ProxyAdmin(); - - //deploy pauser registry - address[] memory pausers = new address[](1); - pausers[0] = pauser; - eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); - - /** - * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are - * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. - */ - emptyContract = new EmptyContract(); - delegation = DelegationManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - strategyManager = StrategyManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - eigenPodManager = EigenPodManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - ethPOSDeposit = new ETHPOSDepositMock(); - pod = new EigenPod( - ethPOSDeposit, - eigenPodManager, - GOERLI_GENESIS_TIME - ); - - eigenPodBeacon = new UpgradeableBeacon(address(pod)); - - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - DelegationManager delegationImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - StrategyManager strategyManagerImplementation = new StrategyManager(delegation, eigenPodManager, slasher); - Slasher slasherImplementation = new Slasher(strategyManager, delegation); - EigenPodManager eigenPodManagerImplementation = new EigenPodManager( - ethPOSDeposit, - eigenPodBeacon, - strategyManager, - slasher, - delegation - ); - - // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegation))), - address(delegationImplementation), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0 /*initialPausedStatus*/, - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation), - abi.encodeWithSelector( - StrategyManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0 /*initialPausedStatus*/ - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0 /*initialPausedStatus*/ - ) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation), - abi.encodeWithSelector( - EigenPodManager.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, - 0 /*initialPausedStatus*/ - ) - ); - - //simple ERC20 (**NOT** WETH-like!), used in a test strategy - weth = new ERC20PresetFixedSupply("weth", "WETH", wethInitialSupply, address(this)); - - // deploy StrategyBase contract implementation, then create upgradeable proxy that points to implementation and initialize it - baseStrategyImplementation = new StrategyBase(strategyManager); - wethStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, weth, eigenLayerPauserReg) - ) - ) - ); - - eigenToken = new ERC20PresetFixedSupply("eigen", "EIGEN", wethInitialSupply, address(this)); - - // deploy upgradeable proxy that points to StrategyBase implementation and initialize it - eigenStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, eigenToken, eigenLayerPauserReg) - ) - ) - ); - - stakers = [acct_0, acct_1]; - } - - function _setAddresses(string memory config) internal { - eigenLayerProxyAdminAddress = stdJson.readAddress(config, ".addresses.eigenLayerProxyAdmin"); - eigenLayerPauserRegAddress = stdJson.readAddress(config, ".addresses.eigenLayerPauserReg"); - delegationAddress = stdJson.readAddress(config, ".addresses.delegation"); - strategyManagerAddress = stdJson.readAddress(config, ".addresses.strategyManager"); - slasherAddress = stdJson.readAddress(config, ".addresses.slasher"); - eigenPodManagerAddress = stdJson.readAddress(config, ".addresses.eigenPodManager"); - emptyContractAddress = stdJson.readAddress(config, ".addresses.emptyContract"); - operationsMultisig = stdJson.readAddress(config, ".parameters.operationsMultisig"); - executorMultisig = stdJson.readAddress(config, ".parameters.executorMultisig"); - } -} diff --git a/src/test/EigenLayerTestHelper.t.sol b/src/test/EigenLayerTestHelper.t.sol deleted file mode 100644 index 62508d5d8..000000000 --- a/src/test/EigenLayerTestHelper.t.sol +++ /dev/null @@ -1,505 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../test/EigenLayerDeployer.t.sol"; -import "../contracts/interfaces/ISignatureUtils.sol"; - -contract EigenLayerTestHelper is EigenLayerDeployer { - uint8 durationToInit = 2; - uint256 public SECP256K1N_MODULUS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; - uint256 public SECP256K1N_MODULUS_HALF = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; - - uint256[] sharesBefore; - uint256[] balanceBefore; - uint256[] priorTotalShares; - uint256[] strategyTokenBalance; - - /** - * @notice Helper function to test `initiateDelegation` functionality. Handles registering as an operator, depositing tokens - * into both Weth and Eigen strategies, as well as delegating assets from "stakers" to the operator. - * @param operatorIndex is the index of the operator to use from the test-data/operators.json file - * @param amountEigenToDeposit amount of eigen token to deposit - * @param amountEthToDeposit amount of eth to deposit - */ - - function _testInitiateDelegation( - uint8 operatorIndex, - uint256 amountEigenToDeposit, - uint256 amountEthToDeposit - ) public returns (uint256 amountEthStaked, uint256 amountEigenStaked) { - address operator = getOperatorAddress(operatorIndex); - - //setting up operator's delegation terms - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(operator, operatorDetails); - - for (uint256 i; i < stakers.length; i++) { - //initialize weth, eigen and eth balances for staker - eigenToken.transfer(stakers[i], amountEigenToDeposit); - weth.transfer(stakers[i], amountEthToDeposit); - - //deposit staker's eigen and weth into strategy manager - _testDepositEigen(stakers[i], amountEigenToDeposit); - _testDepositWeth(stakers[i], amountEthToDeposit); - - //delegate the staker's deposits to operator - uint256 operatorEigenSharesBefore = delegation.operatorShares(operator, eigenStrat); - uint256 operatorWETHSharesBefore = delegation.operatorShares(operator, wethStrat); - _testDelegateToOperator(stakers[i], operator); - //verify that `increaseOperatorShares` worked - assertTrue( - delegation.operatorShares(operator, eigenStrat) - operatorEigenSharesBefore == amountEigenToDeposit - ); - assertTrue(delegation.operatorShares(operator, wethStrat) - operatorWETHSharesBefore == amountEthToDeposit); - } - amountEthStaked += delegation.operatorShares(operator, wethStrat); - amountEigenStaked += delegation.operatorShares(operator, eigenStrat); - - return (amountEthStaked, amountEigenStaked); - } - - /** - * @notice Register 'sender' as an operator, setting their 'OperatorDetails' in DelegationManager to 'operatorDetails', verifies - * that the storage of DelegationManager contract is updated appropriately - * - * @param sender is the address being registered as an operator - * @param operatorDetails is the `sender`'s OperatorDetails struct - */ - function _testRegisterAsOperator( - address sender, - IDelegationManager.OperatorDetails memory operatorDetails - ) internal { - cheats.startPrank(sender); - string memory emptyStringForMetadataURI; - delegation.registerAsOperator(operatorDetails, emptyStringForMetadataURI); - assertTrue(delegation.isOperator(sender), "testRegisterAsOperator: sender is not a operator"); - - assertTrue( - keccak256(abi.encode(delegation.operatorDetails(sender))) == keccak256(abi.encode(operatorDetails)), - "_testRegisterAsOperator: operatorDetails not set appropriately" - ); - - assertTrue(delegation.isDelegated(sender), "_testRegisterAsOperator: sender not marked as actively delegated"); - cheats.stopPrank(); - } - - /** - * @notice Deposits `amountToDeposit` of WETH from address `sender` into `wethStrat`. - * @param sender The address to spoof calls from using `cheats.startPrank(sender)` - * @param amountToDeposit Amount of WETH that is first *transferred from this contract to `sender`* and then deposited by `sender` into `stratToDepositTo` - */ - function _testDepositWeth(address sender, uint256 amountToDeposit) internal returns (uint256 amountDeposited) { - cheats.assume(amountToDeposit <= wethInitialSupply); - amountDeposited = _testDepositToStrategy(sender, amountToDeposit, weth, wethStrat); - } - - /** - * @notice Deposits `amountToDeposit` of EIGEN from address `sender` into `eigenStrat`. - * @param sender The address to spoof calls from using `cheats.startPrank(sender)` - * @param amountToDeposit Amount of EIGEN that is first *transferred from this contract to `sender`* and then deposited by `sender` into `stratToDepositTo` - */ - function _testDepositEigen(address sender, uint256 amountToDeposit) internal returns (uint256 amountDeposited) { - cheats.assume(amountToDeposit <= eigenTotalSupply); - amountDeposited = _testDepositToStrategy(sender, amountToDeposit, eigenToken, eigenStrat); - } - - /** - * @notice Deposits `amountToDeposit` of `underlyingToken` from address `sender` into `stratToDepositTo`. - * *If* `sender` has zero shares prior to deposit, *then* checks that `stratToDepositTo` is correctly added to their `stakerStrategyList` array. - * - * @param sender The address to spoof calls from using `cheats.startPrank(sender)` - * @param amountToDeposit Amount of WETH that is first *transferred from this contract to `sender`* and then deposited by `sender` into `stratToDepositTo` - */ - function _testDepositToStrategy( - address sender, - uint256 amountToDeposit, - IERC20 underlyingToken, - IStrategy stratToDepositTo - ) internal returns (uint256 amountDeposited) { - // deposits will revert when amountToDeposit is 0 - cheats.assume(amountToDeposit > 0); - - // whitelist the strategy for deposit, in case it wasn't before - { - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = stratToDepositTo; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - } - - uint256 operatorSharesBefore = strategyManager.stakerStrategyShares(sender, stratToDepositTo); - // assumes this contract already has the underlying token! - uint256 contractBalance = underlyingToken.balanceOf(address(this)); - // check the expected output - uint256 expectedSharesOut = stratToDepositTo.underlyingToShares(amountToDeposit); - // logging and error for misusing this function (see assumption above) - if (amountToDeposit > contractBalance) { - emit log("amountToDeposit > contractBalance"); - emit log_named_uint("amountToDeposit is", amountToDeposit); - emit log_named_uint("while contractBalance is", contractBalance); - revert("_testDepositToStrategy failure"); - } else { - underlyingToken.transfer(sender, amountToDeposit); - cheats.startPrank(sender); - underlyingToken.approve(address(strategyManager), type(uint256).max); - strategyManager.depositIntoStrategy(stratToDepositTo, underlyingToken, amountToDeposit); - amountDeposited = amountToDeposit; - - //check if depositor has never used this strat, that it is added correctly to stakerStrategyList array. - if (operatorSharesBefore == 0) { - // check that strategy is appropriately added to dynamic array of all of sender's strategies - assertTrue( - strategyManager.stakerStrategyList(sender, strategyManager.stakerStrategyListLength(sender) - 1) == - stratToDepositTo, - "_testDepositToStrategy: stakerStrategyList array updated incorrectly" - ); - } - - // check that the shares out match the expected amount out - assertEq( - strategyManager.stakerStrategyShares(sender, stratToDepositTo) - operatorSharesBefore, - expectedSharesOut, - "_testDepositToStrategy: actual shares out should match expected shares out" - ); - } - cheats.stopPrank(); - } - - /** - * @notice tries to delegate from 'staker' to 'operator', verifies that staker has at least some shares - * delegatedShares update correctly for 'operator' and delegated status is updated correctly for 'staker' - * @param staker the staker address to delegate from - * @param operator the operator address to delegate to - */ - function _testDelegateToOperator(address staker, address operator) internal { - //staker-specific information - (IStrategy[] memory delegateStrategies, uint256[] memory delegateShares) = strategyManager.getDeposits(staker); - - uint256 numStrats = delegateShares.length; - assertTrue(numStrats != 0, "_testDelegateToOperator: delegating from address with no deposits"); - uint256[] memory inititalSharesInStrats = new uint256[](numStrats); - for (uint256 i = 0; i < numStrats; ++i) { - inititalSharesInStrats[i] = delegation.operatorShares(operator, delegateStrategies[i]); - } - - cheats.startPrank(staker); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; - delegation.delegateTo(operator, signatureWithExpiry, bytes32(0)); - cheats.stopPrank(); - - assertTrue( - delegation.delegatedTo(staker) == operator, - "_testDelegateToOperator: delegated address not set appropriately" - ); - assertTrue(delegation.isDelegated(staker), "_testDelegateToOperator: delegated status not set appropriately"); - - for (uint256 i = 0; i < numStrats; ++i) { - uint256 operatorSharesBefore = inititalSharesInStrats[i]; - uint256 operatorSharesAfter = delegation.operatorShares(operator, delegateStrategies[i]); - assertTrue( - operatorSharesAfter == (operatorSharesBefore + delegateShares[i]), - "_testDelegateToOperator: delegatedShares not increased correctly" - ); - } - } - - /** - * @notice deploys 'numStratsToAdd' strategies contracts and initializes them to treat `underlyingToken` as their underlying token - * and then deposits 'amountToDeposit' to each of them from 'sender' - * - * @param sender address that is depositing into the strategies - * @param amountToDeposit amount being deposited - * @param numStratsToAdd number of strategies that are being deployed and deposited into - */ - function _testDepositStrategies(address sender, uint256 amountToDeposit, uint8 numStratsToAdd) internal { - // hard-coded input - IERC20 underlyingToken = weth; - - cheats.assume(numStratsToAdd > 0 && numStratsToAdd <= 20); - IStrategy[] memory stratsToDepositTo = new IStrategy[](numStratsToAdd); - for (uint8 i = 0; i < numStratsToAdd; ++i) { - stratsToDepositTo[i] = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) - ) - ) - ); - _testDepositToStrategy(sender, amountToDeposit, weth, StrategyBase(address(stratsToDepositTo[i]))); - } - for (uint8 i = 0; i < numStratsToAdd; ++i) { - // check that strategy is appropriately added to dynamic array of all of sender's strategies - assertTrue( - strategyManager.stakerStrategyList(sender, i) == stratsToDepositTo[i], - "stakerStrategyList array updated incorrectly" - ); - - // TODO: perhaps remove this is we can. seems brittle if we don't track the number of strategies somewhere - //store strategy in mapping of strategies - strategies[i] = IStrategy(address(stratsToDepositTo[i])); - } - } - - /** - * @notice Creates a queued withdrawal from `staker`. Begins by registering the staker as a delegate (if specified), then deposits `amountToDeposit` - * into the WETH strategy, and then queues a withdrawal using - * `strategyManager.queueWithdrawal(strategyIndexes, strategyArray, tokensArray, shareAmounts, withdrawer)` - * @notice After initiating a queued withdrawal, this test checks that `strategyManager.canCompleteQueuedWithdrawal` immediately returns the correct - * response depending on whether `staker` is delegated or not. - * @param staker The address to initiate the queued withdrawal - * @param registerAsOperator If true, `staker` will also register as a delegate in the course of this function - * @param amountToDeposit The amount of WETH to deposit - */ - function _createQueuedWithdrawal( - address staker, - bool registerAsOperator, - uint256 amountToDeposit, - IStrategy[] memory strategyArray, - uint256[] memory shareAmounts, - uint256[] memory strategyIndexes, - address withdrawer - ) internal returns (bytes32 withdrawalRoot, IDelegationManager.Withdrawal memory queuedWithdrawal) { - require(amountToDeposit >= shareAmounts[0], "_createQueuedWithdrawal: sanity check failed"); - - // we do this here to ensure that `staker` is delegated if `registerAsOperator` is true - if (registerAsOperator) { - assertTrue(!delegation.isDelegated(staker), "_createQueuedWithdrawal: staker is already delegated"); - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: staker, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(staker, operatorDetails); - assertTrue( - delegation.isDelegated(staker), - "_createQueuedWithdrawal: staker isn't delegated when they should be" - ); - } - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: staker, - withdrawer: withdrawer, - nonce: delegation.cumulativeWithdrawalsQueued(staker), - delegatedTo: delegation.delegatedTo(staker), - startBlock: uint32(block.number) - }); - - { - //make deposit in WETH strategy - uint256 amountDeposited = _testDepositWeth(staker, amountToDeposit); - // We can't withdraw more than we deposit - if (shareAmounts[0] > amountDeposited) { - cheats.expectRevert("StrategyManager._removeShares: shareAmount too high"); - } - } - - //queue the withdrawal - withdrawalRoot = _testQueueWithdrawal(staker, strategyIndexes, strategyArray, shareAmounts, withdrawer); - return (withdrawalRoot, queuedWithdrawal); - } - - /** - * Helper for ECDSA signatures: combines V and S into VS - if S is greater than SECP256K1N_MODULUS_HALF, then we - * get the modulus, so that the leading bit of s is always 0. Then we set the leading - * bit to be either 0 or 1 based on the value of v, which is either 27 or 28 - */ - function getVSfromVandS(uint8 v, bytes32 s) internal view returns (bytes32) { - if (uint256(s) > SECP256K1N_MODULUS_HALF) { - s = bytes32(SECP256K1N_MODULUS - uint256(s)); - } - - bytes32 vs = s; - if (v == 28) { - vs = bytes32(uint256(s) ^ (1 << 255)); - } - - return vs; - } - - /// @notice registers a fixed address as an operator, delegates to it from a second address, - /// and checks that the operator's voteWeights increase properly - /// @param operator is the operator being delegated to. - /// @param staker is the staker delegating stake to the operator. - /// @param ethAmount is the amount of ETH to deposit into the operator's strategy. - /// @param eigenAmount is the amount of EIGEN to deposit into the operator's strategy. - function _testDelegation( - address operator, - address staker, - uint256 ethAmount, - uint256 eigenAmount - ) internal { - if (!delegation.isOperator(operator)) { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(operator, operatorDetails); - } - - uint256 amountBefore = delegation.operatorShares(operator, wethStrat); - - //making additional deposits to the strategies - assertTrue(!delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - _testDepositWeth(staker, ethAmount); - _testDepositEigen(staker, eigenAmount); - _testDelegateToOperator(staker, operator); - assertTrue(delegation.isDelegated(staker) == true, "testDelegation: staker is not delegate"); - - (/*IStrategy[] memory updatedStrategies*/, uint256[] memory updatedShares) = strategyManager.getDeposits(staker); - - IStrategy _strat = wethStrat; - // IStrategy _strat = strategyManager.stakerStrategyList(staker, 0); - assertTrue(address(_strat) != address(0), "stakerStrategyList not updated correctly"); - - assertTrue( - delegation.operatorShares(operator, _strat) - updatedShares[0] == amountBefore, - "ETH operatorShares not updated correctly" - ); - } - - /** - * @notice Helper function to complete an existing queued withdrawal in shares - * @param depositor is the address of the staker who queued a withdrawal - * @param strategyArray is the array of strategies to withdraw from - * @param tokensArray is the array of tokens to withdraw from said strategies - * @param shareAmounts is the array of shares to be withdrawn from said strategies - * @param delegatedTo is the address the staker has delegated their shares to - * @param withdrawalStartBlock the block number of the original queued withdrawal - * @param middlewareTimesIndex index in the middlewareTimes array used to queue this withdrawal - */ - - function _testCompleteQueuedWithdrawalShares( - address depositor, - IStrategy[] memory strategyArray, - IERC20[] memory tokensArray, - uint256[] memory shareAmounts, - address delegatedTo, - address withdrawer, - uint256 nonce, - uint32 withdrawalStartBlock, - uint256 middlewareTimesIndex - ) internal { - cheats.startPrank(withdrawer); - - for (uint256 i = 0; i < strategyArray.length; i++) { - sharesBefore.push(strategyManager.stakerStrategyShares(withdrawer, strategyArray[i])); - } - // emit log_named_uint("strategies", strategyArray.length); - // emit log_named_uint("tokens", tokensArray.length); - // emit log_named_uint("shares", shareAmounts.length); - // emit log_named_address("depositor", depositor); - // emit log_named_uint("withdrawalStartBlock", withdrawalStartBlock); - // emit log_named_address("delegatedAddress", delegatedTo); - // emit log("************************************************************************************************"); - - IDelegationManager.Withdrawal memory queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: depositor, - withdrawer: withdrawer, - nonce: nonce, - startBlock: withdrawalStartBlock, - delegatedTo: delegatedTo - }); - - // complete the queued withdrawal - delegation.completeQueuedWithdrawal(queuedWithdrawal, tokensArray, middlewareTimesIndex, false); - - for (uint256 i = 0; i < strategyArray.length; i++) { - require( - strategyManager.stakerStrategyShares(withdrawer, strategyArray[i]) == sharesBefore[i] + shareAmounts[i], - "_testCompleteQueuedWithdrawalShares: withdrawer shares not incremented" - ); - } - cheats.stopPrank(); - } - - /** - * @notice Helper function to complete an existing queued withdrawal in tokens - * @param depositor is the address of the staker who queued a withdrawal - * @param strategyArray is the array of strategies to withdraw from - * @param tokensArray is the array of tokens to withdraw from said strategies - * @param shareAmounts is the array of shares to be withdrawn from said strategies - * @param delegatedTo is the address the staker has delegated their shares to - * @param withdrawalStartBlock the block number of the original queued withdrawal - * @param middlewareTimesIndex index in the middlewareTimes array used to queue this withdrawal - */ - function _testCompleteQueuedWithdrawalTokens( - address depositor, - IStrategy[] memory strategyArray, - IERC20[] memory tokensArray, - uint256[] memory shareAmounts, - address delegatedTo, - address withdrawer, - uint256 nonce, - uint32 withdrawalStartBlock, - uint256 middlewareTimesIndex - ) internal { - cheats.startPrank(withdrawer); - - for (uint256 i = 0; i < strategyArray.length; i++) { - balanceBefore.push(strategyArray[i].underlyingToken().balanceOf(withdrawer)); - priorTotalShares.push(strategyArray[i].totalShares()); - strategyTokenBalance.push(strategyArray[i].underlyingToken().balanceOf(address(strategyArray[i]))); - } - - IDelegationManager.Withdrawal memory queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: depositor, - withdrawer: withdrawer, - nonce: nonce, - startBlock: withdrawalStartBlock, - delegatedTo: delegatedTo - }); - // complete the queued withdrawal - delegation.completeQueuedWithdrawal(queuedWithdrawal, tokensArray, middlewareTimesIndex, true); - - for (uint256 i = 0; i < strategyArray.length; i++) { - //uint256 strategyTokenBalance = strategyArray[i].underlyingToken().balanceOf(address(strategyArray[i])); - uint256 tokenBalanceDelta = (strategyTokenBalance[i] * shareAmounts[i]) / priorTotalShares[i]; - - // filter out unrealistic case, where the withdrawer is the strategy contract itself - cheats.assume(withdrawer != address(strategyArray[i])); - require( - strategyArray[i].underlyingToken().balanceOf(withdrawer) == balanceBefore[i] + tokenBalanceDelta, - "_testCompleteQueuedWithdrawalTokens: withdrawer balance not incremented" - ); - } - cheats.stopPrank(); - } - - function _testQueueWithdrawal( - address depositor, - uint256[] memory /*strategyIndexes*/, - IStrategy[] memory strategyArray, - uint256[] memory shareAmounts, - address withdrawer - ) internal returns (bytes32) { - cheats.startPrank(depositor); - - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - - params[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategyArray, - shares: shareAmounts, - withdrawer: withdrawer - }); - - bytes32[] memory withdrawalRoots = new bytes32[](1); - withdrawalRoots = delegation.queueWithdrawals(params); - cheats.stopPrank(); - return withdrawalRoots[0]; - } -} diff --git a/src/test/Pausable.t.sol b/src/test/Pausable.t.sol deleted file mode 100644 index 9b6b878ec..000000000 --- a/src/test/Pausable.t.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity ^0.8.12; - -import "./EigenLayerTestHelper.t.sol"; - -contract PausableTests is EigenLayerTestHelper { - - /// @notice Emitted when the `pauserRegistry` is set to `newPauserRegistry`. - event PauserRegistrySet(IPauserRegistry pauserRegistry, IPauserRegistry newPauserRegistry); - - ///@dev test that pausing a contract works - function testPausingWithdrawalsFromStrategyManager(uint256 amountToDeposit, uint256 amountToWithdraw) public { - cheats.assume(amountToDeposit <= 1e38 - 1); - cheats.assume(amountToDeposit <= weth.balanceOf(address(this))); - // if first deposit amount to base strategy is too small, it will revert. ignore that case here. - cheats.assume(amountToDeposit >= 1); - cheats.assume(amountToWithdraw <= amountToDeposit); - - address sender = getOperatorAddress(0); - _testDepositToStrategy(sender, amountToDeposit, weth, wethStrat); - - cheats.startPrank(pauser); - strategyManager.pause(type(uint256).max); - cheats.stopPrank(); - - // uint256 strategyIndex = 0; - - cheats.prank(sender); - - // TODO: write this to work with completing a queued withdrawal - // cheats.expectRevert(bytes("Pausable: paused")); - // strategyManager.withdrawFromStrategy(strategyIndex, wethStrat, weth, amountToWithdraw); - // cheats.stopPrank(); - } - - function testUnauthorizedPauserStrategyManager(address unauthorizedPauser) - public - fuzzedAddress(unauthorizedPauser) - { - cheats.assume(!eigenLayerPauserReg.isPauser(unauthorizedPauser)); - cheats.startPrank(unauthorizedPauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as pauser")); - strategyManager.pause(type(uint256).max); - cheats.stopPrank(); - } - - function testSetPauser(address newPauser) public fuzzedAddress(newPauser) { - cheats.startPrank(unpauser); - eigenLayerPauserReg.setIsPauser(newPauser, true); - cheats.stopPrank(); - } - - function testSetUnpauser(address newUnpauser) public fuzzedAddress(newUnpauser) { - cheats.startPrank(unpauser); - eigenLayerPauserReg.setUnpauser(newUnpauser); - cheats.stopPrank(); - } - - function testSetPauserUnauthorized(address fakePauser, address newPauser) - public - fuzzedAddress(newPauser) - fuzzedAddress(fakePauser) - { - cheats.assume(fakePauser != eigenLayerPauserReg.unpauser()); - cheats.startPrank(fakePauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); - eigenLayerPauserReg.setIsPauser(newPauser, true); - cheats.stopPrank(); - } - - function testSetPauserRegistryUnpauser(IPauserRegistry newPauserRegistry) public { - cheats.assume(address(newPauserRegistry) != address(0)); - IPauserRegistry oldPauserRegistry = strategyManager.pauserRegistry(); - cheats.prank(unpauser); - cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit PauserRegistrySet(oldPauserRegistry, newPauserRegistry); - strategyManager.setPauserRegistry(newPauserRegistry); - - assertEq(address(newPauserRegistry), address(strategyManager.pauserRegistry())); - } - - function testSetPauserRegistyUnauthorized(IPauserRegistry newPauserRegistry, address notUnpauser) public fuzzedAddress(notUnpauser) { - cheats.assume(notUnpauser != eigenLayerPauserReg.unpauser()); - - cheats.prank(notUnpauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); - strategyManager.setPauserRegistry(newPauserRegistry); - } -} diff --git a/src/test/Strategy.t.sol b/src/test/Strategy.t.sol deleted file mode 100644 index 3139e92a2..000000000 --- a/src/test/Strategy.t.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "./EigenLayerTestHelper.t.sol"; -import "../contracts/core/StrategyManagerStorage.sol"; - -contract StrategyTests is EigenLayerTestHelper { - /// @notice This function tests to ensure that a delegation contract - /// cannot be intitialized multiple times - function testCannotInitMultipleTimesDelegation() public cannotReinit { - wethStrat.initialize(weth, eigenLayerPauserReg); - } - - ///@notice This function tests to ensure that only the strategyManager - /// can deposit into a strategy - ///@param invalidDepositor is the non-registered depositor - function testInvalidCalltoDeposit(address invalidDepositor) public fuzzedAddress(invalidDepositor) { - IERC20 underlyingToken = wethStrat.underlyingToken(); - - cheats.startPrank(invalidDepositor); - cheats.expectRevert(bytes("StrategyBase.onlyStrategyManager")); - wethStrat.deposit(underlyingToken, 1e18); - cheats.stopPrank(); - } - - ///@notice This function tests to ensure that only the strategyManager - /// can deposit into a strategy - ///@param invalidWithdrawer is the non-registered withdrawer - ///@param depositor is the depositor for which the shares are being withdrawn - function testInvalidCalltoWithdraw(address depositor, address invalidWithdrawer) - public - fuzzedAddress(invalidWithdrawer) - { - IERC20 underlyingToken = wethStrat.underlyingToken(); - - cheats.startPrank(invalidWithdrawer); - cheats.expectRevert(bytes("StrategyBase.onlyStrategyManager")); - wethStrat.withdraw(depositor, underlyingToken, 1e18); - cheats.stopPrank(); - } - - ///@notice This function tests ensures that withdrawing for a depositor that never - /// actually deposited fails. - ///@param depositor is the depositor for which the shares are being withdrawn - function testWithdrawalExceedsTotalShares(address depositor, uint256 shares) public fuzzedAddress(depositor) { - cheats.assume(shares > strategyManager.stakerStrategyShares(depositor, wethStrat)); - IERC20 underlyingToken = wethStrat.underlyingToken(); - - cheats.startPrank(address(strategyManager)); - - cheats.expectRevert( - bytes("StrategyBase.withdraw: amountShares must be less than or equal to totalShares") - ); - wethStrat.withdraw(depositor, underlyingToken, shares); - - cheats.stopPrank(); - } -} diff --git a/src/test/Withdrawals.t.sol b/src/test/Withdrawals.t.sol deleted file mode 100644 index f8f780e7a..000000000 --- a/src/test/Withdrawals.t.sol +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../test/EigenLayerTestHelper.t.sol"; - -contract WithdrawalTests is EigenLayerTestHelper { - // packed info used to help handle stack-too-deep errors - struct DataForTestWithdrawal { - IStrategy[] delegatorStrategies; - uint256[] delegatorShares; - address withdrawer; - uint96 nonce; - } - - bytes32 defaultOperatorId = bytes32(uint256(0)); - - function setUp() public virtual override { - EigenLayerDeployer.setUp(); - } - - //This function helps with stack too deep issues with "testWithdrawal" test - function testWithdrawalWrapper( - address operator, - address depositor, - uint96 ethAmount, - uint96 eigenAmount, - bool withdrawAsTokens, - bool RANDAO - ) public fuzzedAddress(operator) fuzzedAddress(depositor) { - cheats.assume(depositor != operator); - cheats.assume(ethAmount >= 1 && ethAmount <= 1e18); - cheats.assume(eigenAmount >= 1 && eigenAmount <= 1e18); - - address withdrawer = depositor; - - if (RANDAO) { - _testWithdrawalAndDeregistration(operator, depositor, withdrawer, ethAmount, eigenAmount, withdrawAsTokens); - } else { - _testWithdrawalWithStakeUpdate(operator, depositor, withdrawer, ethAmount, eigenAmount, withdrawAsTokens); - } - } - - /// @notice test staker's ability to undelegate/withdraw from an operator. - /// @param operator is the operator being delegated to. - /// @param depositor is the staker delegating stake to the operator. - function _testWithdrawalAndDeregistration( - address operator, - address depositor, - address withdrawer, - uint96 ethAmount, - uint96 eigenAmount, - bool withdrawAsTokens - ) internal { - _initiateDelegation(operator, depositor, ethAmount, eigenAmount); - - address delegatedTo = delegation.delegatedTo(depositor); - - // packed data structure to deal with stack-too-deep issues - DataForTestWithdrawal memory dataForTestWithdrawal; - - // scoped block to deal with stack-too-deep issues - { - //delegator-specific information - (IStrategy[] memory delegatorStrategies, uint256[] memory delegatorShares) = strategyManager.getDeposits( - depositor - ); - dataForTestWithdrawal.delegatorStrategies = delegatorStrategies; - dataForTestWithdrawal.delegatorShares = delegatorShares; - dataForTestWithdrawal.withdrawer = withdrawer; - // harcoded nonce value - dataForTestWithdrawal.nonce = 0; - } - - uint256[] memory strategyIndexes = new uint256[](2); - IERC20[] memory tokensArray = new IERC20[](2); - { - // hardcoded values - strategyIndexes[0] = 0; - strategyIndexes[1] = 0; - tokensArray[0] = weth; - tokensArray[1] = eigenToken; - } - - cheats.warp(uint32(block.timestamp) + 1 days); - cheats.roll(uint32(block.timestamp) + 1 days); - - _testQueueWithdrawal( - depositor, - strategyIndexes, - dataForTestWithdrawal.delegatorStrategies, - dataForTestWithdrawal.delegatorShares, - withdrawer - ); - uint32 queuedWithdrawalBlock = uint32(block.number); - - //now withdrawal block time is before deregistration - cheats.warp(uint32(block.timestamp) + 2 days); - cheats.roll(uint32(block.timestamp) + 2 days); - - { - //warp past the serve until time, which is 3 days from the beginning. THis puts us at 4 days past that point - cheats.warp(uint32(block.timestamp) + 4 days); - cheats.roll(uint32(block.timestamp) + 4 days); - - uint256 middlewareTimeIndex = 1; - if (withdrawAsTokens) { - _testCompleteQueuedWithdrawalTokens( - depositor, - dataForTestWithdrawal.delegatorStrategies, - tokensArray, - dataForTestWithdrawal.delegatorShares, - delegatedTo, - dataForTestWithdrawal.withdrawer, - dataForTestWithdrawal.nonce, - queuedWithdrawalBlock, - middlewareTimeIndex - ); - } else { - _testCompleteQueuedWithdrawalShares( - depositor, - dataForTestWithdrawal.delegatorStrategies, - tokensArray, - dataForTestWithdrawal.delegatorShares, - delegatedTo, - dataForTestWithdrawal.withdrawer, - dataForTestWithdrawal.nonce, - queuedWithdrawalBlock, - middlewareTimeIndex - ); - } - } - } - - /// @notice test staker's ability to undelegate/withdraw from an operator. - /// @param operator is the operator being delegated to. - /// @param depositor is the staker delegating stake to the operator. - function _testWithdrawalWithStakeUpdate( - address operator, - address depositor, - address withdrawer, - uint96 ethAmount, - uint96 eigenAmount, - bool withdrawAsTokens - ) public { - _initiateDelegation(operator, depositor, ethAmount, eigenAmount); - - // emit log_named_uint("Linked list element 1", uint256(uint160(address(generalServiceManager1)))); - // emit log_named_uint("Linked list element 2", uint256(uint160(address(generalServiceManager2)))); - // emit log("________________________________________________________________"); - // emit log_named_uint("Middleware 1 Update Block", uint32(block.number)); - - cheats.warp(uint32(block.timestamp) + 1 days); - cheats.roll(uint32(block.number) + 1); - - // emit log_named_uint("Middleware 2 Update Block", uint32(block.number)); - - address delegatedTo = delegation.delegatedTo(depositor); - - // packed data structure to deal with stack-too-deep issues - DataForTestWithdrawal memory dataForTestWithdrawal; - - // scoped block to deal with stack-too-deep issues - { - //delegator-specific information - (IStrategy[] memory delegatorStrategies, uint256[] memory delegatorShares) = strategyManager.getDeposits( - depositor - ); - dataForTestWithdrawal.delegatorStrategies = delegatorStrategies; - dataForTestWithdrawal.delegatorShares = delegatorShares; - dataForTestWithdrawal.withdrawer = withdrawer; - // harcoded nonce value - dataForTestWithdrawal.nonce = 0; - } - - uint256[] memory strategyIndexes = new uint256[](2); - IERC20[] memory tokensArray = new IERC20[](2); - { - // hardcoded values - strategyIndexes[0] = 0; - strategyIndexes[1] = 0; - tokensArray[0] = weth; - tokensArray[1] = eigenToken; - } - - cheats.warp(uint32(block.timestamp) + 1 days); - cheats.roll(uint32(block.number) + 1); - - _testQueueWithdrawal( - depositor, - strategyIndexes, - dataForTestWithdrawal.delegatorStrategies, - dataForTestWithdrawal.delegatorShares, - dataForTestWithdrawal.withdrawer - ); - uint32 queuedWithdrawalBlock = uint32(block.number); - - //now withdrawal block time is before deregistration - cheats.warp(uint32(block.timestamp) + 2 days); - cheats.roll(uint32(block.number) + 2); - - // uint256 prevElement = uint256(uint160(address(generalServiceManager2))); - - cheats.warp(uint32(block.timestamp) + 1 days); - cheats.roll(uint32(block.number) + 1); - - // prevElement = uint256(uint160(address(generalServiceManager1))); - - { - //warp past the serve until time, which is 3 days from the beginning. THis puts us at 4 days past that point - cheats.warp(uint32(block.timestamp) + 4 days); - cheats.roll(uint32(block.number) + 4); - - uint256 middlewareTimeIndex = 3; - if (withdrawAsTokens) { - _testCompleteQueuedWithdrawalTokens( - depositor, - dataForTestWithdrawal.delegatorStrategies, - tokensArray, - dataForTestWithdrawal.delegatorShares, - delegatedTo, - dataForTestWithdrawal.withdrawer, - dataForTestWithdrawal.nonce, - queuedWithdrawalBlock, - middlewareTimeIndex - ); - } else { - _testCompleteQueuedWithdrawalShares( - depositor, - dataForTestWithdrawal.delegatorStrategies, - tokensArray, - dataForTestWithdrawal.delegatorShares, - delegatedTo, - dataForTestWithdrawal.withdrawer, - dataForTestWithdrawal.nonce, - queuedWithdrawalBlock, - middlewareTimeIndex - ); - } - } - } - - // @notice This function tests to ensure that a delegator can re-delegate to an operator after undelegating. - // @param operator is the operator being delegated to. - // @param staker is the staker delegating stake to the operator. - function testRedelegateAfterWithdrawal( - address operator, - address depositor, - uint96 ethAmount, - uint96 eigenAmount, - bool withdrawAsShares - ) public fuzzedAddress(operator) fuzzedAddress(depositor) { - cheats.assume(depositor != operator); - //this function performs delegation and subsequent withdrawal - testWithdrawalWrapper(operator, depositor, ethAmount, eigenAmount, withdrawAsShares, true); - - cheats.prank(depositor); - delegation.undelegate(depositor); - - //warps past fraudproof time interval - cheats.warp(block.timestamp + 7 days + 1); - _initiateDelegation(operator, depositor, ethAmount, eigenAmount); - } - - // Helper function to begin a delegation - function _initiateDelegation( - address operator, - address staker, - uint96 ethAmount, - uint96 eigenAmount - ) internal fuzzedAddress(operator) fuzzedAddress(staker) fuzzedAmounts(ethAmount, eigenAmount) { - cheats.assume(staker != operator); - // base strategy will revert if these amounts are too small on first deposit - cheats.assume(ethAmount >= 1); - cheats.assume(eigenAmount >= 2); - - _testDelegation(operator, staker, ethAmount, eigenAmount); - } - - modifier fuzzedAmounts(uint256 ethAmount, uint256 eigenAmount) { - cheats.assume(ethAmount >= 0 && ethAmount <= 1e18); - cheats.assume(eigenAmount >= 0 && eigenAmount <= 1e18); - _; - } -} - diff --git a/src/test/events/IAVSDirectoryEvents.sol b/src/test/events/IAVSDirectoryEvents.sol deleted file mode 100644 index a4f0a2962..000000000 --- a/src/test/events/IAVSDirectoryEvents.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IAVSDirectory.sol"; - -interface IAVSDirectoryEvents { - /** - * @notice Emitted when @param avs indicates that they are updating their MetadataURI string - * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing - */ - event AVSMetadataURIUpdated(address indexed avs, string metadataURI); - - /// @notice Emitted when an operator's registration status for an AVS is updated - event OperatorAVSRegistrationStatusUpdated(address indexed operator, address indexed avs, IAVSDirectory.OperatorAVSRegistrationStatus status); -} diff --git a/src/test/events/IDelegationManagerEvents.sol b/src/test/events/IDelegationManagerEvents.sol deleted file mode 100644 index 9677cc226..000000000 --- a/src/test/events/IDelegationManagerEvents.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IDelegationManager.sol"; - -interface IDelegationManagerEvents { - // @notice Emitted when a new operator registers in EigenLayer and provides their OperatorDetails. - event OperatorRegistered(address indexed operator, IDelegationManager.OperatorDetails operatorDetails); - - // @notice Emitted when an operator updates their OperatorDetails to @param newOperatorDetails - event OperatorDetailsModified(address indexed operator, IDelegationManager.OperatorDetails newOperatorDetails); - - /** - * @notice Emitted when @param operator indicates that they are updating their MetadataURI string - * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing - */ - event OperatorMetadataURIUpdated(address indexed operator, string metadataURI); - - /** - * @notice Emitted when @param avs indicates that they are updating their MetadataURI string - * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing - */ - event AVSMetadataURIUpdated(address indexed avs, string metadataURI); - - /// @notice Enum representing the status of an operator's registration with an AVS - enum OperatorAVSRegistrationStatus { - UNREGISTERED, // Operator not registered to AVS - REGISTERED // Operator registered to AVS - } - - /// @notice Emitted when an operator's registration status for an AVS is updated - event OperatorAVSRegistrationStatusUpdated(address indexed operator, address indexed avs, OperatorAVSRegistrationStatus status); - - /// @notice Emitted whenever an operator's shares are increased for a given strategy - event OperatorSharesIncreased(address indexed operator, address staker, IStrategy strategy, uint256 shares); - - /// @notice Emitted whenever an operator's shares are decreased for a given strategy - event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares); - - // @notice Emitted when @param staker delegates to @param operator. - event StakerDelegated(address indexed staker, address indexed operator); - - // @notice Emitted when @param staker undelegates from @param operator. - event StakerUndelegated(address indexed staker, address indexed operator); - - /// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself - event StakerForceUndelegated(address indexed staker, address indexed operator); - - /** - * @notice Emitted when a new withdrawal is queued. - * @param withdrawalRoot Is the hash of the `withdrawal`. - * @param withdrawal Is the withdrawal itself. - */ - event WithdrawalQueued(bytes32 withdrawalRoot, IDelegationManager.Withdrawal withdrawal); - - /// @notice Emitted when a queued withdrawal is completed - event WithdrawalCompleted(bytes32 withdrawalRoot); - - /// @notice Emitted when the `strategyWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. - event StrategyWithdrawalDelayBlocksSet(IStrategy strategy, uint256 previousValue, uint256 newValue); -} diff --git a/src/test/events/IEigenPodEvents.sol b/src/test/events/IEigenPodEvents.sol deleted file mode 100644 index f6302272b..000000000 --- a/src/test/events/IEigenPodEvents.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -interface IEigenPodEvents { - // @notice Emitted when an ETH validator stakes via this eigenPod - event EigenPodStaked(bytes pubkey); - - /// @notice Emitted when a pod owner updates the proof submitter address - event ProofSubmitterUpdated(address prevProofSubmitter, address newProofSubmitter); - - /// @notice Emitted when an ETH validator's withdrawal credentials are successfully verified to be pointed to this eigenPod - event ValidatorRestaked(uint40 validatorIndex); - - /// @notice Emitted when an ETH validator's balance is proven to be updated. Here newValidatorBalanceGwei - // is the validator's balance that is credited on EigenLayer. - event ValidatorBalanceUpdated(uint40 validatorIndex, uint64 balanceTimestamp, uint64 newValidatorBalanceGwei); - - /// @notice Emitted when restaked beacon chain ETH is withdrawn from the eigenPod. - event RestakedBeaconChainETHWithdrawn(address indexed recipient, uint256 amount); - - /// @notice Emitted when podOwner enables restaking - event RestakingActivated(address indexed podOwner); - - /// @notice Emitted when ETH is received via the `receive` fallback - event NonBeaconChainETHReceived(uint256 amountReceived); - - /// @notice Emitted when a checkpoint is created - event CheckpointCreated(uint64 indexed checkpointTimestamp, bytes32 indexed beaconBlockRoot, uint256 validatorCount); - - /// @notice Emitted when a checkpoint is finalized - event CheckpointFinalized(uint64 indexed checkpointTimestamp, int256 totalShareDeltaWei); - - /// @notice Emitted when a validator is proven for a given checkpoint - event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex); - - /// @notice Emitted when a validaor is proven to have 0 balance at a given checkpoint - event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex); -} diff --git a/src/test/events/IEigenPodManagerEvents.sol b/src/test/events/IEigenPodManagerEvents.sol deleted file mode 100644 index 79c11d663..000000000 --- a/src/test/events/IEigenPodManagerEvents.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -interface IEigenPodManagerEvents { - /// @notice Emitted to notify that the denebForkTimestamp has been set - event DenebForkTimestampUpdated(uint64 denebForkTimestamp); - - /// @notice Emitted to notify the deployment of an EigenPod - event PodDeployed(address indexed eigenPod, address indexed podOwner); - - /// @notice Emitted when the balance of an EigenPod is updated - event PodSharesUpdated(address indexed podOwner, int256 sharesDelta); - - /// @notice Emitted every time the total shares of a pod are updated - event NewTotalShares(address indexed podOwner, int256 newTotalShares); -} diff --git a/src/test/events/IRewardsCoordinatorEvents.sol b/src/test/events/IRewardsCoordinatorEvents.sol deleted file mode 100644 index 72832ae68..000000000 --- a/src/test/events/IRewardsCoordinatorEvents.sol +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IRewardsCoordinator.sol"; - -interface IRewardsCoordinatorEvents { - /// EVENTS /// - - /// @notice emitted when an AVS creates a valid RewardsSubmission - event AVSRewardsSubmissionCreated( - address indexed avs, - uint256 indexed submissionNonce, - bytes32 indexed rewardsSubmissionHash, - IRewardsCoordinator.RewardsSubmission rewardsSubmission - ); - /// @notice emitted when a valid RewardsSubmission is created for all stakers by a valid submitter - event RewardsSubmissionForAllCreated( - address indexed submitter, - uint256 indexed submissionNonce, - bytes32 indexed rewardsSubmissionHash, - IRewardsCoordinator.RewardsSubmission rewardsSubmission - ); - /// @notice emitted when a valid RewardsSubmission is created when rewardAllStakersAndOperators is called - event RewardsSubmissionForAllEarnersCreated( - address indexed tokenHopper, - uint256 indexed submissionNonce, - bytes32 indexed rewardsSubmissionHash, - IRewardsCoordinator.RewardsSubmission rewardsSubmission - ); - /// @notice rewardsUpdater is responsible for submiting DistributionRoots, only owner can set rewardsUpdater - event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater); - event RewardsForAllSubmitterSet( - address indexed rewardsForAllSubmitter, - bool indexed oldValue, - bool indexed newValue - ); - event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay); - event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips); - event ClaimerForSet(address indexed earner, address indexed oldClaimer, address indexed claimer); - /// @notice rootIndex is the specific array index of the newly created root in the storage array - event DistributionRootSubmitted( - uint32 indexed rootIndex, - bytes32 indexed root, - uint32 indexed rewardsCalculationEndTimestamp, - uint32 activatedAt - ); - /// @notice root is one of the submitted distribution roots that was claimed against - event RewardsClaimed( - bytes32 root, - address indexed earner, - address indexed claimer, - address indexed recipient, - IERC20 token, - uint256 claimedAmount - ); - - - - /// TOKEN EVENTS FOR TESTING /// - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} diff --git a/src/test/events/IStrategyManagerEvents.sol b/src/test/events/IStrategyManagerEvents.sol deleted file mode 100644 index e0727d069..000000000 --- a/src/test/events/IStrategyManagerEvents.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IStrategyManager.sol"; - -interface IStrategyManagerEvents { - /** - * @notice Emitted when a new deposit occurs on behalf of `depositor`. - * @param depositor Is the staker who is depositing funds into EigenLayer. - * @param strategy Is the strategy that `depositor` has deposited into. - * @param token Is the token that `depositor` deposited. - * @param shares Is the number of new shares `depositor` has been granted in `strategy`. - */ - event Deposit(address depositor, IERC20 token, IStrategy strategy, uint256 shares); - - /** - * @notice Emitted when a new withdrawal occurs on behalf of `depositor`. - * @param depositor Is the staker who is queuing a withdrawal from EigenLayer. - * @param nonce Is the withdrawal's unique identifier (to the depositor). - * @param strategy Is the strategy that `depositor` has queued to withdraw from. - * @param shares Is the number of shares `depositor` has queued to withdraw. - */ - event ShareWithdrawalQueued(address depositor, uint96 nonce, IStrategy strategy, uint256 shares); - - /** - * @notice Emitted when a new withdrawal is queued by `depositor`. - * @param depositor Is the staker who is withdrawing funds from EigenLayer. - * @param nonce Is the withdrawal's unique identifier (to the depositor). - * @param withdrawer Is the party specified by `staker` who will be able to complete the queued withdrawal and receive the withdrawn funds. - * @param delegatedAddress Is the party who the `staker` was delegated to at the time of creating the queued withdrawal - * @param withdrawalRoot Is a hash of the input data for the withdrawal. - */ - event WithdrawalQueued( - address depositor, - uint96 nonce, - address withdrawer, - address delegatedAddress, - bytes32 withdrawalRoot - ); - - /// @notice Emitted when a queued withdrawal is completed - event WithdrawalCompleted( - address indexed depositor, - uint96 nonce, - address indexed withdrawer, - bytes32 withdrawalRoot - ); - - /// @notice Emitted when `thirdPartyTransfersForbidden` is updated for a strategy and value by the owner - event UpdatedThirdPartyTransfersForbidden(IStrategy strategy, bool value); - - /// @notice Emitted when the `strategyWhitelister` is changed - event StrategyWhitelisterChanged(address previousAddress, address newAddress); - - /// @notice Emitted when a strategy is added to the approved list of strategies for deposit - event StrategyAddedToDepositWhitelist(IStrategy strategy); - - /// @notice Emitted when a strategy is removed from the approved list of strategies for deposit - event StrategyRemovedFromDepositWhitelist(IStrategy strategy); - - /// @notice Emitted when the `withdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. - event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue); -} diff --git a/src/test/harnesses/EigenHarness.sol b/src/test/harnesses/EigenHarness.sol index e5f1ccbbf..b8d11b1bc 100644 --- a/src/test/harnesses/EigenHarness.sol +++ b/src/test/harnesses/EigenHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../contracts/token/Eigen.sol"; diff --git a/src/test/harnesses/EigenPodHarness.sol b/src/test/harnesses/EigenPodHarness.sol index f76e00e1f..0be5e4a54 100644 --- a/src/test/harnesses/EigenPodHarness.sol +++ b/src/test/harnesses/EigenPodHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../contracts/pods/EigenPod.sol"; import "forge-std/Test.sol"; diff --git a/src/test/harnesses/EigenPodManagerWrapper.sol b/src/test/harnesses/EigenPodManagerWrapper.sol index 15eec05fd..9e9db1ce9 100644 --- a/src/test/harnesses/EigenPodManagerWrapper.sol +++ b/src/test/harnesses/EigenPodManagerWrapper.sol @@ -1,24 +1,23 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../contracts/pods/EigenPodManager.sol"; -///@notice This contract exposed the internal `_calculateChangeInDelegatableShares` function for testing +///@notice This contract exposes a manual setter for podShares in order to initialize podShares as negative contract EigenPodManagerWrapper is EigenPodManager { - constructor( IETHPOSDeposit _ethPOS, IBeacon _eigenPodBeacon, IStrategyManager _strategyManager, - ISlasher _slasher, - IDelegationManager _delegationManager - ) EigenPodManager(_ethPOS, _eigenPodBeacon, _strategyManager, _slasher, _delegationManager) {} + IDelegationManager _delegationManager, + IPauserRegistry _pauserRegistry + ) EigenPodManager(_ethPOS, _eigenPodBeacon, _strategyManager, _delegationManager, _pauserRegistry) {} - function calculateChangeInDelegatableShares(int256 sharesBefore, int256 sharesAfter) external pure returns (int256) { - return _calculateChangeInDelegatableShares(sharesBefore, sharesAfter); + function setPodOwnerShares(address owner, IEigenPod pod) external { + ownerToPod[owner] = pod; } - function setPodAddress(address owner, IEigenPod pod) external { - ownerToPod[owner] = pod; + function setPodOwnerShares(address owner, int256 shares) external { + podOwnerDepositShares[owner] = shares; } } diff --git a/src/test/harnesses/PausableHarness.sol b/src/test/harnesses/PausableHarness.sol index 7a0e37fdb..1ed228b2e 100644 --- a/src/test/harnesses/PausableHarness.sol +++ b/src/test/harnesses/PausableHarness.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../contracts/permissions/Pausable.sol"; -// wrapper around the Pausable contract that exposes the internal `_initializePauser` function. +// wrapper around the Pausable contract that exposes the internal `_setPausedStatus` function. contract PausableHarness is Pausable { - function initializePauser(IPauserRegistry _pauserRegistry, uint256 initPausedStatus) external { - _initializePauser(_pauserRegistry, initPausedStatus); + constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) {} + + function initializePauser(uint256 initPausedStatus) external { + _setPausedStatus(initPausedStatus); } } diff --git a/src/test/integration/IntegrationBase.t.sol b/src/test/integration/IntegrationBase.t.sol index dc232a98c..228af0435 100644 --- a/src/test/integration/IntegrationBase.t.sol +++ b/src/test/integration/IntegrationBase.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -7,6 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "src/contracts/libraries/BeaconChainProofs.sol"; +import "src/contracts/libraries/SlashingLib.sol"; import "src/test/integration/IntegrationDeployer.t.sol"; import "src/test/integration/TimeMachine.t.sol"; @@ -14,11 +15,14 @@ import "src/test/integration/users/User.t.sol"; import "src/test/integration/users/User_M1.t.sol"; abstract contract IntegrationBase is IntegrationDeployer { - + using StdStyle for *; + using SlashingLib for *; using Strings for *; + using print for *; uint numStakers = 0; uint numOperators = 0; + uint numAVSs = 0; // Lists of stakers/operators created before the m2 upgrade // @@ -44,13 +48,13 @@ abstract contract IntegrationBase is IntegrationDeployer { uint[] memory tokenBalances; if (forkType == MAINNET && !isUpgraded) { - stakerName = string.concat("M1_Staker", numStakers.toString()); + stakerName = string.concat("M1Staker", cheats.toString(numStakers)); (staker, strategies, tokenBalances) = _randUser(stakerName); stakersToMigrate.push(staker); } else { - stakerName = string.concat("Staker", numStakers.toString()); + stakerName = string.concat("staker", cheats.toString(numStakers)); (staker, strategies, tokenBalances) = _randUser(stakerName); } @@ -73,7 +77,7 @@ abstract contract IntegrationBase is IntegrationDeployer { uint[] memory tokenBalances; if (forkType == MAINNET && !isUpgraded) { - string memory operatorName = string.concat("M1_Operator", numOperators.toString()); + string memory operatorName = string.concat("M1Operator", numOperators.toString()); // Create an operator for M1. We omit native ETH because we want to // check staker/operator shares, and we don't award native ETH shares in M1 @@ -82,11 +86,11 @@ abstract contract IntegrationBase is IntegrationDeployer { User_M1(payable(address(operator))).depositIntoEigenlayer_M1(strategies, tokenBalances); uint[] memory addedShares = _calculateExpectedShares(strategies, tokenBalances); - assert_Snap_Added_StakerShares(operator, strategies, addedShares, "_newRandomOperator: failed to add delegatable shares"); + assert_Snap_Added_Staker_DepositShares(operator, strategies, addedShares, "_newRandomOperator: failed to add delegatable shares"); operatorsToMigrate.push(operator); } else { - string memory operatorName = string.concat("Operator", numOperators.toString()); + string memory operatorName = string.concat("operator", numOperators.toString()); (operator, strategies, tokenBalances) = _randUser_NoETH(operatorName); @@ -95,7 +99,7 @@ abstract contract IntegrationBase is IntegrationDeployer { operator.registerAsOperator(); operator.depositIntoEigenlayer(strategies, tokenBalances); - assert_Snap_Added_StakerShares(operator, strategies, addedShares, "_newRandomOperator: failed to add delegatable shares"); + assert_Snap_Added_Staker_DepositShares(operator, strategies, addedShares, "_newRandomOperator: failed to add delegatable shares"); assert_Snap_Added_OperatorShares(operator, strategies, addedShares, "_newRandomOperator: failed to award shares to operator"); assertTrue(delegationManager.isOperator(address(operator)), "_newRandomOperator: operator should be registered"); } @@ -104,6 +108,13 @@ abstract contract IntegrationBase is IntegrationDeployer { return (operator, strategies, tokenBalances); } + function _newRandomAVS() internal returns (AVS avs, OperatorSet[] memory operatorSets) { + string memory avsName = string.concat("avs", numAVSs.toString()); + avs = _genRandAVS(avsName); + operatorSets = avs.createOperatorSets(_randomStrategies()); + ++numAVSs; + } + /// @dev Send a random amount of ETH (up to 10 gwei) to the destination via `call`, /// triggering its fallback function. Sends a gwei-divisible amount as well as a /// non-gwei-divisible amount. @@ -178,14 +189,20 @@ abstract contract IntegrationBase is IntegrationDeployer { return result; } - + + function _getTokenName(IERC20 token) internal view returns (string memory) { + if (token == NATIVE_ETH) { + return "Native ETH"; + } + return IERC20Metadata(address(token)).name(); + } /******************************************************************************* COMMON ASSERTIONS *******************************************************************************/ - function assert_HasNoDelegatableShares(User user, string memory err) internal { + function assert_HasNoDelegatableShares(User user, string memory err) internal view { (IStrategy[] memory strategies, uint[] memory shares) = - delegationManager.getDelegatableShares(address(user)); + delegationManager.getDepositedShares(address(user)); assertEq(strategies.length, 0, err); assertEq(strategies.length, shares.length, "assert_HasNoDelegatableShares: return length mismatch"); @@ -196,7 +213,7 @@ abstract contract IntegrationBase is IntegrationDeployer { IStrategy[] memory strategies, uint[] memory expectedBalances, string memory err - ) internal { + ) internal view { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; @@ -213,7 +230,7 @@ abstract contract IntegrationBase is IntegrationDeployer { } } - function assert_HasNoUnderlyingTokenBalance(User user, IStrategy[] memory strategies, string memory err) internal { + function assert_HasNoUnderlyingTokenBalance(User user, IStrategy[] memory strategies, string memory err) internal view { assert_HasUnderlyingTokenBalances(user, strategies, new uint[](strategies.length), err); } @@ -222,7 +239,7 @@ abstract contract IntegrationBase is IntegrationDeployer { IStrategy[] memory strategies, uint[] memory expectedShares, string memory err - ) internal { + ) internal view { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; @@ -231,14 +248,14 @@ abstract contract IntegrationBase is IntegrationDeployer { // This method should only be used for tests that handle positive // balances. Negative balances are an edge case that require // the own tests and helper methods. - int shares = eigenPodManager.podOwnerShares(address(user)); + int shares = eigenPodManager.podOwnerDepositShares(address(user)); if (shares < 0) { revert("assert_HasExpectedShares: negative shares"); } actualShares = uint(shares); } else { - actualShares = strategyManager.stakerStrategyShares(address(user), strat); + actualShares = strategyManager.stakerDepositShares(address(user), strat); } assertApproxEqAbs(expectedShares[i], actualShares, 1, err); @@ -250,7 +267,7 @@ abstract contract IntegrationBase is IntegrationDeployer { IStrategy[] memory strategies, uint[] memory expectedShares, string memory err - ) internal { + ) internal view { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; @@ -261,43 +278,43 @@ abstract contract IntegrationBase is IntegrationDeployer { } /// @dev Asserts that ALL of the `withdrawalRoots` is in `delegationManager.pendingWithdrawals` - function assert_AllWithdrawalsPending(bytes32[] memory withdrawalRoots, string memory err) internal { + function assert_AllWithdrawalsPending(bytes32[] memory withdrawalRoots, string memory err) internal view { for (uint i = 0; i < withdrawalRoots.length; i++) { assert_WithdrawalPending(withdrawalRoots[i], err); } } /// @dev Asserts that NONE of the `withdrawalRoots` is in `delegationManager.pendingWithdrawals` - function assert_NoWithdrawalsPending(bytes32[] memory withdrawalRoots, string memory err) internal { + function assert_NoWithdrawalsPending(bytes32[] memory withdrawalRoots, string memory err) internal view { for (uint i = 0; i < withdrawalRoots.length; i++) { assert_WithdrawalNotPending(withdrawalRoots[i], err); } } /// @dev Asserts that the hash of each withdrawal corresponds to the provided withdrawal root - function assert_WithdrawalPending(bytes32 withdrawalRoot, string memory err) internal { + function assert_WithdrawalPending(bytes32 withdrawalRoot, string memory err) internal view { assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), err); } - function assert_WithdrawalNotPending(bytes32 withdrawalRoot, string memory err) internal { + function assert_WithdrawalNotPending(bytes32 withdrawalRoot, string memory err) internal view { assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), err); } function assert_ValidWithdrawalHashes( - IDelegationManager.Withdrawal[] memory withdrawals, + IDelegationManagerTypes.Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots, string memory err - ) internal { + ) internal view { for (uint i = 0; i < withdrawals.length; i++) { assert_ValidWithdrawalHash(withdrawals[i], withdrawalRoots[i], err); } } function assert_ValidWithdrawalHash( - IDelegationManager.Withdrawal memory withdrawal, + IDelegationManagerTypes.Withdrawal memory withdrawal, bytes32 withdrawalRoot, string memory err - ) internal { + ) internal view { assertEq(withdrawalRoot, delegationManager.calculateWithdrawalRoot(withdrawal), err); } @@ -305,7 +322,7 @@ abstract contract IntegrationBase is IntegrationDeployer { User staker, uint expectedBalance, string memory err - ) internal { + ) internal view { EigenPod pod = staker.pod(); assertEq(address(pod).balance, expectedBalance, err); } @@ -313,7 +330,7 @@ abstract contract IntegrationBase is IntegrationDeployer { function assert_ProofsRemainingEqualsActive( User staker, string memory err - ) internal { + ) internal view { EigenPod pod = staker.pod(); assertEq(pod.currentCheckpoint().proofsRemaining, pod.activeValidatorCount(), err); } @@ -322,7 +339,7 @@ abstract contract IntegrationBase is IntegrationDeployer { User staker, uint64 expectedPodBalanceGwei, string memory err - ) internal { + ) internal view { EigenPod pod = staker.pod(); assertEq(pod.currentCheckpoint().podBalanceGwei, expectedPodBalanceGwei, err); } @@ -416,17 +433,17 @@ abstract contract IntegrationBase is IntegrationDeployer { SNAPSHOT ASSERTIONS: STAKER SHARES *******************************************************************************/ - /// @dev Check that the staker has `addedShares` additional delegatable shares + /// @dev Check that the staker has `addedShares` additional deposit shares /// for each strategy since the last snapshot - function assert_Snap_Added_StakerShares( + function assert_Snap_Added_Staker_DepositShares( User staker, IStrategy[] memory strategies, uint[] memory addedShares, string memory err ) internal { - uint[] memory curShares = _getStakerShares(staker, strategies); + uint[] memory curShares = _getStakerDepositShares(staker, strategies); // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerShares(staker, strategies); + uint[] memory prevShares = _getPrevStakerDepositShares(staker, strategies); // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { @@ -434,7 +451,7 @@ abstract contract IntegrationBase is IntegrationDeployer { } } - function assert_Snap_Added_StakerShares( + function assert_Snap_Added_Staker_DepositShares( User staker, IStrategy strat, uint _addedShares, @@ -445,20 +462,51 @@ abstract contract IntegrationBase is IntegrationDeployer { strategies[0] = strat; addedShares[0] = _addedShares; - assert_Snap_Added_StakerShares(staker, strategies, addedShares, err); + assert_Snap_Added_Staker_DepositShares(staker, strategies, addedShares, err); } /// @dev Check that the staker has `removedShares` fewer delegatable shares /// for each strategy since the last snapshot - function assert_Snap_Removed_StakerShares( + function assert_Snap_Removed_StakerDepositShares( + User staker, + IStrategy[] memory strategies, + uint[] memory removedShares, + string memory err + ) internal { + uint[] memory curShares = _getStakerDepositShares(staker, strategies); + // Use timewarp to get previous staker shares + uint[] memory prevShares = _getPrevStakerDepositShares(staker, strategies); + + // For each strategy, check (prev - removed == cur) + for (uint i = 0; i < strategies.length; i++) { + assertEq(prevShares[i] - removedShares[i], curShares[i], err); + } + } + + function assert_Snap_Removed_StakerDepositShares( + User staker, + IStrategy strat, + uint _removedShares, + string memory err + ) internal { + IStrategy[] memory strategies = new IStrategy[](1); + uint[] memory removedShares = new uint[](1); + strategies[0] = strat; + removedShares[0] = _removedShares; + + assert_Snap_Removed_StakerDepositShares(staker, strategies, removedShares, err); + } + + /// @dev Check that the staker's withdrawable shares have decreased by `removedShares` + function assert_Snap_Removed_StakerWithdrawableShares( User staker, IStrategy[] memory strategies, uint[] memory removedShares, string memory err ) internal { - uint[] memory curShares = _getStakerShares(staker, strategies); + uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerShares(staker, strategies); + uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); // For each strategy, check (prev - removed == cur) for (uint i = 0; i < strategies.length; i++) { @@ -466,7 +514,7 @@ abstract contract IntegrationBase is IntegrationDeployer { } } - function assert_Snap_Removed_StakerShares( + function assert_Snap_Removed_StakerWithdrawableShares( User staker, IStrategy strat, uint _removedShares, @@ -477,20 +525,52 @@ abstract contract IntegrationBase is IntegrationDeployer { strategies[0] = strat; removedShares[0] = _removedShares; - assert_Snap_Removed_StakerShares(staker, strategies, removedShares, err); + assert_Snap_Removed_StakerWithdrawableShares(staker, strategies, removedShares, err); + } + + /// @dev Check that the staker's withdrawable shares have decreased by at least `removedShares` + /// @dev Used to handle overslashing of beacon chain + function assert_Snap_Removed_Staker_WithdrawableShares_AtLeast( + User staker, + IStrategy[] memory strategies, + uint[] memory removedShares, + string memory err + ) internal { + uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); + // Use timewarp to get previous staker shares + uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); + + // For each strategy, check diff between (prev-removed) and curr is at most 1 gwei + for (uint i = 0; i < strategies.length; i++) { + assertApproxEqAbs(prevShares[i] - removedShares[i], curShares[i], 1e9, err); + } + } + + function assert_Snap_Removed_Staker_WithdrawableShares_AtLeast( + User staker, + IStrategy strat, + uint removedShares, + string memory err + ) internal { + IStrategy[] memory strategies = new IStrategy[](1); + uint[] memory removedSharesArr = new uint[](1); + strategies[0] = strat; + removedSharesArr[0] = removedShares; + + assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, strategies, removedSharesArr, err); } /// @dev Check that the staker's delegatable shares in ALL strategies have not changed /// since the last snapshot - function assert_Snap_Unchanged_StakerShares( + function assert_Snap_Unchanged_StakerDepositShares( User staker, string memory err ) internal { IStrategy[] memory strategies = allStrats; - uint[] memory curShares = _getStakerShares(staker, strategies); + uint[] memory curShares = _getStakerDepositShares(staker, strategies); // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerShares(staker, strategies); + uint[] memory prevShares = _getPrevStakerDepositShares(staker, strategies); // For each strategy, check (prev == cur) for (uint i = 0; i < strategies.length; i++) { @@ -504,9 +584,9 @@ abstract contract IntegrationBase is IntegrationDeployer { int[] memory shareDeltas, string memory err ) internal { - int[] memory curShares = _getStakerSharesInt(staker, strategies); + int[] memory curShares = _getStakerDepositSharesInt(staker, strategies); // Use timewarp to get previous staker shares - int[] memory prevShares = _getPrevStakerSharesInt(staker, strategies); + int[] memory prevShares = _getPrevStakerDepositSharesInt(staker, strategies); // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { @@ -626,7 +706,7 @@ abstract contract IntegrationBase is IntegrationDeployer { function assert_Snap_Added_QueuedWithdrawals( User staker, - IDelegationManager.Withdrawal[] memory withdrawals, + IDelegationManagerTypes.Withdrawal[] memory withdrawals, string memory err ) internal { uint curQueuedWithdrawals = _getCumulativeWithdrawals(staker); @@ -638,7 +718,7 @@ abstract contract IntegrationBase is IntegrationDeployer { function assert_Snap_Added_QueuedWithdrawal( User staker, - IDelegationManager.Withdrawal memory /*withdrawal*/, + IDelegationManagerTypes.Withdrawal memory /*withdrawal*/, string memory err ) internal { uint curQueuedWithdrawal = _getCumulativeWithdrawals(staker); @@ -691,12 +771,12 @@ abstract contract IntegrationBase is IntegrationDeployer { ) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(addedValidators); - IEigenPod.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); - IEigenPod.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); for (uint i = 0; i < curStatuses.length; i++) { - assertTrue(prevStatuses[i] == IEigenPod.VALIDATOR_STATUS.INACTIVE, err); - assertTrue(curStatuses[i] == IEigenPod.VALIDATOR_STATUS.ACTIVE, err); + assertTrue(prevStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.INACTIVE, err); + assertTrue(curStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.ACTIVE, err); } } @@ -707,12 +787,12 @@ abstract contract IntegrationBase is IntegrationDeployer { ) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(exitedValidators); - IEigenPod.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); - IEigenPod.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); for (uint i = 0; i < curStatuses.length; i++) { - assertTrue(prevStatuses[i] == IEigenPod.VALIDATOR_STATUS.ACTIVE, err); - assertTrue(curStatuses[i] == IEigenPod.VALIDATOR_STATUS.WITHDRAWN, err); + assertTrue(prevStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.ACTIVE, err); + assertTrue(curStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.WITHDRAWN, err); } } @@ -806,6 +886,27 @@ abstract contract IntegrationBase is IntegrationDeployer { /******************************************************************************* UTILITY METHODS *******************************************************************************/ + + function _randWadToSlash() internal returns (uint) { + return _randUint({ min: 0.01 ether, max: 1 ether }); + } + + function _randMagnitudes(uint64 sum, uint256 len) internal returns (uint64[] memory magnitudes) { + magnitudes = new uint64[](len); + + if (sum == 0 || len == 0) return magnitudes; + + uint64 remaining = sum; + + for (uint256 i; i < len; ++i) { + if (i == len - 1) { + magnitudes[i] = remaining; + } else { + magnitudes[i] = uint64(_randUint(0, remaining / (len - i))); + remaining -= magnitudes[i]; + } + } + } function _randWithdrawal( IStrategy[] memory strategies, @@ -898,7 +999,7 @@ abstract contract IntegrationBase is IntegrationDeployer { } function _calcNativeETHOperatorShareDelta(User staker, int shareDelta) internal view returns (int) { - int curPodOwnerShares = eigenPodManager.podOwnerShares(address(staker)); + int curPodOwnerShares = eigenPodManager.podOwnerDepositShares(address(staker)); int newPodOwnerShares = curPodOwnerShares + shareDelta; if (curPodOwnerShares <= 0) { @@ -959,7 +1060,7 @@ abstract contract IntegrationBase is IntegrationDeployer { } function _getWithdrawalHashes( - IDelegationManager.Withdrawal[] memory withdrawals + IDelegationManagerTypes.Withdrawal[] memory withdrawals ) internal view returns (bytes32[] memory) { bytes32[] memory withdrawalRoots = new bytes32[](withdrawals.length); @@ -993,17 +1094,11 @@ abstract contract IntegrationBase is IntegrationDeployer { timeMachine.warpToPresent(curState); } + // TODO /// @dev Given a list of strategies, roll the block number forward to the /// a valid blocknumber to completeWithdrawals - function _rollBlocksForCompleteWithdrawals(IStrategy[] memory strategies) internal { - // uint256 blocksToRoll = delegationManager.minWithdrawalDelayBlocks(); - // for (uint i = 0; i < strategies.length; i++) { - // uint256 withdrawalDelayBlocks = delegationManager.strategyWithdrawalDelayBlocks(strategies[i]); - // if (withdrawalDelayBlocks > blocksToRoll) { - // blocksToRoll = withdrawalDelayBlocks; - // } - // } - cheats.roll(block.number + delegationManager.getWithdrawalDelay(strategies)); + function _rollBlocksForCompleteWithdrawals() internal { + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); } /// @dev Uses timewarp modifier to get operator shares at the last snapshot @@ -1026,15 +1121,15 @@ abstract contract IntegrationBase is IntegrationDeployer { } /// @dev Uses timewarp modifier to get staker shares at the last snapshot - function _getPrevStakerShares( + function _getPrevStakerDepositShares( User staker, IStrategy[] memory strategies ) internal timewarp() returns (uint[] memory) { - return _getStakerShares(staker, strategies); + return _getStakerDepositShares(staker, strategies); } /// @dev Looks up each strategy and returns a list of the staker's shares - function _getStakerShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { + function _getStakerDepositShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { uint[] memory curShares = new uint[](strategies.length); for (uint i = 0; i < strategies.length; i++) { @@ -1044,14 +1139,14 @@ abstract contract IntegrationBase is IntegrationDeployer { // This method should only be used for tests that handle positive // balances. Negative balances are an edge case that require // the own tests and helper methods. - int shares = eigenPodManager.podOwnerShares(address(staker)); + int shares = eigenPodManager.podOwnerDepositShares(address(staker)); if (shares < 0) { - revert("_getStakerShares: negative shares"); + revert("_getStakerDepositShares: negative shares"); } curShares[i] = uint(shares); } else { - curShares[i] = strategyManager.stakerStrategyShares(address(staker), strat); + curShares[i] = strategyManager.stakerDepositShares(address(staker), strat); } } @@ -1059,30 +1154,49 @@ abstract contract IntegrationBase is IntegrationDeployer { } /// @dev Uses timewarp modifier to get staker shares at the last snapshot - function _getPrevStakerSharesInt( + function _getPrevStakerDepositSharesInt( User staker, IStrategy[] memory strategies ) internal timewarp() returns (int[] memory) { - return _getStakerSharesInt(staker, strategies); + return _getStakerDepositSharesInt(staker, strategies); } /// @dev Looks up each strategy and returns a list of the staker's shares - function _getStakerSharesInt(User staker, IStrategy[] memory strategies) internal view returns (int[] memory) { + function _getStakerDepositSharesInt(User staker, IStrategy[] memory strategies) internal view returns (int[] memory) { int[] memory curShares = new int[](strategies.length); for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; if (strat == BEACONCHAIN_ETH_STRAT) { - curShares[i] = eigenPodManager.podOwnerShares(address(staker)); + curShares[i] = eigenPodManager.podOwnerDepositShares(address(staker)); } else { - curShares[i] = int(strategyManager.stakerStrategyShares(address(staker), strat)); + curShares[i] = int(strategyManager.stakerDepositShares(address(staker), strat)); } } return curShares; } + function _getPrevStakerWithdrawableShares(User staker, IStrategy[] memory strategies) internal timewarp() returns (uint[] memory) { + return _getStakerWithdrawableShares(staker, strategies); + } + + function _getStakerWithdrawableShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(address(staker), strategies); + return withdrawableShares; + } + + /// @dev Uses timewarp modifier to get staker beacon chain scaling factor at the last snapshot + function _getPrevBeaconChainSlashingFactor(User staker) internal timewarp() returns (uint64) { + return _getBeaconChainSlashingFactor(staker); + } + + /// @dev Looks up the staker's beacon chain scaling factor + function _getBeaconChainSlashingFactor(User staker) internal view returns (uint64) { + return eigenPodManager.beaconChainSlashingFactor(address(staker)); + } + function _getPrevCumulativeWithdrawals(User staker) internal timewarp() returns (uint) { return _getCumulativeWithdrawals(staker); } @@ -1097,7 +1211,7 @@ abstract contract IntegrationBase is IntegrationDeployer { function _getTokenBalances(User staker, IERC20[] memory tokens) internal view returns (uint[] memory) { uint[] memory balances = new uint[](tokens.length); - + for (uint i = 0; i < tokens.length; i++) { if (tokens[i] == NATIVE_ETH) { balances[i] = address(staker).balance; @@ -1135,9 +1249,9 @@ abstract contract IntegrationBase is IntegrationDeployer { return _getActiveValidatorCount(staker); } - function _getValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal view returns (IEigenPod.VALIDATOR_STATUS[] memory) { + function _getValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal view returns (IEigenPodTypes.VALIDATOR_STATUS[] memory) { EigenPod pod = staker.pod(); - IEigenPod.VALIDATOR_STATUS[] memory statuses = new IEigenPod.VALIDATOR_STATUS[](pubkeyHashes.length); + IEigenPodTypes.VALIDATOR_STATUS[] memory statuses = new IEigenPodTypes.VALIDATOR_STATUS[](pubkeyHashes.length); for (uint i = 0; i < statuses.length; i++) { statuses[i] = pod.validatorStatus(pubkeyHashes[i]); @@ -1146,7 +1260,7 @@ abstract contract IntegrationBase is IntegrationDeployer { return statuses; } - function _getPrevValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal timewarp() returns (IEigenPod.VALIDATOR_STATUS[] memory) { + function _getPrevValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal timewarp() returns (IEigenPodTypes.VALIDATOR_STATUS[] memory) { return _getValidatorStatuses(staker, pubkeyHashes); } diff --git a/src/test/integration/IntegrationChecks.t.sol b/src/test/integration/IntegrationChecks.t.sol index 2fc360581..ffe014d78 100644 --- a/src/test/integration/IntegrationChecks.t.sol +++ b/src/test/integration/IntegrationChecks.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationBase.t.sol"; import "src/test/integration/users/User.t.sol"; @@ -18,7 +18,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint64 beaconBalanceGwei ) internal { uint beaconBalanceWei = beaconBalanceGwei * GWEI_TO_WEI; - assert_Snap_Added_StakerShares(staker, BEACONCHAIN_ETH_STRAT, beaconBalanceWei, "staker should have added shares to beacon chain strat"); + assert_Snap_Added_Staker_DepositShares(staker, BEACONCHAIN_ETH_STRAT, beaconBalanceWei, "staker should have added deposit shares to beacon chain strat"); assert_Snap_Added_ActiveValidatorCount(staker, validators.length, "staker should have increased active validator count"); assert_Snap_Added_ActiveValidators(staker, validators, "validators should each be active"); } @@ -43,7 +43,7 @@ contract IntegrationCheckUtils is IntegrationBase { User staker, uint64 sharesAddedGwei ) internal { - assert_Snap_Added_StakerShares(staker, BEACONCHAIN_ETH_STRAT, sharesAddedGwei * GWEI_TO_WEI, "should have added staker shares"); + assert_Snap_Added_Staker_DepositShares(staker, BEACONCHAIN_ETH_STRAT, sharesAddedGwei * GWEI_TO_WEI, "should have added staker shares"); assert_Snap_Added_WithdrawableGwei(staker, sharesAddedGwei, "should have added to withdrawable restaked gwei"); assert_Snap_Unchanged_ActiveValidatorCount(staker, "active validator count should remain 0"); @@ -66,7 +66,7 @@ contract IntegrationCheckUtils is IntegrationBase { check_CompleteCheckpoint_State(staker); uint balanceAddedWei = beaconBalanceAdded * GWEI_TO_WEI; - assert_Snap_Added_StakerShares(staker, BEACONCHAIN_ETH_STRAT, balanceAddedWei, "should have increased shares by excess beacon balance"); + assert_Snap_Added_Staker_DepositShares(staker, BEACONCHAIN_ETH_STRAT, balanceAddedWei, "should have increased shares by excess beacon balance"); } function check_CompleteCheckpoint_WithPodBalance_State( @@ -85,18 +85,44 @@ contract IntegrationCheckUtils is IntegrationBase { ) internal { check_CompleteCheckpoint_State(staker); - assert_Snap_Removed_StakerShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have reduced shares by slashed amount"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have decreased"); + assert_Snap_Removed_StakerWithdrawableShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by slashed amount"); assert_Snap_Removed_ActiveValidatorCount(staker, slashedValidators.length, "should have decreased active validator count"); assert_Snap_Removed_ActiveValidators(staker, slashedValidators, "exited validators should each be WITHDRAWN"); } + function check_CompleteCheckpoint_WithSlashing_HandleRoundDown_State( + User staker, + uint40[] memory slashedValidators, + uint64 slashedAmountGwei + ) internal { + check_CompleteCheckpoint_State(staker); + + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have decreased"); + assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by at least slashed amount"); + assert_Snap_Removed_ActiveValidatorCount(staker, slashedValidators.length, "should have decreased active validator count"); + assert_Snap_Removed_ActiveValidators(staker, slashedValidators, "exited validators should each be WITHDRAWN"); + } + + function check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State( + User staker, + uint64 slashedAmountGwei + ) internal { + check_CompleteCheckpoint_State(staker); + + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have decreased"); + assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by at least slashed amount"); + assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); + } + function check_CompleteCheckpoint_WithCLSlashing_State( User staker, uint64 slashedAmountGwei ) internal { check_CompleteCheckpoint_State(staker); - assert_Snap_Removed_StakerShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have reduced shares by slashed amount"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have decreased"); + assert_Snap_Removed_StakerWithdrawableShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by slashed amount"); assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); } @@ -107,7 +133,7 @@ contract IntegrationCheckUtils is IntegrationBase { ) internal { check_CompleteCheckpoint_WithPodBalance_State(staker, exitedBalanceGwei); - assert_Snap_Unchanged_StakerShares(staker, "staker should not have changed shares"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker should not have changed shares"); assert_Snap_Added_BalanceExitedGwei(staker, exitedBalanceGwei, "should have attributed expected gwei to exited balance"); assert_Snap_Removed_ActiveValidatorCount(staker, exitedValidators.length, "should have decreased active validator count"); assert_Snap_Removed_ActiveValidators(staker, exitedValidators, "exited validators should each be WITHDRAWN"); @@ -129,7 +155,7 @@ contract IntegrationCheckUtils is IntegrationBase { // ... check that all underlying tokens were transferred to the correct destination // and that the staker now has the expected amount of delegated shares in each strategy assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker should have transferred all underlying tokens"); - assert_Snap_Added_StakerShares(staker, strategies, shares, "staker should expect shares in each strategy after depositing"); + assert_Snap_Added_Staker_DepositShares(staker, strategies, shares, "staker should expect shares in each strategy after depositing"); } @@ -141,7 +167,7 @@ contract IntegrationCheckUtils is IntegrationBase { // ... check that some underlying tokens were transferred to the correct destination // and that the staker now has the expected amount of delegated shares in each strategy assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should have transferred some underlying tokens"); - assert_Snap_Added_StakerShares(staker, strategies, shares, "staker should expected shares in each strategy after depositing"); + assert_Snap_Added_Staker_DepositShares(staker, strategies, shares, "staker should expected shares in each strategy after depositing"); } function check_Delegation_State( @@ -157,7 +183,7 @@ contract IntegrationCheckUtils is IntegrationBase { assertTrue(delegationManager.isDelegated(address(staker)), "staker should be delegated"); assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should be delegated to operator"); assert_HasExpectedShares(staker, strategies, shares, "staker should still have expected shares after delegating"); - assert_Snap_Unchanged_StakerShares(staker, "staker shares should be unchanged after delegating"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should be unchanged after delegating"); assert_Snap_Added_OperatorShares(operator, strategies, shares, "operator should have received shares"); } @@ -166,7 +192,7 @@ contract IntegrationCheckUtils is IntegrationBase { User operator, IStrategy[] memory strategies, uint[] memory shares, - IDelegationManager.Withdrawal[] memory withdrawals, + IDelegationManagerTypes.Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots ) internal { // The staker will queue one or more withdrawals for the selected strategies and shares @@ -183,14 +209,14 @@ contract IntegrationCheckUtils is IntegrationBase { "check_QueuedWithdrawal_State: staker should have increased nonce by withdrawals.length"); assert_Snap_Removed_OperatorShares(operator, strategies, shares, "check_QueuedWithdrawal_State: failed to remove operator shares"); - assert_Snap_Removed_StakerShares(staker, strategies, shares, + assert_Snap_Removed_StakerDepositShares(staker, strategies, shares, "check_QueuedWithdrawal_State: failed to remove staker shares"); } function check_Undelegate_State( User staker, User operator, - IDelegationManager.Withdrawal[] memory withdrawals, + IDelegationManagerTypes.Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots, IStrategy[] memory strategies, uint[] memory shares @@ -210,7 +236,7 @@ contract IntegrationCheckUtils is IntegrationBase { "check_Undelegate_State: staker should have increased nonce by withdrawals.length"); assert_Snap_Removed_OperatorShares(operator, strategies, shares, "check_Undelegate_State: failed to remove operator shares"); - assert_Snap_Removed_StakerShares(staker, strategies, shares, + assert_Snap_Removed_StakerDepositShares(staker, strategies, shares, "check_Undelegate_State: failed to remove staker shares"); } @@ -227,7 +253,7 @@ contract IntegrationCheckUtils is IntegrationBase { function check_Withdrawal_AsTokens_State( User staker, User operator, - IDelegationManager.Withdrawal memory withdrawal, + IDelegationManagerTypes.Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory shares, IERC20[] memory tokens, @@ -235,8 +261,9 @@ contract IntegrationCheckUtils is IntegrationBase { ) internal { // Common checks assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens"); - assert_Snap_Unchanged_StakerShares(staker, "staker shares should not have changed"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have changed"); assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented"); // Checks specific to an operator that the Staker has delegated to @@ -251,14 +278,14 @@ contract IntegrationCheckUtils is IntegrationBase { function check_Withdrawal_AsShares_State( User staker, User operator, - IDelegationManager.Withdrawal memory withdrawal, + IDelegationManagerTypes.Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory shares ) internal { // Common checks applicable to both user and non-user operator types assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); assert_Snap_Unchanged_TokenBalances(staker, "staker should not have any change in underlying token balances"); - assert_Snap_Added_StakerShares(staker, strategies, shares, "staker should have received expected shares"); + assert_Snap_Added_Staker_DepositShares(staker, strategies, shares, "staker should have received expected shares"); assert_Snap_Unchanged_StrategyShares(strategies, "strategies should have total shares unchanged"); // Additional checks or handling for the non-user operator scenario @@ -266,7 +293,7 @@ contract IntegrationCheckUtils is IntegrationBase { if (operator != staker) { assert_Snap_Unchanged_TokenBalances(User(operator), "operator should not have any change in underlying token balances"); } - assert_Snap_Added_OperatorShares(User(operator), withdrawal.strategies, withdrawal.shares, "operator should have received shares"); + assert_Snap_Added_OperatorShares(User(operator), withdrawal.strategies, withdrawal.scaledShares, "operator should have received shares"); } } @@ -274,7 +301,7 @@ contract IntegrationCheckUtils is IntegrationBase { function check_Withdrawal_AsShares_Undelegated_State( User staker, User operator, - IDelegationManager.Withdrawal memory withdrawal, + IDelegationManagerTypes.Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory shares ) internal { @@ -287,7 +314,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); assert_Snap_Unchanged_TokenBalances(staker, "staker should not have any change in underlying token balances"); assert_Snap_Unchanged_TokenBalances(operator, "operator should not have any change in underlying token balances"); - assert_Snap_Added_StakerShares(staker, strategies, shares, "staker should have received expected shares"); + assert_Snap_Added_Staker_DepositShares(staker, strategies, shares, "staker should have received expected shares"); assert_Snap_Unchanged_OperatorShares(operator, "operator should have shares unchanged"); assert_Snap_Unchanged_StrategyShares(strategies, "strategies should have total shares unchanged"); } diff --git a/src/test/integration/IntegrationDeployer.t.sol b/src/test/integration/IntegrationDeployer.t.sol index b870a86d2..2b97b3f91 100644 --- a/src/test/integration/IntegrationDeployer.t.sol +++ b/src/test/integration/IntegrationDeployer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; // Imports import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; @@ -11,39 +11,54 @@ import "forge-std/Test.sol"; import "src/contracts/core/DelegationManager.sol"; import "src/contracts/core/StrategyManager.sol"; -import "src/contracts/core/Slasher.sol"; import "src/contracts/strategies/StrategyFactory.sol"; import "src/contracts/strategies/StrategyBase.sol"; import "src/contracts/strategies/StrategyBaseTVLLimits.sol"; import "src/contracts/pods/EigenPodManager.sol"; import "src/contracts/pods/EigenPod.sol"; import "src/contracts/permissions/PauserRegistry.sol"; +import "src/contracts/permissions/PermissionController.sol"; +import "src/test/utils/Logger.t.sol"; import "src/test/mocks/EmptyContract.sol"; import "src/test/mocks/ETHDepositMock.sol"; import "src/test/integration/mocks/BeaconChainMock.t.sol"; +import "src/test/integration/users/AVS.t.sol"; import "src/test/integration/users/User.t.sol"; import "src/test/integration/users/User_M1.t.sol"; import "script/utils/ExistingDeploymentParser.sol"; -abstract contract IntegrationDeployer is ExistingDeploymentParser { - - Vm cheats = Vm(VM_ADDRESS); +// DelegationManager +uint8 constant PAUSED_NEW_DELEGATION = 0; +uint8 constant PAUSED_ENTER_WITHDRAWAL_QUEUE = 1; +uint8 constant PAUSED_EXIT_WITHDRAWAL_QUEUE = 2; +// StrategyManager +uint8 constant PAUSED_DEPOSITS = 0; +// EigenpodManager +uint8 constant PAUSED_NEW_EIGENPODS = 0; +uint8 constant PAUSED_WITHDRAW_RESTAKED_ETH = 1; +uint8 constant PAUSED_EIGENPODS_VERIFY_CREDENTIALS = 2; +uint8 constant PAUSED_EIGENPODS_VERIFY_BALANCE_UPDATE = 3; +uint8 constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4; +uint8 constant PAUSED_NON_PROOF_WITHDRAWALS = 5; + +abstract contract IntegrationDeployer is ExistingDeploymentParser, Logger { + using StdStyle for *; // Fork ids for specific fork tests bool isUpgraded; - uint256 mainnetForkBlock = 19_280_000; - uint256 mainnetForkId; - uint256 holeskyForkBLock = 1_213_950; - uint256 holeskyForkId; - uint64 constant DENEB_FORK_TIMESTAMP = 1705473120; + uint mainnetForkBlock = 19_280_000; + uint mainnetForkId; + uint holeskyForkBLock = 1_213_950; + uint holeskyForkId; + uint64 constant DENEB_FORK_TIMESTAMP = 1_705_473_120; // Beacon chain genesis time when running locally // Multiple of 12 for sanity's sake uint64 constant GENESIS_TIME_LOCAL = 1 hours * 12; - uint64 constant GENESIS_TIME_MAINNET = 1606824023; + uint64 constant GENESIS_TIME_MAINNET = 1_606_824_023; TimeMachine public timeMachine; @@ -52,7 +67,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // When we select random user assets, we use the `assetType` to determine // which of these lists to select user assets from. IStrategy[] lstStrats; - IStrategy[] ethStrats; // only has one strat tbh + IStrategy[] ethStrats; // only has one strat tbh IStrategy[] allStrats; // just a combination of the above 2 lists IERC20[] allTokens; // `allStrats`, but contains all of the underlying tokens instead @@ -67,7 +82,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { address eigenLayerReputedMultisig = address(this); // admin address address constant pauser = address(555); address constant unpauser = address(556); - + // Randomness state vars bytes32 random; // After calling `_configRand`, these are the allowed "variants" on users that will @@ -80,85 +95,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // Constants uint64 constant MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32e9; - IStrategy constant BEACONCHAIN_ETH_STRAT = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - IERC20 constant NATIVE_ETH = IERC20(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - - uint constant MIN_BALANCE = 1e6; - uint constant MAX_BALANCE = 5e6; - uint constant GWEI_TO_WEI = 1e9; - - // Paused Constants - // DelegationManager - uint8 internal constant PAUSED_NEW_DELEGATION = 0; - uint8 internal constant PAUSED_ENTER_WITHDRAWAL_QUEUE = 1; - uint8 internal constant PAUSED_EXIT_WITHDRAWAL_QUEUE = 2; - // StrategyManager - uint8 internal constant PAUSED_DEPOSITS = 0; - // EigenpodManager - uint8 internal constant PAUSED_NEW_EIGENPODS = 0; - uint8 internal constant PAUSED_WITHDRAW_RESTAKED_ETH = 1; - uint8 internal constant PAUSED_EIGENPODS_VERIFY_CREDENTIALS = 2; - uint8 internal constant PAUSED_EIGENPODS_VERIFY_BALANCE_UPDATE = 3; - uint8 internal constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4; - uint8 internal constant PAUSED_NON_PROOF_WITHDRAWALS = 5; - - // Flags - uint constant FLAG = 1; - - /// @dev Asset flags - /// These are used with _configRand to determine what assets are given - /// to a user when they are created. - uint constant NO_ASSETS = (FLAG << 0); // will have no assets - uint constant HOLDS_LST = (FLAG << 1); // will hold some random amount of LSTs - uint constant HOLDS_ETH = (FLAG << 2); // will hold some random amount of ETH - uint constant HOLDS_ALL = (FLAG << 3); // will hold every LST and ETH - - /// @dev User contract flags - /// These are used with _configRand to determine what User contracts can be deployed - uint constant DEFAULT = (FLAG << 0); - uint constant ALT_METHODS = (FLAG << 1); - - /// @dev Shadow Fork flags - /// These are used for upgrade integration testing. - uint constant LOCAL = (FLAG << 0); - uint constant MAINNET = (FLAG << 1); - uint constant HOLESKY = (FLAG << 2); - - // /// @dev Withdrawal flags - // /// These are used with _configRand to determine how a user conducts a withdrawal - // uint constant FULL_WITHDRAW_SINGLE = (FLAG << 0); // stakers will withdraw all assets using a single queued withdrawal - // uint constant FULL_WITHDRAW_MULTI = (FLAG << 1); // stakers will withdraw all assets using multiple queued withdrawals - // uint constant PART_WITHDRAW_SINGLE = (FLAG << 2); // stakers will withdraw some, but not all assets - - /// Note: Thought about the following flags (but did not implement) - - /// - /// WithdrawerType (SELF_WITHDRAWER, OTHER_WITHDRAWER) - /// - especially with EPM share handling, this felt like it deserved its own test rather than a fuzzy state - /// CompletionType (AS_TOKENS, AS_SHARES) - /// - same reason as above - /// - /// WithdrawalMethod (QUEUE_WITHDRAWAL, UNDELEGATE, REDELEGATE) - /// - could still do this! - /// - This would trigger staker.queueWithdrawals to use either `queueWithdrawals` or `undelegate` under the hood - /// - "redelegate" would be like the above, but adding a new `delegateTo` step after undelegating - - mapping(uint => string) assetTypeToStr; - mapping(uint => string) userTypeToStr; - mapping(uint => string) forkTypeToStr; - - constructor () { - assetTypeToStr[NO_ASSETS] = "NO_ASSETS"; - assetTypeToStr[HOLDS_LST] = "HOLDS_LST"; - assetTypeToStr[HOLDS_ETH] = "HOLDS_ETH"; - assetTypeToStr[HOLDS_ALL] = "HOLDS_ALL"; - - userTypeToStr[DEFAULT] = "DEFAULT"; - userTypeToStr[ALT_METHODS] = "ALT_METHODS"; - - forkTypeToStr[LOCAL] = "LOCAL"; - forkTypeToStr[MAINNET] = "MAINNET"; - forkTypeToStr[HOLESKY] = "HOLESKY"; - + constructor() { address stETH_Holesky = 0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034; address stETH_Mainnet = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; address OETH_Mainnet = 0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3; @@ -173,10 +110,14 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { tokensNotTested[cbETH_Holesky] = true; } + function NAME() public view virtual override returns (string memory) { + return "Integration Deployer"; + } + /** * @dev Anyone who wants to test using this contract in a separate repo via submodules may have to * override this function to set the correct paths for the deployment info files. - * + * * This setUp function will account for specific --fork-url flags and deploy/upgrade contracts accordingly. * Note that forkIds are also created so you can make explicit fork tests using cheats.selectFork(forkId) */ @@ -189,19 +130,17 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { * Running foundry like this will trigger the fork test profile, * lowering fuzz runs and using a remote RPC to test against mainnet state */ - bool forkMainnet = - _hash("forktest") == - _hash(cheats.envOr(string("FOUNDRY_PROFILE"), string("default"))); + bool forkMainnet = _hash("forktest") == _hash(cheats.envOr(string("FOUNDRY_PROFILE"), string("default"))); if (forkMainnet) { - emit log("setUp: running tests against mainnet fork"); - emit log_named_string("- using RPC url", cheats.rpcUrl("mainnet")); - emit log_named_uint("- forking at block", mainnetForkBlock); + console.log("Setting up `%s` integration tests:", "MAINNET_FORK".green().bold()); + console.log("RPC:", cheats.rpcUrl("mainnet")); + console.log("Block:", mainnetForkBlock); cheats.createSelectFork(cheats.rpcUrl("mainnet"), mainnetForkBlock); forkType = MAINNET; } else { - emit log("setUp: running tests locally"); + console.log("Setting up `%s` integration tests:", "LOCAL".yellow().bold()); forkType = LOCAL; } @@ -233,9 +172,6 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { strategyManager = StrategyManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); eigenPodManager = EigenPodManager( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); @@ -245,130 +181,132 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { strategyFactory = StrategyFactory( address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) ); + allocationManager = AllocationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + permissionController = PermissionController( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); // Deploy EigenPod Contracts - eigenPodImplementation = new EigenPod( - ethPOSDeposit, - eigenPodManager, - GENESIS_TIME_LOCAL - ); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GENESIS_TIME_LOCAL); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); + delegationManagerImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); - avsDirectoryImplementation = new AVSDirectory(delegationManager); - strategyFactoryImplementation = new StrategyFactory(strategyManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); + eigenPodManagerImplementation = + new EigenPodManager(ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); + strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg); + allocationManagerImplementation = new AllocationManager(delegationManager, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY); + permissionControllerImplementation = new PermissionController(); // Third, upgrade the proxy contracts to point to the implementations - uint256 withdrawalDelayBlocks = 7 days / 12 seconds; - IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); - uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); // DelegationManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegationManager))), + ITransparentUpgradeableProxy(payable(address(delegationManager))), address(delegationManagerImplementation), abi.encodeWithSelector( DelegationManager.initialize.selector, eigenLayerReputedMultisig, // initialOwner - eigenLayerPauserReg, - 0 /* initialPausedStatus */, - withdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks + 0 /* initialPausedStatus */ ) ); // StrategyManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), + ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation), abi.encodeWithSelector( StrategyManager.initialize.selector, eigenLayerReputedMultisig, //initialOwner eigenLayerReputedMultisig, //initial whitelister - eigenLayerPauserReg, - 0 // initialPausedStatus - ) - ); - // Slasher - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - eigenLayerReputedMultisig, - eigenLayerPauserReg, 0 // initialPausedStatus ) ); // EigenPodManager eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, eigenLayerReputedMultisig, // initialOwner - eigenLayerPauserReg, 0 // initialPausedStatus ) ); // AVSDirectory eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), + ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation), abi.encodeWithSelector( AVSDirectory.initialize.selector, eigenLayerReputedMultisig, // initialOwner - eigenLayerPauserReg, 0 // initialPausedStatus ) ); + // AllocationManager + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), + abi.encodeWithSelector( + AllocationManager.initialize.selector, + eigenLayerReputedMultisig, // initialOwner + 0 // initialPausedStatus + ) + ); + //PermissionController + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector( + PermissionController.initialize.selector + ) + ); // Create base strategy implementation and deploy a few strategies - baseStrategyImplementation = new StrategyBase(strategyManager); + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); // Create a proxy beacon for base strategy implementation strategyBeacon = new UpgradeableBeacon(address(baseStrategyImplementation)); // Strategy Factory, upgrade and initalized eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyFactory))), + ITransparentUpgradeableProxy(payable(address(strategyFactory))), address(strategyFactoryImplementation), abi.encodeWithSelector( StrategyFactory.initialize.selector, eigenLayerReputedMultisig, - IPauserRegistry(address(eigenLayerPauserReg)), 0, // initial paused status IBeacon(strategyBeacon) ) ); - + cheats.prank(eigenLayerReputedMultisig); strategyManager.setStrategyWhitelister(address(strategyFactory)); // Normal deployments - _newStrategyAndToken("Strategy1Token", "str1", 10e50, address(this), false); // initialSupply, owner - _newStrategyAndToken("Strategy2Token", "str2", 10e50, address(this), false); // initialSupply, owner - _newStrategyAndToken("Strategy3Token", "str3", 10e50, address(this), false); // initialSupply, owner - + _newStrategyAndToken("Strategy1 token", "str1", 10e50, address(this), false); // initialSupply, owner + _newStrategyAndToken("Strategy2 token", "str2", 10e50, address(this), false); // initialSupply, owner + _newStrategyAndToken("Strategy3 token", "str3", 10e50, address(this), false); // initialSupply, owner + // Factory deployments - _newStrategyAndToken("Strategy4Token", "str4", 10e50, address(this), true); // initialSupply, owner - _newStrategyAndToken("Strategy5Token", "str5", 10e50, address(this), true); // initialSupply, owner - _newStrategyAndToken("Strategy6Token", "str6", 10e50, address(this), true); // initialSupply, owner + _newStrategyAndToken("Strategy4 token", "str4", 10e50, address(this), true); // initialSupply, owner + _newStrategyAndToken("Strategy5 token", "str5", 10e50, address(this), true); // initialSupply, owner + _newStrategyAndToken("Strategy6 token", "str6", 10e50, address(this), true); // initialSupply, owner ethStrats.push(BEACONCHAIN_ETH_STRAT); allStrats.push(BEACONCHAIN_ETH_STRAT); allTokens.push(NATIVE_ETH); // Create time machine and beacon chain. Set block time to beacon chain genesis time + // TODO: update if needed to sane timestamp cheats.warp(GENESIS_TIME_LOCAL); timeMachine = new TimeMachine(); beaconChain = new BeaconChainMock(eigenPodManager, GENESIS_TIME_LOCAL); @@ -377,7 +315,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { /** * @notice deploy current implementation contracts and upgrade the existing proxy EigenLayer contracts * on Mainnet. Setup for integration tests on mainnet fork. - * + * * Note that beacon chain oracle and eth deposit contracts are mocked and pointed to different addresses for these tests. */ function _upgradeMainnetContracts() public virtual { @@ -387,11 +325,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { ETHPOSDepositAddress = address(ethPOSDeposit); // overwrite for upgrade checks later // Deploy EigenPod Contracts - eigenPodImplementation = new EigenPod( - ethPOSDeposit, - eigenPodManager, - GENESIS_TIME_MAINNET - ); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GENESIS_TIME_MAINNET); eigenPodBeacon.upgradeTo(address(eigenPodImplementation)); // Deploy AVSDirectory, contract has not been deployed on mainnet yet avsDirectory = AVSDirectory( @@ -399,59 +333,52 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { ); // First, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); + delegationManagerImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); - avsDirectoryImplementation = new AVSDirectory(delegationManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); + eigenPodManagerImplementation = + new EigenPodManager(ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); // Second, upgrade the proxy contracts to point to the implementations // DelegationManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(delegationManager))), - address(delegationManagerImplementation) + ITransparentUpgradeableProxy(payable(address(delegationManager))), address(delegationManagerImplementation) ); // StrategyManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation) - ); - // Slasher - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation) + ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation) ); // EigenPodManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation) + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) ); // AVSDirectory, upgrade and initalized eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), + ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation), abi.encodeWithSelector( AVSDirectory.initialize.selector, executorMultisig, - eigenLayerPauserReg, 0 // initialPausedStatus ) ); // Create base strategy implementation and deploy a few strategies - baseStrategyImplementation = new StrategyBase(strategyManager); + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); // Upgrade All deployed strategy contracts to new base strategy for (uint i = 0; i < numStrategiesDeployed; i++) { // Upgrade existing strategy eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), + ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), address(baseStrategyImplementation) ); } @@ -471,7 +398,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { /** * @notice deploy current implementation contracts and upgrade the existing proxy EigenLayer contracts * on Holesky. Setup for integration tests on Holesky fork. - * + * * Note that beacon chain oracle and eth deposit contracts are mocked and pointed to different addresses for these tests. */ function _upgradeHoleskyContracts() public virtual { @@ -481,11 +408,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { ETHPOSDepositAddress = address(ethPOSDeposit); // overwrite for upgrade checks later // Deploy EigenPod Contracts - eigenPodImplementation = new EigenPod( - ethPOSDeposit, - eigenPodManager, - 0 - ); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, 0); eigenPodBeacon.upgradeTo(address(eigenPodImplementation)); // Deploy AVSDirectory, contract has not been deployed on mainnet yet avsDirectory = AVSDirectory( @@ -493,59 +416,52 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { ); // First, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); + delegationManagerImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, eigenLayerPauserReg, permissionController, MIN_WITHDRAWAL_DELAY); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, - slasher, - delegationManager + delegationManager, + eigenLayerPauserReg ); - avsDirectoryImplementation = new AVSDirectory(delegationManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg); + eigenPodManagerImplementation = + new EigenPodManager(ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager, eigenLayerPauserReg); + avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg); // Second, upgrade the proxy contracts to point to the implementations // DelegationManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(delegationManager))), - address(delegationManagerImplementation) + ITransparentUpgradeableProxy(payable(address(delegationManager))), address(delegationManagerImplementation) ); // StrategyManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation) - ); - // Slasher - eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation) + ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation) ); // EigenPodManager eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation) + ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) ); // AVSDirectory, upgrade and initalized eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), + ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation), abi.encodeWithSelector( AVSDirectory.initialize.selector, executorMultisig, - eigenLayerPauserReg, 0 // initialPausedStatus ) ); // Create base strategy implementation and deploy a few strategies - baseStrategyImplementation = new StrategyBase(strategyManager); + baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg); // Upgrade All deployed strategy contracts to new base strategy for (uint i = 0; i < numStrategiesDeployed; i++) { // Upgrade existing strategy eigenLayerProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), + ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), address(baseStrategyImplementation) ); } @@ -564,24 +480,26 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { /// @dev Deploy a strategy and its underlying token, push to global lists of tokens/strategies, and whitelist /// strategy in strategyManager - function _newStrategyAndToken(string memory tokenName, string memory tokenSymbol, uint initialSupply, address owner, bool useFactory) internal { - IERC20 underlyingToken = new ERC20PresetFixedSupply(tokenName, tokenSymbol, initialSupply, owner); - + function _newStrategyAndToken( + string memory tokenName, + string memory tokenSymbol, + uint initialSupply, + address owner, + bool useFactory + ) internal { + IERC20 underlyingToken = new ERC20PresetFixedSupply(tokenName, tokenSymbol, initialSupply, owner); + StrategyBase strategy; if (useFactory) { - strategy = StrategyBase( - address( - strategyFactory.deployNewStrategy(underlyingToken) - ) - ); + strategy = StrategyBase(address(strategyFactory.deployNewStrategy(underlyingToken))); } else { strategy = StrategyBase( address( new TransparentUpgradeableProxy( address(baseStrategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) + abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); @@ -589,17 +507,16 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // Whitelist strategy IStrategy[] memory strategies = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); strategies[0] = strategy; if (forkType == MAINNET) { cheats.prank(strategyManager.strategyWhitelister()); IStrategyManager_DeprecatedM1(address(strategyManager)).addStrategiesToDepositWhitelist(strategies); cheats.prank(eigenLayerPauserReg.unpauser()); - StrategyBaseTVLLimits(address(strategy)).setTVLLimits(type(uint256).max, type(uint256).max); + StrategyBaseTVLLimits(address(strategy)).setTVLLimits(type(uint).max, type(uint).max); } else { cheats.prank(strategyManager.strategyWhitelister()); - strategyManager.addStrategiesToDepositWhitelist(strategies, _thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategies); } // Add to lstStrats and allStrats @@ -608,30 +525,15 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { allTokens.push(underlyingToken); } - function _configRand( - uint24 _randomSeed, - uint _assetTypes, - uint _userTypes - ) internal { + function _configRand(uint24 _randomSeed, uint _assetTypes, uint _userTypes) internal { // Using uint24 for the seed type so that if a test fails, it's easier // to manually use the seed to replay the same test. - emit log_named_uint("_configRand: set random seed to: ", _randomSeed); - random = keccak256(abi.encodePacked(_randomSeed)); - + random = _hash(_randomSeed); + // Convert flag bitmaps to bytes of set bits for easy use with _randUint assetTypes = _bitmapToBytes(_assetTypes); userTypes = _bitmapToBytes(_userTypes); - emit log("_configRand: Users will be initialized with these asset types:"); - for (uint i = 0; i < assetTypes.length; i++) { - emit log(assetTypeToStr[uint(uint8(assetTypes[i]))]); - } - - emit log("_configRand: these User contracts will be initialized:"); - for (uint i = 0; i < userTypes.length; i++) { - emit log(userTypeToStr[uint(uint8(userTypes[i]))]); - } - assertTrue(assetTypes.length != 0, "_configRand: no asset types selected"); assertTrue(userTypes.length != 0, "_configRand: no user types selected"); } @@ -643,8 +545,6 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { * Note: for non-LOCAL forktypes, upgrade of contracts will be peformed after user initialization. */ function _deployOrFetchContracts() internal { - emit log_named_string("_deployOrFetchContracts using fork for test", forkTypeToStr[forkType]); - if (forkType == LOCAL) { _setUpLocal(); // Set Upgraded as local setup deploys most up to date contracts @@ -721,17 +621,19 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { /** * @dev Create a new User with a random config using the range defined in `_configRand` - * + * * Assets are pulled from `strategies` based on a random staker/operator `assetType` */ - function _randUser(string memory name) internal returns (User, IStrategy[] memory, uint[] memory) { + function _randUser( + string memory name + ) internal returns (User, IStrategy[] memory, uint[] memory) { // For the new user, select what type of assets they'll have and whether // they'll use `xWithSignature` methods. // // The values selected here are in the ranges configured via `_configRand` uint assetType = _randAssetType(); uint userType = _randUserType(); - + // Deploy new User contract User user = _genRandUser(name, userType); @@ -739,12 +641,14 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // strategies and deal the user some corresponding underlying token balances (IStrategy[] memory strategies, uint[] memory tokenBalances) = _dealRandAssets(user, assetType); - _printUserInfo(name, assetType, userType, strategies, tokenBalances); + print.user(name, assetType, userType, strategies, tokenBalances); return (user, strategies, tokenBalances); } /// @dev Create a new user without native ETH. See _randUser above for standard usage - function _randUser_NoETH(string memory name) internal returns (User, IStrategy[] memory, uint[] memory) { + function _randUser_NoETH( + string memory name + ) internal returns (User, IStrategy[] memory, uint[] memory) { // For the new user, select what type of assets they'll have and whether // they'll use `xWithSignature` methods. // @@ -759,7 +663,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } else if (assetType == HOLDS_ALL) { assetType = HOLDS_LST; } - + // Deploy new User contract User user = _genRandUser(name, userType); @@ -767,21 +671,19 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // strategies and deal the user some corresponding underlying token balances (IStrategy[] memory strategies, uint[] memory tokenBalances) = _dealRandAssets(user, assetType); - _printUserInfo(name, assetType, userType, strategies, tokenBalances); + print.user(name, assetType, userType, strategies, tokenBalances); return (user, strategies, tokenBalances); } - function _genRandUser(string memory name, uint userType) internal returns (User) { + function _genRandUser(string memory name, uint userType) internal returns (User user) { // Create User contract based on userType: - User user; if (forkType == LOCAL) { user = new User(name); if (userType == DEFAULT) { user = new User(name); } else if (userType == ALT_METHODS) { - // User will use nonstandard methods like: - // `delegateToBySignature` and `depositIntoStrategyWithSignature` + // User will use nonstandard methods like `depositIntoStrategyWithSignature` user = User(new User_AltMethods(name)); } else { revert("_randUser: unimplemented userType"); @@ -790,13 +692,11 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { if (userType == DEFAULT) { user = User(new User_M1(name)); } else if (userType == ALT_METHODS) { - // User will use nonstandard methods like: - // `delegateToBySignature` and `depositIntoStrategyWithSignature` + // User will use nonstandard methods like `depositIntoStrategyWithSignature` user = User(new User_M1_AltMethods(name)); } else { revert("_randUser: unimplemented userType"); } - } else if (forkType == HOLESKY) { // User deployment for Holesky is exact same as holesky. // Current Holesky deployment is up to date and no deprecated interfaces have been added. @@ -806,8 +706,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { if (userType == DEFAULT) { user = new User(name); } else if (userType == ALT_METHODS) { - // User will use nonstandard methods like: - // `delegateToBySignature` and `depositIntoStrategyWithSignature` + // User will use nonstandard methods like `depositIntoStrategyWithSignature` user = User(new User_AltMethods(name)); } else { revert("_randUser: unimplemented userType"); @@ -815,8 +714,20 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } else { revert("_randUser: unimplemented forkType"); } + } - return user; + function _genRandAVS( + string memory name + ) internal returns (AVS avs) { + if (forkType == LOCAL) { + avs = new AVS(name); + } else if (forkType == MAINNET) { + avs = new AVS(name); + } else if (forkType == HOLESKY) { + avs = new AVS(name); + } else { + revert("_genRandAVS: unimplemented forkType"); + } } /// @dev For a given `assetType`, select a random assortment of strategies and assets @@ -836,7 +747,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } else if (assetType == HOLDS_LST) { assetType = HOLDS_LST; // Select a random number of assets - uint numAssets = _randUint({ min: 1, max: lstStrats.length }); + uint numAssets = _randUint({min: 1, max: lstStrats.length}); strategies = new IStrategy[](numAssets); tokenBalances = new uint[](numAssets); @@ -844,7 +755,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { for (uint i = 0; i < numAssets; i++) { IStrategy strat = lstStrats[i]; IERC20 underlyingToken = strat.underlyingToken(); - uint balance = _randUint({ min: MIN_BALANCE, max: MAX_BALANCE }); + uint balance = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); StdCheats.deal(address(underlyingToken), address(user), balance); tokenBalances[i] = balance; @@ -856,7 +767,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // Award the user with a random amount of ETH // This guarantees a multiple of 32 ETH (at least 1, up to/incl 5) - uint amount = 32 ether * _randUint({ min: 1, max: 5 }); + uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(user), amount); strategies[0] = BEACONCHAIN_ETH_STRAT; @@ -865,12 +776,12 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { uint numLSTs = lstStrats.length; strategies = new IStrategy[](numLSTs + 1); tokenBalances = new uint[](numLSTs + 1); - + // For each LST, award the user a random balance of the underlying token for (uint i = 0; i < numLSTs; i++) { IStrategy strat = lstStrats[i]; IERC20 underlyingToken = strat.underlyingToken(); - uint balance = _randUint({ min: MIN_BALANCE, max: MAX_BALANCE }); + uint balance = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); StdCheats.deal(address(underlyingToken), address(user), balance); tokenBalances[i] = balance; @@ -879,7 +790,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // Award the user with a random amount of ETH // This guarantees a multiple of 32 ETH (at least 1, up to/incl 5) - uint amount = 32 ether * _randUint({ min: 1, max: 5 }); + uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(user), amount); // Add BEACONCHAIN_ETH_STRAT and eth balance @@ -893,9 +804,11 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } /// @dev By default will have a assetType of HOLDS_LST - function _dealRandAssets_M1(User user) internal returns (IStrategy[] memory, uint[] memory) { + function _dealRandAssets_M1( + User user + ) internal returns (IStrategy[] memory, uint[] memory) { // Select a random number of assets - uint numAssets = _randUint({ min: 1, max: lstStrats.length }); + uint numAssets = _randUint({min: 1, max: lstStrats.length}); IStrategy[] memory strategies = new IStrategy[](numAssets); uint[] memory tokenBalances = new uint[](numAssets); @@ -904,7 +817,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { for (uint i = 0; i < numAssets; i++) { IStrategy strat = lstStrats[i]; IERC20 underlyingToken = strat.underlyingToken(); - uint balance = _randUint({ min: MIN_BALANCE, max: MAX_BALANCE }); + uint balance = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); StdCheats.deal(address(underlyingToken), address(user), balance); tokenBalances[i] = balance; @@ -916,7 +829,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { /// @dev Uses `random` to return a random uint, with a range given by `min` and `max` (inclusive) /// @return `min` <= result <= `max` - function _randUint(uint min, uint max) internal returns (uint) { + function _randUint(uint min, uint max) internal returns (uint) { uint range = max - min + 1; // calculate the number of bits needed for the range @@ -938,39 +851,72 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } // Hash `random` with itself so the next value we generate is different - random = keccak256(abi.encodePacked(random)); + random = _hash(uint(random)); return min + value; } function _randBool() internal returns (bool) { - return _randUint({ min: 0, max: 1 }) == 0; + return _randUint({min: 0, max: 1}) == 0; } function _randAssetType() internal returns (uint) { - uint idx = _randUint({ min: 0, max: assetTypes.length - 1 }); + uint idx = _randUint({min: 0, max: assetTypes.length - 1}); uint assetType = uint(uint8(assetTypes[idx])); return assetType; } function _randUserType() internal returns (uint) { - uint idx = _randUint({ min: 0, max: userTypes.length - 1 }); + uint idx = _randUint({min: 0, max: userTypes.length - 1}); uint userType = uint(uint8(userTypes[idx])); return userType; } + function _shuffle(IStrategy[] memory strats) internal returns (IStrategy[] memory) { + // Fisher-Yates shuffle algorithm + for (uint i = strats.length - 1; i > 0; i--) { + uint randomIndex = _randUint({ min: 0, max: i }); + + // Swap elements + IStrategy temp = strats[i]; + strats[i] = strats[randomIndex]; + strats[randomIndex] = temp; + } + + return strats; + } + + function _randomStrategies() internal returns (IStrategy[][] memory strategies) { + uint numOpSets = _randUint({ min: 1, max: 5 }); + + strategies = new IStrategy[][](numOpSets); + + for (uint i; i < numOpSets; ++i) { + IStrategy[] memory randomStrategies = _shuffle(allStrats); + + uint numStrategies = _randUint({ min: 1, max: allStrats.length }); + + // Modify the length of the array in memory (thus ignoring remaining elements). + assembly { + mstore(randomStrategies, numStrategies) + } + + strategies[i] = randomStrategies; + } + } + /** * @dev Converts a bitmap into an array of bytes * @dev Each byte in the input is processed as indicating a single bit to flip in the bitmap */ - function _bitmapToBytes(uint bitmap) internal pure returns (bytes memory bytesArray) { + function _bitmapToBytes( + uint bitmap + ) internal pure returns (bytes memory bytesArray) { for (uint i = 0; i < 256; ++i) { // Mask for i-th bit uint mask = uint(1 << i); - // emit log_named_uint("mask: ", mask); - // If the i-th bit is flipped, add a byte to the return array if (bitmap & mask != 0) { bytesArray = bytes.concat(bytesArray, bytes1(uint8(1 << i))); @@ -979,41 +925,15 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { return bytesArray; } - function _printUserInfo( - string memory name, - uint assetType, - uint userType, - IStrategy[] memory strategies, - uint[] memory tokenBalances - ) internal { - - emit log("===Created User==="); - emit log_named_string("Name", name); - emit log_named_string("assetType", assetTypeToStr[assetType]); - emit log_named_string("userType", userTypeToStr[userType]); - emit log_named_string("forkType", forkTypeToStr[forkType]); - - emit log_named_uint("num assets: ", strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - IStrategy strat = strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) { - emit log_named_string("token name: ", "Native ETH"); - emit log_named_uint("token balance: ", tokenBalances[i]); - } else { - IERC20 underlyingToken = strat.underlyingToken(); - - emit log_named_string("token name: ", IERC20Metadata(address(underlyingToken)).name()); - emit log_named_uint("token balance: ", tokenBalances[i]); - } - } - - emit log("=================="); + function _hash( + string memory x + ) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(x)); } - /// @dev Helper because solidity syntax is exhausting - function _hash(string memory s) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(s)); + function _hash( + uint x + ) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(x)); } } diff --git a/src/test/integration/README.md b/src/test/integration/README.md index 992d2a326..2a2be0b63 100644 --- a/src/test/integration/README.md +++ b/src/test/integration/README.md @@ -51,18 +51,52 @@ function testFuzz_deposit_delegate_EXAMPLE(uint24 _random) public { // - `strategyManager.depositIntoStrategyWithSignature` staker.depositIntoEigenlayer(strategies, tokenBalances); // assertions go here +} +``` - // Because of the `userTypes` flags above, this user might be using either: - // - `delegation.delegateTo` - // - `delegation.delegateToBySignature` - staker.delegateTo(operator); - // assertions go here +### `print` Library Overview + +The `print` library provides utilities for structured and stylized logging to streamline debugging in EigenLayer contracts. It includes helpers for common tasks such as logging user actions, integration test details. The library works in conjunction with the `Logger` abstract contract, which must be inherited by contracts that use `print`. + +NOTE: `print` is intended to be used in conjunction with `console.log`. + +```solidity +import "src/test/utils/Logger.t.sol"; + +// The `User` contract inherits `Logger` to enable `print` functionalities. +contract User is Logger { + string public _name; + + constructor(string memory name) { + _name = name; + } + + function NAME() public override view returns (string memory) { + return _name; + } + + function vote(User who, uint256 votes) public { + print.method( + "vote", + string.concat( + "{who: ", who.NAME_COLORED(), + ", votes: ", votes.asWad(), + "}" + ) + ); + } } + +User alice = User("Alice"); +User bob = User("Bob"); + +// Will emit a log equal to: `console.log("Alice.vote({who: Bob, votes: 1.0 (wad)})");` +alice.vote(bob, 1 ether); ``` **If you want to know about the time travel**, there's a few things to note: -The main feature we're using is foundry's `cheats.snapshot()` and `cheats.revertTo(snapshot)` to zip around in time. You can look at the [Cheatcodes Reference](https://book.getfoundry.sh/cheatcodes/#cheatcodes-interface) to get some idea, but the docs aren't actually correct. The best thing to do is look through our tests and see how it's being used. If you see an assertion called `assert_Snap_...`, that's using the `TimeMachine` under the hood. +The main feature we're using is foundry's `cheats.snapshotState()` and `cheats.revertToState(snapshot)` to zip around in time. You can look at the [Cheatcodes Reference](https://book.getfoundry.sh/cheatcodes/#cheatcodes-interface) to get some idea, but the docs aren't actually correct. The best thing to do is look through our tests and see how it's being used. If you see an assertion called `assert_Snap_...`, that's using the `TimeMachine` under the hood. Speaking of, the `TimeMachine` is a global contract that controls the time, fate, and destiny of all who use it. * `Users` use the `TimeMachine` to snapshot chain state *before* every action they perform. (see the [`User.createSnapshot`](https://github.com/layr-labs/eigenlayer-contracts/blob/c5193f7bff00903a4323be2a1500cbf7137a83e9/src/test/integration/User.t.sol#L43-L46) modifier). diff --git a/src/test/integration/TimeMachine.t.sol b/src/test/integration/TimeMachine.t.sol index 66bf59e8e..616f56423 100644 --- a/src/test/integration/TimeMachine.t.sol +++ b/src/test/integration/TimeMachine.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -11,7 +11,7 @@ contract TimeMachine is Test { uint lastSnapshot; function createSnapshot() public returns (uint) { - uint snapshot = cheats.snapshot(); + uint snapshot = cheats.snapshotState(); lastSnapshot = snapshot; pastExists = true; return snapshot; @@ -22,12 +22,12 @@ contract TimeMachine is Test { // so we don't accidentally prevent our own births assertTrue(pastExists, "Global.warpToPast: invalid usage, past does not exist"); - curState = cheats.snapshot(); - cheats.revertTo(lastSnapshot); + curState = cheats.snapshotState(); + cheats.revertToState(lastSnapshot); return curState; } function warpToPresent(uint curState) public { - cheats.revertTo(curState); + cheats.revertToState(curState); } } diff --git a/src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol b/src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol index 89af42013..41c8a043d 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/contracts/libraries/Merkle.sol"; import "src/contracts/libraries/Endian.sol"; diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol b/src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol index 2bb2c818e..cb36eda5b 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @notice DEPRECATED INTERFACE at commit hash https://github.com/Layr-Labs/eigenlayer-contracts/tree/0139d6213927c0a7812578899ddd3dda58051928 diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol b/src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol index 8abb54a86..06d66c1e6 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /// @notice DEPRECATED INTERFACE at commit hash https://github.com/Layr-Labs/eigenlayer-contracts/tree/0139d6213927c0a7812578899ddd3dda58051928 interface IDelayedWithdrawalRouter_DeprecatedM1 { diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol b/src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol index 0171653be..2866a9b83 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./BeaconChainProofs.sol"; import "./IEigenPodManager.sol"; diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol b/src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol index d5795bf5d..3fbf139cc 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./IStrategyManager.sol"; import "./IEigenPod.sol"; @@ -78,9 +78,6 @@ interface IEigenPodManager_DeprecatedM1 is IPausable { /// @notice EigenLayer's StrategyManager contract function strategyManager() external view returns(IStrategyManager_DeprecatedM1); - - /// @notice EigenLayer's Slasher contract - function slasher() external view returns(ISlasher); - + function hasPod(address podOwner) external view returns (bool); } diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol b/src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol index be5745683..fc4614d3b 100644 --- a/src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol +++ b/src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/contracts/interfaces/IStrategy.sol"; -import "src/contracts/interfaces/ISlasher.sol"; import "src/contracts/interfaces/IDelegationManager.sol"; /** @@ -102,7 +101,7 @@ interface IStrategyManager_DeprecatedM1 { returns (uint256 shares); /// @notice Returns the current shares of `user` in `strategy` - function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares); + function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 shares); /** * @notice Get all details on the depositor's deposits and corresponding shares @@ -247,9 +246,6 @@ interface IStrategyManager_DeprecatedM1 { /// @notice Returns the single, central Delegation contract of EigenLayer function delegation() external view returns (IDelegationManager); - /// @notice Returns the single, central Slasher contract of EigenLayer - function slasher() external view returns (ISlasher); - /// @notice returns the enshrined, virtual 'beaconChainETH' Strategy function beaconChainETHStrategy() external view returns (IStrategy); diff --git a/src/test/integration/mocks/BeaconChainMock.t.sol b/src/test/integration/mocks/BeaconChainMock.t.sol index a49263a95..414d18b66 100644 --- a/src/test/integration/mocks/BeaconChainMock.t.sol +++ b/src/test/integration/mocks/BeaconChainMock.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -8,7 +8,7 @@ import "src/contracts/libraries/Merkle.sol"; import "src/contracts/pods/EigenPodManager.sol"; import "src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol"; -import "src/test/integration/utils/PrintUtils.t.sol"; +import "src/test/utils/Logger.t.sol"; struct ValidatorFieldsProof { bytes32[] validatorFields; @@ -38,9 +38,9 @@ struct StaleBalanceProofs { BeaconChainProofs.ValidatorProof validatorProof; } -contract BeaconChainMock is PrintUtils { - - Vm cheats = Vm(VM_ADDRESS); +contract BeaconChainMock is Logger { + using StdStyle for *; + using print for *; struct Validator { bool isDummy; @@ -53,7 +53,6 @@ contract BeaconChainMock is PrintUtils { } /// @dev All withdrawals are processed with index == 0 - uint constant GWEI_TO_WEI = 1e9; uint constant ZERO_NODES_LENGTH = 100; // Rewards given to each validator during epoch processing @@ -155,7 +154,7 @@ contract BeaconChainMock is PrintUtils { function newValidator( bytes memory withdrawalCreds ) public payable returns (uint40) { - _logM("newValidator"); + print.method("newValidator"); uint balanceWei = msg.value; @@ -191,7 +190,7 @@ contract BeaconChainMock is PrintUtils { /// /// TODO we may need to advance a slot here to maintain the properties we want in startCheckpoint function exitValidator(uint40 validatorIndex) public returns (uint64 exitedBalanceGwei) { - _logM("exitValidator"); + print.method("exitValidator"); // Update validator.exitEpoch Validator storage v = validators[validatorIndex]; @@ -211,7 +210,7 @@ contract BeaconChainMock is PrintUtils { } function slashValidators(uint40[] memory _validators) public returns (uint64 slashedBalanceGwei) { - _logM("slashValidators"); + print.method("slashValidators"); for (uint i = 0; i < _validators.length; i++) { uint40 validatorIndex = _validators[i]; @@ -254,11 +253,9 @@ contract BeaconChainMock is PrintUtils { /// - DOES generate consensus rewards for ALL non-exited validators /// - DOES withdraw in excess of 32 ETH / if validator is exited function advanceEpoch() public { - _logM("advanceEpoch"); - + print.method("advanceEpoch"); _generateRewards(); _withdrawExcess(); - _advanceEpoch(); } @@ -270,10 +267,8 @@ contract BeaconChainMock is PrintUtils { /// - does NOT generate consensus rewards /// - DOES withdraw in excess of 32 ETH / if validator is exited function advanceEpoch_NoRewards() public { - _logM("advanceEpoch_NoRewards"); - + print.method("advanceEpoch_NoRewards"); _withdrawExcess(); - _advanceEpoch(); } @@ -286,10 +281,8 @@ contract BeaconChainMock is PrintUtils { /// - does NOT withdraw in excess of 32 ETH /// - does NOT withdraw if validator is exited function advanceEpoch_NoWithdraw() public { - _logM("advanceEpoch_NoWithdraw"); - + print.method("advanceEpoch_NoWithdraw"); _generateRewards(); - _advanceEpoch(); } @@ -311,7 +304,7 @@ contract BeaconChainMock is PrintUtils { } } - _log("- generated rewards for num validators", totalRewarded); + console.log(" - Generated rewards for %s of %s validators.", totalRewarded, validators.length); } /// @dev Iterate over all validators. If the validator has > 32 ETH current balance @@ -349,10 +342,12 @@ contract BeaconChainMock is PrintUtils { } if (totalExcessWei != 0) - _log("- withdrew excess balance", totalExcessWei); + console.log("- Withdrew excess balance:", totalExcessWei.asGwei()); } function _advanceEpoch() public { + cheats.pauseTracing(); + // Update effective balances for each validator for (uint i = 0; i < validators.length; i++) { Validator storage v = validators[i]; @@ -367,20 +362,19 @@ contract BeaconChainMock is PrintUtils { v.effectiveBalanceGwei = balanceGwei; } - _log("- updated effective balances"); - - // Move forward one epoch - // _log("-- current time", block.timestamp); - _log("-- current epoch", currentEpoch()); + // console.log(" Updated effective balances...".dim()); + // console.log(" timestamp:", block.timestamp); + // console.log(" epoch:", currentEpoch()); uint64 curEpoch = currentEpoch(); cheats.warp(_nextEpochStartTimestamp(curEpoch)); curTimestamp = uint64(block.timestamp); - // _log("-- new time", block.timestamp); - _log("- jumped to next epoch", currentEpoch()); - - _log("- building beacon state trees"); + // console.log(" Jumping to next epoch...".dim()); + // console.log(" timestamp:", block.timestamp); + // console.log(" epoch:", currentEpoch()); + + // console.log(" Building beacon state trees...".dim()); // Log total number of validators and number being processed for the first time if (validators.length > 0) { @@ -389,7 +383,7 @@ contract BeaconChainMock is PrintUtils { // generate an empty root if we don't have any validators EIP_4788_ORACLE.setBlockRoot(curTimestamp, keccak256("")); - _log("-- no validators; added empty block root"); + // console.log("-- no validators; added empty block root"); return; } @@ -399,7 +393,7 @@ contract BeaconChainMock is PrintUtils { treeHeight: BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1, tree: trees[curTimestamp].validatorTree }); - // _log("-- validator container root", validatorsRoot); + // console.log("-- validator container root", validatorsRoot); // Build merkle tree for current balances bytes32 balanceContainerRoot = _buildMerkleTree({ @@ -407,7 +401,7 @@ contract BeaconChainMock is PrintUtils { treeHeight: BeaconChainProofs.BALANCE_TREE_HEIGHT + 1, tree: trees[curTimestamp].balancesTree }); - // _log("-- balances container root", balanceContainerRoot); + // console.log("-- balances container root", balanceContainerRoot); // Build merkle tree for BeaconState bytes32 beaconStateRoot = _buildMerkleTree({ @@ -415,7 +409,7 @@ contract BeaconChainMock is PrintUtils { treeHeight: BeaconChainProofs.BEACON_STATE_TREE_HEIGHT, tree: trees[curTimestamp].stateTree }); - // _log("-- beacon state root", beaconStateRoot); + // console.log("-- beacon state root", beaconStateRoot); // Build merkle tree for BeaconBlock bytes32 beaconBlockRoot = _buildMerkleTree({ @@ -423,7 +417,9 @@ contract BeaconChainMock is PrintUtils { treeHeight: BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT, tree: trees[curTimestamp].blockTree }); - _log("-- beacon block root", beaconBlockRoot); + + + // console.log("-- beacon block root", cheats.toString(beaconBlockRoot)); // Push new block root to oracle EIP_4788_ORACLE.setBlockRoot(curTimestamp, beaconBlockRoot); @@ -433,6 +429,8 @@ contract BeaconChainMock is PrintUtils { _genBalanceContainerProof(balanceContainerRoot); _genCredentialProofs(); _genBalanceProofs(); + + cheats.resumeTracing(); } /******************************************************************************* @@ -440,6 +438,7 @@ contract BeaconChainMock is PrintUtils { *******************************************************************************/ function _createValidator(bytes memory withdrawalCreds, uint64 balanceGwei) internal returns (uint40) { + cheats.pauseTracing(); uint40 validatorIndex = uint40(validators.length); // HACK to make balance proofs work. Every 4 validators we create @@ -481,6 +480,8 @@ contract BeaconChainMock is PrintUtils { })); _setCurrentBalance(validatorIndex, balanceGwei); + cheats.resumeTracing(); + return validatorIndex; } diff --git a/src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol b/src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol index b83aac72a..37cb50c59 100644 --- a/src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol +++ b/src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; contract EIP_4788_Oracle_Mock { diff --git a/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol b/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol index 1c20e1807..1fa2d2535 100644 --- a/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { - function testFuzz_delegate_deposit_queue_completeAsShares(uint24 _random) public { // Configure the random parameters for the test _configRand({ @@ -32,12 +31,12 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { assert_Snap_Added_OperatorShares(operator, strategies, shares, "operator should have received shares"); // 3. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], strategies, shares); @@ -71,12 +70,12 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { assert_Snap_Added_OperatorShares(operator, strategies, shares, "operator should have received shares"); // 3. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); diff --git a/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol b/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol new file mode 100644 index 000000000..ee3958dcf --- /dev/null +++ b/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/users/User.t.sol"; + +contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { + function testFuzz_deposit_delegate_allocate(uint24 _random) public { + // Configure the random parameters for the test + _configRand({ + _randomSeed: _random, + _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, + _userTypes: DEFAULT | ALT_METHODS + }); + + // Create a staker and an operator with a nonzero balance and corresponding strategies + (AVS avs, OperatorSet[] memory operatorSets) = _newRandomAVS(); + (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (User operator, ,) = _newRandomOperator(); + + // Upgrade contracts if forkType is not local + _upgradeEigenLayerContracts(); + + // 1. Delegate to operator + staker.delegateTo(operator); + check_Delegation_State(staker, operator, strategies, new uint256[](strategies.length)); // Initial shares are zero + + // 2. Deposit into strategies + staker.depositIntoEigenlayer(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + + // Check that the deposit increased operator shares the staker is delegated to + check_Deposit_State(staker, strategies, shares); + assert_Snap_Added_OperatorShares(operator, strategies, shares, "operator should have received shares"); + + operator.registerForOperatorSets(operatorSets); + + for (uint i; i < operatorSets.length; ++i) { + uint256 len = allocationManager.getStrategiesInOperatorSet(operatorSets[i]).length; + operator.modifyAllocations(operatorSets[i], _randMagnitudes({ sum: 1 ether / uint64(operatorSets.length), len: len })); + avs.slashOperator(operator, operatorSets[i].id, _randWadToSlash()); + } + + // TODO: write checks for slashing... + } +} \ No newline at end of file diff --git a/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol index 7a703dea9..edb076135 100644 --- a/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; @@ -10,6 +10,7 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { FULL WITHDRAWALS *******************************************************************************/ + // TODO: fix test /// Generates a random staker and operator. The staker: /// 1. deposits all assets into strategies /// 2. delegates to an operator @@ -51,16 +52,16 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, shares); // 3. Queue Withdrawals - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; i++) { - uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens); } @@ -113,13 +114,13 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, shares); // 3. Queue Withdrawals - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; i++) { staker.completeWithdrawalAsShares(withdrawals[i]); @@ -184,15 +185,15 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory withdrawShares ) = _randWithdrawal(strategies, shares); - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, withdrawStrats, withdrawShares, withdrawals, withdrawalRoots); // 4. Complete withdrawals // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; i++) { - uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawStrats, withdrawShares, tokens, expectedTokens); } @@ -249,13 +250,13 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory withdrawShares ) = _randWithdrawal(strategies, shares); - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, withdrawStrats, withdrawShares, withdrawals, withdrawalRoots); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { staker.completeWithdrawalAsShares(withdrawals[i]); diff --git a/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol index e5bc6b91d..e3014c55e 100644 --- a/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; @@ -51,16 +51,16 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // 5. Delegate to a new operator @@ -75,13 +75,13 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 7. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawals for (uint i = 0; i < withdrawals.length; i++) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares, tokens, expectedTokens); } } @@ -123,16 +123,16 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // 5. Delegate to a new operator @@ -147,7 +147,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 7. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete all but last withdrawal as tokens for (uint i = 0; i < withdrawals.length - 1; i++) { @@ -218,16 +218,16 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, halfShares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, halfShares); // 4. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // 5. Delegate to a new operator @@ -245,17 +245,17 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti { // 7. Queue Withdrawal shares = _calculateExpectedShares(strategies, tokenBalances); - IDelegationManager.Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory newWithdrawalRoots = _getWithdrawalHashes(newWithdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, newWithdrawals, newWithdrawalRoots); // 8. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawals for (uint i = 0; i < newWithdrawals.length; i++) { - uint[] memory expectedTokens = _calculateExpectedTokens(newWithdrawals[i].strategies, newWithdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(newWithdrawals[i].strategies, newWithdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(newWithdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator2, newWithdrawals[i], strategies, shares, tokens, expectedTokens); } @@ -310,16 +310,16 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, halfShares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, halfShares); // 4. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // 5. Deposit into Strategies @@ -337,17 +337,17 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti { // 7. Queue Withdrawal shares = _calculateExpectedShares(strategies, tokenBalances); - IDelegationManager.Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory newWithdrawalRoots = _getWithdrawalHashes(newWithdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, newWithdrawals, newWithdrawalRoots); // 8. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawals for (uint i = 0; i < newWithdrawals.length; i++) { - uint[] memory expectedTokens = _calculateExpectedTokens(newWithdrawals[i].strategies, newWithdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(newWithdrawals[i].strategies, newWithdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(newWithdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator2, newWithdrawals[i], strategies, shares, tokens, expectedTokens); } @@ -388,17 +388,17 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal as tokens // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares, tokens, expectedTokens); } //5. Deposit into Strategies @@ -418,11 +418,11 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 8. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawals as tokens for (uint i = 0; i < withdrawals.length; i++) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], strategies, shares, tokens, expectedTokens); } @@ -462,17 +462,17 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator1, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal as Tokens // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares, tokens, expectedTokens); } //5. Deposit into Strategies @@ -492,7 +492,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 8. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawals as shares for (uint i = 0; i < withdrawals.length; i++) { diff --git a/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol index 9307eb358..50eec4ca2 100644 --- a/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUtils { - /// Randomly generates a user with different held assets. Then: /// 1. deposit into strategy /// 2. delegate to an operator @@ -48,19 +47,19 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); // Complete withdrawal for (uint256 i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares, tokens, expectedTokens); } // Check Final State @@ -111,17 +110,17 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator, strategies, shares); // 3. Undelegate from an operator - IDelegationManager.Withdrawal[] memory withdrawals = staker.undelegate(); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // Check final state: @@ -167,18 +166,18 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator, strategies, shares); // 3. Force undelegate - IDelegationManager.Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].shares); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares, tokens, expectedTokens); } // Check Final State @@ -224,16 +223,16 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti check_Delegation_State(staker, operator, strategies, shares); // 3. Force undelegate - IDelegationManager.Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 4. Complete withdrawal // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint256 i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].shares); + check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares); } // Check final state: diff --git a/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol b/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol index 53b42ff4a..e96f46082 100644 --- a/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol @@ -1,74 +1,76 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; contract Integration_Deposit_Delegate_UpdateBalance is IntegrationCheckUtils { - + // TODO: fix for slashing /// Generates a random stake and operator. The staker: /// 1. deposits all assets into strategies /// 2. delegates to an operator /// 3. queues a withdrawal for a ALL shares /// 4. updates their balance randomly /// 5. completes the queued withdrawal as tokens - function testFuzz_deposit_delegate_updateBalance_completeAsTokens(uint24 _random) public { - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); + // function testFuzz_deposit_delegate_updateBalance_completeAsTokens(uint24 _random) public { + // _configRand({ + // _randomSeed: _random, + // _assetTypes: HOLDS_ETH, // HOLDS_LST | HOLDS_ETH | HOLDS_ALL, + // _userTypes: DEFAULT //| ALT_METHODS + // }); + + // /// 0. Create an operator and staker with some underlying assets + // ( + // User staker, + // IStrategy[] memory strategies, + // uint[] memory tokenBalances + // ) = _newRandomStaker(); + // (User operator, ,) = _newRandomOperator(); + // // Upgrade contracts if forkType is not local + // _upgradeEigenLayerContracts(); - /// 0. Create an operator and staker with some underlying assets - ( - User staker, - IStrategy[] memory strategies, - uint[] memory tokenBalances - ) = _newRandomStaker(); - (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); + // uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + // assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); + // assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); - assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); - assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); + // /// 1. Deposit into strategies + // staker.depositIntoEigenlayer(strategies, tokenBalances); + // check_Deposit_State(staker, strategies, shares); - /// 1. Deposit into strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); - check_Deposit_State(staker, strategies, shares); + // /// 2. Delegate to an operator + // staker.delegateTo(operator); + // check_Delegation_State(staker, operator, strategies, shares); - /// 2. Delegate to an operator - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); + // /// 3. Queue withdrawals for ALL shares + // IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + // bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + // check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); - /// 3. Queue withdrawals for ALL shares - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); + // // Generate a random balance update: + // // - For LSTs, the tokenDelta is positive tokens minted to the staker + // // - For ETH, the tokenDelta is a positive or negative change in beacon chain balance + // ( + // int[] memory tokenDeltas, + // int[] memory stakerShareDeltas, + // int[] memory operatorShareDeltas + // ) = _randBalanceUpdate(staker, strategies); - // Generate a random balance update: - // - For LSTs, the tokenDelta is positive tokens minted to the staker - // - For ETH, the tokenDelta is a positive or negative change in beacon chain balance - ( - int[] memory tokenDeltas, - int[] memory stakerShareDeltas, - int[] memory operatorShareDeltas - ) = _randBalanceUpdate(staker, strategies); + // // 4. Update LST balance by depositing, and beacon balance by submitting a proof + // staker.updateBalances(strategies, tokenDeltas); + // assert_Snap_Delta_StakerShares(staker, strategies, stakerShareDeltas, "staker should have applied deltas correctly"); + // assert_Snap_Delta_OperatorShares(operator, strategies, operatorShareDeltas, "operator should have applied deltas correctly"); - // 4. Update LST balance by depositing, and beacon balance by submitting a proof - staker.updateBalances(strategies, tokenDeltas); - assert_Snap_Delta_StakerShares(staker, strategies, stakerShareDeltas, "staker should have applied deltas correctly"); - assert_Snap_Delta_OperatorShares(operator, strategies, operatorShareDeltas, "operator should have applied deltas correctly"); + // console.log("withdrawble: ", staker.pod().withdrawableRestakedExecutionLayerGwei()); - // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + // // Fast forward to when we can complete the withdrawal + // _rollBlocksForCompleteWithdrawals(); - // 5. Complete queued withdrawals as tokens - staker.completeWithdrawalsAsTokens(withdrawals); - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); - assert_Snap_Unchanged_TokenBalances(operator, "operator token balances should not have changed"); - assert_Snap_Unchanged_OperatorShares(operator, "operator shares should not have changed"); - } + // // 5. Complete queued withdrawals as tokens + // staker.completeWithdrawalsAsTokens(withdrawals); + // assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); + // assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); + // assert_Snap_Unchanged_TokenBalances(operator, "operator token balances should not have changed"); + // assert_Snap_Unchanged_OperatorShares(operator, "operator shares should not have changed"); + // } } diff --git a/src/test/integration/tests/Deposit_Queue_Complete.t.sol b/src/test/integration/tests/Deposit_Queue_Complete.t.sol index 3260cf32c..ca6820aab 100644 --- a/src/test/integration/tests/Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Queue_Complete.t.sol @@ -1,16 +1,15 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { - /// Randomly generates a user with different held assets. Then: /// 1. deposit into strategy /// 2. queueWithdrawal /// 3. completeQueuedWithdrawal" - function testFuzz_deposit_queueWithdrawal_completeAsTokens(uint24 _random) public { + function testFuzz_deposit_queueWithdrawal_completeAsTokens(uint24 _random) public { // Configure the random parameters for the test _configRand({ _randomSeed: _random, @@ -32,10 +31,10 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { assertFalse(delegationManager.isDelegated(address(staker)), "Staker should not be delegated after deposit"); // 2. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); // 3. Complete Queued Withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); @@ -68,10 +67,10 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { assertFalse(delegationManager.isDelegated(address(staker)), "Staker should not be delegated after deposit"); // 2. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); // 3. Complete Queued Withdrawal - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_State(staker, User(payable(0)), withdrawals[i], strategies, shares); diff --git a/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol b/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol index 9da5443a1..362bd1d7e 100644 --- a/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; @@ -28,12 +28,12 @@ contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationChe assertTrue(delegationManager.isOperator(address(staker)), "Staker should be registered as an operator"); // 3. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, staker, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal as Shares - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_State(staker, staker, withdrawals[i], strategies, shares); @@ -63,12 +63,12 @@ contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationChe assertTrue(delegationManager.isOperator(address(staker)), "Staker should be registered as an operator"); // 3. Queue Withdrawal - IDelegationManager.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, staker, strategies, shares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal as Tokens - _rollBlocksForCompleteWithdrawals(strategies); + _rollBlocksForCompleteWithdrawals(); for (uint i = 0; i < withdrawals.length; i++) { IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); diff --git a/src/test/integration/tests/Upgrade_Setup.t.sol b/src/test/integration/tests/Upgrade_Setup.t.sol index fa7677633..e33921c34 100644 --- a/src/test/integration/tests/Upgrade_Setup.t.sol +++ b/src/test/integration/tests/Upgrade_Setup.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; @@ -68,7 +68,6 @@ contract IntegrationMainnetFork_UpgradeSetup is IntegrationCheckUtils { "avsDirectory: delegationManager address not set correctly" ); // DelegationManager - require(delegationManager.slasher() == slasher, "delegationManager: slasher address not set correctly"); require( delegationManager.strategyManager() == strategyManager, "delegationManager: strategyManager address not set correctly" @@ -78,15 +77,10 @@ contract IntegrationMainnetFork_UpgradeSetup is IntegrationCheckUtils { "delegationManager: eigenPodManager address not set correctly" ); // StrategyManager - require(strategyManager.slasher() == slasher, "strategyManager: slasher address not set correctly"); require( strategyManager.delegation() == delegationManager, "strategyManager: delegationManager address not set correctly" ); - require( - strategyManager.eigenPodManager() == eigenPodManager, - "strategyManager: eigenPodManager address not set correctly" - ); // EPM require( eigenPodManager.eigenPodBeacon() == eigenPodBeacon, @@ -96,7 +90,6 @@ contract IntegrationMainnetFork_UpgradeSetup is IntegrationCheckUtils { eigenPodManager.strategyManager() == strategyManager, "eigenPodManager: strategyManager contract address not set correctly" ); - require(eigenPodManager.slasher() == slasher, "eigenPodManager: slasher contract address not set correctly"); require( eigenPodManager.delegationManager() == delegationManager, "eigenPodManager: delegationManager contract address not set correctly" diff --git a/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol b/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol index fd641bab2..2c425d3a5 100644 --- a/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol +++ b/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; @@ -111,7 +111,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { staker.verifyWithdrawalCredentials(validators); check_VerifyWC_State(staker, validators, beaconBalanceGwei); - cheats.expectRevert("EigenPod._verifyWithdrawalCredentials: validator must be inactive to prove withdrawal credentials"); + cheats.expectRevert(IEigenPodErrors.CredentialsAlreadyVerified.selector); staker.verifyWithdrawalCredentials(validators); } @@ -132,7 +132,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { staker.startCheckpoint(); check_StartCheckpoint_State(staker); - cheats.expectRevert("EigenPod._startCheckpoint: must finish previous checkpoint before starting another"); + cheats.expectRevert(IEigenPodErrors.CheckpointAlreadyActive.selector); staker.startCheckpoint(); } @@ -157,7 +157,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { staker.completeCheckpoint(); check_CompleteCheckpoint_State(staker); - cheats.expectRevert("EigenPod._startCheckpoint: cannot checkpoint twice in one block"); + cheats.expectRevert(IEigenPodErrors.CannotCheckpointTwiceInSingleBlock.selector); staker.startCheckpoint(); } @@ -227,7 +227,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { staker.exitValidators(validators); beaconChain.advanceEpoch_NoRewards(); - cheats.expectRevert("EigenPod._verifyWithdrawalCredentials: validator must not be exiting"); + cheats.expectRevert(IEigenPodErrors.ValidatorIsExitingBeaconChain.selector); staker.verifyWithdrawalCredentials(validators); } @@ -312,7 +312,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { // Advance epoch, withdrawing slashed validators to pod beaconChain.advanceEpoch_NoRewards(); - cheats.expectRevert("EigenPod._verifyWithdrawalCredentials: validator must not be exiting"); + cheats.expectRevert(IEigenPodErrors.ValidatorIsExitingBeaconChain.selector); staker.verifyWithdrawalCredentials(validators); } @@ -342,7 +342,6 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { check_CompleteCheckpoint_WithSlashing_State(staker, validators, slashedBalanceGwei); } - /// 1. Verify validators' withdrawal credentials /// 2. start a checkpoint /// -- get slashed on beacon chain; exit to pod @@ -379,6 +378,41 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { check_CompleteCheckpoint_WithSlashing_State(staker, validators, slashedBalanceGwei); } + /// 1. Verify validators' withdrawal credentials + /// 2. slash validators + /// 3. start a checkpoint + /// 4. verify withdrawal credentials for another validator while checkpoint in progress + /// 5. complete a checkpoint + /// => Increase in shares between 1 and 4 should reflect the new validator, less the slashed amount + function test_VerifyWC_Slash_StartCP_VerifyWC_CompleteCP(uint24 _rand) public r(_rand) { + (User staker, ,) = _newRandomStaker(); + _upgradeEigenLayerContracts(); + + (uint40[] memory validators, uint64 beaconBalanceGwei) = staker.startValidators(); + beaconChain.advanceEpoch_NoRewards(); + + staker.verifyWithdrawalCredentials(validators); + check_VerifyWC_State(staker, validators, beaconBalanceGwei); + + // Slash validators + uint64 slashedBalanceGwei = beaconChain.slashValidators(validators); + beaconChain.advanceEpoch_NoRewards(); + + // Start a checkpoint + staker.startCheckpoint(); + check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedBalanceGwei); + + // Start a new validator & verify withdrawal credentials + cheats.deal(address(staker), 32 ether); + (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei) = staker.startValidators(); + beaconChain.advanceEpoch_NoRewards(); + staker.verifyWithdrawalCredentials(newValidators); + check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei); + + staker.completeCheckpoint(); + check_CompleteCheckpoint_WithSlashing_HandleRoundDown_State(staker, validators, slashedBalanceGwei); + } + /******************************************************************************* VERIFY -> PROVE STALE BALANCE -> COMPLETE CHECKPOINT *******************************************************************************/ @@ -443,7 +477,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { check_StartCheckpoint_WithPodBalance_State(staker, 0); staker.completeCheckpoint(); - check_CompleteCheckpoint_WithCLSlashing_State(staker, secondSlashedBalanceGwei); + check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State(staker, secondSlashedBalanceGwei); } /// 1. Verify validators' withdrawal credentials @@ -692,7 +726,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { check_StartCheckpoint_WithPodBalance_State(staker, gweiSent); staker.completeCheckpoint(); - // check that `pod.balance == withdrawableRestakedExecutionLayerGwei + remainderSent + // check that `pod.balance == restakedExecutionLayerGwei + remainderSent assert_PodBalance_Eq(staker, (gweiSent * GWEI_TO_WEI) + remainderSent, "pod balance should equal expected"); check_CompleteCheckpoint_WithPodBalance_State(staker, gweiSent); } @@ -720,7 +754,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { check_StartCheckpoint_WithPodBalance_State(staker, gweiSent); staker.completeCheckpoint(); - // check that `pod.balance == withdrawableRestakedExecutionLayerGwei + remainderSent + // check that `pod.balance == restakedExecutionLayerGwei + remainderSent assert_PodBalance_Eq(staker, (gweiSent * GWEI_TO_WEI) + remainderSent, "pod balance should equal expected"); check_CompleteCheckpoint_WithPodBalance_State(staker, gweiSent); } diff --git a/src/test/integration/users/AVS.t.sol b/src/test/integration/users/AVS.t.sol new file mode 100644 index 000000000..1678762e8 --- /dev/null +++ b/src/test/integration/users/AVS.t.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "forge-std/Test.sol"; + +import "src/contracts/core/AllocationManager.sol"; +import "src/contracts/strategies/StrategyFactory.sol"; + +import "src/test/mocks/ERC20Mock.sol"; +import "src/test/integration/users/User.t.sol"; +import "src/test/integration/TimeMachine.t.sol"; +import "src/test/utils/Logger.t.sol"; + +import "src/test/utils/SingleItemArrayLib.sol"; +import "src/contracts/interfaces/IAVSRegistrar.sol"; + +interface IAVSDeployer { + function allocationManager() external view returns (AllocationManager); + function strategyFactory() external view returns (StrategyFactory); + function timeMachine() external view returns (TimeMachine); +} + +contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { + using print for *; + using SingleItemArrayLib for *; + + AllocationManager immutable allocationManager; + StrategyFactory immutable strategyFactory; + TimeMachine immutable timeMachine; + string _NAME; + + uint32 totalOperatorSets; + + constructor( + string memory name + ) { + IAVSDeployer deployer = IAVSDeployer(msg.sender); + allocationManager = deployer.allocationManager(); + strategyFactory = deployer.strategyFactory(); + timeMachine = deployer.timeMachine(); + _NAME = name; + } + + modifier createSnapshot() virtual { + timeMachine.createSnapshot(); + _; + } + + receive() external payable {} + + function NAME() public view override returns (string memory) { + return _NAME; + } + + /// ----------------------------------------------------------------------- + /// AllocationManager + /// ----------------------------------------------------------------------- + + function createOperatorSets( + IStrategy[][] memory strategies + ) public createSnapshot returns (OperatorSet[] memory operatorSets) { + print.method("createOperatorSets"); + + uint256 len = strategies.length; + CreateSetParams[] memory p = new CreateSetParams[](len); + operatorSets = new OperatorSet[](len); + + for (uint256 i; i < len; ++i) { + p[i] = CreateSetParams({operatorSetId: totalOperatorSets++, strategies: strategies[i]}); + + operatorSets[i] = OperatorSet(address(this), p[i].operatorSetId); + } + + print.createOperatorSets(p); + allocationManager.createOperatorSets(address(this), p); + } + + function createOperatorSet( + IStrategy[] memory strategies + ) public createSnapshot returns (OperatorSet memory operatorSet) { + print.method("createOperatorSets"); + + operatorSet = OperatorSet(address(this), totalOperatorSets++); + + CreateSetParams[] memory p = CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray(); + + print.createOperatorSets(p); + allocationManager.createOperatorSets(address(this), p); + } + + function slashOperator(User operator, uint32 operatorSetId, uint256 wadToSlash) public createSnapshot { + print.method( + "slashOperator", + string.concat( + "{operator: ", + operator.NAME_COLORED(), + ", operatorSetId: ", + cheats.toString(operatorSetId), + ", wadToSlash: ", + wadToSlash.asWad(), + "}" + ) + ); + + SlashingParams memory p = SlashingParams({ + operator: address(operator), + operatorSetId: operatorSetId, + wadToSlash: wadToSlash, + description: "bad operator" + }); + + allocationManager.slashOperator(address(this), p); + } + + function deregisterFromOperatorSets(User operator, uint32[] memory operatorSetIds) public createSnapshot { + print.method("deregisterFromOperatorSets"); + + DeregisterParams memory p = + DeregisterParams({operator: address(operator), avs: address(this), operatorSetIds: operatorSetIds}); + + print.deregisterFromOperatorSets(p); + allocationManager.deregisterFromOperatorSets(p); + } + + function setAVSRegistrar( + IAVSRegistrar registrar + ) public createSnapshot { + print.method("setAVSRegistrar"); + console.log("Setting AVS registrar to: %s", address(registrar)); + allocationManager.setAVSRegistrar(address(this), registrar); + } + + function addStrategiesToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) public createSnapshot { + print.method("addStrategiesToOperatorSet"); + + console.log("Adding strategies to operator set: %d", operatorSetId); + + for (uint256 i; i < strategies.length; ++i) { + console.log(" strategy: %s", address(strategies[i])); + } + + allocationManager.addStrategiesToOperatorSet(address(this), operatorSetId, strategies); + } + + function removeStrategiesFromOperatorSet( + uint32 operatorSetId, + IStrategy[] memory strategies + ) public createSnapshot { + print.method("removeStrategiesFromOperatorSet"); + + console.log("Removing strategies from operator set: %d", operatorSetId); + + for (uint256 i; i < strategies.length; ++i) { + console.log(" strategy: %s", address(strategies[i])); + } + + allocationManager.removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies); + } + + /// ----------------------------------------------------------------------- + /// IAVSRegistrar + /// ----------------------------------------------------------------------- + + function registerOperator( + address operator, + uint32[] calldata operatorSetIds, + bytes calldata data + ) external override {} + + function deregisterOperator(address operator, uint32[] calldata operatorSetIds) external override {} +} diff --git a/src/test/integration/users/User.t.sol b/src/test/integration/users/User.t.sol index 8afd3db90..dd772cf29 100644 --- a/src/test/integration/users/User.t.sol +++ b/src/test/integration/users/User.t.sol @@ -1,25 +1,25 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; +import "src/contracts/core/AllocationManager.sol"; import "src/contracts/core/DelegationManager.sol"; import "src/contracts/core/StrategyManager.sol"; import "src/contracts/pods/EigenPodManager.sol"; import "src/contracts/pods/EigenPod.sol"; -import "src/contracts/interfaces/IDelegationManager.sol"; -import "src/contracts/interfaces/IStrategy.sol"; - import "src/test/integration/TimeMachine.t.sol"; import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/integration/utils/PrintUtils.t.sol"; +import "src/test/utils/Logger.t.sol"; +import "src/test/utils/SingleItemArrayLib.sol"; struct Validator { uint40 index; } interface IUserDeployer { + function allocationManager() external view returns (AllocationManager); function delegationManager() external view returns (DelegationManager); function strategyManager() external view returns (StrategyManager); function eigenPodManager() external view returns (EigenPodManager); @@ -27,10 +27,11 @@ interface IUserDeployer { function beaconChain() external view returns (BeaconChainMock); } -contract User is PrintUtils { - - Vm cheats = Vm(VM_ADDRESS); +contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { + using SingleItemArrayLib for *; + using print for *; + AllocationManager allocationManager; DelegationManager delegationManager; StrategyManager strategyManager; EigenPodManager eigenPodManager; @@ -43,18 +44,17 @@ contract User is PrintUtils { EigenPod public pod; uint40[] validators; - IStrategy constant BEACONCHAIN_ETH_STRAT = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - IERC20 constant NATIVE_ETH = IERC20(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - uint constant GWEI_TO_WEI = 1e9; - - constructor(string memory name) { + constructor( + string memory name + ) { IUserDeployer deployer = IUserDeployer(msg.sender); + allocationManager = deployer.allocationManager(); delegationManager = deployer.delegationManager(); strategyManager = deployer.strategyManager(); eigenPodManager = deployer.eigenPodManager(); timeMachine = deployer.timeMachine(); - + beaconChain = deployer.beaconChain(); _createPod(); @@ -72,85 +72,178 @@ contract User is PrintUtils { return _NAME; } - /******************************************************************************* - DELEGATIONMANAGER METHODS - *******************************************************************************/ + /// ----------------------------------------------------------------------- + /// Allocation Manager Methods + /// ----------------------------------------------------------------------- + + /// @dev Allocates randomly accross the operator set's strategies with a sum of `magnitudeSum`. + /// NOTE: Calling more than once will lead to deallocations... + function modifyAllocations(OperatorSet memory operatorSet, uint64[] memory magnitudes) public virtual createSnapshot { + print.method( + "modifyAllocations", + string.concat( + "{avs: ", + Logger(operatorSet.avs).NAME_COLORED(), + ", operatorSetId: ", + cheats.toString(operatorSet.id), + "}" + ) + ); + + IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); + + require(strategies.length == magnitudes.length, "User.modifyAllocations: length mismatch"); + + AllocateParams[] memory params = AllocateParams({ + operatorSet: operatorSet, + strategies: strategies, + newMagnitudes: magnitudes + }).toArray(); - function registerAsOperator() public createSnapshot virtual { - _logM("registerAsOperator"); + allocationManager.modifyAllocations(address(this), params); + (, uint32 delay) = allocationManager.getAllocationDelay(address(this)); + rollForward({blocks: delay}); + } + + function deallocateAll( + OperatorSet memory operatorSet + ) public virtual { + modifyAllocations(operatorSet, new uint64[](allocationManager.getStrategiesInOperatorSet(operatorSet).length)); + } - IDelegationManager.OperatorDetails memory details = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: address(this), - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); + function registerForOperatorSets( + OperatorSet[] memory operatorSets + ) public virtual createSnapshot { + for (uint256 i; i < operatorSets.length; ++i) { + registerForOperatorSet(operatorSets[i]); + } + } + + function registerForOperatorSet( + OperatorSet memory operatorSet + ) public virtual createSnapshot { + print.method( + "registerForOperatorSet", + string.concat( + "{avs: ", + Logger(operatorSet.avs).NAME_COLORED(), + ", operatorSetId: ", + cheats.toString(operatorSet.id), + "}" + ) + ); - delegationManager.registerAsOperator(details, "metadata"); + allocationManager.registerForOperatorSets( + address(this), + RegisterParams({avs: operatorSet.avs, operatorSetIds: operatorSet.id.toArrayU32(), data: ""}) + ); + } + + function deregisterFromOperatorSet( + OperatorSet memory operatorSet + ) public virtual createSnapshot { + print.method( + "deregisterFromOperatorSet", + string.concat( + "{avs: ", + Logger(operatorSet.avs).NAME_COLORED(), + ", operatorSetId: ", + cheats.toString(operatorSet.id), + "}" + ) + ); + + allocationManager.deregisterFromOperatorSets( + DeregisterParams({ + operator: address(this), + avs: operatorSet.avs, + operatorSetIds: operatorSet.id.toArrayU32() + }) + ); + } + + function setAllocationDelay(uint32 delay) public virtual createSnapshot { + print.method("setAllocationDelay"); + allocationManager.setAllocationDelay(address(this), delay); + rollForward({blocks: allocationManager.ALLOCATION_CONFIGURATION_DELAY()}); + } + + /// ----------------------------------------------------------------------- + /// Delegation Manager Methods + /// ----------------------------------------------------------------------- + + uint32 withdrawalDelay = 1; + + function registerAsOperator() public virtual createSnapshot { + print.method("registerAsOperator"); + + delegationManager.registerAsOperator(address(0), withdrawalDelay, "metadata"); } /// @dev Delegate to the operator without a signature - function delegateTo(User operator) public createSnapshot virtual { - _logM("delegateTo", operator.NAME()); + function delegateTo( + User operator + ) public virtual createSnapshot { + print.method("delegateTo", operator.NAME_COLORED()); ISignatureUtils.SignatureWithExpiry memory emptySig; delegationManager.delegateTo(address(operator), emptySig, bytes32(0)); } /// @dev Undelegate from operator - function undelegate() public createSnapshot virtual returns(IDelegationManager.Withdrawal[] memory){ - _logM("undelegate"); + function undelegate() public virtual createSnapshot returns (Withdrawal[] memory) { + print.method("undelegate"); - IDelegationManager.Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(this)); + Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(this)); delegationManager.undelegate(address(this)); - for (uint i = 0; i < expectedWithdrawals.length; i++) { + for (uint256 i = 0; i < expectedWithdrawals.length; i++) { emit log("expecting withdrawal:"); emit log_named_uint("nonce: ", expectedWithdrawals[i].nonce); emit log_named_address("strat: ", address(expectedWithdrawals[i].strategies[0])); - emit log_named_uint("shares: ", expectedWithdrawals[i].shares[0]); + emit log_named_uint("shares: ", expectedWithdrawals[i].scaledShares[0]); } - + return expectedWithdrawals; } /// @dev Force undelegate staker - function forceUndelegate(User staker) public createSnapshot virtual returns(IDelegationManager.Withdrawal[] memory){ - _logM("forceUndelegate", staker.NAME()); + function forceUndelegate( + User staker + ) public virtual createSnapshot returns (Withdrawal[] memory) { + print.method("forceUndelegate", staker.NAME()); - IDelegationManager.Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(staker)); + Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(staker)); delegationManager.undelegate(address(staker)); return expectedWithdrawals; } /// @dev Queues a single withdrawal for every share and strategy pair function queueWithdrawals( - IStrategy[] memory strategies, - uint[] memory shares - ) public createSnapshot virtual returns (IDelegationManager.Withdrawal[] memory) { - _logM("queueWithdrawals"); + IStrategy[] memory strategies, + uint256[] memory depositShares + ) public virtual createSnapshot returns (Withdrawal[] memory) { + print.method("queueWithdrawals"); address operator = delegationManager.delegatedTo(address(this)); address withdrawer = address(this); - uint nonce = delegationManager.cumulativeWithdrawalsQueued(address(this)); + uint256 nonce = delegationManager.cumulativeWithdrawalsQueued(address(this)); // Create queueWithdrawals params - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - params[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategies, - shares: shares, - withdrawer: withdrawer - }); + QueuedWithdrawalParams[] memory params = new QueuedWithdrawalParams[](1); + params[0] = + QueuedWithdrawalParams({strategies: strategies, depositShares: depositShares, withdrawer: withdrawer}); // Create Withdrawal struct using same info - IDelegationManager.Withdrawal[] memory withdrawals = new IDelegationManager.Withdrawal[](1); - withdrawals[0] = IDelegationManager.Withdrawal({ + Withdrawal[] memory withdrawals = new Withdrawal[](1); + withdrawals[0] = Withdrawal({ staker: address(this), delegatedTo: operator, withdrawer: withdrawer, nonce: nonce, startBlock: uint32(block.number), strategies: strategies, - shares: shares + scaledShares: depositShares // TODO: convert depositShares to shares and then scale in withdrawal }); bytes32[] memory withdrawalRoots = delegationManager.queueWithdrawals(params); @@ -161,45 +254,53 @@ contract User is PrintUtils { return (withdrawals); } - function completeWithdrawalsAsTokens(IDelegationManager.Withdrawal[] memory withdrawals) public createSnapshot virtual returns (IERC20[][] memory) { - _logM("completeWithdrawalsAsTokens"); + function completeWithdrawalsAsTokens( + Withdrawal[] memory withdrawals + ) public virtual createSnapshot returns (IERC20[][] memory) { + print.method("completeWithdrawalsAsTokens"); IERC20[][] memory tokens = new IERC20[][](withdrawals.length); - for (uint i = 0; i < withdrawals.length; i++) { + for (uint256 i = 0; i < withdrawals.length; i++) { tokens[i] = _completeQueuedWithdrawal(withdrawals[i], true); } return tokens; } - - function completeWithdrawalAsTokens(IDelegationManager.Withdrawal memory withdrawal) public createSnapshot virtual returns (IERC20[] memory) { - _logM("completeWithdrawalsAsTokens"); + + function completeWithdrawalAsTokens( + Withdrawal memory withdrawal + ) public virtual createSnapshot returns (IERC20[] memory) { + print.method("completeWithdrawalsAsTokens"); return _completeQueuedWithdrawal(withdrawal, true); } - function completeWithdrawalsAsShares(IDelegationManager.Withdrawal[] memory withdrawals) public createSnapshot virtual returns (IERC20[][] memory) { - _logM("completeWithdrawalAsShares"); - + function completeWithdrawalsAsShares( + Withdrawal[] memory withdrawals + ) public virtual createSnapshot returns (IERC20[][] memory) { + print.method("completeWithdrawalAsShares"); + IERC20[][] memory tokens = new IERC20[][](withdrawals.length); - for (uint i = 0; i < withdrawals.length; i++) { + for (uint256 i = 0; i < withdrawals.length; i++) { tokens[i] = _completeQueuedWithdrawal(withdrawals[i], false); } return tokens; } - function completeWithdrawalAsShares(IDelegationManager.Withdrawal memory withdrawal) public createSnapshot virtual returns (IERC20[] memory) { - _logM("completeWithdrawalAsShares"); + function completeWithdrawalAsShares( + Withdrawal memory withdrawal + ) public virtual createSnapshot returns (IERC20[] memory) { + print.method("completeWithdrawalAsShares"); return _completeQueuedWithdrawal(withdrawal, false); } - /******************************************************************************* - BEACON CHAIN METHODS - *******************************************************************************/ + /// ----------------------------------------------------------------------- + /// Beacon Chain Methods + /// ----------------------------------------------------------------------- /// @dev Uses any ETH held by the User to start validators on the beacon chain /// @return A list of created validator indices @@ -207,44 +308,48 @@ contract User is PrintUtils { /// Note: If the user does not have enough ETH to start a validator, this method reverts /// Note: This method also advances one epoch forward on the beacon chain, so that /// withdrawal credential proofs are generated for each validator. - function startValidators() public createSnapshot virtual returns (uint40[] memory, uint64) { - _logM("startValidators"); + function startValidators() public virtual createSnapshot returns (uint40[] memory, uint64) { + print.method("startValidators"); return _startValidators(); } - function exitValidators(uint40[] memory _validators) public createSnapshot virtual returns (uint64 exitedBalanceGwei) { - _logM("exitValidators"); + function exitValidators( + uint40[] memory _validators + ) public virtual createSnapshot returns (uint64 exitedBalanceGwei) { + print.method("exitValidators"); return _exitValidators(_validators); } - /******************************************************************************* - EIGENPOD METHODS - *******************************************************************************/ + /// ----------------------------------------------------------------------- + /// Eigenpod Methods + /// ----------------------------------------------------------------------- function verifyWithdrawalCredentials( uint40[] memory _validators - ) public createSnapshot virtual { - _logM("verifyWithdrawalCredentials"); + ) public virtual createSnapshot { + print.method("verifyWithdrawalCredentials"); _verifyWithdrawalCredentials(_validators); } - function startCheckpoint() public createSnapshot virtual { - _logM("startCheckpoint"); + function startCheckpoint() public virtual createSnapshot { + print.method("startCheckpoint"); _startCheckpoint(); } - function completeCheckpoint() public createSnapshot virtual { - _logM("completeCheckpoint"); + function completeCheckpoint() public virtual createSnapshot { + print.method("completeCheckpoint"); _completeCheckpoint(); } - function verifyStaleBalance(uint40 validatorIndex) public createSnapshot virtual { - _logM("verifyStaleBalance"); + function verifyStaleBalance( + uint40 validatorIndex + ) public virtual createSnapshot { + print.method("verifyStaleBalance"); StaleBalanceProofs memory proof = beaconChain.getStaleBalanceProofs(validatorIndex); @@ -252,25 +357,28 @@ contract User is PrintUtils { beaconTimestamp: proof.beaconTimestamp, stateRootProof: proof.stateRootProof, proof: proof.validatorProof - }) { } catch (bytes memory err) { + }) {} catch (bytes memory err) { _revert(err); } } - /******************************************************************************* - STRATEGY METHODS - *******************************************************************************/ + /// ----------------------------------------------------------------------- + /// Strategy Methods + /// ----------------------------------------------------------------------- /// @dev For each strategy/token balance, call the relevant deposit method - function depositIntoEigenlayer(IStrategy[] memory strategies, uint[] memory tokenBalances) public createSnapshot virtual { - _logM("depositIntoEigenlayer"); + function depositIntoEigenlayer( + IStrategy[] memory strategies, + uint256[] memory tokenBalances + ) public virtual createSnapshot { + print.method("depositIntoEigenlayer"); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - uint tokenBalance = tokenBalances[i]; + uint256 tokenBalance = tokenBalances[i]; if (strat == BEACONCHAIN_ETH_STRAT) { - (uint40[] memory newValidators, ) = _startValidators(); + (uint40[] memory newValidators,) = _startValidators(); // Advance forward one epoch and generate credential and balance proofs for each validator beaconChain.advanceEpoch_NoRewards(); _verifyWithdrawalCredentials(newValidators); @@ -282,12 +390,12 @@ contract User is PrintUtils { } } - function updateBalances(IStrategy[] memory strategies, int[] memory tokenDeltas) public createSnapshot virtual { - _logM("updateBalances"); + function updateBalances(IStrategy[] memory strategies, int256[] memory tokenDeltas) public virtual createSnapshot { + print.method("updateBalances"); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - int delta = tokenDeltas[i]; + int256 delta = tokenDeltas[i]; if (strat == BEACONCHAIN_ETH_STRAT) { // If any balance update has occured, a checkpoint will pick it up @@ -296,7 +404,7 @@ contract User is PrintUtils { _completeCheckpoint(); } } else { - uint tokens = uint(delta); + uint256 tokens = uint256(delta); IERC20 underlyingToken = strat.underlyingToken(); underlyingToken.approve(address(strategyManager), tokens); strategyManager.depositIntoStrategy(strat, underlyingToken, tokens); @@ -304,17 +412,17 @@ contract User is PrintUtils { } } - /******************************************************************************* - INTERNAL METHODS - *******************************************************************************/ + /// ----------------------------------------------------------------------- + /// Internal Methods + /// ----------------------------------------------------------------------- function _completeQueuedWithdrawal( - IDelegationManager.Withdrawal memory withdrawal, + Withdrawal memory withdrawal, bool receiveAsTokens ) internal virtual returns (IERC20[] memory) { IERC20[] memory tokens = new IERC20[](withdrawal.strategies.length); - for (uint i = 0; i < tokens.length; i++) { + for (uint256 i = 0; i < tokens.length; i++) { IStrategy strat = withdrawal.strategies[i]; if (strat == BEACONCHAIN_ETH_STRAT) { @@ -323,8 +431,7 @@ contract User is PrintUtils { // If we're withdrawing native ETH as tokens, stop ALL validators // and complete a checkpoint if (receiveAsTokens) { - - _log("- exiting all validators and completing checkpoint"); + console.log("- exiting all validators and completing checkpoint"); _exitValidators(getActiveValidators()); beaconChain.advanceEpoch_NoRewards(); @@ -339,7 +446,7 @@ contract User is PrintUtils { } } - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0, receiveAsTokens); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); return tokens; } @@ -355,17 +462,17 @@ contract User is PrintUtils { /// Note: This method also advances one epoch forward on the beacon chain, so that /// withdrawal credential proofs are generated for each validator. function _startValidators() internal returns (uint40[] memory, uint64) { - uint balanceWei = address(this).balance; + uint256 balanceWei = address(this).balance; // Number of full validators: balance / 32 ETH - uint numValidators = balanceWei / 32 ether; + uint256 numValidators = balanceWei / 32 ether; balanceWei -= (numValidators * 32 ether); // If we still have at least 1 ETH left over, we can create another (non-full) validator // Note that in the mock beacon chain this validator will generate rewards like any other. // The main point is to ensure pods are able to handle validators that have less than 32 ETH - uint lastValidatorBalance; - uint totalValidators = numValidators; + uint256 lastValidatorBalance; + uint256 totalValidators = numValidators; if (balanceWei >= 1 ether) { lastValidatorBalance = balanceWei - (balanceWei % 1 gwei); balanceWei -= lastValidatorBalance; @@ -376,14 +483,12 @@ contract User is PrintUtils { uint40[] memory newValidators = new uint40[](totalValidators); uint64 totalBeaconBalanceGwei = uint64((address(this).balance - balanceWei) / GWEI_TO_WEI); - _log("- creating new validators", newValidators.length); - _log("- depositing balance to beacon chain (gwei)", totalBeaconBalanceGwei); + console.log("- creating new validators", newValidators.length); + console.log("- depositing balance to beacon chain (gwei)", totalBeaconBalanceGwei); // Create each of the full validators - for (uint i = 0; i < numValidators; i++) { - uint40 validatorIndex = beaconChain.newValidator{ - value: 32 ether - }(_podWithdrawalCredentials()); + for (uint256 i = 0; i < numValidators; i++) { + uint40 validatorIndex = beaconChain.newValidator{value: 32 ether}(_podWithdrawalCredentials()); newValidators[i] = validatorIndex; validators.push(validatorIndex); @@ -391,9 +496,7 @@ contract User is PrintUtils { // If we had a remainder, create the final, non-full validator if (totalValidators == numValidators + 1) { - uint40 validatorIndex = beaconChain.newValidator{ - value: lastValidatorBalance - }(_podWithdrawalCredentials()); + uint40 validatorIndex = beaconChain.newValidator{value: lastValidatorBalance}(_podWithdrawalCredentials()); newValidators[newValidators.length - 1] = validatorIndex; validators.push(validatorIndex); @@ -402,27 +505,31 @@ contract User is PrintUtils { return (newValidators, totalBeaconBalanceGwei); } - function _exitValidators(uint40[] memory _validators) internal returns (uint64 exitedBalanceGwei) { - _log("- exiting num validators", _validators.length); + function _exitValidators( + uint40[] memory _validators + ) internal returns (uint64 exitedBalanceGwei) { + console.log("- exiting num validators", _validators.length); - for (uint i = 0; i < _validators.length; i++) { + for (uint256 i = 0; i < _validators.length; i++) { exitedBalanceGwei += beaconChain.exitValidator(_validators[i]); } - _log("- exited balance to pod (gwei)", exitedBalanceGwei); + console.log("- exited balance to pod (gwei)", exitedBalanceGwei); return exitedBalanceGwei; } function _startCheckpoint() internal { - try pod.startCheckpoint(false) {} catch (bytes memory err) { + try pod.startCheckpoint(false) {} + catch (bytes memory err) { _revert(err); } } function _completeCheckpoint() internal { - _log("- active validator count", pod.activeValidatorCount()); - _log("- proofs remaining", pod.currentCheckpoint().proofsRemaining); + cheats.pauseTracing(); + console.log("- active validator count", pod.activeValidatorCount()); + console.log("- proofs remaining", pod.currentCheckpoint().proofsRemaining); uint64 checkpointTimestamp = pod.currentCheckpointTimestamp(); if (checkpointTimestamp == 0) { @@ -430,15 +537,16 @@ contract User is PrintUtils { } CheckpointProofs memory proofs = beaconChain.getCheckpointProofs(validators, checkpointTimestamp); - _log("- submitting num checkpoint proofs", proofs.balanceProofs.length); + console.log("- submitting num checkpoint proofs", proofs.balanceProofs.length); - pod.verifyCheckpointProofs({ - balanceContainerProof: proofs.balanceContainerProof, - proofs: proofs.balanceProofs - }); + pod.verifyCheckpointProofs({balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs}); + cheats.resumeTracing(); } - function _verifyWithdrawalCredentials(uint40[] memory _validators) internal { + function _verifyWithdrawalCredentials( + uint40[] memory _validators + ) internal { + cheats.pauseTracing(); CredentialProofs memory proofs = beaconChain.getCredentialProofs(_validators); try pod.verifyWithdrawalCredentials({ @@ -447,15 +555,20 @@ contract User is PrintUtils { validatorIndices: _validators, validatorFieldsProofs: proofs.validatorFieldsProofs, validatorFields: proofs.validatorFields - }) { } catch (bytes memory err) { - _revert(err); + }) {} catch (bytes memory err) { + _revert(err); } + cheats.resumeTracing(); } /// @dev Revert, passing through an error message - function _revert(bytes memory err) internal pure { + function _revert( + bytes memory err + ) internal pure { if (err.length != 0) { - assembly { revert(add(32, err), mload(err)) } + assembly { + revert(add(32, err), mload(err)) + } } revert("reverted with unknown error"); } @@ -466,27 +579,28 @@ contract User is PrintUtils { /// @notice Gets the expected withdrawals to be created when the staker is undelegated via a call to `DelegationManager.undelegate()` /// @notice Assumes staker and withdrawer are the same and that all strategies and shares are withdrawn - function _getExpectedWithdrawalStructsForStaker(address staker) internal view returns (IDelegationManager.Withdrawal[] memory) { - (IStrategy[] memory strategies, uint256[] memory shares) - = delegationManager.getDelegatableShares(staker); + function _getExpectedWithdrawalStructsForStaker( + address staker + ) internal view returns (Withdrawal[] memory) { + (IStrategy[] memory strategies, uint256[] memory shares) = delegationManager.getDepositedShares(staker); - IDelegationManager.Withdrawal[] memory expectedWithdrawals = new IDelegationManager.Withdrawal[](strategies.length); + Withdrawal[] memory expectedWithdrawals = new Withdrawal[](strategies.length); address delegatedTo = delegationManager.delegatedTo(staker); uint256 nonce = delegationManager.cumulativeWithdrawalsQueued(staker); - + for (uint256 i = 0; i < strategies.length; ++i) { IStrategy[] memory singleStrategy = new IStrategy[](1); uint256[] memory singleShares = new uint256[](1); singleStrategy[0] = strategies[i]; singleShares[0] = shares[i]; - expectedWithdrawals[i] = IDelegationManager.Withdrawal({ + expectedWithdrawals[i] = Withdrawal({ staker: staker, delegatedTo: delegatedTo, withdrawer: staker, nonce: (nonce + i), startBlock: uint32(block.number), strategies: singleStrategy, - shares: singleShares + scaledShares: singleShares }); } @@ -496,9 +610,9 @@ contract User is PrintUtils { function getActiveValidators() public view returns (uint40[] memory) { uint40[] memory activeValidators = new uint40[](validators.length); - uint numActive; - uint pos; - for(uint i = 0; i < validators.length; i++) { + uint256 numActive; + uint256 pos; + for (uint256 i = 0; i < validators.length; i++) { if (beaconChain.isActive(validators[i])) { activeValidators[pos] = validators[i]; numActive++; @@ -507,7 +621,9 @@ contract User is PrintUtils { } // Manually update length - assembly { mstore(activeValidators, numActive) } + assembly { + mstore(activeValidators, numActive) + } return activeValidators; } @@ -515,44 +631,25 @@ contract User is PrintUtils { /// @notice A user contract that calls nonstandard methods (like xBySignature methods) contract User_AltMethods is User { - mapping(bytes32 => bool) public signedHashes; - constructor(string memory name) User(name) {} - - function delegateTo(User operator) public createSnapshot override { - _logM("delegateTo_ALT", operator.NAME()); - - // Create empty data - ISignatureUtils.SignatureWithExpiry memory emptySig; - uint256 expiry = type(uint256).max; - - // Get signature - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry; - stakerSignatureAndExpiry.expiry = expiry; - bytes32 digestHash = delegationManager.calculateCurrentStakerDelegationDigestHash(address(this), address(operator), expiry); - stakerSignatureAndExpiry.signature = bytes(abi.encodePacked(digestHash)); // dummy sig data + constructor( + string memory name + ) User(name) {} - // Mark hash as signed - signedHashes[digestHash] = true; + function depositIntoEigenlayer( + IStrategy[] memory strategies, + uint256[] memory tokenBalances + ) public override createSnapshot { + print.method("depositIntoEigenlayer_ALT"); - // Delegate - delegationManager.delegateToBySignature(address(this), address(operator), stakerSignatureAndExpiry, emptySig, bytes32(0)); - - // Mark hash as used - signedHashes[digestHash] = false; - } - - function depositIntoEigenlayer(IStrategy[] memory strategies, uint[] memory tokenBalances) public createSnapshot override { - _logM("depositIntoEigenlayer_ALT"); - uint256 expiry = type(uint256).max; - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - uint tokenBalance = tokenBalances[i]; + uint256 tokenBalance = tokenBalances[i]; if (strat == BEACONCHAIN_ETH_STRAT) { - (uint40[] memory newValidators, ) = _startValidators(); + (uint40[] memory newValidators,) = _startValidators(); // Advance forward one epoch and generate credential and balance proofs for each validator beaconChain.advanceEpoch_NoRewards(); _verifyWithdrawalCredentials(newValidators); @@ -564,9 +661,18 @@ contract User_AltMethods is User { // Get signature uint256 nonceBefore = strategyManager.nonces(address(this)); bytes32 structHash = keccak256( - abi.encode(strategyManager.DEPOSIT_TYPEHASH(), address(this), strat, underlyingToken, tokenBalance, nonceBefore, expiry) + abi.encode( + strategyManager.DEPOSIT_TYPEHASH(), + address(this), + strat, + underlyingToken, + tokenBalance, + nonceBefore, + expiry + ) ); - bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", strategyManager.domainSeparator(), structHash)); + bytes32 digestHash = + keccak256(abi.encodePacked("\x19\x01", strategyManager.domainSeparator(), structHash)); bytes memory signature = bytes(abi.encodePacked(digestHash)); // dummy sig data // Mark hash as signed @@ -574,12 +680,7 @@ contract User_AltMethods is User { // Deposit strategyManager.depositIntoStrategyWithSignature( - strat, - underlyingToken, - tokenBalance, - address(this), - expiry, - signature + strat, underlyingToken, tokenBalance, address(this), expiry, signature ); // Mark hash as used @@ -587,13 +688,14 @@ contract User_AltMethods is User { } } } - + bytes4 internal constant MAGIC_VALUE = 0x1626ba7e; + function isValidSignature(bytes32 hash, bytes memory) external view returns (bytes4) { - if(signedHashes[hash]){ + if (signedHashes[hash]) { return MAGIC_VALUE; } else { return 0xffffffff; } - } + } } diff --git a/src/test/integration/users/User_M1.t.sol b/src/test/integration/users/User_M1.t.sol index 3f914cfaf..1652adeae 100644 --- a/src/test/integration/users/User_M1.t.sol +++ b/src/test/integration/users/User_M1.t.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol"; import "src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol"; import "src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol"; import "src/test/integration/users/User.t.sol"; +import "src/contracts/mixins/SignatureUtils.sol"; interface IUserMainnetForkDeployer { function delegationManager() external view returns (DelegationManager); @@ -41,7 +42,7 @@ contract User_M1 is User { IStrategy[] memory strategies, uint256[] memory tokenBalances ) public virtual createSnapshot { - _logM("depositIntoEigenlayer_M1"); + print.method("depositIntoEigenlayer_M1"); for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; @@ -68,6 +69,11 @@ contract User_M1 is User { } contract User_M1_AltMethods is User_M1 { + /// @notice The EIP-712 typehash for the contract's domain. + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + + mapping(bytes32 => bool) public signedHashes; constructor(string memory name) User_M1(name) {} @@ -76,7 +82,7 @@ contract User_M1_AltMethods is User_M1 { IStrategy[] memory strategies, uint256[] memory tokenBalances ) public override createSnapshot { - _logM(".depositIntoEigenlayer_M1_ALT"); + print.method(".depositIntoEigenlayer_M1_ALT"); uint256 expiry = type(uint256).max; for (uint256 i = 0; i < strategies.length; i++) { @@ -103,7 +109,7 @@ contract User_M1_AltMethods is User_M1 { expiry ) ); - bytes32 domain_separator = keccak256(abi.encode(strategyManager.DOMAIN_TYPEHASH(), keccak256(bytes("EigenLayer")), block.chainid, address(strategyManager))); + bytes32 domain_separator = strategyManager.domainSeparator(); bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", domain_separator, structHash)); bytes memory signature = bytes(abi.encodePacked(digestHash)); // dummy sig data diff --git a/src/test/integration/utils/PrintUtils.t.sol b/src/test/integration/utils/PrintUtils.t.sol deleted file mode 100644 index c80dd42ff..000000000 --- a/src/test/integration/utils/PrintUtils.t.sol +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "forge-std/Test.sol"; - -import "@openzeppelin/contracts/utils/Strings.sol"; - -abstract contract PrintUtils is Test { - - using Strings for *; - using StdStyle for *; - - string constant HEADER_DELIMITER = "=================================================="; - string constant SECTION_DELIMITER = "======"; - - /// @dev Inheriting contracts implement this method - function NAME() public virtual view returns (string memory); - - function _logHeader(string memory key) internal { - emit log(HEADER_DELIMITER); - - emit log(key); - - emit log(HEADER_DELIMITER); - } - - function _logHeader(string memory key, address a) internal { - emit log(HEADER_DELIMITER); - - emit log_named_string(key.cyan(), a.yellow()); - // emit log_named_address(key.cyan(), a); - - emit log(HEADER_DELIMITER); - } - - function _logSection(string memory key) internal { - emit log(string.concat( - SECTION_DELIMITER, - key, - SECTION_DELIMITER - )); - } - - function _logSection(string memory key, address a) internal { - emit log(string.concat( - SECTION_DELIMITER, - key.cyan(), - ": ", - a.yellow().dim(), - SECTION_DELIMITER - )); - } - - function _logAction(string memory key, string memory action) internal { - emit log_named_string( - key.cyan(), - action.italic() - ); - } - - /// @dev Log method name - function _logM(string memory method) internal { - emit log(string.concat( - NAME().cyan(), - ".", - method.italic() - )); - } - - function _logM(string memory method, string memory arg) internal { - emit log(string.concat( - NAME().cyan(), - ".", - method.italic(), - ":", - arg - )); - } - - function _log(string memory s) internal { - emit log(s); - } - - function _logGreen(string memory s) internal { - emit log(s.green()); - } - - function _logGreen(string memory s, string memory value) internal { - emit log_named_string(s, value.green()); - } - - function _logYellow(string memory s, string memory value) internal { - emit log_named_string(s, value.yellow()); - } - - function _log(string memory key, string memory value) internal { - emit log_named_string(key, value); - } - - function _log(string memory key, uint value) internal { - emit log_named_uint(key, value); - } - - function _log(string memory key, address value) internal { - emit log_named_string(key, value.yellow()); - } - - function _logDim(string memory key, address value) internal { - emit log_named_string(key.dim(), value.yellow().dim()); - } - - function _log(string memory key, bytes32 value) internal { - emit log_named_string(key, value.dimBytes32()); - } - - function _log(string memory key, bool value) internal { - emit log_named_string(key, value ? "true".green() : "false".magenta()); - } -} \ No newline at end of file diff --git a/src/test/mocks/AVSDirectoryMock.sol b/src/test/mocks/AVSDirectoryMock.sol new file mode 100644 index 000000000..8179ecf86 --- /dev/null +++ b/src/test/mocks/AVSDirectoryMock.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.9; + +import "forge-std/Test.sol"; +import "src/contracts/interfaces/IAVSDirectory.sol"; +import "src/contracts/libraries/OperatorSetLib.sol"; + +contract AVSDirectoryMock is Test { + receive() external payable {} + fallback() external payable {} +} \ No newline at end of file diff --git a/src/test/mocks/AllocationManagerMock.sol b/src/test/mocks/AllocationManagerMock.sol new file mode 100644 index 000000000..9ccb063a0 --- /dev/null +++ b/src/test/mocks/AllocationManagerMock.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.9; + +import "forge-std/Test.sol"; +import "../../contracts/interfaces/IStrategy.sol"; +import "../../contracts/libraries/Snapshots.sol"; + +contract AllocationManagerMock is Test { + using Snapshots for Snapshots.DefaultWadHistory; + + receive() external payable {} + fallback() external payable {} + + mapping(address avs => uint256) public getOperatorSetCount; + mapping(address => mapping(IStrategy => Snapshots.DefaultWadHistory)) internal _maxMagnitudeHistory; + + function setMaxMagnitudes( + address operator, + IStrategy[] calldata strategies, + uint64[] calldata maxMagnitudes + ) external { + for (uint256 i = 0; i < strategies.length; ++i) { + setMaxMagnitude(operator, strategies[i], maxMagnitudes[i]); + } + } + + function setMaxMagnitude( + address operator, + IStrategy strategy, + uint64 maxMagnitude + ) public { + _maxMagnitudeHistory[operator][strategy].push({ + key: uint32(block.number), + value: maxMagnitude + }); + } + + function getMaxMagnitude( + address operator, + IStrategy strategy + ) external view returns (uint64) { + return _maxMagnitudeHistory[operator][strategy].latest(); + } + + function getMaxMagnitudes( + address operator, + IStrategy[] calldata strategies + ) external view returns (uint64[] memory) { + uint64[] memory maxMagnitudes = new uint64[](strategies.length); + + for (uint256 i = 0; i < strategies.length; ++i) { + maxMagnitudes[i] = _maxMagnitudeHistory[operator][strategies[i]].latest(); + } + + return maxMagnitudes; + } + + function getMaxMagnitudesAtBlock( + address operator, + IStrategy[] calldata strategies, + uint32 blockNumber + ) external view returns (uint64[] memory) { + uint64[] memory maxMagnitudes = new uint64[](strategies.length); + + for (uint256 i = 0; i < strategies.length; ++i) { + maxMagnitudes[i] = _maxMagnitudeHistory[operator][strategies[i]].upperLookup({ + key: blockNumber + }); + } + + return maxMagnitudes; + } + + function setAVSSetCount(address avs, uint256 numSets) external { + getOperatorSetCount[avs] = numSets; + } +} \ No newline at end of file diff --git a/src/test/mocks/DelegationManagerMock.sol b/src/test/mocks/DelegationManagerMock.sol index 7facde3a0..771c4e502 100644 --- a/src/test/mocks/DelegationManagerMock.sol +++ b/src/test/mocks/DelegationManagerMock.sol @@ -1,13 +1,18 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; -import "../../contracts/interfaces/IDelegationManager.sol"; -import "../../contracts/interfaces/IStrategyManager.sol"; +import "src/contracts/interfaces/IDelegationManager.sol"; +import "src/contracts/interfaces/IStrategyManager.sol"; +import "src/contracts/libraries/SlashingLib.sol"; + +contract DelegationManagerMock is Test { + receive() external payable {} + fallback() external payable {} -contract DelegationManagerMock is IDelegationManager, Test { mapping(address => bool) public isOperator; + mapping (address => address) public delegatedTo; mapping(address => mapping(IStrategy => uint256)) public operatorShares; function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory) {} @@ -20,158 +25,66 @@ contract DelegationManagerMock is IDelegationManager, Test { isOperator[operator] = _isOperatorReturnValue; } + function burnOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external { + uint256 amountSlashed = SlashingLib.calcSlashedAmount({ + operatorShares: operatorShares[operator][strategy], + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + + operatorShares[operator][strategy] -= amountSlashed; + } + /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. function setOperatorShares(address operator, IStrategy strategy, uint256 shares) external { operatorShares[operator][strategy] = shares; } - mapping (address => address) public delegatedTo; - - function registerAsOperator(OperatorDetails calldata /*registeringOperatorDetails*/, string calldata /*metadataURI*/) external pure {} - - function updateOperatorMetadataURI(string calldata /*metadataURI*/) external pure {} - - function updateAVSMetadataURI(string calldata /*metadataURI*/) external pure {} + /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. + function setOperatorsShares(address operator, IStrategy[] memory strategies, uint256 shares) external { + for (uint i = 0; i < strategies.length; i++) { + operatorShares[operator][strategies[i]] = shares; + } + } - function delegateTo(address operator, SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { + function delegateTo(address operator, ISignatureUtils.SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { delegatedTo[msg.sender] = operator; } - function modifyOperatorDetails(OperatorDetails calldata /*newOperatorDetails*/) external pure {} - - function delegateToBySignature( - address /*staker*/, - address /*operator*/, - SignatureWithExpiry memory /*stakerSignatureAndExpiry*/, - SignatureWithExpiry memory /*approverSignatureAndExpiry*/, - bytes32 /*approverSalt*/ - ) external pure {} - function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot) { delegatedTo[staker] = address(0); return withdrawalRoot; } - function increaseDelegatedShares(address /*staker*/, IStrategy /*strategy*/, uint256 /*shares*/) external pure {} - - function decreaseDelegatedShares( - address /*staker*/, - IStrategy /*strategy*/, - uint256 /*shares*/ - ) external pure {} + function getOperatorsShares(address[] memory operators, IStrategy[] memory strategies) external view returns (uint256[][] memory) { + uint256[][] memory operatorSharesArray = new uint256[][](operators.length); + for (uint256 i = 0; i < operators.length; i++) { + operatorSharesArray[i] = new uint256[](strategies.length); + for (uint256 j = 0; j < strategies.length; j++) { + operatorSharesArray[i][j] = operatorShares[operators[i]][strategies[j]]; + } + } + return operatorSharesArray; + } - function operatorDetails(address operator) external pure returns (OperatorDetails memory) { - OperatorDetails memory returnValue = OperatorDetails({ + function operatorDetails(address operator) external pure returns (IDelegationManagerTypes.OperatorDetails memory) { + IDelegationManagerTypes.OperatorDetails memory returnValue = IDelegationManagerTypes.OperatorDetails({ __deprecated_earningsReceiver: operator, delegationApprover: operator, - stakerOptOutWindowBlocks: 0 + __deprecated_stakerOptOutWindowBlocks: 0 }); return returnValue; } - - function delegationApprover(address operator) external pure returns (address) { - return operator; - } - - function stakerOptOutWindowBlocks(address /*operator*/) external pure returns (uint256) { - return 0; - } - - function minWithdrawalDelayBlocks() external pure returns (uint256) { - return 0; - } - - /// @notice return address of the beaconChainETHStrategy - function beaconChainETHStrategy() external view returns (IStrategy) {} - - /** - * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). - */ - function strategyWithdrawalDelayBlocks(IStrategy /*strategy*/) external pure returns (uint256) { - return 0; - } - function getOperatorShares( - address operator, - IStrategy[] memory strategies - ) external view returns (uint256[] memory) {} - - function getWithdrawalDelay(IStrategy[] calldata /*strategies*/) public pure returns (uint256) { - return 0; - } - function isDelegated(address staker) external view returns (bool) { return (delegatedTo[staker] != address(0)); } - function isNotDelegated(address /*staker*/) external pure returns (bool) {} - - // function isOperator(address /*operator*/) external pure returns (bool) {} - - function stakerNonce(address /*staker*/) external pure returns (uint256) {} - - function delegationApproverSaltIsSpent(address /*delegationApprover*/, bytes32 /*salt*/) external pure returns (bool) {} - - function calculateCurrentStakerDelegationDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} - - function calculateStakerDelegationDigestHash(address /*staker*/, uint256 /*stakerNonce*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} - - function calculateDelegationApprovalDigestHash( - address /*staker*/, - address /*operator*/, - address /*_delegationApprover*/, - bytes32 /*approverSalt*/, - uint256 /*expiry*/ - ) external view returns (bytes32) {} - - function calculateStakerDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) - external pure returns (bytes32 stakerDigestHash) {} - - function calculateApproverDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) - external pure returns (bytes32 approverDigestHash) {} - - function calculateOperatorAVSRegistrationDigestHash(address /*operator*/, address /*avs*/, bytes32 /*salt*/, uint256 /*expiry*/) - external pure returns (bytes32 digestHash) {} - - function DOMAIN_TYPEHASH() external view returns (bytes32) {} - - function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32) {} - - function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32) {} - - function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} - - function cumulativeWithdrawalsQueued(address staker) external view returns (uint256) {} - - function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32) {} - - function registerOperatorToAVS(address operator, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature) external {} - - function deregisterOperatorFromAVS(address operator) external {} - - function operatorSaltIsSpent(address avs, bytes32 salt) external view returns (bool) {} - - function domainSeparator() external view returns (bytes32) {} - - function queueWithdrawals( - QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes32[] memory) {} - - function completeQueuedWithdrawal( - Withdrawal calldata withdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external {} - - function completeQueuedWithdrawals( - Withdrawal[] calldata withdrawals, - IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, - bool[] calldata receiveAsTokens - ) external {} - // onlyDelegationManager functions in StrategyManager function addShares( IStrategyManager strategyManager, @@ -180,16 +93,16 @@ contract DelegationManagerMock is IDelegationManager, Test { IStrategy strategy, uint256 shares ) external { - strategyManager.addShares(staker, token, strategy, shares); + strategyManager.addShares(staker, strategy, token, shares); } - function removeShares( + function removeDepositShares( IStrategyManager strategyManager, address staker, IStrategy strategy, uint256 shares ) external { - strategyManager.removeShares(staker, strategy, shares); + strategyManager.removeDepositShares(staker, strategy, shares); } function withdrawSharesAsTokens( @@ -199,6 +112,6 @@ contract DelegationManagerMock is IDelegationManager, Test { uint256 shares, IERC20 token ) external { - strategyManager.withdrawSharesAsTokens(recipient, strategy, shares, token); + strategyManager.withdrawSharesAsTokens(recipient, strategy, token, shares); } } diff --git a/src/test/mocks/Dummy.sol b/src/test/mocks/Dummy.sol index 79160b45f..6990c4e26 100644 --- a/src/test/mocks/Dummy.sol +++ b/src/test/mocks/Dummy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; contract EmptyContract { function foo() public pure returns (uint256) { diff --git a/src/test/mocks/ERC20Mock.sol b/src/test/mocks/ERC20Mock.sol index 5e02b68e8..ca0e4f677 100644 --- a/src/test/mocks/ERC20Mock.sol +++ b/src/test/mocks/ERC20Mock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/interfaces/IERC20.sol"; import "@openzeppelin/contracts/utils/Context.sol"; diff --git a/src/test/mocks/ERC20_OneWeiFeeOnTransfer.sol b/src/test/mocks/ERC20_OneWeiFeeOnTransfer.sol index 173acf69b..7606b2a31 100644 --- a/src/test/mocks/ERC20_OneWeiFeeOnTransfer.sol +++ b/src/test/mocks/ERC20_OneWeiFeeOnTransfer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; // copy-pasted OZ code with _balances mapping made *internal* instead of private diff --git a/src/test/mocks/ERC20_SetTransferReverting_Mock.sol b/src/test/mocks/ERC20_SetTransferReverting_Mock.sol index dd12a7fd3..70230a464 100644 --- a/src/test/mocks/ERC20_SetTransferReverting_Mock.sol +++ b/src/test/mocks/ERC20_SetTransferReverting_Mock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; diff --git a/src/test/mocks/ETHDepositMock.sol b/src/test/mocks/ETHDepositMock.sol index 8b8841974..8ad2ee0d5 100644 --- a/src/test/mocks/ETHDepositMock.sol +++ b/src/test/mocks/ETHDepositMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../contracts/interfaces/IETHPOSDeposit.sol"; diff --git a/src/test/mocks/EigenPodManagerMock.sol b/src/test/mocks/EigenPodManagerMock.sol index 127fcc49a..5bac4aba1 100644 --- a/src/test/mocks/EigenPodManagerMock.sol +++ b/src/test/mocks/EigenPodManagerMock.sol @@ -2,69 +2,76 @@ pragma solidity ^0.8.9; import "forge-std/Test.sol"; -import "../../contracts/interfaces/IEigenPodManager.sol"; +import "../../contracts/interfaces/IStrategy.sol"; import "../../contracts/permissions/Pausable.sol"; +contract EigenPodManagerMock is Test, Pausable { + receive() external payable {} + fallback() external payable {} -contract EigenPodManagerMock is IEigenPodManager, Test, Pausable { - IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - IBeacon public eigenPodBeacon; - IETHPOSDeposit public ethPOS; + mapping(address => int256) public podOwnerDepositShares; - mapping(address => int256) public podShares; + mapping(address => uint256) public podOwnerSharesWithdrawn; - constructor(IPauserRegistry _pauserRegistry) { - _initializePauser(_pauserRegistry, 0); + struct BeaconChainSlashingFactor { + bool isSet; + uint64 slashingFactor; } - function slasher() external view returns(ISlasher) {} + mapping(address => BeaconChainSlashingFactor) _beaconChainSlashingFactor; - function createPod() external returns(address) {} + constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { + _setPausedStatus(0); + } - function stake(bytes calldata /*pubkey*/, bytes calldata /*signature*/, bytes32 /*depositDataRoot*/) external payable {} + function podOwnerShares(address podOwner) external view returns (int256) { + return podOwnerDepositShares[podOwner]; + } - function recordBeaconChainETHBalanceUpdate(address /*podOwner*/, int256 /*sharesDelta*/) external pure {} + function stakerDepositShares(address user, address) public view returns (uint256 depositShares) { + return podOwnerDepositShares[user] < 0 ? 0 : uint256(podOwnerDepositShares[user]); + } - function ownerToPod(address /*podOwner*/) external pure returns(IEigenPod) { - return IEigenPod(address(0)); + function setPodOwnerShares(address podOwner, int256 shares) external { + podOwnerDepositShares[podOwner] = shares; } - function getPod(address podOwner) external pure returns(IEigenPod) { - return IEigenPod(podOwner); + function addShares( + address podOwner, + IStrategy, + IERC20, + uint256 shares + ) external returns (uint256 existingDepositShares, uint256 newDepositShares) { + existingDepositShares = uint256(podOwnerDepositShares[podOwner]); + podOwnerDepositShares[podOwner] += int256(shares); + newDepositShares = uint256(podOwnerDepositShares[podOwner]); } - function strategyManager() external pure returns(IStrategyManager) { - return IStrategyManager(address(0)); - } - - function hasPod(address /*podOwner*/) external pure returns (bool) { - return false; + function removeDepositShares( + address podOwner, + IStrategy, // strategy + uint256 shares + ) external { + podOwnerDepositShares[podOwner] -= int256(shares); } - function podOwnerShares(address podOwner) external view returns (int256) { - return podShares[podOwner]; + function denebForkTimestamp() external pure returns (uint64) { + return type(uint64).max; } - function setPodOwnerShares(address podOwner, int256 shares) external { - podShares[podOwner] = shares; + function withdrawSharesAsTokens(address podOwner, address /** strategy */, address /** token */, uint256 shares) external { + podOwnerSharesWithdrawn[podOwner] += shares; } - function addShares(address /*podOwner*/, uint256 shares) external pure returns (uint256) { - // this is the "increase in delegateable tokens" - return (shares); + function setBeaconChainSlashingFactor(address staker, uint64 bcsf) external { + _beaconChainSlashingFactor[staker] = BeaconChainSlashingFactor({ + isSet: true, + slashingFactor: bcsf + }); } - function withdrawSharesAsTokens(address podOwner, address destination, uint256 shares) external {} - - function removeShares(address podOwner, uint256 shares) external {} - - function numPods() external view returns (uint256) {} - - function updateStaleValidatorCount(address, int256) external {} - - function denebForkTimestamp() external pure returns (uint64) { - return type(uint64).max; + function beaconChainSlashingFactor(address staker) external view returns (uint64) { + BeaconChainSlashingFactor memory bsf = _beaconChainSlashingFactor[staker]; + return bsf.isSet ? bsf.slashingFactor : WAD; } - - function setDenebForkTimestamp(uint64 timestamp) external{} } \ No newline at end of file diff --git a/src/test/mocks/EmptyContract.sol b/src/test/mocks/EmptyContract.sol index 79160b45f..6990c4e26 100644 --- a/src/test/mocks/EmptyContract.sol +++ b/src/test/mocks/EmptyContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; contract EmptyContract { function foo() public pure returns (uint256) { diff --git a/src/test/mocks/MockAVSRegistrar.sol b/src/test/mocks/MockAVSRegistrar.sol new file mode 100644 index 000000000..1135d0743 --- /dev/null +++ b/src/test/mocks/MockAVSRegistrar.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +contract MockAVSRegistrar { + fallback () external {} +} \ No newline at end of file diff --git a/src/test/mocks/MockDecimals.sol b/src/test/mocks/MockDecimals.sol index 6f5afc44c..e450fdd5b 100644 --- a/src/test/mocks/MockDecimals.sol +++ b/src/test/mocks/MockDecimals.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; contract MockDecimals { function decimals() public pure returns (uint8) { diff --git a/src/test/mocks/OwnableMock.sol b/src/test/mocks/OwnableMock.sol index 11ba5c53f..48abf590a 100644 --- a/src/test/mocks/OwnableMock.sol +++ b/src/test/mocks/OwnableMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/src/test/mocks/SlasherMock.sol b/src/test/mocks/SlasherMock.sol deleted file mode 100644 index 6524fc466..000000000 --- a/src/test/mocks/SlasherMock.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "forge-std/Test.sol"; -import "../../contracts/interfaces/ISlasher.sol"; - - -contract SlasherMock is ISlasher, Test { - - mapping(address => bool) public isFrozen; - bool public _canWithdraw = true; - IStrategyManager public strategyManager; - IDelegationManager public delegation; - - function setCanWithdrawResponse(bool response) external { - _canWithdraw = response; - } - - function setOperatorFrozenStatus(address operator, bool status) external{ - isFrozen[operator] = status; - } - - function freezeOperator(address toBeFrozen) external { - isFrozen[toBeFrozen] = true; - } - - function optIntoSlashing(address contractAddress) external{} - - function resetFrozenStatus(address[] calldata frozenAddresses) external{} - - function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external{} - - function recordStakeUpdate(address operator, uint32 updateBlock, uint32 serveUntilBlock, uint256 insertAfter) external{} - - function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external{} - - /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`. - function canSlash(address toBeSlashed, address slashingContract) external view returns (bool) {} - - /// @notice Returns the UTC timestamp until which `serviceContract` is allowed to slash the `operator`. - function contractCanSlashOperatorUntilBlock(address operator, address serviceContract) external view returns (uint32) {} - - /// @notice Returns the block at which the `serviceContract` last updated its view of the `operator`'s stake - function latestUpdateBlock(address operator, address serviceContract) external view returns (uint32) {} - - /// @notice A search routine for finding the correct input value of `insertAfter` to `recordStakeUpdate` / `_updateMiddlewareList`. - function getCorrectValueForInsertAfter(address operator, uint32 updateBlock) external view returns (uint256) {} - - function canWithdraw(address /*operator*/, uint32 /*withdrawalStartBlock*/, uint256 /*middlewareTimesIndex*/) external view returns(bool) { - return _canWithdraw; - } - - /** - * operator => - * [ - * ( - * the least recent update block of all of the middlewares it's serving/served, - * latest time that the stake bonded at that update needed to serve until - * ) - * ] - */ - function operatorToMiddlewareTimes(address operator, uint256 arrayIndex) external view returns (MiddlewareTimes memory) {} - - /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length` - function middlewareTimesLength(address operator) external view returns (uint256) {} - - /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`. - function getMiddlewareTimesIndexStalestUpdateBlock(address operator, uint32 index) external view returns(uint32) {} - - /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].latestServeUntilBlock`. - function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns(uint32) {} - - /// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`. - function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256) {} - - /// @notice Getter function for fetching a single node in the operator's linked list (`_operatorToWhitelistedContractsByUpdate[operator]`). - function operatorWhitelistedContractsLinkedListEntry(address operator, address node) external view returns (bool, uint256, uint256) {} -} diff --git a/src/test/mocks/StrategyManagerMock.sol b/src/test/mocks/StrategyManagerMock.sol index 4a5f39cb2..e0e2cdb07 100644 --- a/src/test/mocks/StrategyManagerMock.sol +++ b/src/test/mocks/StrategyManagerMock.sol @@ -1,75 +1,28 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; -import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; -import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "../../contracts/permissions/Pausable.sol"; -import "../../contracts/core/StrategyManagerStorage.sol"; -import "../../contracts/interfaces/IEigenPodManager.sol"; -import "../../contracts/interfaces/IDelegationManager.sol"; - -// import "forge-std/Test.sol"; +pragma solidity ^0.8.27; -contract StrategyManagerMock is - Initializable, - IStrategyManager, - OwnableUpgradeable, - ReentrancyGuardUpgradeable, - Pausable - // ,Test -{ +import "forge-std/Test.sol"; +import "../../contracts/interfaces/IDelegationManager.sol"; +contract StrategyManagerMock is Test { IDelegationManager public delegation; - IEigenPodManager public eigenPodManager; - ISlasher public slasher; address public strategyWhitelister; mapping(address => IStrategy[]) public strategiesToReturn; mapping(address => uint256[]) public sharesToReturn; + /// @notice Mapping staker => strategy => shares withdrawn after a withdrawal has been completed + mapping(address => mapping(IStrategy => uint256)) public strategySharesWithdrawn; + mapping(IStrategy => bool) public strategyIsWhitelistedForDeposit; /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. only increments (doesn't decrement) mapping(address => uint256) public cumulativeWithdrawalsQueued; - - mapping(IStrategy => bool) public thirdPartyTransfersForbidden; - - function setAddresses(IDelegationManager _delegation, IEigenPodManager _eigenPodManager, ISlasher _slasher) external - { - delegation = _delegation; - slasher = _slasher; - eigenPodManager = _eigenPodManager; - } - - function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) - external - returns (uint256) {} - - - function depositBeaconChainETH(address staker, uint256 amount) external{} - - - function recordBeaconChainETHBalanceUpdate(address overcommittedPodOwner, uint256 beaconChainETHStrategyIndex, int256 sharesDelta) - external{} - - function setStrategyWhitelister(address newStrategyWhitelister) external {} - function depositIntoStrategyWithSignature( - IStrategy strategy, - IERC20 token, - uint256 amount, - address staker, - uint256 expiry, - bytes memory signature - ) - external - returns (uint256 shares) {} - - /// @notice Returns the current shares of `user` in `strategy` - function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares) {} + constructor(IDelegationManager _delegation) { + delegation = _delegation; + } /** * @notice mocks the return value of getDeposits @@ -83,9 +36,13 @@ contract StrategyManagerMock is sharesToReturn[staker] = _sharesToReturn; } - function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external { - emit UpdatedThirdPartyTransfersForbidden(strategy, value); - thirdPartyTransfersForbidden[strategy] = value; + /** + * @notice Adds deposit to the staker's deposits. Note that this function does not check if the staker + * has already deposited for the strategy. + */ + function addDeposit(address staker, IStrategy strategy, uint256 shares) external { + strategiesToReturn[staker].push(strategy); + sharesToReturn[staker].push(shares); } /** @@ -96,10 +53,13 @@ contract StrategyManagerMock is return (strategiesToReturn[staker], sharesToReturn[staker]); } - /// @notice Returns the array of strategies in which `staker` has nonzero shares - function stakerStrats(address staker) external view returns (IStrategy[] memory) {} + function stakerDepositShares(address staker, IStrategy strategy) public view returns (uint256) { + uint256 strategyIndex = _getStrategyIndex(staker, strategy); + return sharesToReturn[staker][strategyIndex]; + } uint256 public stakerStrategyListLengthReturnValue; + /// @notice Simple getter function that returns `stakerStrategyList[staker].length`. function stakerStrategyListLength(address /*staker*/) external view returns (uint256) { return stakerStrategyListLengthReturnValue; @@ -113,28 +73,71 @@ contract StrategyManagerMock is strategyIsWhitelistedForDeposit[strategy] = value; } - function removeShares(address staker, IStrategy strategy, uint256 shares) external {} - - function addShares(address staker, IERC20 token, IStrategy strategy, uint256 shares) external {} - - function withdrawSharesAsTokens(address recipient, IStrategy strategy, uint256 shares, IERC20 token) external {} - - /// @notice returns the enshrined beaconChainETH Strategy - function beaconChainETHStrategy() external view returns (IStrategy) {} - - // function withdrawalDelayBlocks() external view returns (uint256) {} - - function domainSeparator() external view returns (bytes32) {} - function addStrategiesToDepositWhitelist( - IStrategy[] calldata strategiesToWhitelist, - bool[] calldata thirdPartyTransfersForbiddenValues + IStrategy[] calldata strategiesToWhitelist ) external { for (uint256 i = 0; i < strategiesToWhitelist.length; ++i) { strategyIsWhitelistedForDeposit[strategiesToWhitelist[i]] = true; - thirdPartyTransfersForbidden[strategiesToWhitelist[i]] = thirdPartyTransfersForbiddenValues[i]; } } + function removeDepositShares( + address staker, IStrategy strategy, uint256 sharesToRemove + ) external { + uint256 strategyIndex = _getStrategyIndex(staker, strategy); + sharesToReturn[staker][strategyIndex] -= sharesToRemove; + } + function removeStrategiesFromDepositWhitelist(IStrategy[] calldata /*strategiesToRemoveFromWhitelist*/) external pure {} + + + function withdrawSharesAsTokens( + address staker, + IStrategy strategy, + address, // token + uint256 shares + ) external { + strategySharesWithdrawn[staker][strategy] += shares; + } + + function addShares( + address staker, + IStrategy strategy, + IERC20, // token + uint256 addedShares + ) external returns (uint, uint) { + // Increase the staker's shares + uint256 strategyIndex = _getStrategyIndex(staker, strategy); + sharesToReturn[staker][strategyIndex] += addedShares; + + // Call increase delegated shared + uint256 existingShares = stakerDepositShares(staker, strategy); + + return (existingShares, addedShares); + } + + function burnShares(IStrategy strategy, uint256 sharesToBurn) external {} + + function _getStrategyIndex(address staker, IStrategy strategy) internal view returns (uint256) { + IStrategy[] memory strategies = strategiesToReturn[staker]; + uint256 strategyIndex = type(uint256).max; + for (uint256 i = 0; i < strategies.length; ++i) { + if (strategies[i] == strategy) { + strategyIndex = i; + break; + } + } + if (strategyIndex == type(uint256).max) { + revert ("StrategyManagerMock: strategy not found"); + } + + return strategyIndex; + } + + function setDelegationManager(IDelegationManager _delegation) external { + delegation = _delegation; + } + + fallback() external payable {} + receive() external payable {} } diff --git a/src/test/token/EigenTransferRestrictions.t.sol b/src/test/token/EigenTransferRestrictions.t.sol index c254f97a7..49fb00e4a 100644 --- a/src/test/token/EigenTransferRestrictions.t.sol +++ b/src/test/token/EigenTransferRestrictions.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; -import "@openzeppelin-v4.9.0/contracts/proxy/transparent/ProxyAdmin.sol"; -import "@openzeppelin-v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "@openzeppelin-v4.9.0/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "../harnesses/EigenHarness.sol"; contract EigenTransferRestrictionsTest is Test { diff --git a/src/test/token/EigenWrapping.t.sol b/src/test/token/EigenWrapping.t.sol index 76b9e6385..4c1270721 100644 --- a/src/test/token/EigenWrapping.t.sol +++ b/src/test/token/EigenWrapping.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -53,8 +53,8 @@ contract EigenWrappingTests is Test { bEIGENImpl = new BackingEigen(IERC20(address(eigen))); // upgrade proxies - proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(eigen))), address(eigenImpl)); - proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl)); + proxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigen))), address(eigenImpl)); + proxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl)); vm.stopPrank(); diff --git a/src/test/token/bEIGEN.t.sol b/src/test/token/bEIGEN.t.sol index 06de8b60e..358d064ca 100644 --- a/src/test/token/bEIGEN.t.sol +++ b/src/test/token/bEIGEN.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -39,8 +39,8 @@ contract bEIGENTest is Test { bEIGENImpl = new BackingEigen(IERC20(address(eigen))); // upgrade proxies - proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(eigen))), address(eigenImpl)); - proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl)); + proxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigen))), address(eigenImpl)); + proxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl)); vm.stopPrank(); } diff --git a/src/test/tree/AllocationManagerUnit.tree b/src/test/tree/AllocationManagerUnit.tree new file mode 100644 index 000000000..6f8477ebb --- /dev/null +++ b/src/test/tree/AllocationManagerUnit.tree @@ -0,0 +1,86 @@ +. +├── AllocationManager Tree (**** denotes that integration tests are needed to fully validate path) +├── when setAllocationDelay is called by the operator +│ ├── given that the caller is not an operator in the delegationManager +│ │ └── it should revert +│ ├── given that the delay is set to 0 +│ │ └── it should revert +│ ├── given that a previous delay is set and has passed +│ │ └── it should set the new delay to the previous delay +│ └── given the caller provides a valid delay +│ ├── given that a previous delay is set and has passed +│ │ └── it should set the new delay to the previous delay delay +│ ├── given that a previous delay is set and has not passed +│ │ └── it should should overwrite the previous pending delay with the new delay +│ └── it should set the pendingDelay, update the effectBlock, and emit an `AllocationDelaySetEvent` +├── when setAllocationDelay is called by the delegationManager +│ ├── given that the caller is not the delegationManager +│ │ └── it should revert +│ ├── given that the delay is set to 0 +│ │ └── it should revert +│ ├── given that a previous delay is set and has passed +│ │ └── it should set the new delay to the previous delay +│ └── given the caller provides a valid delay +│ ├── given that a previous delay is set and has passed +│ │ └── it should set the new delay to the previous delay delay +│ ├── given that a previous delay is set and has not passed +│ │ └── it should should overwrite the previous pending delay with the new delay +│ └── it should set the pendingDelay, update the effectBlock, and emit an `AllocationDelaySetEvent` +├── when clearModificationQueue is called +│ ├── given that the length of the strategies and numToClear are not equal +│ │ └── it should revert +│ ├── given that the operator is registered in the delegationManager +│ │ └── it should revert +│ ├── given that there are no modifications OR numToClear is 0 +│ │ └── no modifications should be cleared +│ └── it should loop through the modification queue and the numToClear +│ ├── given that the latest effect block has not been reached +│ │ └── it should break the loop +│ └── given that the latest effect block has been reached +│ ├── it should update the magnitude info to the currentMagnitude, with a pendingDiff of 0 and effectBlock of 0 +│ ├── it should change the encumbered magnitude if the pendingDiff was less than 0 +│ ├── it should emit an EncumberedmagnitudeUpdated event +│ ├── it should remove the modification from the queue +│ └── it should continue to pop off the modification queue if the size is greater than 0 and numToClear is less than numCompleted +├── given that modifyAllocations is called +│ ├── given that the allocation delay is not set for the msg.sender +│ │ └── it should revert +│ └── it should loop through the list of allocations +│ ├── given that the length of operator sets and magnitudes does not match +│ │ └── it should revert +│ ├── given that the operatorSets to allocate mags to do not exist in the AVSD +│ │ └── it should revert +│ ├── it should clear the modification queue for the given strategy for the type(uint16).max number of modifications +│ ├── given that the maximum magnitude does not equal the expected maximum magnitude +│ │ └── it should revert +│ └── it should loop through the list of operator sets for the allocation +│ ├── given that the pendingDiff is nonZero +│ │ └── it should revert +│ ├── given that that the magnitude delta is the same as the pendingDiff +│ │ └── it should revert +│ ├── given that the pendingDiff is less than 0 (this is a deallocation) +│ │ └── it should update the effect block in memory to be the operator deallocation delay +│ ├── given that the pendingDiff is greater than 0 (this is an allocation) +│ │ ├── it should update the effect timestmap in memory to be the operator allocation delay +│ │ └── it should increase the encumberedMagnitude in memory by the pendingDiff +│ ├── it should push to the modification queue +│ ├── it should update the magnitude info, encumbered magnitude, emit an event for encumbered magnitude +│ └── it should emit an AllocationUpdated Event +└── when slashOperator is called + ├── given that the wads to slash is 0 + │ └── it should revert + ├── given that the wads to slash is greater than WAD + │ └── it should revert + ├── given that the operator is not registered in the delegationManager + │ └── it should revert + ├── given that the operator is deregistered from AVS for the given block + │ └── it should revert + └── it should loop through all slashing params + ├── it should slash the current magnitude by wads to slash + ├── given that there is a pending deallocation + │ ├── it should slash the pending diff + │ └── it should emit an event for AllocationUpdated with the orginial deallocation's effect timestamp + ├── it should update the magnitude info, encumbered magnitude, emit an event for encumbered magnitude + ├── it should decrease the operator's max magnitude + ├── it should decrease the operators shares in the delegation manager + └── It should emit an AllocationUpdated event \ No newline at end of file diff --git a/src/test/tree/DelegationManagerUnit.tree b/src/test/tree/DelegationManagerUnit.tree index ea9589119..aacf62b1f 100644 --- a/src/test/tree/DelegationManagerUnit.tree +++ b/src/test/tree/DelegationManagerUnit.tree @@ -4,12 +4,11 @@ │ ├── given that the caller has already delegated to an operator │ │ └── it should revert │ ├── it should call `_setOperatorDetails` -│ │ ├── given operatorDetails.stakerOptOutWindowBlocks is > MAX_STAKER_OPT_OUT_WINDOW_BLOCKS -│ │ │ └── it should revert │ │ └── it should emit an OperatorDetailsModified event │ └── it should call `_delegate` │ ├── given that delegation is paused │ │ └── it should revert +│ ├── it should set the operator allocation delay in the AllocationManager contract │ ├── it should set the operator delegated to itself and emit a StakerDelegated event │ ├── given the caller has delegateable shares │ │ └── it should increase the operator's shares and and emit an OperatorSharesIncreased event @@ -18,22 +17,26 @@ ├── when modifyOperatorDetails is called │ ├── given caller is not an operator │ │ └── it should revert -│ ├── given operatorDetails.stakerOptOutWindowBlocks is > MAX_STAKER_OPT_OUT_WINDOW_BLOCKS -│ │ └── it should revert -│ ├── given operatorDetails.stakerOptOutWindowBlocks is less than the current stakerOptOutWindowBlocks -│ │ └── it should revert -│ └── given caller is an operator and provides a valid stakerOptOutWindowBlocks +│ └── given caller is an operator │ └── it should update the operatorDetails and emit an OperatorDetailsModified event ├── when updateOperatorMetadataURI is called │ ├── given caller is not an operator │ │ └── it should revert │ └── given caller is an operator -│ └── it should emit an event +│ └── it should emit an OperatorMetadataURIUpdated event ├── when delegateTo is called -│ └── it calls _delegate() (internal function) with msg.sender as the staker +│ ├── given operator is not registered +│ │ └── it should revert +│ ├── given staker is already delegated to an operator +│ │ └── it should revert +│ └── it should call `_delegate` (internal function) with msg.sender as the staker ├── when delegateToBySignature is called │ ├── given block timestamp is > staker signature expiry │ │ └── it should revert +│ ├── given operator is not registered +│ │ └── it should revert +│ ├── given staker is already delegated to an operator +│ │ └── it should revert │ ├── given staker signature verification fails │ │ └── it should revert │ └── given staker signature verification succeeds @@ -41,24 +44,13 @@ ├── when _delegate() is called │ ├── given that new delegations are paused │ │ └── it should revert -│ ├── given staker is already delegated to an operator -│ │ └── it should revert -│ ├── given passed in operator param isn't a registered operator -│ │ └── it should revert │ ├── given operator's delegationApprover is set to zero address OR given caller is the delegationApprover │ │ └── it should check delegatable shares and update accordingly (**below logic tree reused elsewhere**) │ │ ├── given staker doesn't have delegatable shares │ │ │ └── it should set staker delegated to operator, call the StakeRegistry, and emit events │ │ └── given staker has delegatable shares -│ │ ├── given staker has EigenPod shares -│ │ │ ├── given EigenPod shares are <= 0 -│ │ │ │ └── it should set staker delegated to operator, operator beaconChainStrategy shares unchanged, call the StakeRegistry, and emit events -│ │ │ └── given EigenPod shares are > 0 -│ │ │ └── it should set staker delegated to operator, increase operator beaconChainStrategy shares, call the StakeRegistry, and emit events -│ │ ├── given staker has StrategyManager shares -│ │ │ └── it should set staker delegated to operator, increase operator StrategyManager shares, call the StakeRegistry, and emit events -│ │ └── given staker has shares in both EigenPod and StrategyManager -│ │ └── it should set staker delegated to operator, increase operator shares (EPM and SM), call the StakeRegistry, and emit events +│ │ ├── it should get the maxMagnitudes for each strategy from the staker's delegated operator +│ │ └── it should call `_increaseDelegation` with the maxMagnitude of the staker's operator │ └── given operator's delegationApprover is set to nonzero address AND the caller is not the delegationApprover │ ├── given the delegationApprover is an EOA │ │ ├── given the block timestamp is past the expiry timestamp @@ -68,7 +60,7 @@ │ │ ├── given the signature verification fails │ │ │ └── it should revert │ │ └── given the signature verification succeeds -│ │ └── it should check delegatable shares and update accordingly (**logic tree reused from above**) +│ │ └── it should set salt as spent, check delegatable shares and update accordingly (**logic tree reused from above**) │ └── given the delegationApprover is a contract │ ├── given the block timestamp is past the expiry timestamp │ │ └── it should revert @@ -79,11 +71,11 @@ │ ├── given the signature verification fails, isValidSignature() does not return EIP1271_MAGICVALUE │ │ └── it should revert │ └── given the signature verification succeeds, isValidSignature() returns EIP1271_MAGICVALUE -│ └── it should check delegatable shares and update accordingly (**logic tree reused from above**) +│ └── it should set salt as spent, check delegatable shares and update accordingly (**logic tree reused from above**) ├── when undelegate is called -│ ├── given caller is not delegated to an operator +│ ├── given staker is not delegated to an operator │ │ └── it should revert -│ ├── given that the caller is registered as operator +│ ├── given that the staker is registered as operator │ │ └── it should revert │ ├── given that staker param is zero address │ │ └── it should revert @@ -92,31 +84,38 @@ │ ├── given the msg.sender is the operator or delegationApprover │ │ └── it should emit a StakerForceUndelegated event │ └── it should emit a StakerUndelegatedEvent and undelegate the staker -│ ├── given the staker doesn't have delegateable shares -│ │ └── it should return a zero withdrawal root -│ └── given the staker has delegateable shares *** -│ └── it should call _removeSharesAndQueueWithdrawal +│ └── it should loop through each strategy that the staker has non-zero depositShares +│ ├── given `_hasNonZeroScalingFactors` returns false (the strategy has a maxMagnitude of 0 OR the strategy is the beacon chain strategy and the beaconChainScalingFactor is 0) +│ │ └── it should decrement all operator depositShares with a respective withdrawalRoot of 0x0 +│ └── given `_hasNonZeroScalingFactors` returns true +│ └── it should convert depositShares to sharesToWithdraw to factor in Slashed amounts and call _removeSharesAndQueueWithdrawal and return a withdrawalRoot ├── when queueWithdrawals is called *** │ ├── given that entering the withdrawal queue is paused │ │ └── it should revert -│ └── it should loop through each withdrawal and call _removeSharesAndQueueWithdrawal +│ ├── given for a withdrawal, the withdrawer address is not the msg.sender +│ │ └── it should revert +│ ├── given for a withdrawal, the strategies and shares arrays are not equal length +│ │ └── it should revert +│ └── it should loop through each withdrawal and call `_removeSharesAndQueueWithdrawal` ├── when _removeSharesAndQueueWithdrawal is called │ ├── given that the staker is a zero address │ │ └── it should revert │ ├── given that the length of strategies is 0 │ │ └── it should revert │ └── it should loop through each strategy +│ ├── given `_hasNonZeroScalingFactors` returns false (the strategy has a maxMagnitude of 0 OR the strategy is the beacon chain strategy and the beaconChainScalingFactor is 0) +│ │ └── it should revert +│ ├── given that the sharesToWithdraw is greater than the staker's withdrawable shares (accounting for slashing) +│ │ └── it should revert │ ├── given that the staker is delegated to (not zero address) -│ │ └── it should decrease the operator's shares +│ │ └── it should decrease the operator's shares and emit OperatorSharesDecreased │ ├── given that the strategy is the beacon chain strategy │ │ └── it should remove shares from the eigen pod manager │ ├── given that the strategy is not the beacon chain eth strategy │ │ └── it should remove shares from the strategy manager -│ ├── given that the staker is delegated to (not zero address) -│ │ └── it should push a stake update │ ├── it should increment the staker's cumulativeWithdrawalsQueued -│ ├── it should calculate and set the withdrawal root as pending -│ └── it should emit a WithdrawalQueued event and return the withdrawal root +│ ├── it should calculate the scaled shares for queued withdrawal and set the withdrawal root as pending +│ └── it should emit a SlashingWithdrawalQueued event and return the withdrawal root ├── when completeQueuedWithdrawal OR completeQueuedWithdrawals is called *** │ ├── given that the exiting the withdrawal queue is paused │ │ └── it should revert @@ -124,54 +123,52 @@ │ │ └── it should revert │ └── it should call _completeQueuedWithdrawal (internal function) for each withdrawal ├── when _completeQueuedWithdrawal is called *** +│ ├── given that the tokens and strategies arrays are not equal length +│ │ └── it should revert +│ ├── given that the caller is not the withdrawer +│ │ └── it should revert │ ├── given that the withdrawal root is not pending │ │ └── it should revert -│ ├── given that the withdrawal delay blocks period has not elapsed +│ ├── given that the withdrawal is a legacy pre-slashing upgrade withdrawal and LEGACY_MIN_WITHDRAWAL_DELAY_BLOCKS have not passed │ │ └── it should revert -│ ├── given that the caller is not the withdrawer +│ ├── given that the withdrawal is a post slashing upgrade withdrawal and MIN_WITHDRAWAL_DELAY seconds have not passed │ │ └── it should revert -│ ├── given that receiveAsTokens is true -│ │ └── given that the tokens and strategies length are not equal -│ │ └── it should revert │ └── given that the above conditions are satisfied -│ ├── it should delete the withdrawal root from pending withdrawals -│ ├── given that receiveAsTokens is true -│ │ └── it should call _withdrawSharesAsTokens for each strategy to withdraw from │ ├── given that receiveAsTokens is false -│ │ ├── it should loop through each strategy to withdraw from -│ │ ├── given that the strategy is the beaconChainETHStrategy -│ │ │ ├── it should call addShares on the eigenPodManager with the staker as the original pod owner -│ │ │ └── given that the staker is delegated to (operator not zero address) -│ │ │ ├── it should increase the original pod operator's shares -│ │ │ └── it should push a stake update for the original pod operator -│ │ ├── given that the strategy is not the beaconChainETHStrategy -│ │ │ ├── it should call addShares on the strategyManager with the staker as the withdrawer -│ │ │ └── it should increase the operator's shares with the staker as the withdrawer -│ │ └── it should push an operator stake update +│ │ └── for each strategy, it should call addShares on the shareManager to withdraw from +│ │ ├── given the shareManager is the EigenPodManager +│ │ │ └── it should call `EigenPodManager.addShares` which may callback `increaseDelegatedShares` to the DelegationManager +│ │ └── given the shareManager is the StrategyManager +│ │ └── it should call `StrategyManager.addShares` which will callback `increaseDelegatedShares` to the DelegationManager +│ ├── given that receiveAsTokens is true +│ │ └── for each strategy, it should call withdrawSharesAsTokens on the shareManager to withdraw from +│ │ ├── given the shareManager is the EigenPodManager +│ │ │ └── it should call `EigenPodManager.withdrawSharesAsTokens` which will withdraw ETH from the staker EigenPod if EPM shares not in deficit +│ │ └── given the shareManager is the StrategyManager +│ │ └── it should call `StrategyManager.withdrawSharesAsTokens` which will withdraw the strategy's underlying token +│ ├── it should delete the withdrawal root from pending withdrawals │ └── it should emit a WithdrawalCompleted event -├── when _withdrawSharesAsTokens is called (internal function) *** -│ ├── given that the strategy is the beaconChainStrategy -│ │ └── it should call withdrawSharesAsTokens on the eigen pod manager -│ └── given that the strategy is not the beaconChainStrategy -│ └── it should call withdrawSharesAsTokens on the strategy manager ├── when increaseDelegatedShares is called │ ├── if the caller is not the strategy manager or eigen pod manager │ │ └── it should revert │ └── given that the staker is delegated -│ ├── it should increase the operator's share for the staker and its associated strategy -│ └── it should push an operator stake update -├── when decreaseDelegatedShares is called -│ ├── if the caller is not the strategy manager or eigen pod manager +│ ├── it should get the maxMagnitudes for each strategy from the staker's delegated operator +│ └── it should call `_increaseDelegation` with the maxMagnitude of the staker's operator +├── when _increaseDelegation is called +│ ├── given `_hasNonZeroScalingFactors` returns false (the strategy has a maxMagnitude of 0 OR the strategy is the beacon chain strategy and the beaconChainScalingFactor is 0) +│ │ └── it should revert +│ └── it should increase the operator's shares by addedShares amount, update the staker's depositScalingFactor, and emit OperatorSharesIncreased, DepositScalingFactorUpdated +├── when decreaseBeaconChainScalingFactor is called +│ ├── if the caller is not the eigen pod manager │ │ └── it should revert +│ ├── it should decrease the beacon chain scaling factor and emit a BeaconChainScalingFactorDecreased event │ └── given that the staker is delegated -│ ├── it should increase the operator's share for the staker and its associated strategy -│ └── it should push an operator stake update -└── when setStakeRegistry is called - ├── given not called by owner - │ └── it should revert - ├── given existing stakeRegistry address is set - │ └── it should revert - ├── given new stakeRegistry address is 0 +│ └── it should decrease operator shares with the beacon chain shares slashed and emit OperatorSharesDecreased +├── when _decreaseDelegation is called +│ ├── given `_hasNonZeroScalingFactors` returns false (the strategy has a maxMagnitude of 0 OR the strategy is the beacon chain strategy and the beaconChainScalingFactor is 0) +│ │ └── it should revert +│ └── it should decrease the operator's shares by slashed shares amount, update the staker's depositScalingFactor, and emit OperatorSharesDecreased, DepositScalingFactorUpdated +└── when decreaseOperatorShares is called + ├── given not called by AllocationManager │ └── it should revert - └── given called by owner, existing address not set, and new address is nonzero - └── it should set the new stakeRegistry address and emit event \ No newline at end of file + └── it should decrease the operator's shares by slashed shares amount and emit OperatorSharesDecreased \ No newline at end of file diff --git a/src/test/tree/PermissionControllerUnit.tree b/src/test/tree/PermissionControllerUnit.tree new file mode 100644 index 000000000..d021bf87a --- /dev/null +++ b/src/test/tree/PermissionControllerUnit.tree @@ -0,0 +1,27 @@ +. +└── PermissionController (**** denotes that integration tests are needed to fully validate path) + ├── when setAdmin is called + │ ├── given that the current admin it not set + │ │ └── given that the caller is not the account + │ │ └── it should revert + │ ├── given that the current admin is set + │ │ └── given taht the msg.sender is not the current admin + │ │ └── it should revert + │ ├── given that the new admin is the zero address + │ │ └── it should revert + │ └── given that a valid caller sets a valid admin + │ └── it should update the permissions of the account & emit an AdminSet event + ├── when setAppointee is called + │ ├── given that the caller is not the admin + │ │ └── it should revert + │ ├── given that the appointee already has permissions + │ │ └── it should revert + │ └── given that proper permissions are set + │ └── it should emit a DelegateSet event, and update the `appointeePermissions` and `permissionAppointee` mappings for the account + └── when removeAppointee is called + ├── given that the caller is not the admin + │ └── it should revert + ├── given that the appointee does not have permissions + │ └── it should revert + └── given that proper permissions are set + └── it should emit a DelegateRemoved event, and update the `appointeePermissions` and `permissionAppointee` mappings for the account \ No newline at end of file diff --git a/src/test/unit/AVSDirectoryUnit.t.sol b/src/test/unit/AVSDirectoryUnit.t.sol index 667adc557..71c770886 100644 --- a/src/test/unit/AVSDirectoryUnit.t.sol +++ b/src/test/unit/AVSDirectoryUnit.t.sol @@ -1,353 +1,182 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; -import "@openzeppelin/contracts/mocks/ERC1271WalletMock.sol"; - -import "src/contracts/core/DelegationManager.sol"; import "src/contracts/core/AVSDirectory.sol"; - -import "src/test/events/IAVSDirectoryEvents.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; -/** - * @notice Unit testing of the AVSDirectory contract. An AVSs' service manager contract will - * call this to register an operator with the AVS. - * Contracts tested: AVSDirectory - * Contracts not mocked: DelegationManager - */ -contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents { - // Contract under test - AVSDirectory avsDirectory; - AVSDirectory avsDirectoryImplementation; - - // Contract dependencies - DelegationManager delegationManager; - DelegationManager delegationManagerImplementation; - - // Delegation signer - uint256 delegationSignerPrivateKey = uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); - uint256 stakerPrivateKey = uint256(123_456_789); - - // empty string reused across many tests - string emptyStringForMetadataURI; +contract AVSDirectoryUnitTests is EigenLayerUnitTestSetup, IAVSDirectoryEvents, IAVSDirectoryErrors, ISignatureUtils { + uint8 constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; - // reused in various tests. in storage to help handle stack-too-deep errors - address defaultAVS = address(this); - - uint256 minWithdrawalDelayBlocks = 216_000; - IStrategy[] public initializeStrategiesToSetDelayBlocks; - uint256[] public initializeWithdrawalDelayBlocks; + AVSDirectory avsDirectory; - // Index for flag that pauses registering/deregistering for AVSs - uint8 internal constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; + address defaultAVS; + address defaultOperator; + uint256 defaultOperatorPk; + SignatureWithSaltAndExpiry defaultOperatorSignature; function setUp() public virtual override { - // Setup EigenLayerUnitTestSetup.setUp(); - // Deploy DelegationManager implmentation and proxy - initializeStrategiesToSetDelayBlocks = new IStrategy[](0); - initializeWithdrawalDelayBlocks = new uint256[](0); - delegationManagerImplementation = new DelegationManager(strategyManagerMock, slasherMock, eigenPodManagerMock); - delegationManager = DelegationManager( - address( - new TransparentUpgradeableProxy( - address(delegationManagerImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - address(this), - pauserRegistry, - 0, // 0 is initialPausedStatus - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ) - ) - ) - ); + avsDirectory = _deployAVSD(address(delegationManagerMock), pauserRegistry); - // Deploy AVSDirectory implmentation and proxy - avsDirectoryImplementation = new AVSDirectory(delegationManager); - avsDirectory = AVSDirectory( + defaultAVS = cheats.randomAddress(); + defaultOperatorPk = cheats.randomUint(1, MAX_PRIVATE_KEY); + defaultOperator = cheats.addr(defaultOperatorPk); + defaultOperatorSignature = _newOperatorRegistrationSignature({ + operatorPk: defaultOperatorPk, + avs: defaultAVS, + salt: bytes32(cheats.randomUint()), + expiry: type(uint256).max + }); + + delegationManagerMock.setIsOperator(defaultOperator, true); + } + + function _deployAVSD( + address delegationManager, + IPauserRegistry pauserRegistry + ) internal returns (AVSDirectory avsd) { + avsd = AVSDirectory( address( new TransparentUpgradeableProxy( - address(avsDirectoryImplementation), + address(new AVSDirectory(IDelegationManager(delegationManager), pauserRegistry)), address(eigenLayerProxyAdmin), abi.encodeWithSelector( AVSDirectory.initialize.selector, address(this), - pauserRegistry, 0 // 0 is initialPausedStatus ) ) ) ); - - // Exclude delegation manager from fuzzed tests - addressIsExcludedFromFuzzedInputs[address(avsDirectory)] = true; + isExcludedFuzzAddress[address(avsd)] = true; } - /** - * INTERNAL / HELPER FUNCTIONS - */ - - /** - * @notice internal function for calculating a signature from the operator corresponding to `_operatorPrivateKey`, delegating them to - * the `operator`, and expiring at `expiry`. - */ - function _getOperatorSignature( - uint256 _operatorPrivateKey, - address operator, + function _newOperatorRegistrationSignature( + uint256 operatorPk, address avs, bytes32 salt, uint256 expiry - ) internal view returns (ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature) { - operatorSignature.expiry = expiry; - operatorSignature.salt = salt; - { - bytes32 digestHash = avsDirectory.calculateOperatorAVSRegistrationDigestHash(operator, avs, salt, expiry); - (uint8 v, bytes32 r, bytes32 s) = cheats.sign(_operatorPrivateKey, digestHash); - operatorSignature.signature = abi.encodePacked(r, s, v); - } - return operatorSignature; + ) internal view returns (SignatureWithSaltAndExpiry memory) { + (uint8 v, bytes32 r, bytes32 s) = cheats.sign( + operatorPk, avsDirectory.calculateOperatorAVSRegistrationDigestHash(cheats.addr(operatorPk), avs, salt, expiry) + ); + return SignatureWithSaltAndExpiry({signature: abi.encodePacked(r, s, v), salt: salt, expiry: expiry}); } - function _registerOperatorWithBaseDetails(address operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); - } + /// ----------------------------------------------------------------------- + /// initialize() + /// ----------------------------------------------------------------------- - function _registerOperatorWithDelegationApprover(address operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: cheats.addr(delegationSignerPrivateKey), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); + function test_initialize_Correctness() public { + assertEq(address(avsDirectory.delegation()), address(delegationManagerMock)); + cheats.expectRevert("Initializable: contract is already initialized"); + avsDirectory.initialize(address(this), 0); } - function _registerOperatorWith1271DelegationApprover(address operator) internal returns (ERC1271WalletMock) { - address delegationSigner = cheats.addr(delegationSignerPrivateKey); - /** - * deploy a ERC1271WalletMock contract with the `delegationSigner` address as the owner, - * so that we can create valid signatures from the `delegationSigner` for the contract to check when called - */ - ERC1271WalletMock wallet = new ERC1271WalletMock(delegationSigner); - - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(wallet), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); + /// ----------------------------------------------------------------------- + /// updateAVSMetadataURI() + /// ----------------------------------------------------------------------- - return wallet; + function test_updateAVSMetadataURI_Correctness() public { + cheats.expectEmit(true, true, true, true, address(avsDirectory)); + emit AVSMetadataURIUpdated(address(this), "test"); + avsDirectory.updateAVSMetadataURI("test"); } - function _registerOperator( - address operator, - IDelegationManager.OperatorDetails memory operatorDetails, - string memory metadataURI - ) internal filterFuzzedAddressInputs(operator) { - _filterOperatorDetails(operator, operatorDetails); - cheats.prank(operator); - delegationManager.registerAsOperator(operatorDetails, metadataURI); - } + /// ----------------------------------------------------------------------- + /// cancelSalt() + /// ----------------------------------------------------------------------- - function _filterOperatorDetails( - address operator, - IDelegationManager.OperatorDetails memory operatorDetails - ) internal view { - // filter out zero address since people can't delegate to the zero address and operators are delegated to themselves - cheats.assume(operator != address(0)); - // filter out disallowed stakerOptOutWindowBlocks values - cheats.assume(operatorDetails.stakerOptOutWindowBlocks <= delegationManager.MAX_STAKER_OPT_OUT_WINDOW_BLOCKS()); + function test_cancelSalt_Correctness() public { + bytes32 salt = bytes32(cheats.randomUint()); + cheats.prank(defaultAVS); + avsDirectory.cancelSalt(salt); + assertTrue(avsDirectory.operatorSaltIsSpent(defaultAVS, salt)); } -} -contract AVSDirectoryUnitTests_operatorAVSRegisterationStatus is AVSDirectoryUnitTests { - function test_revert_whenRegisterDeregisterToAVSPaused() public { - // set the pausing flag + /// ----------------------------------------------------------------------- + /// registerOperatorToAVS() + /// ----------------------------------------------------------------------- + + function test_registerOperatorToAVS_Paused() public { cheats.prank(pauser); avsDirectory.pause(2 ** PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS); - - cheats.expectRevert("Pausable: index is paused"); - avsDirectory.registerOperatorToAVS(address(0), ISignatureUtils.SignatureWithSaltAndExpiry(abi.encodePacked(""), 0, 0)); - - cheats.expectRevert("Pausable: index is paused"); - avsDirectory.deregisterOperatorFromAVS(address(0)); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); } - // @notice Tests that an avs who calls `updateAVSMetadataURI` will correctly see an `AVSMetadataURIUpdated` event emitted with their input - function testFuzz_UpdateAVSMetadataURI(string memory metadataURI) public { - // call `updateAVSMetadataURI` and check for event - cheats.expectEmit(true, true, true, true, address(avsDirectory)); - cheats.prank(defaultAVS); - emit AVSMetadataURIUpdated(defaultAVS, metadataURI); - avsDirectory.updateAVSMetadataURI(metadataURI); + function test_registerOperatorToAVS_SignatureExpired() public { + defaultOperatorSignature.expiry = block.timestamp - 1; + cheats.expectRevert(SignatureExpired.selector); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); } - // @notice Verifies an operator registers successfull to avs and see an `OperatorAVSRegistrationStatusUpdated` event emitted - function testFuzz_registerOperatorToAVS(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - - cheats.expectEmit(true, true, true, true, address(avsDirectory)); - emit OperatorAVSRegistrationStatusUpdated( - operator, defaultAVS, IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED - ); - - uint256 expiry = type(uint256).max; - - cheats.prank(defaultAVS); - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - avsDirectory.registerOperatorToAVS(operator, operatorSignature); + function test_registerOperatorToAVS_OperatorAlreadyRegistered() public { + cheats.startPrank(defaultAVS); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); + cheats.expectRevert(OperatorAlreadyRegisteredToAVS.selector); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); + cheats.stopPrank(); } - // @notice Verifies an operator registers successfull to avs and see an `OperatorAVSRegistrationStatusUpdated` event emitted - function testFuzz_revert_whenOperatorNotRegisteredToEigenLayerYet(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - + function test_registerOperatorToAVS_SaltSpent() public { + cheats.prank(defaultOperator); + avsDirectory.cancelSalt(defaultOperatorSignature.salt); cheats.prank(defaultAVS); - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - cheats.expectRevert("AVSDirectory.registerOperatorToAVS: operator not registered to EigenLayer yet"); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); + cheats.expectRevert(SaltSpent.selector); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); } - // @notice Verifies an operator registers fails when the signature is not from the operator - function testFuzz_revert_whenSignatureAddressIsNotOperator(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer"); - cheats.prank(operator); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); - } - - // @notice Verifies an operator registers fails when the signature expiry already expires - function testFuzz_revert_whenExpiryHasExpired( - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) public { - address operator = cheats.addr(delegationSignerPrivateKey); - operatorSignature.expiry = bound(operatorSignature.expiry, 0, block.timestamp - 1); - - cheats.expectRevert("AVSDirectory.registerOperatorToAVS: operator signature expired"); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); + function test_registerOperatorToAVS_OperatorNotRegisteredToEigenLayer() public { + delegationManagerMock.setIsOperator(defaultOperator, false); + cheats.expectRevert(OperatorNotRegisteredToEigenLayer.selector); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); } - // @notice Verifies an operator registers fails when it's already registered to the avs - function testFuzz_revert_whenOperatorAlreadyRegisteredToAVS(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); + function test_registerOperatorToAVS_Correctness() public { + cheats.expectEmit(true, true, true, false, address(avsDirectory)); + emit OperatorAVSRegistrationStatusUpdated(defaultOperator, defaultAVS, OperatorAVSRegistrationStatus.REGISTERED); - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - cheats.startPrank(defaultAVS); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); + cheats.prank(defaultAVS); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); - cheats.expectRevert("AVSDirectory.registerOperatorToAVS: operator already registered"); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); - cheats.stopPrank(); + assertTrue( + avsDirectory.avsOperatorStatus(defaultAVS, defaultOperator) == OperatorAVSRegistrationStatus.REGISTERED + ); + assertTrue(avsDirectory.operatorSaltIsSpent(defaultOperator, defaultOperatorSignature.salt)); } - /// @notice Checks that cancelSalt updates the operatorSaltIsSpent mapping correctly - function testFuzz_cancelSalt(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - - assertFalse(avsDirectory.operatorSaltIsSpent(operator, salt), "bad test setup"); - assertFalse(avsDirectory.operatorSaltIsSpent(defaultAVS, salt), "bad test setup"); - - cheats.prank(operator); - avsDirectory.cancelSalt(salt); - - assertTrue(avsDirectory.operatorSaltIsSpent(operator, salt), "salt was not successfully cancelled"); - assertFalse(avsDirectory.operatorSaltIsSpent(defaultAVS, salt), "salt should only be cancelled for the operator"); - - bytes32 newSalt; - unchecked { newSalt = bytes32(uint(salt) + 1); } - - assertFalse(salt == newSalt, "bad test setup"); + /// ----------------------------------------------------------------------- + /// deregisterOperatorFromAVS() + /// ----------------------------------------------------------------------- - cheats.prank(operator); - avsDirectory.cancelSalt(newSalt); - - assertTrue(avsDirectory.operatorSaltIsSpent(operator, salt), "original salt should still be cancelled"); - assertTrue(avsDirectory.operatorSaltIsSpent(operator, newSalt), "new salt should be cancelled"); + function test_deregisterOperatorFromAVS_Paused() public { + cheats.prank(pauser); + avsDirectory.pause(2 ** PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + avsDirectory.deregisterOperatorFromAVS(defaultOperator); } - /// @notice Verifies that registration fails when the salt has been cancelled via cancelSalt - function testFuzz_revert_whenRegisteringWithCancelledSalt(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - cheats.prank(operator); - avsDirectory.cancelSalt(salt); - - cheats.expectRevert("AVSDirectory.registerOperatorToAVS: salt already spent"); - cheats.prank(defaultAVS); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); + function test_deregisterOperatorFromAVS_OperatorNotRegisteredToAVS() public { + cheats.expectRevert(OperatorNotRegisteredToAVS.selector); + avsDirectory.deregisterOperatorFromAVS(defaultOperator); } - /// @notice Verifies that an operator cannot cancel the same salt twice - function testFuzz_revert_whenSaltCancelledTwice(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - - // uint256 expiry = type(uint256).max; - // ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - // _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); + function test_deregisterOperatorFromAVS_Correctness() public { + cheats.startPrank(defaultAVS); + avsDirectory.registerOperatorToAVS(defaultOperator, defaultOperatorSignature); - cheats.startPrank(operator); - avsDirectory.cancelSalt(salt); + cheats.expectEmit(true, true, true, false, address(avsDirectory)); + emit OperatorAVSRegistrationStatusUpdated( + defaultOperator, defaultAVS, OperatorAVSRegistrationStatus.UNREGISTERED + ); - cheats.expectRevert("AVSDirectory.cancelSalt: cannot cancel spent salt"); - avsDirectory.cancelSalt(salt); + avsDirectory.deregisterOperatorFromAVS(defaultOperator); cheats.stopPrank(); - } - - /// @notice Verifies that an operator cannot cancel the same salt twice - function testFuzz_revert_whenCancellingSaltUsedToRegister(bytes32 salt) public { - address operator = cheats.addr(delegationSignerPrivateKey); - assertFalse(delegationManager.isOperator(operator), "bad test setup"); - _registerOperatorWithBaseDetails(operator); - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = - _getOperatorSignature(delegationSignerPrivateKey, operator, defaultAVS, salt, expiry); - - cheats.prank(defaultAVS); - avsDirectory.registerOperatorToAVS(operator, operatorSignature); - - cheats.prank(operator); - cheats.expectRevert("AVSDirectory.cancelSalt: cannot cancel spent salt"); - avsDirectory.cancelSalt(salt); + assertTrue( + avsDirectory.avsOperatorStatus(defaultAVS, defaultOperator) == OperatorAVSRegistrationStatus.UNREGISTERED + ); } } diff --git a/src/test/unit/AllocationManagerUnit.t.sol b/src/test/unit/AllocationManagerUnit.t.sol new file mode 100644 index 000000000..651fd81ea --- /dev/null +++ b/src/test/unit/AllocationManagerUnit.t.sol @@ -0,0 +1,3726 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/contracts/core/AllocationManager.sol"; +import "src/test/utils/EigenLayerUnitTestSetup.sol"; +import "src/test/mocks/MockAVSRegistrar.sol"; + +contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManagerErrors, IAllocationManagerEvents { + using StdStyle for *; + using SingleItemArrayLib for *; + + /// ----------------------------------------------------------------------- + /// Constants + /// ----------------------------------------------------------------------- + + /// NOTE: Raising these values directly increases cpu time for tests. + uint256 internal constant FUZZ_MAX_ALLOCATIONS = 8; + uint256 internal constant FUZZ_MAX_STRATS = 8; + uint256 internal constant FUZZ_MAX_OP_SETS = 8; + + uint8 internal constant PAUSED_MODIFY_ALLOCATIONS = 0; + uint8 internal constant PAUSED_OPERATOR_SLASHING = 1; + uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 2; + + uint32 constant ASSUMED_BLOCK_TIME = 12 seconds; + uint32 constant DEALLOCATION_DELAY = 14 days / ASSUMED_BLOCK_TIME; + uint32 constant ALLOCATION_CONFIGURATION_DELAY = 21 days / ASSUMED_BLOCK_TIME; + uint32 constant DEFAULT_OPERATOR_ALLOCATION_DELAY = 1 days / ASSUMED_BLOCK_TIME; + + uint256 constant DEFAULT_OPERATOR_SHARES = 1e18; + + /// ----------------------------------------------------------------------- + /// Mocks + /// ----------------------------------------------------------------------- + + AllocationManager allocationManager; + ERC20PresetFixedSupply tokenMock; + StrategyBase strategyMock; + + /// ----------------------------------------------------------------------- + /// Defaults + /// ----------------------------------------------------------------------- + + OperatorSet defaultOperatorSet; + IStrategy[] defaultStrategies; + address defaultOperator = address(this); + address defaultAVS = address(new MockAVSRegistrar()); + + /// ----------------------------------------------------------------------- + /// Internal Storage Helpers + /// ----------------------------------------------------------------------- + mapping(IStrategy => uint64) _encumberedMagnitudes; + + /// ----------------------------------------------------------------------- + /// Setup + /// ----------------------------------------------------------------------- + + function setUp() public virtual override { + EigenLayerUnitTestSetup.setUp(); + _initializeAllocationManager(address(this), pauserRegistry, 0); + tokenMock = new ERC20PresetFixedSupply("Mock Token", "MOCK", type(uint256).max, address(this)); + strategyMock = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry)), + address(eigenLayerProxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, tokenMock) + ) + ) + ); + defaultStrategies = strategyMock.toArray(); + defaultOperatorSet = OperatorSet(defaultAVS, 0); + + _createOperatorSet(defaultOperatorSet, defaultStrategies); + _registerOperator(defaultOperator); + _setAllocationDelay(defaultOperator, DEFAULT_OPERATOR_ALLOCATION_DELAY); + _registerForOperatorSet(defaultOperator, defaultOperatorSet); + _grantDelegatedStake(defaultOperator, defaultOperatorSet, DEFAULT_OPERATOR_SHARES); + } + + /// ----------------------------------------------------------------------- + /// Internal Helpers + /// ----------------------------------------------------------------------- + + function _initializeAllocationManager( + address _initialOwner, + IPauserRegistry _pauserRegistry, + uint256 _initialPausedStatus + ) internal returns (AllocationManager) { + return allocationManager = AllocationManager( + address( + new TransparentUpgradeableProxy( + address( + new AllocationManager( + IDelegationManager(address(delegationManagerMock)), + _pauserRegistry, + IPermissionController(address(permissionController)), + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY + ) + ), + address(eigenLayerProxyAdmin), + abi.encodeWithSelector(AllocationManager.initialize.selector, _initialOwner, _initialPausedStatus) + ) + ) + ); + } + + function _registerOperator( + address operator + ) internal { + delegationManagerMock.setIsOperator(operator, true); + } + + function _setAllocationDelay(address operator, uint32 delay) internal { + cheats.prank(operator); + allocationManager.setAllocationDelay(operator, delay); + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + } + + function _createOperatorSet( + OperatorSet memory operatorSet, + IStrategy[] memory strategies + ) internal returns (OperatorSet memory) { + cheats.prank(operatorSet.avs); + allocationManager.createOperatorSets( + operatorSet.avs, + CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray() + ); + return operatorSet; + } + + function _createOperatorSets(OperatorSet[] memory operatorSets, IStrategy[] memory strategies) internal { + CreateSetParams[] memory createSetParams = new CreateSetParams[](operatorSets.length); + + for (uint256 i; i < operatorSets.length; ++i) { + createSetParams[i] = CreateSetParams({operatorSetId: operatorSets[i].id, strategies: strategies}); + } + + cheats.prank(operatorSets[0].avs); + allocationManager.createOperatorSets(operatorSets[0].avs, createSetParams); + } + + function _registerForOperatorSet(address operator, OperatorSet memory operatorSet) internal { + cheats.prank(operator); + allocationManager.registerForOperatorSets( + operator, + RegisterParams({avs: operatorSet.avs, operatorSetIds: operatorSet.id.toArrayU32(), data: ""}) + ); + } + + function _grantDelegatedStake(address operator, OperatorSet memory operatorSet, uint256 stake) internal { + IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); + delegationManagerMock.setOperatorsShares(operator, strategies, stake); + } + + function _registerForOperatorSets(address operator, OperatorSet[] memory operatorSets) internal { + cheats.startPrank(operator); + for (uint256 i; i < operatorSets.length; ++i) { + allocationManager.registerForOperatorSets( + operator, + RegisterParams({avs: operatorSets[i].avs, operatorSetIds: operatorSets[i].id.toArrayU32(), data: ""}) + ); + } + cheats.stopPrank(); + } + + struct Magnitudes { + uint256 encumbered; + uint256 max; + uint256 allocatable; + } + + /** + * Get expected post slash storage values + * Assumes that: + * 1. WAD is max before slash + * 2. encumbered is equal to magnitude before slash + */ + function _getExpectedSlashVals( + uint256 wadToSlash, + uint64 magBeforeSlash + ) internal pure returns (uint256 wadSlashed, uint64 newCurrentMag, uint64 newMaxMag, uint64 newEncumberedMag) { + return _getExpectedSlashVals(wadToSlash, magBeforeSlash, magBeforeSlash); + } + /** + * Get expected post slash storage values + * Assumes that: + * 1. WAD is max before slash + */ + function _getExpectedSlashVals( + uint256 wadToSlash, + uint64 magBeforeSlash, + uint64 encumberedMagBeforeSlash + ) internal pure returns (uint256 wadSlashed, uint64 newCurrentMag, uint64 newMaxMag, uint64 newEncumberedMag) { + // Get slippage to apply to returned values - we basically recreate mulWadRoundUp here + uint64 slippage = _calculateSlippage(magBeforeSlash, wadToSlash); + // Get the magnitude to slash - this value is rounded UP in the implementation + uint64 slashedMag = uint64((uint256(magBeforeSlash) * wadToSlash / WAD + slippage)); + wadSlashed = slashedMag; + newCurrentMag = magBeforeSlash - slashedMag; + newMaxMag = WAD - slashedMag; + newEncumberedMag = encumberedMagBeforeSlash - slashedMag; + } + + /// @dev Returns 0 or 1, depending on the remainder of the division + function _calculateSlippage(uint64 magnitude, uint256 wadToSlash) internal pure returns (uint64) { + return mulmod(magnitude, wadToSlash, WAD) > 0 ? 1 : 0; + } + + function _checkAllocationStorage( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy, + Allocation memory expectedAllocation, + Magnitudes memory expectedMagnitudes + ) internal view { + Allocation memory allocation = allocationManager.getAllocation(operator, operatorSet, strategy); + + console.log("\nChecking Allocation Storage:".yellow()); + console.log(" currentMagnitude: %d", allocation.currentMagnitude); + console.log(" pendingDiff: %d", allocation.pendingDiff); + console.log(" effectBlock: %d", allocation.effectBlock); + + assertEq( + expectedAllocation.currentMagnitude, allocation.currentMagnitude, "currentMagnitude != expected" + ); + assertEq(expectedAllocation.pendingDiff, allocation.pendingDiff, "pendingDiff != expected"); + assertEq(expectedAllocation.effectBlock, allocation.effectBlock, "effectBlock != expected"); + + uint256 encumberedMagnitude = allocationManager.encumberedMagnitude(operator, strategy); + uint256 maxMagnitude = allocationManager.getMaxMagnitudes(operator, strategy.toArray())[0]; + uint256 allocatableMagnitude = allocationManager.getAllocatableMagnitude(operator, strategy); + + console.log(" encumberedMagnitude: %d", encumberedMagnitude); + console.log(" maxMagnitude: %d", maxMagnitude); + console.log(" allocatableMagnitude: %d", allocatableMagnitude); + + assertEq(expectedMagnitudes.encumbered, encumberedMagnitude, "encumberedMagnitude != expected"); + assertEq(expectedMagnitudes.max, maxMagnitude, "maxMagnitude != expected"); + assertEq(expectedMagnitudes.allocatable, allocatableMagnitude, "allocatableMagnitude != expected"); + + // Check `getMaxMagnitudes` alias for coverage. + assertEq( + expectedMagnitudes.max, + allocationManager.getMaxMagnitudes(operator.toArray(), strategy)[0], + "maxMagnitude != expected" + ); + + // Check `getAllocations` alias for coverage. + Allocation memory getAllocations = + allocationManager.getAllocations(operator.toArray(), operatorSet, strategy)[0]; + assertEq( + expectedAllocation.currentMagnitude, getAllocations.currentMagnitude, "currentMagnitude != expected" + ); + assertEq(expectedAllocation.pendingDiff, getAllocations.pendingDiff, "pendingDiff != expected"); + assertEq(expectedAllocation.effectBlock, getAllocations.effectBlock, "effectBlock != expected"); + + console.log("Success!".green().bold()); + } + + function _checkSlashableStake( + OperatorSet memory operatorSet, + address operator, + IStrategy[] memory strategies, + uint256 expectedStake + ) internal view { + _checkSlashableStake(operatorSet, operator, strategies, expectedStake, block.number); + } + + function _checkSlashableStake( + OperatorSet memory operatorSet, + address operator, + IStrategy[] memory strategies, + uint256 expectedStake, + uint256 futureBlock + ) internal view { + uint256[] memory slashableStake = allocationManager.getMinimumSlashableStake({ + operatorSet: operatorSet, + operators: operator.toArray(), + strategies: strategies, + futureBlock: uint32(futureBlock) + })[0]; + + for (uint256 i = 0; i < strategies.length; i++) { + console.log("\nChecking Slashable Stake:".yellow()); + console.log(" slashableStake[%d] = %d", i, slashableStake[i]); + assertEq(slashableStake[i], expectedStake, "slashableStake != expected"); + } + + console.log("Success!".green().bold()); + } + + function _checkAllocationEvents( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy, + uint64 magnitude, + uint64 encumberedMagnitude, + uint32 effectBlock + ) internal { + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit EncumberedMagnitudeUpdated(operator, strategy, encumberedMagnitude); + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationUpdated(operator, operatorSet, strategy, magnitude, effectBlock); + } + + function _checkDeallocationEvent( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy, + uint64 magnitude, + uint32 effectBlock + ) internal { + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationUpdated(operator, operatorSet, strategy, magnitude, effectBlock); + } + + function _checkClearDeallocationQueueEvents( + address operator, + IStrategy strategy, + uint64 encumberedMagnitude + ) internal { + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit EncumberedMagnitudeUpdated(operator, strategy, encumberedMagnitude); + } + + function _checkSlashEvents( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy, + uint256 wadToSlash, + string memory description, + uint64 currentMag, + uint64 maxMag, + uint64 encumberedMag + ) internal { + return _checkSlashEvents( + operator, + operatorSet, + strategy.toArray(), + wadToSlash.toArrayU256(), + description, + currentMag.toArrayU64(), + maxMag.toArrayU64(), + encumberedMag.toArrayU64() + ); + } + + function _checkSlashEvents( + address operator, + OperatorSet memory operatorSet, + IStrategy[] memory strategies, + uint256[] memory wadToSlash, + string memory description, + uint64[] memory currentMags, + uint64[] memory maxMags, + uint64[] memory encumberedMags + ) internal { + for(uint256 i = 0; i < strategies.length; i++) { + // If there is nothing slashed, we don't emit events for encumbered magnitude + if (wadToSlash[i] == 0) { + continue; + } + cheats.expectEmit(true, true, true, false, address(allocationManager)); + emit EncumberedMagnitudeUpdated(operator, strategies[i], encumberedMags[i]); + cheats.expectEmit(true, true, true, false, address(allocationManager)); + emit AllocationUpdated(operator, operatorSet, strategies[i], currentMags[i], uint32(block.number)); + cheats.expectEmit(true, true, true, false, address(allocationManager)); + emit MaxMagnitudeUpdated(operator, strategies[i], maxMags[i]); + } + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit OperatorSlashed(operator, operatorSet, strategies, wadToSlash, description); + } + + /// ----------------------------------------------------------------------- + /// Allocate/deallocate params + /// ----------------------------------------------------------------------- + + /// @dev Create allocate params, allocating `magnitude` to each strategy in the set + function _newAllocateParams( + OperatorSet memory operatorSet, + uint64 magnitude + ) internal view returns (AllocateParams[] memory) { + IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); + uint64[] memory newMagnitudes = new uint64[](strategies.length); + + for (uint256 i; i < strategies.length; ++i) { + newMagnitudes[i] = magnitude; + } + + return + AllocateParams({operatorSet: operatorSet, strategies: strategies, newMagnitudes: newMagnitudes}).toArray(); + } + + /// @dev Create allocate params for multiple operator sets + function _newAllocateParams( + OperatorSet[] memory operatorSets, + uint64 magnitude + ) internal view returns (AllocateParams[] memory) { + AllocateParams[] memory allocateParams = new AllocateParams[](operatorSets.length); + + for (uint256 i; i < operatorSets.length; ++i) { + allocateParams[i] = _newAllocateParams(operatorSets[i], magnitude)[0]; + } + + return allocateParams; + } + + /// @dev Create random allocation params to the default operator set and strategy + function _randAllocateParams_DefaultOpSet() internal returns (AllocateParams[] memory) { + return _randAllocateParams_SingleMockStrategy(defaultOperatorSet.toArray()); + } + + /// @dev Create allocate params for random magnitudes to the same default strategy across multiple operator sets + function _randAllocateParams_SingleMockStrategy( + OperatorSet[] memory operatorSets + ) internal returns (AllocateParams[] memory) { + // Give each set a minimum of 1 magnitude + uint64[] memory magnitudes = new uint64[](operatorSets.length); + uint64 usedMagnitude; + for (uint8 i = 0; i < magnitudes.length; ++i) { + magnitudes[i] = 1; + usedMagnitude++; + } + + // Distribute remaining magnitude + uint64 maxMagnitude = WAD; + for (uint8 i = 0; i < magnitudes.length; ++i) { + uint64 remainingMagnitude = maxMagnitude - usedMagnitude; + if (remainingMagnitude > 0) { + magnitudes[i] += uint64(random().Uint256(0, remainingMagnitude)); + usedMagnitude += magnitudes[i] - 1; + } + } + + AllocateParams[] memory params = new AllocateParams[](magnitudes.length); + for (uint256 i; i < params.length; ++i) { + params[i] = AllocateParams({ + operatorSet: operatorSets[i], + strategies: defaultStrategies, + newMagnitudes: magnitudes[i].toArrayU64() + }); + } + + return params; + } + + /// @dev Create allocate params for random magnitudes to the same default strategy across multiple operator sets + /// NOTE: this variant allocates ALL magnitude (1 WAD) + function _randAllocateParams_SingleMockStrategy_AllocAll( + OperatorSet[] memory operatorSets + ) internal returns (AllocateParams[] memory) { + // Give each set a minimum of 1 magnitude + uint64[] memory magnitudes = new uint64[](operatorSets.length); + uint64 usedMagnitude; + for (uint8 i = 0; i < magnitudes.length; ++i) { + magnitudes[i] = 1; + usedMagnitude++; + } + + // Distribute remaining magnitude + uint64 maxMagnitude = WAD; + for (uint8 i = 0; i < magnitudes.length; ++i) { + uint64 remainingMagnitude = maxMagnitude - usedMagnitude; + if (remainingMagnitude > 0) { + magnitudes[i] += uint64(random().Uint64(0, remainingMagnitude)); + usedMagnitude += magnitudes[i] - 1; + } + } + + // If there's any left, dump it on a random set + uint64 magnitudeLeft = maxMagnitude - usedMagnitude; + if (magnitudeLeft > 0) { + uint256 randIdx = random().Uint256(0, magnitudes.length - 1); + magnitudes[randIdx] += magnitudeLeft; + usedMagnitude += magnitudeLeft; + } + + AllocateParams[] memory params = new AllocateParams[](magnitudes.length); + for (uint256 i; i < params.length; ++i) { + params[i] = AllocateParams({ + operatorSet: operatorSets[i], + strategies: defaultStrategies, + newMagnitudes: magnitudes[i].toArrayU64() + }); + } + + return params; + } + + /// @dev Create allocate/deallocate params to the same default strategy across multiple sets + function _randAllocAndDeallocParams_SingleMockStrategy( + OperatorSet[] memory operatorSets + ) internal returns (AllocateParams[] memory, AllocateParams[] memory) { + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); + AllocateParams[] memory deallocateParams = new AllocateParams[](allocateParams.length); + + // Generate a random deallocation for each operator set + for (uint256 i; i < deallocateParams.length; ++i) { + deallocateParams[i] = AllocateParams({ + operatorSet: allocateParams[i].operatorSet, + strategies: allocateParams[i].strategies, + newMagnitudes: uint64(random().Uint256({min: 0, max: allocateParams[i].newMagnitudes[0] - 1})).toArrayU64() + }); + } + + return (allocateParams, deallocateParams); + } + + /// ----------------------------------------------------------------------- + /// Utils + /// ----------------------------------------------------------------------- + + function _maxNumToClear() internal pure returns (uint16[] memory) { + uint16[] memory numToClear = new uint16[](1); + numToClear[0] = type(uint16).max; + return numToClear; + } + + function _defaultAllocEffectBlock() internal view returns (uint32) { + return uint32(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + } +} + +contract AllocationManagerUnitTests_Initialization_Setters is AllocationManagerUnitTests { + /// ----------------------------------------------------------------------- + /// initialize() + /// ----------------------------------------------------------------------- + + /// @dev Asserts the following: + /// 1. The fn can only be called once, during deployment. + /// 2. The fn initializes the contract state correctly (owner, pauserRegistry, and initialPausedStatus). + function testFuzz_Initialize( + Randomness r + ) public rand(r) { + // Generate random values for the expected initial state of the contract. + address expectedInitialOwner = r.Address(); + IPauserRegistry expectedPauserRegistry = IPauserRegistry(r.Address()); + + // Deploy the contract with the expected initial state. + uint256 initialPausedStatus = r.Uint256(); + AllocationManager alm = + _initializeAllocationManager(expectedInitialOwner, expectedPauserRegistry, initialPausedStatus); + + // Assert that the contract can only be initialized once. + vm.expectRevert("Initializable: contract is already initialized"); + alm.initialize(expectedInitialOwner, initialPausedStatus); + + // Assert immutable state + assertEq(address(alm.delegation()), address(delegationManagerMock)); + assertEq(alm.DEALLOCATION_DELAY(), DEALLOCATION_DELAY); + assertEq(alm.ALLOCATION_CONFIGURATION_DELAY(), ALLOCATION_CONFIGURATION_DELAY); + + // Assert initialiation state + assertEq(alm.owner(), expectedInitialOwner); + assertEq(alm.paused(), initialPausedStatus); + } +} + +contract AllocationManagerUnitTests_SlashOperator is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + using SlashingLib for *; + + /// ----------------------------------------------------------------------- + /// slashOperator() + /// ----------------------------------------------------------------------- + + function _randSlashingParams(address operator, uint32 operatorSetId) internal returns (SlashingParams memory) { + return SlashingParams({ + operator: operator, + operatorSetId: operatorSetId, + wadToSlash: random().Uint256(1, WAD), + description: "test" + }); + } + + function test_revert_paused() public { + allocationManager.pause(2 ** PAUSED_OPERATOR_SLASHING); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + allocationManager.slashOperator(defaultAVS, _randSlashingParams(defaultOperator, 0)); + } + + function test_revert_slashZero() public { + SlashingParams memory slashingParams = _randSlashingParams(defaultOperator, 0); + slashingParams.wadToSlash = 0; + + cheats.prank(defaultAVS); + cheats.expectRevert(InvalidWadToSlash.selector); + allocationManager.slashOperator(defaultAVS, slashingParams); + } + + function test_revert_slashGreaterThanWAD() public { + SlashingParams memory slashingParams = _randSlashingParams(defaultOperator, 0); + slashingParams.wadToSlash = WAD + 1; + + cheats.prank(defaultAVS); + cheats.expectRevert(InvalidWadToSlash.selector); + allocationManager.slashOperator(defaultAVS, slashingParams); + } + + function test_revert_NotRegisteredToSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(NotMemberOfSet.selector); + allocationManager.slashOperator(defaultAVS, _randSlashingParams(random().Address(), 0)); + } + + /** + * Attempts to slash an operator before the allocation is active + * Validates: + * 1. The events of the slash indicate nothing was slashed + * 2. Storage is not mutated post slash + * 3. The operator's allocation takes effect as normal post slash + */ + function test_operatorAllocated_notActive() public { + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + uint64 encumberedMagnitudeBefore = allocationManager.encumberedMagnitude(defaultOperator, strategyMock); + uint64 maxMagnitudeBefore = allocationManager.getMaxMagnitudes(defaultOperator, strategyMock.toArray())[0]; + + // The only slash event we expect is the OperatorSlashed. There isn't a way to validate + // an event is NOT emitted, but we've manually validated that + cheats.expectEmit(true, true, true, false, address(allocationManager)); + emit OperatorSlashed(defaultOperator, defaultOperatorSet, defaultStrategies, uint256(0).toArrayU256(), "test"); + + cheats.prank(defaultAVS); + allocationManager.slashOperator( + defaultAVS, + SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); + + // Assert encumberedMagnitude and maxMagnitude are unchanged + assertEq( + encumberedMagnitudeBefore, + allocationManager.encumberedMagnitude(defaultOperator, strategyMock), + "encumberedMagnitude mutated" + ); + + assertEq( + maxMagnitudeBefore, + allocationManager.getMaxMagnitudes(defaultOperator, strategyMock.toArray())[0], + "maxMagnitude mutated" + ); + + // Roll to effect block and validate allocation + uint32 effectBlock = uint32(block.number) + DEFAULT_OPERATOR_ALLOCATION_DELAY; + uint64 pendingIncrease = allocateParams[0].newMagnitudes[0]; + cheats.roll(effectBlock); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: pendingIncrease, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: pendingIncrease, max: WAD, allocatable: WAD - pendingIncrease}) + }); + } + + /** + * Allocates all magnitude to for a single strategy to an operatorSet. Slashes 25% + * Validates: + * 1. Events are emitted + * 2. Allocation & info introspection + * 3. Slashable stake introspection + */ + function test_slashPostAllocation() public { + // Generate allocation for this operator set, we allocate max + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: uint256(25e16), + description: "test", + currentMag: uint64(75e16), + maxMag: uint64(75e16), + encumberedMag: uint64(75e16) + }); + + // Slash operator for 25% + cheats.prank(defaultAVS); + allocationManager.slashOperator( + defaultAVS, + SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: 25e16, + description: "test" + }) + ); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 75e16, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: 75e16, max: 75e16, allocatable: 0}) + }); + + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(75e16) + }); + } + + /// @notice Same test as above, but fuzzes the allocation + function testFuzz_slashPostAllocation( + Randomness r + ) public rand(r) { + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + + // Allocate magnitude and roll forward to completable block + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + SlashingParams memory slashingParams = _randSlashingParams(defaultOperator, defaultOperatorSet.id); + + (uint256 expectedWadSlashed, uint64 expectedCurrentMag, uint64 expectedMaxMag, uint64 expectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: allocateParams[0].newMagnitudes[0], + wadToSlash: slashingParams.wadToSlash + }); + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: expectedWadSlashed, + description: "test", + currentMag: expectedCurrentMag, + maxMag: expectedMaxMag, + encumberedMag: expectedEncumberedMag + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: expectedCurrentMag, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: expectedMaxMag - expectedEncumberedMag + }) + }); + + uint256 slashedStake = DEFAULT_OPERATOR_SHARES.mulWad(expectedWadSlashed); // Wad is same as slashed mag since we start with max mag + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: (DEFAULT_OPERATOR_SHARES - slashedStake).mulWad(expectedCurrentMag.divWad(expectedMaxMag)) + }); + } + + /** + * Allocates half of magnitude for a single strategy to an operatorSet. Then allocates again. Slashes 50% + * Asserts that: + * 1. Events are emitted + * 2. Encumbered mag is updated + * 3. Max mag is updated + * 4. Calculations for `getAllocatableMagnitude` and `getAllocation` are correct + * 5. The second allocation is not slashed from + */ + function testFuzz_slash_oneCompletedAlloc_onePendingAlloc( + Randomness r + ) public rand(r) { + uint64 wadToSlash = r.Uint64(0.01 ether, WAD); + + // Generate allocation for `strategyMock`, we allocate half + { + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + } + + // Allocate the other half + AllocateParams[] memory allocateParams2 = _newAllocateParams(defaultOperatorSet, WAD); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams2); + uint32 secondAllocEffectBlock = _defaultAllocEffectBlock(); + + // Slash operator for 50% + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: wadToSlash, + description: "test" + }); + + (uint256 expectedWadSlashed, uint64 expectedCurrentMag, uint64 expectedMaxMag, uint64 expectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: 5e17, + encumberedMagBeforeSlash: WAD, + wadToSlash: wadToSlash + }); + + uint256 slashedStake = DEFAULT_OPERATOR_SHARES.mulWad(expectedWadSlashed); // Wad is same as slashed mag since we start with max mag + uint256 newTotalStake = DEFAULT_OPERATOR_SHARES - slashedStake; + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: expectedWadSlashed, + description: "test", + currentMag: expectedCurrentMag, + maxMag: expectedMaxMag, + encumberedMag: expectedEncumberedMag + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: expectedCurrentMag, + pendingDiff: 5e17, + effectBlock: secondAllocEffectBlock + }), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: 0 + }) + }); + + // Slashable stake should include first allocation and slashed magnitude + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: newTotalStake.mulWad(expectedCurrentMag.divWad(expectedMaxMag)) + }); + + cheats.roll(secondAllocEffectBlock); + + uint64 newSlashableMagnitude = expectedCurrentMag + 5e17; + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: newSlashableMagnitude, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: 0 + }) + }); + + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: newTotalStake.mulWad(newSlashableMagnitude.divWad(expectedMaxMag)) + }); + } + + /** + * Allocates 100% magnitude for a single strategy to an operatorSet. + * First slashes 99% from the operatorSet, slashes 99.99% a second time, and on the third slash, slashes + * 99.9999999999999% which should get rounded up to 100% or WAD wadSlashed leaving the operator with no magnitude + * in the operatorSet, 0 encumbered magnitude, and 0 max magnitude. + * + * Asserts that: + * 1. Events are emitted + * 2. Storage properly updated after each slash + * 3. Slashed amounts are rounded up to ensure magnitude is always slashed + */ + function test_repeatUntilFullSlash() public { + // Generate allocation for `strategyMock`, we allocate 100% to opSet 0 + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // 1. Slash operator for 99% in opSet 0 bringing their magnitude to 1e16 + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: 99e16, + description: "test" + }); + + uint64 expectedEncumberedMagnitude = 1e16; // After slashing 99%, only 1% expected encumberedMagnitude + uint64 magnitudeAfterSlash = 1e16; + uint64 maxMagnitudeAfterSlash = 1e16; // 1e15 is maxMagnitude + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: uint256(99e16), + description: "test", + currentMag: magnitudeAfterSlash, + maxMag: maxMagnitudeAfterSlash, + encumberedMag: expectedEncumberedMagnitude + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: magnitudeAfterSlash, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMagnitude, + max: maxMagnitudeAfterSlash, + allocatable: maxMagnitudeAfterSlash - expectedEncumberedMagnitude + }) + }); + + + // 2. Slash operator again for 99.99% in opSet 0 bringing their magnitude to 1e14 + slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: 9999e14, + description: "test" + }); + + expectedEncumberedMagnitude = 1e12; // After slashing 99.99%, only 0.01% expected encumberedMagnitude + magnitudeAfterSlash = 1e12; + maxMagnitudeAfterSlash = 1e12; + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: uint256(9999e14), + description: "test", + currentMag: magnitudeAfterSlash, + maxMag: maxMagnitudeAfterSlash, + encumberedMag: expectedEncumberedMagnitude + }); + + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: magnitudeAfterSlash, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMagnitude, + max: maxMagnitudeAfterSlash, + allocatable: maxMagnitudeAfterSlash - expectedEncumberedMagnitude + }) + }); + + // 3. Slash operator again for 99.9999999999999% in opSet 0 + slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: WAD - 1e3, + description: "test" + }); + // Should technically be 1e3 remaining but with rounding error and rounding up slashed amounts + // the remaining magnitude is 0 + expectedEncumberedMagnitude = 0; // Should technically be 1e3 remaining but with rounding error and rounding up slashed amounts. + magnitudeAfterSlash = 0; + maxMagnitudeAfterSlash = 0; + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: WAD, + description: "test", + currentMag: magnitudeAfterSlash, + maxMag: maxMagnitudeAfterSlash, + encumberedMag: expectedEncumberedMagnitude + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: 0, + max: 0, + allocatable: 0 + }) + }); + + // Check slashable amount after final slash + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: 0 + }); + } + + /** + * Allocates all of magnitude to a single strategy to an operatorSet. Deallocate half. Finally, slash while deallocation is pending + * Asserts that: + * 1. Events are emitted, including for deallocation + * 2. Encumbered mag is updated + * 3. Max mag is updated + * 4. Calculations for `getAllocatableMagnitude` and `getAllocation` are correct + * 5. The deallocation is slashed from + * 6. Pending magnitude updates post deallocation are valid + */ + function testFuzz_SlashWhileDeallocationPending( + Randomness r + ) public rand(r) { + // Initialize state + AllocateParams[] memory allocateParams = r.AllocateParams(defaultAVS, 1, 1); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + RegisterParams memory registerParams = r.RegisterParams(allocateParams); + SlashingParams memory slashingParams = r.SlashingParams(defaultOperator, allocateParams[0]); + + delegationManagerMock.setOperatorShares( + defaultOperator, allocateParams[0].strategies[0], DEFAULT_OPERATOR_SHARES + ); + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + cheats.startPrank(defaultOperator); + allocationManager.registerForOperatorSets(defaultOperator, registerParams); + + // Allocate + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + cheats.stopPrank(); + + uint256 magnitudeAllocated = allocateParams[0].newMagnitudes[0]; + uint256 magnitudeDeallocated = magnitudeAllocated - deallocateParams[0].newMagnitudes[0]; + uint256 magnitudeSlashed = (magnitudeAllocated * slashingParams.wadToSlash / WAD) + _calculateSlippage(uint64(magnitudeAllocated), slashingParams.wadToSlash); + uint256 expectedCurrentMagnitude = magnitudeAllocated - magnitudeSlashed; + int128 expectedPendingDiff = + -int128(uint128(magnitudeDeallocated - magnitudeDeallocated.mulWadRoundUp(slashingParams.wadToSlash))); + + // Manually check slash events since we have a deallocation pending + // Deallocation update is emitted first + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationUpdated(defaultOperator, allocateParams[0].operatorSet, allocateParams[0].strategies[0], uint64(uint128(int128(uint128(expectedCurrentMagnitude)) + expectedPendingDiff)), deallocationEffectBlock); + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit EncumberedMagnitudeUpdated(defaultOperator, allocateParams[0].strategies[0], uint64(magnitudeAllocated - magnitudeSlashed)); + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationUpdated(defaultOperator, allocateParams[0].operatorSet, allocateParams[0].strategies[0], uint64(expectedCurrentMagnitude), uint32(block.number)); + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit MaxMagnitudeUpdated(defaultOperator, allocateParams[0].strategies[0], uint64(WAD - magnitudeSlashed)); + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit OperatorSlashed(defaultOperator, allocateParams[0].operatorSet, allocateParams[0].strategies, magnitudeSlashed.toArrayU256(), "test"); + + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: allocateParams[0].operatorSet, + strategy: allocateParams[0].strategies[0], + expectedAllocation: Allocation({ + currentMagnitude: uint64(expectedCurrentMagnitude), + pendingDiff: expectedPendingDiff, + effectBlock: deallocationEffectBlock + }), + expectedMagnitudes: Magnitudes({ + encumbered: expectedCurrentMagnitude, + max: uint64(WAD - magnitudeSlashed), + allocatable: 0 + }) + }); + + cheats.roll(deallocationEffectBlock); + allocationManager.clearDeallocationQueue(defaultOperator, allocateParams[0].strategies, _maxNumToClear()); + + uint64 newMag = uint64(uint128(int128(uint128(expectedCurrentMagnitude)) + expectedPendingDiff)); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: allocateParams[0].operatorSet, + strategy: allocateParams[0].strategies[0], + expectedAllocation: Allocation({currentMagnitude: newMag, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: newMag, + max: uint64(WAD - magnitudeSlashed), + allocatable: uint128(-expectedPendingDiff) // This works because we allocated all in the randomization allocation helper + }) + }); + } + + /** + * Allocates all magnitude to a single opSet. Then slashes the entire magnitude + * Validates: + * 1. Storage post slash + * 2. The operator cannot allocate again + */ + function testRevert_allocateAfterSlashedEntirely() public { + // Allocate all magnitude + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: WAD, + description: "test", + currentMag: 0, + maxMag: 0, + encumberedMag: 0 + }); + + // Slash operator for 100% + cheats.prank(defaultAVS); + allocationManager.slashOperator( + defaultAVS, + SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); + + // Validate storage post slash + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: 0, max: 0, allocatable: 0}) + }); + + OperatorSet memory operatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); + AllocateParams[] memory allocateParams2 = _newAllocateParams(operatorSet, 1); + + // Attempt to allocate + cheats.prank(defaultOperator); + cheats.expectRevert(InsufficientMagnitude.selector); + allocationManager.modifyAllocations(defaultOperator, allocateParams2); + } + + /** + * Allocates all magnitude to a single opSet. Deallocates magnitude. Slashes all + * Asserts that: + * 1. The Allocation is 0 after slash + * 2. Them storage post slash for encumbered and maxMags is zero + */ + function test_slash_allocateAll_deallocateAll() public { + // Allocate all magnitude + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, _newAllocateParams(defaultOperatorSet, WAD)); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate all + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, _newAllocateParams(defaultOperatorSet, 0)); + + // Validate event for the deallocation + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationUpdated(defaultOperator, defaultOperatorSet, strategyMock, 0, uint32(block.number + DEALLOCATION_DELAY)); + + // Slash operator for 100% + cheats.prank(defaultAVS); + allocationManager.slashOperator( + defaultAVS, + SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: WAD, + description: "test" + }) + ); + + // forgefmt: disable-next-item + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: uint32(block.number) + DEALLOCATION_DELAY}), + expectedMagnitudes: Magnitudes({encumbered: 0, max: 0, allocatable: 0}) + }); + } + + /** + * Slashes the operator after deallocation, even if the deallocation has not been cleared. + * Validates that: + * 1. Even if we do not clear deallocation queue, the deallocation is NOT slashed from since we're passed the deallocationEffectBlock + * 2. Validates storage post slash & post clearing deallocation queue + * 3. Max magnitude only decreased proportionally by the magnitude set after deallocation + */ + function test_allocate_deallocate_slashAfterDeallocation() public { + // Allocate all magnitude + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate half + AllocateParams[] memory deallocateParams = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + + // Warp to deallocation effect block + cheats.roll(deallocationEffectBlock); + + // Slash operator for 25% + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: 25e16, + description: "test" + }); + + uint64 expectedEncumberedMagnitude = 375e15; // 25e16 is slashed. 5e17 was previously + uint64 magnitudeAfterSlash = 375e15; + uint64 maxMagnitudeAfterSlash = 875e15; // Operator can only allocate up to 75e16 magnitude since 25% is slashed + uint256 expectedSlashedMagnitude = SlashingLib.mulWadRoundUp(5e17, 25e16); + + // Slash Operator, only emit events assuming that there is no deallocation + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + wadToSlash: expectedSlashedMagnitude, + description: "test", + currentMag: magnitudeAfterSlash, + maxMag: maxMagnitudeAfterSlash, + encumberedMag: expectedEncumberedMagnitude + }); + + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + + uint64 allocatableMagnitudeAfterSlash = allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: magnitudeAfterSlash, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMagnitude, + max: maxMagnitudeAfterSlash, + allocatable: allocatableMagnitudeAfterSlash + }) + }); + } + + /** + * Allocates to multiple operatorSets for a strategy. Only slashes from one operatorSet. + * Validates: + * 1. The first operatorSet has less slashable shares post slash + * 2. The second operatorSet has the same number slashable shares post slash (within slippage) + * 3. The PROPORTION that is slashable for opSet 2 has increased + */ + function testFuzz_allocateMultipleOpsets_slashSingleOpset(Randomness r) rand(r) public { + // Get magnitude to allocate + uint64 magnitudeToAllocate = r.Uint64(1, 5e17); + uint256 wadToSlash = r.Uint256(1, 1e18); + + OperatorSet memory operatorSet = OperatorSet(defaultAVS, 1); + OperatorSet memory operatorSet2 = OperatorSet(defaultAVS, 2); + + // Allocate 40% to firstOperatorSet, 40% to secondOperatorSet + AllocateParams[] memory allocateParams = new AllocateParams[](2); + allocateParams[0] = _newAllocateParams( + _createOperatorSet(OperatorSet(defaultAVS, 1), defaultStrategies), magnitudeToAllocate + )[0]; + allocateParams[1] = _newAllocateParams( + _createOperatorSet(OperatorSet(defaultAVS, 2), defaultStrategies), magnitudeToAllocate + )[0]; + + // Register operator for both operatorSets + _registerForOperatorSet(defaultOperator, operatorSet); + _registerForOperatorSet(defaultOperator, operatorSet2); + + // Modify allocations + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Get slashable shares for each operatorSet + uint256 opset2SlashableSharesBefore = allocationManager.getMinimumSlashableStake(operatorSet2, defaultOperator.toArray(), defaultStrategies, uint32(block.number))[0][0]; + // Slash operator on operatorSet1 for 50% + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: allocateParams[0].operatorSet.id, + wadToSlash: wadToSlash, + description: "test" + }); + + (, uint64 expectedCurrentMag, uint64 expectedMaxMag, uint64 expectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: allocateParams[0].newMagnitudes[0], + wadToSlash: slashingParams.wadToSlash, + encumberedMagBeforeSlash: allocateParams[0].newMagnitudes[0] * 2 + }); + + // Slash Operator + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Validate storage operatorSet1 + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: expectedCurrentMag, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: expectedMaxMag - expectedEncumberedMag + }) + }); + + // Validate storage for operatorSet2 + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSet2, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: magnitudeToAllocate, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: expectedMaxMag - expectedEncumberedMag + }) + }); + + // Check proportion after slash + uint256 opSet2PortionOfMaxMagnitudeAfterSlash = uint256(magnitudeToAllocate) * WAD / expectedMaxMag; + assertGt( + opSet2PortionOfMaxMagnitudeAfterSlash, + magnitudeToAllocate, // This is the same as proportion before slash + "opSet2 should have a greater proportion to slash from previous" + ); + + // Assert that slashable stake is the same - we add slippage here due to rounding error from the slash itself + assertEq( + opset2SlashableSharesBefore, + allocationManager.getMinimumSlashableStake(operatorSet2, defaultOperator.toArray(), defaultStrategies, uint32(block.number))[0][0] + + 1, + "opSet2 slashable shares should be the same" + ); + } + + /** + * Allocates to multiple strategies for the given operatorSetKey. Slashes from both strategies Validates a slash propagates to both strategies. + * Validates that + * 1. Proper events are emitted for each strategy slashed + * 2. Each strategy is slashed proportional to its allocation + * 3. Storage is updated for each strategy, opSet + */ + function testFuzz_allocateMultipleStrategies_slashMultiple(Randomness r) rand(r) public { + // Initialize random params + uint64 strategy1Magnitude = r.Uint64(1, 1e18); + uint64 strategy2Magnitude = r.Uint64(1, 1e18); + uint256 wadToSlash = r.Uint256(1, 1e18); + + // Crate and allocate to operatorSets + OperatorSet memory operatorSet = OperatorSet(defaultAVS, random().Uint32()); + _createOperatorSet(operatorSet, random().StrategyArray(2)); + _registerForOperatorSet(defaultOperator, operatorSet); + + IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); + { + AllocateParams memory allocateParams = + AllocateParams({operatorSet: operatorSet, strategies: strategies, newMagnitudes: new uint64[](2)}); + allocateParams.newMagnitudes[0] = strategy1Magnitude; + allocateParams.newMagnitudes[1] = strategy2Magnitude; + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams.toArray()); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + } + + // Store post-slash vars to check against + uint64[] memory expectedEncumberedMags = new uint64[](2); + uint256[] memory expectedSlashedMagnitude = new uint256[](2); + uint64[] memory expectedMagnitudeAfterSlash = new uint64[](2); + uint64[] memory expectedMaxMagnitudeAfterSlash = new uint64[](2); + + { + (uint256 strat1ExpectedWadSlashed, uint64 strat1ExpectedCurrentMag, uint64 strat1ExpectedMaxMag, uint64 strat1ExpectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: strategy1Magnitude, + wadToSlash: wadToSlash + }); + expectedEncumberedMags[0] = strat1ExpectedEncumberedMag; + expectedSlashedMagnitude[0] = strat1ExpectedWadSlashed; + expectedMagnitudeAfterSlash[0] = strat1ExpectedCurrentMag; + expectedMaxMagnitudeAfterSlash[0] = strat1ExpectedMaxMag; + } + { + (uint256 strat2ExpectedWadSlashed, uint64 strat2ExpectedCurrentMag, uint64 strat2ExpectedMaxMag, uint64 strat2ExpectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: strategy2Magnitude, + wadToSlash: wadToSlash + }); + expectedEncumberedMags[1] = strat2ExpectedEncumberedMag; + expectedSlashedMagnitude[1] = strat2ExpectedWadSlashed; + expectedMagnitudeAfterSlash[1] = strat2ExpectedCurrentMag; + expectedMaxMagnitudeAfterSlash[1] = strat2ExpectedMaxMag; + } + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategies: strategies, + wadToSlash: expectedSlashedMagnitude, + description: "test", + currentMags: expectedMagnitudeAfterSlash, + maxMags: expectedMaxMagnitudeAfterSlash, + encumberedMags: expectedEncumberedMags + }); + + // Slash Operator + { + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: operatorSet.id, + wadToSlash: wadToSlash, + description: "test" + }); + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + } + + // Check storage + for (uint256 i; i < strategies.length; ++i) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategies[i], + expectedAllocation: Allocation({ + currentMagnitude: expectedMagnitudeAfterSlash[i], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMags[i], + max: expectedMaxMagnitudeAfterSlash[i], + allocatable: expectedMaxMagnitudeAfterSlash[i] - expectedEncumberedMags[i] + }) + }); + } + } + + /// @dev Allocates magnitude. Deallocates some. Slashes a portion, and then allocates up to the max available magnitude + function testFuzz_allocate_deallocate_allocateMax( + Randomness r + ) public rand(r) { + AllocateParams[] memory allocateParams = r.AllocateParams({avs: defaultAVS, numAllocations: 1, numStrats: 1}); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + OperatorSet memory operatorSet = allocateParams[0].operatorSet; + IStrategy strategy = allocateParams[0].strategies[0]; + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + + _registerForOperatorSet(defaultOperator, operatorSet); + + // Allocate some magnitude, then deallocate some. + cheats.startPrank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + cheats.roll(block.number + DEALLOCATION_DELAY); + cheats.stopPrank(); + + // Slash operator for some random amount (1% -> 99%). + SlashingParams memory slashingParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: operatorSet.id, + wadToSlash: r.Uint64(0.01 ether, 0.99 ether), + description: "test" + }); + + (uint256 expectedWadSlashed, uint64 expectedCurrentMag, uint64 expectedMaxMag, uint64 expectedEncumberedMag) = _getExpectedSlashVals({ + magBeforeSlash: deallocateParams[0].newMagnitudes[0], + wadToSlash: slashingParams.wadToSlash + }); + + _checkSlashEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: allocateParams[0].strategies[0], + wadToSlash: expectedWadSlashed, + description: "test", + currentMag: expectedCurrentMag, + maxMag: expectedMaxMag, + encumberedMag: expectedEncumberedMag + }); + + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Clear deallocation queue. + allocationManager.clearDeallocationQueue(defaultOperator, strategy.toArray(), _maxNumToClear()); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategy, + expectedAllocation: Allocation({currentMagnitude: expectedCurrentMag, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedEncumberedMag, + max: expectedMaxMag, + allocatable: expectedMaxMag - expectedEncumberedMag + }) + }); + + // Allocate up to max magnitude + AllocateParams[] memory allocateParams2 = _newAllocateParams(operatorSet, expectedMaxMag); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams2); + + int128 pendingDiff = int128(uint128(expectedMaxMag - expectedCurrentMag)); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategy, + expectedAllocation: Allocation({currentMagnitude: expectedCurrentMag, pendingDiff: pendingDiff, effectBlock: _defaultAllocEffectBlock()}), + expectedMagnitudes: Magnitudes({ + encumbered: expectedMaxMag, + max: expectedMaxMag, + allocatable: 0 + }) + }); + } +} + +contract AllocationManagerUnitTests_ModifyAllocations is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + using OperatorSetLib for *; + using SlashingLib for *; + + function test_revert_paused() public { + allocationManager.pause(2 ** PAUSED_MODIFY_ALLOCATIONS); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + allocationManager.modifyAllocations(address(this), new AllocateParams[](0)); + } + + function test_revert_invalidCaller() public { + address invalidOperator = address(0x2); + cheats.expectRevert(InvalidCaller.selector); + allocationManager.modifyAllocations(invalidOperator, new AllocateParams[](0)); + } + + function test_revert_allocationDelayNotSet() public { + address invalidOperator = address(0x2); + cheats.prank(invalidOperator); + cheats.expectRevert(UninitializedAllocationDelay.selector); + allocationManager.modifyAllocations(invalidOperator, new AllocateParams[](0)); + } + + function test_revert_allocationDelayNotInEffect() public { + address operator = address(0x2); + _registerOperator(operator); + + cheats.startPrank(operator); + allocationManager.setAllocationDelay(operator, 5); + // even though the operator has an allocation delay set, it is not in effect + // and modifyAllocations should still be blocked + cheats.expectRevert(UninitializedAllocationDelay.selector); + allocationManager.modifyAllocations(operator, new AllocateParams[](0)); + } + + function test_revert_lengthMismatch() public { + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + allocateParams[0].newMagnitudes = new uint64[](0); + + cheats.expectRevert(InputArrayLengthMismatch.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function test_revert_invalidOperatorSet() public { + AllocateParams[] memory allocateParams = AllocateParams({ + operatorSet: OperatorSet(random().Address(), 0), + strategies: defaultStrategies, + newMagnitudes: uint64(0.5 ether).toArrayU64() + }).toArray(); + + cheats.expectRevert(InvalidOperatorSet.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function test_revert_multiAlloc_modificationAlreadyPending_diffTx() public { + // Allocate magnitude + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.startPrank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to just before allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY - 1); + + // Attempt to allocate magnitude again + cheats.expectRevert(ModificationAlreadyPending.selector); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.stopPrank(); + } + + function test_revert_multiAlloc_modificationAlreadyPending_sameTx() public { + // Allocate magnitude + AllocateParams[] memory allocateParams = new AllocateParams[](2); + allocateParams[0] = _randAllocateParams_DefaultOpSet()[0]; + allocateParams[1] = allocateParams[0]; + + cheats.expectRevert(ModificationAlreadyPending.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function test_revert_allocateZeroMagnitude() public { + // Allocate exact same magnitude as initial allocation (0) + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + allocateParams[0].newMagnitudes[0] = 0; + + cheats.expectRevert(SameMagnitude.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function test_revert_allocateSameMagnitude() public { + // Allocate nonzero magnitude + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Attempt to allocate no magnitude (ie. same magnitude) + cheats.expectRevert(SameMagnitude.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function testFuzz_revert_insufficientAllocatableMagnitude( + Randomness r + ) public rand(r) { + // Allocate some magnitude + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Attempt to allocate more magnitude than the operator has + // uint64 allocatedMag = allocateParams[0].newMagnitudes[0]; + allocateParams[0].newMagnitudes[0] = WAD + 1; + cheats.expectRevert(InsufficientMagnitude.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function testFuzz_revert_overAllocate( + Randomness r + ) public rand(r) { + uint8 numOpSets = uint8(r.Uint256(2, FUZZ_MAX_OP_SETS)); + + // Create and register for operator sets + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(operatorSets, defaultStrategies); + + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); + uint256 randIdx = r.Uint256(0, allocateParams.length - 1); + + allocateParams[randIdx].newMagnitudes[0] = WAD + 1; + + // Overallocate + cheats.expectRevert(InsufficientMagnitude.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + // TODO: yash + // function test_allocateMaxToMultipleStrategies( + // Randomness r + // ) public rand(r) { + // // Create a handful of operator sets under the same AVS, each with a unique strategy + // OperatorSet[] memory operatorSets = _newOperatorSets_SingleUniqueStrategy(defaultAVS, r.Uint256(2, 10)); + + // // Register for each operator set + // _registerForOperatorSets(defaultOperator, operatorSets); + + // // Allocate max to each operator set + // AllocateParams[] memory allocateParams = new AllocateParams[](operatorSets.length); + // for (uint256 i = 0; i < operatorSets.length; i++) { + // allocateParams[i] = AllocateParams({ + // operatorSet: operatorSets[i], + // strategies: allocationManager.getStrategiesInOperatorSet(operatorSets[i]), + // newMagnitudes: WAD.toArrayU64() + // }); + // } + + // cheats.prank(defaultOperator); + // allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // // Ensure encumbered magnitude is updated for each strategy + // for (uint256 i = 0; i < allocateParams.length; i++) { + // assertEq( + // WAD, + // allocationManager.encumberedMagnitude(defaultOperator, allocateParams[i].strategies[0]), + // "encumberedMagnitude not max" + // ); + // } + // } + + function test_revert_allocateDeallocate_modificationPending() public { + // Allocate + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Deallocate + allocateParams[0].newMagnitudes[0] -= 1; + cheats.expectRevert(ModificationAlreadyPending.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + function test_revert_deallocateTwice_modificationPending() public { + // Allocate + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp past allocation complete timestsamp + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + allocateParams[0].newMagnitudes[0] -= 1; + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Deallocate again -> expect revert + cheats.expectRevert(ModificationAlreadyPending.selector); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + } + + /** + * @notice Tests edge cases around allocation delay: + * 1. Set allocation delay to a value greater than ALLOCATION_CONFIGURATION_DELAY + * 2. Allocate magnitude before the configured delay is hit + * 3. Set allocation delay to a value less than ALLOCATION_CONFIGURATION_DELAY + * 4. Allocate magnitude after allocation in step 2 takes effect, but before the new delay is hit + * Validates that you should be able to allocate in step 4 since there is no other pending modifications + */ + function testFuzz_ShouldBeAbleToAllocateSoonerThanLastDelay( + Randomness r + ) public rand(r) { + uint32 firstDelay = r.Uint32(ALLOCATION_CONFIGURATION_DELAY, type(uint24).max); + uint32 secondDelay = r.Uint32(1, ALLOCATION_CONFIGURATION_DELAY - 1); + uint64 half = 0.5 ether; + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, CreateSetParams(1, defaultStrategies).toArray()); + + cheats.startPrank(defaultOperator); + + allocationManager.setAllocationDelay(defaultOperator, firstDelay); + + allocationManager.modifyAllocations(defaultOperator, _newAllocateParams(defaultOperatorSet, half)); + + // Validate storage - the `firstDelay` should not be applied yet + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: int64(half), effectBlock: _defaultAllocEffectBlock()}), + expectedMagnitudes: Magnitudes({encumbered: half, max: WAD, allocatable: WAD - half}) + }); + + allocationManager.setAllocationDelay(defaultOperator, secondDelay); + + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + allocationManager.modifyAllocations(defaultOperator, _newAllocateParams(defaultOperatorSet, half+1)); + + cheats.stopPrank(); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: half, pendingDiff: int64(1), effectBlock: uint32(block.number + secondDelay)}), + expectedMagnitudes: Magnitudes({encumbered: half+1, max: WAD, allocatable: WAD - (half + 1)}) + }); + } + + /** + * @notice Allocates a random magnitude to the default operatorSet. + * Validates: + * 1. Storage is clear prior to allocation + * 2. Events are emitted + * 3. Allocation storage/introspection after allocation + * 4. Allocation storage/introspection after roll to allocation effect block + */ + function testFuzz_allocate_singleStrat_singleOperatorSet( + Randomness r + ) public rand(r) { + // Create allocation + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + + // Save vars to check against + uint64 magnitude = allocateParams[0].newMagnitudes[0]; + uint32 effectBlock = _defaultAllocEffectBlock(); + + // Check that the operator has no allocated sets/strats before allocation + OperatorSet[] memory allocatedSets = allocationManager.getAllocatedSets(defaultOperator); + IStrategy[] memory allocatedStrats = + allocationManager.getAllocatedStrategies(defaultOperator, defaultOperatorSet); + assertEq(allocatedSets.length, 0, "should not have any allocated sets before allocation"); + assertEq(allocatedStrats.length, 0, "should not have any allocated strats before allocation"); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: magnitude, + encumberedMagnitude: magnitude, + effectBlock: effectBlock + }); + + // Allocate magnitude + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage Prior to Completion + + // 1. Validate allocated sets and strategies + allocatedSets = allocationManager.getAllocatedSets(defaultOperator); + allocatedStrats = allocationManager.getAllocatedStrategies(defaultOperator, defaultOperatorSet); + assertEq(allocatedSets.length, 1, "should have a single allocated set"); + assertEq(allocatedSets[0].key(), defaultOperatorSet.key(), "should be allocated to default set"); + assertEq(allocatedStrats.length, 1, "should have a single allocated strategy to default set"); + assertEq(address(allocatedStrats[0]), address(strategyMock), "should have allocated default strat"); + + // 2. Validate allocation + info + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: 0, + pendingDiff: int128(uint128(magnitude)), + effectBlock: effectBlock + }), + expectedMagnitudes: Magnitudes({encumbered: magnitude, max: WAD, allocatable: WAD - magnitude}) + }); + + + // 3. Check allocation and info after roll to completion + cheats.roll(effectBlock); + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: magnitude, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: magnitude, max: WAD, allocatable: WAD - magnitude}) + }); + } + + /** + * @notice Allocates magnitude for a single strategy to multiple operatorSets + * Validates: + * 1. Events + * 2. Allocation storage/introspection after allocation + * 3. Allocation storage/introspection after roll to allocation effect block + */ + function testFuzz_allocate_singleStrat_multipleSets( + Randomness r + ) public rand(r) { + uint8 numOpSets = uint8(r.Uint256(1, FUZZ_MAX_OP_SETS)); + + // Create and register for operator sets, each with a single default strategy + OperatorSet[] memory operatorSets = r.OperatorSetArray(defaultAVS, numOpSets); + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(operatorSets); + + _createOperatorSets(operatorSets, defaultStrategies); + _registerForOperatorSets(defaultOperator, operatorSets); + + // Save vars to check against + uint32 effectBlock = _defaultAllocEffectBlock(); + uint64 usedMagnitude; + for (uint256 i; i < allocateParams.length; ++i) { + usedMagnitude += allocateParams[i].newMagnitudes[0]; + } + + // Validate events + for (uint256 i; i < allocateParams.length; ++i) { + // There is only one strategy in each allocateParams, so we don't need a nested for loop + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + magnitude: allocateParams[i].newMagnitudes[0], + encumberedMagnitude: _encumberedMagnitudes[strategyMock] + allocateParams[i].newMagnitudes[0], + effectBlock: effectBlock + }); + _encumberedMagnitudes[strategyMock] += allocateParams[i].newMagnitudes[0]; + } + + // Allocate magnitude + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage + + // 1. Sanity check number of allocated sets + OperatorSet[] memory allocatedSets = allocationManager.getAllocatedSets(defaultOperator); + assertEq(allocatedSets.length, numOpSets, "should have multiple allocated sets"); + + // 2. Check storage after allocation + for (uint256 i; i < allocateParams.length; ++i) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: 0, + pendingDiff: int128(uint128(allocateParams[i].newMagnitudes[0])), + effectBlock: effectBlock + }), + expectedMagnitudes: Magnitudes({ + encumbered: _encumberedMagnitudes[strategyMock], + max: WAD, + allocatable: WAD - _encumberedMagnitudes[strategyMock] + }) + }); + + IStrategy[] memory allocatedStrats = allocationManager.getAllocatedStrategies(defaultOperator, operatorSets[i]); + assertEq(allocatedStrats.length, 1, "should have a single allocated strategy to each set"); + assertEq(address(allocatedStrats[0]), address(strategyMock), "should have allocated default strat"); + assertEq(allocatedSets[i].key(), operatorSets[i].key(), "should be allocated to expected set"); + } + + // 3. Check storage after roll to completion + cheats.roll(effectBlock); + for (uint256 i; i < allocateParams.length; ++i) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSets[i], + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[i].newMagnitudes[0], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: _encumberedMagnitudes[strategyMock], + max: WAD, + allocatable: WAD - _encumberedMagnitudes[strategyMock] + }) + }); + } + } + + /** + * @notice Allocates once, warps to allocation effect block, then allocates again + * Validates: + * 1. Events for each allocation + * 2. Allocation storage/introspection immediately after each allocation + */ + function testFuzz_allocateMultipleTimes( + Randomness r + ) public rand(r) { + uint64 firstAlloc = r.Uint64(1, WAD - 1); + uint64 secondAlloc = r.Uint64(firstAlloc + 1, WAD); + + // Validate events + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: firstAlloc, + encumberedMagnitude: firstAlloc, + effectBlock: _defaultAllocEffectBlock() + }); + + // Allocate magnitude + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstAlloc); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: int64(firstAlloc), effectBlock: _defaultAllocEffectBlock()}), + expectedMagnitudes: Magnitudes({encumbered: firstAlloc, max: WAD, allocatable: WAD - firstAlloc}) + }); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Allocate magnitude again + allocateParams = _newAllocateParams(defaultOperatorSet, secondAlloc); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: secondAlloc, + encumberedMagnitude: secondAlloc, + effectBlock: _defaultAllocEffectBlock() + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: firstAlloc, pendingDiff: int64(secondAlloc - firstAlloc), effectBlock: _defaultAllocEffectBlock()}), + expectedMagnitudes: Magnitudes({encumbered: secondAlloc, max: WAD, allocatable: WAD - secondAlloc}) + }); + } + + /** + * Allocates maximum magnitude to multiple strategies for the same operatorSet + * Validates that encumbered magnitude is max for each strategy + */ + function testFuzz_allocateMaxToMultipleStrategies( + Randomness r + ) public rand(r) { + uint256 numStrats = r.Uint256(2, FUZZ_MAX_STRATS); + + OperatorSet memory operatorSet = OperatorSet(defaultAVS, r.Uint32()); + IStrategy[] memory strategies = r.StrategyArray(numStrats); + + _createOperatorSet(operatorSet, strategies); + _registerForOperatorSet(defaultOperator, operatorSet); + + for (uint256 i; i < numStrats; ++i) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSet, + strategy: strategies[i], + magnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: _defaultAllocEffectBlock() + }); + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations( + defaultOperator, + AllocateParams({operatorSet: operatorSet, strategies: strategies, newMagnitudes: WAD.toArrayU64(numStrats)}) + .toArray() + ); + + for (uint256 i; i < numStrats; ++i) { + assertEq( + WAD, + allocationManager.encumberedMagnitude(defaultOperator, strategies[i]), + "encumberedMagnitude not max" + ); + } + } + + /** + * Allocates to `firstMod` magnitude and then deallocate to `secondMod` magnitude + * Validates: + * 1. Events are valid for the allocation and deallocation + * 2. Storage after the allocation is made + * 3. Storage after the deallocation is made + * 4. Storage after the deallocation effect block is hit + * 5. Storage after the deallocation queue is cleared (specifically encumbered mag is decreased) + */ + function testFuzz_allocate_deallocate_whenRegistered( + Randomness r + ) public rand(r) { + // Bound allocation and deallocation + uint64 firstMod = r.Uint64(1, WAD); + uint64 secondMod = r.Uint64(0, firstMod - 1); + + // Allocate magnitude to default registered set + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstMod); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: firstMod, + encumberedMagnitude: firstMod, + effectBlock: _defaultAllocEffectBlock() + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + allocateParams = _newAllocateParams(defaultOperatorSet, secondMod); + + _checkDeallocationEvent({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: secondMod, + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage after dealloc + uint32 effectBlock = uint32(block.number + DEALLOCATION_DELAY); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: firstMod, + pendingDiff: -int128(uint128(firstMod - secondMod)), + effectBlock: effectBlock + }), + expectedMagnitudes: Magnitudes({encumbered: firstMod, max: WAD, allocatable: WAD - firstMod}) + }); + + // Check storage after roll to completion + cheats.roll(effectBlock); + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: secondMod, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: firstMod, max: WAD, allocatable: WAD - secondMod}) + }); + + // Check storage after clearing deallocation queue + allocationManager.clearDeallocationQueue(defaultOperator, strategyMock.toArray(), uint16(1).toArrayU16()); + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: secondMod, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: secondMod, max: WAD, allocatable: WAD - secondMod}) + }); + } + + /** + * Allocates to an operatorSet, then fully deallocates after the strategy is removed from the set. + * Validates that the deallocation takes effect immediately after the strategy is removed + */ + function test_allocate_removeStrategyFromSet_fullyDeallocate() public { + // Allocate + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(defaultOperatorSet.toArray()); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Remove strategy from operatorSet + cheats.prank(defaultAVS); + allocationManager.removeStrategiesFromOperatorSet(defaultAVS, defaultOperatorSet.id, defaultStrategies); + + // Deallocate All Instantly + AllocateParams[] memory deallocateParams = allocateParams; + deallocateParams[0].newMagnitudes[0] = 0; + + // We check the allocation event and not the deallocation event since the encumbered mag is updated too! + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: 0, + encumberedMagnitude: 0, + effectBlock: uint32(block.number) + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: 0, max: WAD, allocatable: WAD}) + }); + } + + /** + * Allocates to an operatorSet, deallocates, then removes a strategy from the operatorSet + * Validates that: + * 1. The deallocation still completes at its expected time + */ + function testFuzz_allocate_deallocate_removeStrategyFromSet(Randomness r) public { + // Allocate + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy(defaultOperatorSet.toArray()); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + uint32 deallocEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + + // Remove strategy from operatorSet + cheats.prank(defaultAVS); + allocationManager.removeStrategiesFromOperatorSet(defaultAVS, defaultOperatorSet.id, defaultStrategies); + + // Roll to just before deallocation complete block & clear deallocation queue for sanity + cheats.roll(deallocEffectBlock - 1); + allocationManager.clearDeallocationQueue(defaultOperator, strategyMock.toArray(), _maxNumToClear()); + + int128 expectedDiff = -int128(uint128(allocateParams[0].newMagnitudes[0] - deallocateParams[0].newMagnitudes[0])); + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: allocateParams[0].newMagnitudes[0], pendingDiff: expectedDiff, effectBlock: deallocEffectBlock}), + expectedMagnitudes: Magnitudes({encumbered: allocateParams[0].newMagnitudes[0], max: WAD, allocatable: WAD - allocateParams[0].newMagnitudes[0]}) + }); + + // Roll to deallocation complete block + cheats.roll(deallocEffectBlock); + + // Note that the encumbered mag hasn't been updated since we haven't cleared the deallocaction queue! + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: deallocateParams[0].newMagnitudes[0], pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: allocateParams[0].newMagnitudes[0], max: WAD, allocatable: WAD - deallocateParams[0].newMagnitudes[0]}) + }); + } + + /** + * Allocates to an operator set, then fully deallocates when not registered to the set. + * Validates that: + * 1. Events are properly emitted post instantaneous deallocation + * 2. The deallocation is instant & can be reallocated immediately + * 3. Storage/introspection post combined deallocation/allocation + */ + function testFuzz_allocate_fullyDeallocate_reallocate_WhenNotRegistered( + Randomness r + ) public rand(r) { + // Bound allocation and deallocation + uint64 firstMod = r.Uint64(1, WAD); + + // Create new operator sets that the operator is not registered for + OperatorSet memory operatorSetA = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + OperatorSet memory operatorSetB = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + + // Allocate magnitude to operator set + AllocateParams[] memory allocateParams = _newAllocateParams(operatorSetA, firstMod); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate instantly and reallocate all magnitude to second operator set + allocateParams = new AllocateParams[](2); + allocateParams[0] = _newAllocateParams(operatorSetA, 0)[0]; + allocateParams[1] = _newAllocateParams(operatorSetB, firstMod)[0]; + + // We check the allocation event and not the deallocation event since + // encumbered magnitude is also updated here + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSetA, + strategy: strategyMock, + magnitude: 0, + encumberedMagnitude: 0, + effectBlock: uint32(block.number) // Instant deallocation + }); + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: operatorSetB, + strategy: strategyMock, + magnitude: firstMod, + encumberedMagnitude: firstMod, + effectBlock: _defaultAllocEffectBlock() + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage after deallocation + // Check operator set A + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSetA, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: firstMod, max: WAD, allocatable: WAD - firstMod}) // This is from opsetB + }); + + // Check operator set B + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSetB, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: 0, + pendingDiff: int128(uint128(firstMod)), + effectBlock: _defaultAllocEffectBlock() + }), + expectedMagnitudes: Magnitudes({encumbered: firstMod, max: WAD, allocatable: WAD - firstMod}) + }); + } + + /** + * Allocates all magnitude to a single strategy across multiple operatorSets. Deallocates fully, and then reallocates + * Validates: + * 1. Events are emitted for the allocation, deallocation, and reallocation (including the deallocation queue clear) + * 2. Stake is fully allocated & encumbered mag used up + * 3. Stake can be reallocated after the deallocation delay + */ + function testFuzz_allocate_fromClearedDeallocQueue( + Randomness r + ) public rand(r) { + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + + // Create multiple operator sets, register, and allocate to each. Ensure all magnitude is fully allocated. + OperatorSet[] memory deallocSets = r.OperatorSetArray(defaultAVS, numOpSets); + _createOperatorSets(deallocSets, defaultStrategies); + _registerForOperatorSets(defaultOperator, deallocSets); + AllocateParams[] memory allocateParams = _randAllocateParams_SingleMockStrategy_AllocAll(deallocSets); + + for (uint256 i; i < allocateParams.length; ++i) { + // There is only one strategy each allocateParams, so we don't need a nested for loop + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: allocateParams[i].operatorSet, + strategy: strategyMock, + magnitude: allocateParams[i].newMagnitudes[0], + encumberedMagnitude: _encumberedMagnitudes[strategyMock] + allocateParams[i].newMagnitudes[0], + effectBlock: _defaultAllocEffectBlock() + }); + _encumberedMagnitudes[strategyMock] += allocateParams[i].newMagnitudes[0]; + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + assertEq( + allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + 0, + "operator should not have any remaining allocatable magnitude" + ); + + // Move forward to allocation completion + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate fully from each operator set + AllocateParams[] memory deallocateParams = _newAllocateParams(deallocSets, 0); + + for (uint256 i; i < numOpSets; ++i) { + _checkDeallocationEvent({ + operator: defaultOperator, + operatorSet: deallocSets[i], + strategy: strategyMock, + magnitude: 0, + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + + assertEq( + allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + 0, + "operator should still not have any allocatable magnitude" + ); + + // Move forward to deallocation completion + cheats.roll(block.number + DEALLOCATION_DELAY); + + // Check that we now have sufficient allocatable magnitude + assertEq( + allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock), + WAD, + "operator should have all magnitude allocatable" + ); + + // Create and register for a new operator set with the same default strategy. + // If we try to allocate to this new set, it should clear the deallocation queue, + // allowing all magnitude to be allocated + OperatorSet memory finalOpSet = _createOperatorSet(OperatorSet(defaultAVS, r.Uint32()), defaultStrategies); + _registerForOperatorSet(defaultOperator, finalOpSet); + AllocateParams[] memory finalAllocParams = _newAllocateParams(finalOpSet, WAD); + + _checkClearDeallocationQueueEvents({ + operator: defaultOperator, + strategy: strategyMock, + encumberedMagnitude: 0 + }); + + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: finalOpSet, + strategy: strategyMock, + magnitude: WAD, + encumberedMagnitude: WAD, + effectBlock: _defaultAllocEffectBlock() + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, finalAllocParams); + + // Check that all magnitude will be allocated to the new set, and each prior set + // has a zeroed-out allocation + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: finalOpSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: 0, + pendingDiff: int128(uint128(WAD)), + effectBlock: _defaultAllocEffectBlock() + }), + expectedMagnitudes: Magnitudes({encumbered: WAD, max: WAD, allocatable: 0}) + }); + } + + /** + * Allocates all mag and then deallocates all mag + * Validates + * 1. Events for the deallocation + * 2. Storage after deallocation + * 3. Storage after clearing the deallocation queue + */ + function test_deallocate_all() public { + // Allocate all + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, WAD); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate all + allocateParams[0].newMagnitudes[0] = 0; + + _checkDeallocationEvent({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: 0, + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Warp to completion and clear deallocation queue + cheats.roll(block.number + DEALLOCATION_DELAY); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, uint16(1).toArrayU16()); + + // Check storage + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({currentMagnitude: 0, pendingDiff: 0, effectBlock: 0}), + expectedMagnitudes: Magnitudes({encumbered: 0, max: WAD, allocatable: WAD}) + }); + } + + + /** + * Allocates, deallocates, and then clears the deallocation queue. Multiple strategies & sets in a single operatorSet + * Validates: + * 1. Events for allocation, deallocation, and deallocation queue clear + * 2. Storage after allocation & after allocation effect block + * 3. Storage after deallocation & after deallocation effect block + */ + function testFuzz_lifecycle_allocate_deallocate_MultipleSetsAndStrats( + Randomness r + ) public rand(r) { + uint256 numAllocations = r.Uint256(2, FUZZ_MAX_ALLOCATIONS); + uint256 numStrats = r.Uint256(2, FUZZ_MAX_STRATS); + + AllocateParams[] memory allocateParams = r.AllocateParams(defaultAVS, numAllocations, numStrats); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + + for(uint256 i = 0; i < allocateParams.length; i++) { + _registerForOperatorSet(defaultOperator, allocateParams[i].operatorSet); + } + + // Allocate + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j; j < allocateParams[i].strategies.length; ++j) { + _checkAllocationEvents({ + operator: defaultOperator, + operatorSet: allocateParams[i].operatorSet, + strategy: allocateParams[i].strategies[j], + magnitude: allocateParams[i].newMagnitudes[j], + encumberedMagnitude: allocateParams[i].newMagnitudes[j], + effectBlock: _defaultAllocEffectBlock() + }); + } + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Check storage after allocation + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: allocateParams[i].operatorSet, + strategy: allocateParams[i].strategies[j], + expectedAllocation: Allocation({ + currentMagnitude: 0, + pendingDiff: int128(uint128(allocateParams[i].newMagnitudes[j])), + effectBlock: _defaultAllocEffectBlock() + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[i].newMagnitudes[j], + max: WAD, + allocatable: WAD - allocateParams[i].newMagnitudes[j] + }) + }); + } + } + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Check storage after roll to completion + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: allocateParams[i].operatorSet, + strategy: allocateParams[i].strategies[j], + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[i].newMagnitudes[j], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[i].newMagnitudes[j], + max: WAD, + allocatable: WAD - allocateParams[i].newMagnitudes[j] + }) + }); + } + } + + // Deallocate + + for (uint256 i; i < deallocateParams.length; ++i) { + for (uint256 j = 0; j < deallocateParams[i].strategies.length; j++) { + _checkDeallocationEvent({ + operator: defaultOperator, + operatorSet: deallocateParams[i].operatorSet, + strategy: deallocateParams[i].strategies[j], + magnitude: deallocateParams[i].newMagnitudes[j], + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + } + } + + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + int128 expectedDiff = -int128(uint128(allocateParams[i].newMagnitudes[j] - deallocateParams[i].newMagnitudes[j])); + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: deallocateParams[i].operatorSet, + strategy: deallocateParams[i].strategies[j], + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[i].newMagnitudes[j], + pendingDiff: expectedDiff, + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[i].newMagnitudes[j], + max: WAD, + allocatable: WAD - allocateParams[i].newMagnitudes[j] + }) + }); + } + } + + // Warp to deallocation complete block + cheats.roll(block.number + DEALLOCATION_DELAY); + for (uint256 i; i < allocateParams.length; ++i) { + for (uint256 j = 0; j < allocateParams[i].strategies.length; j++) { + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: deallocateParams[i].operatorSet, + strategy: allocateParams[i].strategies[j], + expectedAllocation: Allocation({ + currentMagnitude: deallocateParams[i].newMagnitudes[j], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[i].newMagnitudes[j], + max: WAD, + allocatable: WAD - deallocateParams[i].newMagnitudes[j] + }) + }); + } + } + } +} + +contract AllocationManagerUnitTests_ClearDeallocationQueue is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + /// ----------------------------------------------------------------------- + /// clearDeallocationQueue() + /// ----------------------------------------------------------------------- + + function test_revert_paused() public { + allocationManager.pause(2 ** PAUSED_MODIFY_ALLOCATIONS); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + allocationManager.clearDeallocationQueue(defaultOperator, new IStrategy[](0), new uint16[](0)); + } + + function test_revert_arrayMismatch() public { + IStrategy[] memory strategies = new IStrategy[](1); + uint16[] memory numToClear = new uint16[](2); + + cheats.expectRevert(InputArrayLengthMismatch.selector); + allocationManager.clearDeallocationQueue(defaultOperator, strategies, numToClear); + } + + /** + * @notice Allocates magnitude to an operator and then + * - Clears deallocation queue when only an allocation exists + * - Clears deallocation queue when the alloc can be completed - asserts emit has been emitted + * - Validates storage after the second clear + */ + function testFuzz_allocate( + Randomness r + ) public rand(r) { + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + + // Allocate magnitude + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Attempt to clear queue, assert no events emitted + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(0, entries.length, "should not have emitted any events"); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Clear queue - this is a noop + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + entries = vm.getRecordedLogs(); + assertEq(0, entries.length, "should not have emitted any events 2"); + + // Validate allocation is no longer pending + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[0].newMagnitudes[0], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[0].newMagnitudes[0], + max: WAD, + allocatable: WAD - allocateParams[0].newMagnitudes[0] + }) + }); + } + + /** + * @notice Allocates magnitude to an operator registered for some operator sets, and then + * - Clears deallocation queue when nothing can be completed + * - After the first clear, asserts the allocation info takes into account the deallocation + * - Clears deallocation queue when the dealloc can be completed + * - Assert events & validates storage after the deallocateParams are completed + */ + function testFuzz_allocate_deallocate( + Randomness r + ) public rand(r) { + // Generate a random allocation and subsequent deallocation from the default operator set + (AllocateParams[] memory allocateParams, AllocateParams[] memory deallocateParams) = + _randAllocAndDeallocParams_SingleMockStrategy(defaultOperatorSet.toArray()); + + // Allocate + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // Roll to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + _checkDeallocationEvent({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + magnitude: deallocateParams[0].newMagnitudes[0], + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + + // Clear queue - since we have not rolled forward, this should be a no-op + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + + // Validate storage - encumbered magnitude should just be allocateParams (we only have 1 allocation) + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[0].newMagnitudes[0], + pendingDiff: -int128(uint128(allocateParams[0].newMagnitudes[0] - deallocateParams[0].newMagnitudes[0])), + effectBlock: uint32(block.number + DEALLOCATION_DELAY) + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[0].newMagnitudes[0], + max: WAD, + allocatable: WAD - allocateParams[0].newMagnitudes[0] + }) + }); + + // Warp to deallocation complete block + cheats.roll(block.number + DEALLOCATION_DELAY); + + // Clear queue + _checkClearDeallocationQueueEvents({ + operator: defaultOperator, + strategy: strategyMock, + encumberedMagnitude: deallocateParams[0].newMagnitudes[0] + }); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + + // Validate storage - encumbered magnitude should just be deallocateParams (we only have 1 deallocation) + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: defaultOperatorSet, + strategy: strategyMock, + expectedAllocation: Allocation({ + currentMagnitude: deallocateParams[0].newMagnitudes[0], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: deallocateParams[0].newMagnitudes[0], + max: WAD, + allocatable: WAD - deallocateParams[0].newMagnitudes[0] + }) + }); + } + + /** + * Allocates, deallocates, and then allocates again. Asserts that + * - The deallocation does not block state updates from the second allocation, even though the allocation has an earlier + * effect block + */ + function test_allocate_deallocate_allocate() public { + // Allocate half of mag to default operator set + AllocateParams[] memory firstAllocation = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, firstAllocation); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate half from default operator set + uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + AllocateParams[] memory firstDeallocation = _newAllocateParams(defaultOperatorSet, 25e16); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, firstDeallocation); + Allocation memory allocation = + allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); + assertEq(deallocationEffectBlock, allocation.effectBlock, "effect block not correct"); + + // Create and register for a new operator set + OperatorSet memory newOperatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); + _registerForOperatorSet(defaultOperator, newOperatorSet); + + // Allocate 33e16 mag to new operator set + uint32 allocationEffectBlock = _defaultAllocEffectBlock(); + AllocateParams[] memory secondAllocation = _newAllocateParams(newOperatorSet, 33e16); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, secondAllocation); + allocation = allocationManager.getAllocation(defaultOperator, newOperatorSet, strategyMock); + assertEq(allocationEffectBlock, allocation.effectBlock, "effect block not correct"); + + // Warp to allocation effect block & clear the queue - clearing is a noop here + cheats.roll(allocationEffectBlock); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + + // Validate `getAllocatableMagnitude`. Allocatable magnitude should be the difference between the max magnitude and the encumbered magnitude + uint64 allocatableMagnitude = allocationManager.getAllocatableMagnitude(defaultOperator, strategyMock); + assertEq(WAD - 33e16 - 5e17, allocatableMagnitude, "allocatableMagnitude not correct"); + + // Validate that we can allocate again for opset2. This should not revert + AllocateParams[] memory thirdAllocation = _newAllocateParams(newOperatorSet, 10e16); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, thirdAllocation); + + // Warp & validate deallocation + cheats.roll(deallocationEffectBlock); + _checkClearDeallocationQueueEvents({ + operator: defaultOperator, + strategy: strategyMock, + encumberedMagnitude: 58e16 + }); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + } + + /** + * Allocates to opset1, allocates to opset2, deallocates from opset1. Asserts that the allocation, which has a higher + * effect block is not blocking the deallocation. + * The allocs/deallocs looks like + * 1. (allocation, opSet2, mag: 5e17, effectBlock: 50th day) + * 2. (deallocation, opSet1, mag: 0, effectBlock: 42.5 day) + * + * The deallocation queue looks like + * 1. (deallocation, opSet1, mag: 0, effectBlock: 42.5 day) + */ + function test_regression_deallocationNotBlocked() public { + // Set allocation delay to be longer than the deallocation delay + uint32 allocationDelay = DEALLOCATION_DELAY * 2; + cheats.prank(defaultOperator); + allocationManager.setAllocationDelay(defaultOperator, allocationDelay); + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + (, uint32 storedDelay) = allocationManager.getAllocationDelay(defaultOperator); + assertEq(allocationDelay, storedDelay, "allocation delay not valid"); + + // Allocate half of mag to default operator set + AllocateParams[] memory firstAllocation = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, firstAllocation); + cheats.roll(block.number + allocationDelay); + + // Create and register for a second operator set + OperatorSet memory newOperatorSet = + _createOperatorSet(OperatorSet(defaultAVS, random().Uint32()), defaultStrategies); + _registerForOperatorSet(defaultOperator, newOperatorSet); + + // Allocate half of mag to opset2 + AllocateParams[] memory secondAllocation = _newAllocateParams(newOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, secondAllocation); + + uint32 allocationEffectBlock = uint32(block.number + allocationDelay); + Allocation memory allocation = allocationManager.getAllocation(defaultOperator, newOperatorSet, strategyMock); + assertEq(allocationEffectBlock, allocation.effectBlock, "effect block not correct"); + + // Deallocate all from opSet1 + uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + AllocateParams[] memory firstDeallocation = _newAllocateParams(defaultOperatorSet, 0); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, firstDeallocation); + allocation = allocationManager.getAllocation(defaultOperator, defaultOperatorSet, strategyMock); + assertEq(deallocationEffectBlock, allocation.effectBlock, "effect block not correct"); + + // Warp to deallocation effect block & clear the queue + cheats.roll(deallocationEffectBlock); + allocationManager.clearDeallocationQueue(defaultOperator, defaultStrategies, _maxNumToClear()); + + // At this point, we should be able to allocate again to opSet1 AND have only 5e17 encumbered magnitude + assertEq( + 5e17, + allocationManager.encumberedMagnitude(defaultOperator, strategyMock), + "encumbered magnitude not correct" + ); + AllocateParams[] memory thirdAllocation = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, thirdAllocation); + } +} + +contract AllocationManagerUnitTests_SetAllocationDelay is AllocationManagerUnitTests { + /// ----------------------------------------------------------------------- + /// setAllocationDelay() + getAllocationDelay() + /// ----------------------------------------------------------------------- + + address operatorToSet = address(0x1); + + function setUp() public override { + AllocationManagerUnitTests.setUp(); + _registerOperator(operatorToSet); + } + + function test_revert_callerNotOperator() public { + delegationManagerMock.setIsOperator(operatorToSet, false); + cheats.prank(operatorToSet); + cheats.expectRevert(InvalidOperator.selector); + allocationManager.setAllocationDelay(operatorToSet, 1); + } + + function test_revert_callerNotAuthorized() public { + cheats.expectRevert(InvalidCaller.selector); + allocationManager.setAllocationDelay(operatorToSet, 1); + } + + function testFuzz_setDelay( + Randomness r + ) public rand(r) { + uint32 delay = r.Uint32(0, type(uint32).max); + + // Set delay + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationDelaySet(operatorToSet, delay, uint32(block.number + ALLOCATION_CONFIGURATION_DELAY)); + cheats.prank(operatorToSet); + allocationManager.setAllocationDelay(operatorToSet, delay); + + // Check values after set + (bool isSet, uint32 returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertFalse(isSet, "isSet should not be set"); + assertEq(0, returnedDelay, "returned delay should be 0"); + + // Warp to effect block + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + + // Check values after config delay + (isSet, returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertTrue(isSet, "isSet should be set"); + assertEq(delay, returnedDelay, "delay not set"); + } + + function test_fuzz_setDelay_multipleTimesWithinConfigurationDelay( + Randomness r + ) public rand(r) { + uint32 firstDelay = r.Uint32(1, type(uint32).max); + uint32 secondDelay = r.Uint32(1, type(uint32).max); + + // Set delay + cheats.prank(operatorToSet); + allocationManager.setAllocationDelay(operatorToSet, firstDelay); + + // Warp just before effect block + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY - 1); + + // Set delay again + cheats.expectEmit(true, true, true, true, address(allocationManager)); + emit AllocationDelaySet(operatorToSet, secondDelay, uint32(block.number + ALLOCATION_CONFIGURATION_DELAY)); + cheats.prank(operatorToSet); + allocationManager.setAllocationDelay(operatorToSet, secondDelay); + + // Warp to effect block of first delay + cheats.roll(block.number + 1); + + // Assert that the delay is still not set + (bool isSet, uint32 returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertFalse(isSet, "isSet should not be set"); + assertEq(0, returnedDelay, "returned delay should be 0"); + + // Warp to effect block of second delay + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + (isSet, returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertTrue(isSet, "isSet should be set"); + assertEq(secondDelay, returnedDelay, "delay not set"); + } + + function testFuzz_multipleDelays( + Randomness r + ) public rand(r) { + uint32 firstDelay = r.Uint32(1, type(uint32).max); + uint32 secondDelay = r.Uint32(1, type(uint32).max); + + // Set delay + cheats.prank(operatorToSet); + allocationManager.setAllocationDelay(operatorToSet, firstDelay); + + // Warp to effect block of first delay + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + + // Set delay again + cheats.prank(operatorToSet); + allocationManager.setAllocationDelay(operatorToSet, secondDelay); + + // Assert that first delay is set + (bool isSet, uint32 returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertTrue(isSet, "isSet should be set"); + assertEq(firstDelay, returnedDelay, "delay not set"); + + // Warp to effect block of second delay + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + + // Check values after second delay + (isSet, returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertTrue(isSet, "isSet should be set"); + assertEq(secondDelay, returnedDelay, "delay not set"); + } + + function testFuzz_setDelay_DMCaller( + Randomness r + ) public rand(r) { + uint32 delay = r.Uint32(1, type(uint32).max); + + cheats.prank(address(delegationManagerMock)); + allocationManager.setAllocationDelay(operatorToSet, delay); + + // Warp to effect block + cheats.roll(block.number + ALLOCATION_CONFIGURATION_DELAY); + (bool isSet, uint32 returnedDelay) = allocationManager.getAllocationDelay(operatorToSet); + assertTrue(isSet, "isSet should be set"); + assertEq(delay, returnedDelay, "delay not set"); + } +} + +contract AllocationManagerUnitTests_registerForOperatorSets is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + RegisterParams defaultRegisterParams; + + function setUp() public override { + AllocationManagerUnitTests.setUp(); + defaultRegisterParams = RegisterParams(defaultAVS, defaultOperatorSet.id.toArrayU32(), ""); + } + + function test_registerForOperatorSets_Paused() public { + allocationManager.pause(2 ** PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + allocationManager.registerForOperatorSets(defaultOperator, defaultRegisterParams); + } + + function testFuzz_registerForOperatorSets_InvalidOperator_x( + Randomness r + ) public rand(r) { + address operator = r.Address(); + cheats.prank(operator); + cheats.expectRevert(InvalidOperator.selector); + allocationManager.registerForOperatorSets(operator, defaultRegisterParams); + } + + function testFuzz_registerForOperatorSets_InvalidOperatorSet( + Randomness r + ) public rand(r) { + cheats.prank(defaultOperator); + cheats.expectRevert(InvalidOperatorSet.selector); + defaultRegisterParams.operatorSetIds[0] = 1; // invalid id + allocationManager.registerForOperatorSets(defaultOperator, defaultRegisterParams); // invalid id + } + + function testFuzz_registerForOperatorSets_AlreadyMemberOfSet( + Randomness r + ) public rand(r) { + cheats.prank(defaultOperator); + cheats.expectRevert(AlreadyMemberOfSet.selector); + allocationManager.registerForOperatorSets(defaultOperator, defaultRegisterParams); + } + + function testFuzz_registerForOperatorSets_Correctness( + Randomness r + ) public rand(r) { + address operator = r.Address(); + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + uint32[] memory operatorSetIds = new uint32[](numOpSets); + CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); + + _registerOperator(operator); + + for (uint256 i; i < numOpSets; ++i) { + operatorSetIds[i] = r.Uint32(1, type(uint32).max); + createSetParams[i].operatorSetId = operatorSetIds[i]; + createSetParams[i].strategies = defaultStrategies; + } + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + + for (uint256 j; j < numOpSets; ++j) { + cheats.expectEmit(true, true, false, false, address(allocationManager)); + emit OperatorAddedToOperatorSet(operator, OperatorSet(defaultAVS, operatorSetIds[j])); + } + + cheats.expectCall( + defaultAVS, abi.encodeWithSelector(IAVSRegistrar.registerOperator.selector, operator, operatorSetIds, "") + ); + + cheats.prank(operator); + allocationManager.registerForOperatorSets(operator, RegisterParams(defaultAVS, operatorSetIds, "")); + + assertEq(allocationManager.getRegisteredSets(operator).length, numOpSets, "should be registered for all sets"); + + for (uint256 k; k < numOpSets; ++k) { + assertEq( + allocationManager.getMembers(OperatorSet(defaultAVS, operatorSetIds[k]))[0], + operator, + "should be member of set" + ); + } + } +} + +contract AllocationManagerUnitTests_deregisterFromOperatorSets is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + DeregisterParams defaultDeregisterParams; + + function setUp() public override { + AllocationManagerUnitTests.setUp(); + defaultDeregisterParams = DeregisterParams(defaultOperator, defaultAVS, defaultOperatorSet.id.toArrayU32()); + } + + function test_deregisterFromOperatorSets_Paused() public { + allocationManager.pause(2 ** PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + allocationManager.deregisterFromOperatorSets(defaultDeregisterParams); + } + + function test_deregisterFromOperatorSets_revert_invalidCaller_notOperator() public { + address randomOperator = address(0x1); + defaultDeregisterParams.operator = randomOperator; + + cheats.expectRevert(InvalidCaller.selector); + allocationManager.deregisterFromOperatorSets(defaultDeregisterParams); + } + + function test_deregisterFromOperatorSets_revert_invalidCaller_notAVS() public { + address randomAVS = address(0x1); + + cheats.prank(randomAVS); + cheats.expectRevert(InvalidCaller.selector); + allocationManager.deregisterFromOperatorSets(defaultDeregisterParams); + } + + function testFuzz_deregisterFromOperatorSets_InvalidOperatorSet( + Randomness r + ) public rand(r) { + defaultDeregisterParams.operatorSetIds = uint32(1).toArrayU32(); // invalid id + cheats.prank(defaultOperator); + cheats.expectRevert(InvalidOperatorSet.selector); + allocationManager.deregisterFromOperatorSets(defaultDeregisterParams); + } + + function testFuzz_deregisterFromOperatorSets_NotMemberOfSet( + Randomness r + ) public rand(r) { + defaultDeregisterParams.operator = r.Address(); + cheats.prank(defaultDeregisterParams.operator); + cheats.expectRevert(NotMemberOfSet.selector); + allocationManager.deregisterFromOperatorSets(defaultDeregisterParams); + } + + function testFuzz_deregisterFromOperatorSets_Correctness( + Randomness r + ) public rand(r) { + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + uint32[] memory operatorSetIds = new uint32[](numOpSets); + CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); + + for (uint256 i; i < numOpSets; ++i) { + operatorSetIds[i] = r.Uint32(1, type(uint32).max); + createSetParams[i].operatorSetId = operatorSetIds[i]; + createSetParams[i].strategies = defaultStrategies; + } + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + + address operator = r.Address(); + _registerOperator(operator); + + cheats.prank(operator); + allocationManager.registerForOperatorSets(operator, RegisterParams(defaultAVS, operatorSetIds, "")); + + for (uint256 j; j < numOpSets; ++j) { + cheats.expectEmit(true, true, false, false, address(allocationManager)); + emit OperatorRemovedFromOperatorSet(operator, OperatorSet(defaultAVS, operatorSetIds[j])); + } + + cheats.expectCall( + defaultAVS, abi.encodeWithSelector(IAVSRegistrar.deregisterOperator.selector, operator, operatorSetIds) + ); + + bool callFromAVS = r.Boolean(); + if (callFromAVS) { + cheats.prank(defaultAVS); + } else { + cheats.prank(operator); + } + allocationManager.deregisterFromOperatorSets(DeregisterParams(operator, defaultAVS, operatorSetIds)); + + assertEq(allocationManager.getRegisteredSets(operator).length, 0, "should not be registered for any sets"); + + for (uint256 k; k < numOpSets; ++k) { + assertEq( + allocationManager.getMemberCount(OperatorSet(defaultAVS, operatorSetIds[k])), + 0, + "should not be member of set" + ); + } + } +} + +contract AllocationManagerUnitTests_addStrategiesToOperatorSet is AllocationManagerUnitTests { + function test_addStrategiesToOperatorSet_InvalidOperatorSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(InvalidOperatorSet.selector); + allocationManager.addStrategiesToOperatorSet(defaultAVS, 1, defaultStrategies); + } + + function test_addStrategiesToOperatorSet_StrategyAlreadyInOperatorSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(StrategyAlreadyInOperatorSet.selector); + allocationManager.addStrategiesToOperatorSet(defaultAVS, defaultOperatorSet.id, defaultStrategies); + } + + function testFuzz_addStrategiesToOperatorSet_Correctness( + Randomness r + ) public rand(r) { + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); + + IStrategy[] memory strategies = new IStrategy[](numStrategies); + + for (uint256 i; i < numStrategies; ++i) { + strategies[i] = IStrategy(r.Address()); + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit StrategyAddedToOperatorSet(defaultOperatorSet, strategies[i]); + } + + cheats.prank(defaultAVS); + allocationManager.addStrategiesToOperatorSet(defaultAVS, defaultOperatorSet.id, strategies); + + IStrategy[] memory strategiesInSet = allocationManager.getStrategiesInOperatorSet(defaultOperatorSet); + + for (uint256 j; j < numStrategies; ++j) { + assertTrue(strategiesInSet[j + 1] == strategies[j], "should be strat of set"); + } + } +} + +contract AllocationManagerUnitTests_removeStrategiesFromOperatorSet is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + function test_removeStrategiesFromOperatorSet_InvalidOperatorSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(InvalidOperatorSet.selector); + allocationManager.removeStrategiesFromOperatorSet(defaultAVS, 1, defaultStrategies); + } + + function test_removeStrategiesFromOperatorSet_StrategyNotInOperatorSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(StrategyNotInOperatorSet.selector); + allocationManager.removeStrategiesFromOperatorSet( + defaultAVS, defaultOperatorSet.id, IStrategy(random().Address()).toArray() + ); + } + + function testFuzz_removeStrategiesFromOperatorSet_Correctness( + Randomness r + ) public rand(r) { + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); + IStrategy[] memory strategies = r.StrategyArray(numStrategies); + + cheats.prank(defaultAVS); + allocationManager.addStrategiesToOperatorSet(defaultAVS, defaultOperatorSet.id, strategies); + + for (uint256 i; i < numStrategies; ++i) { + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit StrategyRemovedFromOperatorSet(defaultOperatorSet, strategies[i]); + } + + assertEq( + allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length, numStrategies + 1, "sanity check" + ); + + cheats.prank(defaultAVS); + allocationManager.removeStrategiesFromOperatorSet(defaultAVS, defaultOperatorSet.id, strategies); + + // The orginal strategy should still be in the operator set. + assertEq( + allocationManager.getStrategiesInOperatorSet(defaultOperatorSet).length, 1, "should not be strat of set" + ); + } +} + +contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitTests { + using SingleItemArrayLib for *; + + function test_createOperatorSets_InvalidOperatorSet() public { + cheats.prank(defaultAVS); + cheats.expectRevert(InvalidOperatorSet.selector); + allocationManager.createOperatorSets(defaultAVS, CreateSetParams(defaultOperatorSet.id, defaultStrategies).toArray()); + } + + function testFuzz_createOperatorSets_Correctness( + Randomness r + ) public rand(r) { + address avs = r.Address(); + uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS); + uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS); + + CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets); + + for (uint256 i; i < numOpSets; ++i) { + createSetParams[i].operatorSetId = r.Uint32(1, type(uint32).max); + createSetParams[i].strategies = r.StrategyArray(numStrategies); + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit OperatorSetCreated(OperatorSet(avs, createSetParams[i].operatorSetId)); + for (uint256 j; j < numStrategies; ++j) { + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit StrategyAddedToOperatorSet( + OperatorSet(avs, createSetParams[i].operatorSetId), createSetParams[i].strategies[j] + ); + } + } + + cheats.prank(avs); + allocationManager.createOperatorSets(avs, createSetParams); + + for (uint256 k; k < numOpSets; ++k) { + OperatorSet memory opSet = OperatorSet(avs, createSetParams[k].operatorSetId); + assertTrue(allocationManager.isOperatorSet(opSet), "should be operator set"); + IStrategy[] memory strategiesInSet = allocationManager.getStrategiesInOperatorSet(opSet); + assertEq(strategiesInSet.length, numStrategies, "strategiesInSet length should be numStrategies"); + for (uint256 l; l < numStrategies; ++l) { + assertTrue( + allocationManager.getStrategiesInOperatorSet(opSet)[l] == createSetParams[k].strategies[l], + "should be strat of set" + ); + } + } + + assertEq(createSetParams.length, allocationManager.getOperatorSetCount(avs), "should be correct number of sets"); + } +} + +contract AllocationManagerUnitTests_setAVSRegistrar is AllocationManagerUnitTests { + + function test_getAVSRegistrar() public { + address randomAVS = random().Address(); + IAVSRegistrar avsRegistrar = allocationManager.getAVSRegistrar(randomAVS); + assertEq(address(avsRegistrar), address(randomAVS), "AVS registrar should return default"); + } + + function testFuzz_setAVSRegistrar_Correctness( + Randomness r + ) public rand(r) { + address avs = r.Address(); + IAVSRegistrar avsRegistrar = IAVSRegistrar(r.Address()); + + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit AVSRegistrarSet(avs, avsRegistrar); + + cheats.prank(avs); + allocationManager.setAVSRegistrar(avs, avsRegistrar); + assertTrue(avsRegistrar == allocationManager.getAVSRegistrar(avs), "should be set"); + } +} + +contract AllocationManagerUnitTests_updateAVSMetadataURI is AllocationManagerUnitTests { + function test_updateAVSMetadataURI_Correctness() public { + string memory newURI = "test"; + cheats.expectEmit(true, false, false, false, address(allocationManager)); + emit AVSMetadataURIUpdated(defaultAVS, newURI); + cheats.prank(defaultAVS); + allocationManager.updateAVSMetadataURI(defaultAVS, newURI); + } +} + +contract AllocationManagerUnitTests_getStrategyAllocations is AllocationManagerUnitTests { + function testFuzz_getStrategyAllocations_Correctness( + Randomness r + ) public rand(r) { + AllocateParams[] memory allocateParams = r.AllocateParams(defaultAVS, 1, 1); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + + cheats.startPrank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.stopPrank(); + + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + (OperatorSet[] memory operatorSets, ) = + allocationManager.getStrategyAllocations(defaultOperator, allocateParams[0].strategies[0]); + + assertEq(operatorSets[0].avs, allocateParams[0].operatorSet.avs, "should be defaultAVS"); + assertEq(operatorSets[0].id, allocateParams[0].operatorSet.id, "should be defaultOperatorSet"); + + _checkAllocationStorage({ + operator: defaultOperator, + operatorSet: operatorSets[0], + strategy: createSetParams[0].strategies[0], + expectedAllocation: Allocation({ + currentMagnitude: allocateParams[0].newMagnitudes[0], + pendingDiff: 0, + effectBlock: 0 + }), + expectedMagnitudes: Magnitudes({ + encumbered: allocateParams[0].newMagnitudes[0], + max: WAD, + allocatable: WAD - allocateParams[0].newMagnitudes[0] + }) + }); + } +} + +contract AllocationManagerUnitTests_getSlashableStake is AllocationManagerUnitTests { + using SlashingLib for *; + + /** + * Allocates half of magnitude for a single strategy to an operatorSet. Then allocates again. Slashes 50% + * of the first allocation. Validates slashable stake at each step. + */ + function test_allocate_onePendingAllocation( + Randomness r + ) public rand(r) { + // Generate allocation for `strategyMock`, we allocate half + { + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, 5e17); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + } + + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(5e17) + }); + + // Allocate the other half + AllocateParams[] memory allocateParams2 = _newAllocateParams(defaultOperatorSet, WAD); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams2); + uint32 secondAllocEffectBlock = _defaultAllocEffectBlock(); + + // Check minimum slashable stake remains the same + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(5e17) + }); + + // Check minimum slashable stake would not change even after the second allocation becomes effective + // This is because the allocation is not effective yet & we're getting a MINIMUM + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(5e17), + futureBlock: secondAllocEffectBlock + 1 + }); + + // Check minimum slashable stake after the second allocation becomes effective + cheats.roll(secondAllocEffectBlock); + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES + }); + } + + /** + * Allocates to `firstMod` magnitude and then deallocate to `secondMod` magnitude + * Validates slashable stake at each step after allocation and deallocation + */ + function testFuzz_allocate_deallocate_validateSlashableStake( + Randomness r + ) public rand(r) { + // Bound allocation and deallocation + uint64 firstMod = r.Uint64(1, WAD); + uint64 secondMod = r.Uint64(0, firstMod - 1); + + // Allocate magnitude to default registered set + AllocateParams[] memory allocateParams = _newAllocateParams(defaultOperatorSet, firstMod); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + + // 1. Validate slashable stake. + // This value should be 0 even at the effectBlock since its minimal slashable stake + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: 0, + futureBlock: _defaultAllocEffectBlock() + }); + + // Warp to allocation complete block + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // 2. Check slashable stake after allocation effect block + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(firstMod) + }); + + // Deallocate + allocateParams = _newAllocateParams(defaultOperatorSet, secondMod); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + // 3. Check slashable stake after deallocation - should be same at current block + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(firstMod), + futureBlock: uint32(block.number) + }); + + // 4. Check slashable stake at the deallocation effect block + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(secondMod), + futureBlock: uint32(block.number + DEALLOCATION_DELAY) + }); + + // Warp to deallocation effect block + cheats.roll(block.number + DEALLOCATION_DELAY); + + // 5. Check slashable stake at the deallocation effect block + _checkSlashableStake({ + operatorSet: defaultOperatorSet, + operator: defaultOperator, + strategies: defaultStrategies, + expectedStake: DEFAULT_OPERATOR_SHARES.mulWad(secondMod) + }); + } + + /** + * Allocates all of magnitude to a single strategy to an operatorSet. + * Deallocate some portion. Finally, slash while deallocation is pending + */ + function testFuzz_SlashWhileDeallocationPending( + Randomness r + ) public rand(r) { + // Initialize state + AllocateParams[] memory allocateParams = r.AllocateParams(defaultAVS, 1, 1); + AllocateParams[] memory deallocateParams = r.DeallocateParams(allocateParams); + CreateSetParams[] memory createSetParams = r.CreateSetParams(allocateParams); + RegisterParams memory registerParams = r.RegisterParams(allocateParams); + SlashingParams memory slashingParams = r.SlashingParams(defaultOperator, allocateParams[0]); + + delegationManagerMock.setOperatorShares( + defaultOperator, allocateParams[0].strategies[0], DEFAULT_OPERATOR_SHARES + ); + + cheats.prank(defaultAVS); + allocationManager.createOperatorSets(defaultAVS, createSetParams); + cheats.startPrank(defaultOperator); + allocationManager.registerForOperatorSets(defaultOperator, registerParams); + + // Allocate + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Deallocate + allocationManager.modifyAllocations(defaultOperator, deallocateParams); + uint32 deallocationEffectBlock = uint32(block.number + DEALLOCATION_DELAY); + cheats.stopPrank(); + + // Check slashable stake after deallocation (still pending; no change) + _checkSlashableStake({ + operatorSet: allocateParams[0].operatorSet, + operator: defaultOperator, + strategies: allocateParams[0].strategies, + expectedStake: allocateParams[0].newMagnitudes[0] + }); + + // Check slashable stake after deallocation takes effect, before slashing + _checkSlashableStake({ + operatorSet: allocateParams[0].operatorSet, + operator: defaultOperator, + strategies: allocateParams[0].strategies, + expectedStake: deallocateParams[0].newMagnitudes[0], + futureBlock: deallocationEffectBlock + }); + + uint256 magnitudeAllocated = allocateParams[0].newMagnitudes[0]; + uint256 magnitudeDeallocated = magnitudeAllocated - deallocateParams[0].newMagnitudes[0]; + uint256 magnitudeSlashed = magnitudeAllocated.mulWad(slashingParams.wadToSlash); + uint256 expectedCurrentMagnitude = magnitudeAllocated - magnitudeSlashed; + int128 expectedPendingDiff = + -int128(uint128(magnitudeDeallocated - magnitudeDeallocated.mulWadRoundUp(slashingParams.wadToSlash))); + + // Slash + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashingParams); + + // Check slashable stake after slash + _checkSlashableStake({ + operatorSet: allocateParams[0].operatorSet, + operator: defaultOperator, + strategies: allocateParams[0].strategies, + expectedStake: expectedCurrentMagnitude + }); + + // Check slashable stake after deallocation takes effect + // Add 1 slippage for rounding down slashable stake + _checkSlashableStake({ + operatorSet: allocateParams[0].operatorSet, + operator: defaultOperator, + strategies: allocateParams[0].strategies, + expectedStake: expectedCurrentMagnitude - uint128(-expectedPendingDiff) - 1, + futureBlock: deallocationEffectBlock + }); + + cheats.roll(deallocationEffectBlock); + allocationManager.clearDeallocationQueue(defaultOperator, allocateParams[0].strategies, _maxNumToClear()); + + // Check slashable stake after slash and deallocation + // Add 1 slippage for rounding down slashable stake + _checkSlashableStake({ + operatorSet: allocateParams[0].operatorSet, + operator: defaultOperator, + strategies: allocateParams[0].strategies, + expectedStake: expectedCurrentMagnitude - uint128(-expectedPendingDiff) - 1 + }); + } +} + +contract AllocationManagerUnitTests_getMaxMagnitudesAtBlock is AllocationManagerUnitTests { + + function testFuzz_correctness(Randomness r) rand(r) public { + // Randomly allocate + AllocateParams[] memory allocateParams = _randAllocateParams_DefaultOpSet(); + cheats.prank(defaultOperator); + allocationManager.modifyAllocations(defaultOperator, allocateParams); + cheats.roll(block.number + DEFAULT_OPERATOR_ALLOCATION_DELAY); + + // Slash first time + SlashingParams memory slashParams = SlashingParams({ + operator: defaultOperator, + operatorSetId: defaultOperatorSet.id, + wadToSlash: r.Uint64(0.1 ether, 0.99 ether), + description: "test" + }); + uint32 firstSlashBlock = uint32(block.number); + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashParams); + uint64 maxMagnitudeAfterFirstSlash = allocationManager.getMaxMagnitude(defaultOperator, strategyMock); + + // Warp to random block + uint32 secondSlashBlock = uint32(block.number + r.Uint32()); + cheats.roll(secondSlashBlock); + + // Slash second time + slashParams.wadToSlash = r.Uint64(0.1 ether, 0.99 ether); + cheats.prank(defaultAVS); + allocationManager.slashOperator(defaultAVS, slashParams); + uint64 maxMagnitudeAfterSecondSlash = allocationManager.getMaxMagnitude(defaultOperator, strategyMock); + + // Warp to a block after the second slash + cheats.roll(block.number + r.Uint32()); + + // Validate get max magnitudes at block + assertEq( + allocationManager.getMaxMagnitudesAtBlock(defaultOperator, defaultStrategies, firstSlashBlock)[0], + maxMagnitudeAfterFirstSlash, + "max magnitude after first slash not correct" + ); + + assertEq( + allocationManager.getMaxMagnitudesAtBlock(defaultOperator, defaultStrategies, secondSlashBlock)[0], + maxMagnitudeAfterSecondSlash, + "max magnitude after second slash not correct" + ); + } +} \ No newline at end of file diff --git a/src/test/unit/DelegationUnit.t.sol b/src/test/unit/DelegationUnit.t.sol index aa9312395..c9098fb9b 100644 --- a/src/test/unit/DelegationUnit.t.sol +++ b/src/test/unit/DelegationUnit.t.sol @@ -1,14 +1,17 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/mocks/ERC1271WalletMock.sol"; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "src/contracts/core/DelegationManager.sol"; import "src/contracts/strategies/StrategyBase.sol"; - -import "src/test/events/IDelegationManagerEvents.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; +import "src/contracts/libraries/SlashingLib.sol"; +import "src/test/utils/SingleItemArrayLib.sol"; + +// TODO: add upgrade tests for completing withdrawals queued before upgrade in integration tests +// TODO: add slashing cases for withdrawing as shares (can also be in integration tests) /** * @notice Unit testing of the DelegationManager contract. Withdrawals are tightly coupled @@ -16,16 +19,34 @@ import "src/test/utils/EigenLayerUnitTestSetup.sol"; * Contracts tested: DelegationManager * Contracts not mocked: StrategyBase, PauserRegistry */ -contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManagerEvents { +contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManagerEvents, IDelegationManagerErrors { + using SlashingLib for *; + using SingleItemArrayLib for *; + // Contract under test DelegationManager delegationManager; DelegationManager delegationManagerImplementation; + // Helper to use in storage + DepositScalingFactor dsf; + // Mocks StrategyBase strategyImplementation; StrategyBase strategyMock; - IERC20 mockToken; - uint256 mockTokenInitialSupply = 10e50; + + IERC20 tokenMock; + uint256 tokenMockInitialSupply = 10e50; + + uint32 constant MIN_WITHDRAWAL_DELAY_BLOCKS = 126_000; // 17.5 days in blocks + + // Fuzz bound checks + uint256 constant MIN_FUZZ_SHARES = 10_000; + uint256 constant MIN_FUZZ_MAGNITUDE = 10_000; + uint256 constant APPROX_REL_DIFF = 1e14; // 0.01% relative difference for assertion checks. Needed due to rounding errors + + // Max shares in a strategy, see StrategyBase.sol + uint256 constant MAX_STRATEGY_SHARES = 1e38 - 1; + uint256 constant MAX_ETH_SUPPLY = 120_400_000 ether; // Delegation signer uint256 delegationSignerPrivateKey = uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); @@ -45,8 +66,6 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag // 604800 seconds in week / 12 = 50,400 blocks uint256 minWithdrawalDelayBlocks = 50400; - IStrategy[] public initializeStrategiesToSetDelayBlocks; - uint256[] public initializeWithdrawalDelayBlocks; IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); @@ -64,50 +83,67 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag /// @notice mappings used to handle duplicate entries in fuzzed address array input mapping(address => uint256) public totalSharesForStrategyInArray; + mapping(IStrategy => uint256) public totalSharesDecreasedForStrategy; mapping(IStrategy => uint256) public delegatedSharesBefore; + mapping(address => uint256) public stakerDepositShares; + + // Keep track of queued withdrawals + mapping(address => IDelegationManagerTypes.Withdrawal[]) public stakerQueuedWithdrawals; + function setUp() public virtual override { // Setup EigenLayerUnitTestSetup.setUp(); - // Deploy DelegationManager implmentation and proxy - initializeStrategiesToSetDelayBlocks = new IStrategy[](0); - initializeWithdrawalDelayBlocks = new uint256[](0); - delegationManagerImplementation = new DelegationManager(strategyManagerMock, slasherMock, eigenPodManagerMock); delegationManager = DelegationManager( - address( - new TransparentUpgradeableProxy( - address(delegationManagerImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - address(this), - pauserRegistry, - 0, // 0 is initialPausedStatus - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ) - ) + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // Redeploy StrategyManagerMock with DM + strategyManagerMock = StrategyManagerMock(payable(address(new StrategyManagerMock(delegationManager)))); + + // Deploy DelegationManager implmentation and upgrade proxy + delegationManagerImplementation = new DelegationManager( + IAVSDirectory(address(avsDirectoryMock)), + IStrategyManager(address(strategyManagerMock)), + IEigenPodManager(address(eigenPodManagerMock)), + IAllocationManager(address(allocationManagerMock)), + pauserRegistry, + IPermissionController(address(permissionController)), + MIN_WITHDRAWAL_DELAY_BLOCKS + ); + + eigenLayerProxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + address(this), + 0 // 0 is initial paused status ) ); // Deploy mock token and strategy - mockToken = new ERC20PresetFixedSupply("Mock Token", "MOCK", mockTokenInitialSupply, address(this)); - strategyImplementation = new StrategyBase(strategyManagerMock); + tokenMock = new ERC20PresetFixedSupply("Mock Token", "MOCK", tokenMockInitialSupply, address(this)); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyMock = StrategyBase( address( new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, mockToken, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, tokenMock) ) ) ); + // Roll blocks forward so that block.number - MIN_WITHDRAWAL_DELAY_BLOCKS doesn't revert + // in _getSlashableSharesInQueue + cheats.roll(MIN_WITHDRAWAL_DELAY_BLOCKS); + // Exclude delegation manager from fuzzed tests - addressIsExcludedFromFuzzedInputs[address(delegationManager)] = true; - addressIsExcludedFromFuzzedInputs[defaultApprover] = true; + isExcludedFuzzAddress[address(delegationManager)] = true; + isExcludedFuzzAddress[address(strategyManagerMock)] = true; + isExcludedFuzzAddress[defaultApprover] = true; } /** @@ -121,17 +157,22 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag */ function _deployAndDepositIntoStrategies( address staker, - uint256[] memory sharesAmounts + uint256[] memory sharesAmounts, + bool depositBeaconChainShares ) internal returns (IStrategy[] memory) { uint256 numStrats = sharesAmounts.length; IStrategy[] memory strategies = new IStrategy[](numStrats); - uint256[] memory withdrawalDelayBlocks = new uint256[](strategies.length); for (uint8 i = 0; i < numStrats; i++) { - withdrawalDelayBlocks[i] = bound(uint256(keccak256(abi.encode(staker, i))), 0, MAX_WITHDRAWAL_DELAY_BLOCKS); + // If depositing beaconShares, then for last index of shareAmount, set shares into EPM instead + if (depositBeaconChainShares && i == numStrats - 1) { + strategies[i] = beaconChainETHStrategy; + eigenPodManagerMock.setPodOwnerShares(staker, int256(sharesAmounts[numStrats - 1])); + break; + } ERC20PresetFixedSupply token = new ERC20PresetFixedSupply( string(abi.encodePacked("Mock Token ", i)), string(abi.encodePacked("MOCK", i)), - mockTokenInitialSupply, + tokenMockInitialSupply, address(this) ); strategies[i] = StrategyBase( @@ -139,16 +180,36 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, token) ) ) ); + strategyManagerMock.addDeposit(staker, strategies[i], sharesAmounts[i]); } - delegationManager.setStrategyWithdrawalDelayBlocks(strategies, withdrawalDelayBlocks); - strategyManagerMock.setDeposits(staker, strategies, sharesAmounts); return strategies; } + /** + * @notice internal function to deploy mock tokens and strategies and have the staker deposit into them. + * Since we are mocking the strategyManager we call strategyManagerMock.setDeposits so that when + * DelegationManager calls getDeposits, we can have these share amounts returned. + */ + function _depositIntoStrategies( + address staker, + IStrategy[] memory strategies, + uint256[] memory sharesAmounts + ) internal { + uint256 numStrats = strategies.length; + require(numStrats == sharesAmounts.length, "DelegationManagerUnitTests: length mismatch"); + for (uint8 i = 0; i < numStrats; i++) { + // If depositing beaconShares, then for last index of shareAmount, set shares into EPM instead + if (strategies[i] == beaconChainETHStrategy) { + eigenPodManagerMock.setPodOwnerShares(staker, int256(sharesAmounts[i])); + } + strategyManagerMock.addDeposit(staker, strategies[i], sharesAmounts[i]); + } + } + /** * @notice internal function for calculating a signature from the delegationSigner corresponding to `_delegationSignerPrivateKey`, approving * the `staker` to delegate to `operator`, with the specified `salt`, and expiring at `expiry`. @@ -175,25 +236,6 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag return approverSignatureAndExpiry; } - /** - * @notice internal function for calculating a signature from the staker corresponding to `_stakerPrivateKey`, delegating them to - * the `operator`, and expiring at `expiry`. - */ - function _getStakerSignature( - uint256 _stakerPrivateKey, - address operator, - uint256 expiry - ) internal view returns (ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry) { - address staker = cheats.addr(stakerPrivateKey); - stakerSignatureAndExpiry.expiry = expiry; - { - bytes32 digestHash = delegationManager.calculateCurrentStakerDelegationDigestHash(staker, operator, expiry); - (uint8 v, bytes32 r, bytes32 s) = cheats.sign(_stakerPrivateKey, digestHash); - stakerSignatureAndExpiry.signature = abi.encodePacked(r, s, v); - } - return stakerSignatureAndExpiry; - } - // @notice Assumes operator does not have a delegation approver & staker != approver function _delegateToOperatorWhoAcceptsAllStakers(address staker, address operator) internal { ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; @@ -218,65 +260,12 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag _delegateToOperatorWhoRequiresSig(staker, operator, emptySalt); } - function _delegateToBySignatureOperatorWhoAcceptsAllStakers( - address staker, - address caller, - address operator, - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry, - bytes32 salt - ) internal { - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - cheats.prank(caller); - delegationManager.delegateToBySignature( - staker, - operator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - salt - ); - } - - function _delegateToBySignatureOperatorWhoRequiresSig( - address staker, - address caller, - address operator, - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry, - bytes32 salt - ) internal { - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( - delegationSignerPrivateKey, - staker, - operator, - salt, - expiry - ); - cheats.prank(caller); - delegationManager.delegateToBySignature( - staker, - operator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - salt - ); - } - function _registerOperatorWithBaseDetails(address operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); + _registerOperator(operator, address(0), emptyStringForMetadataURI); } function _registerOperatorWithDelegationApprover(address operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: defaultApprover, - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); + _registerOperator(operator, defaultApprover, emptyStringForMetadataURI); } function _registerOperatorWith1271DelegationApprover(address operator) internal returns (ERC1271WalletMock) { @@ -286,85 +275,81 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag * so that we can create valid signatures from the `delegationSigner` for the contract to check when called */ ERC1271WalletMock wallet = new ERC1271WalletMock(delegationSigner); - - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(wallet), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(operator, operatorDetails, emptyStringForMetadataURI); + _registerOperator(operator, address(wallet), emptyStringForMetadataURI); return wallet; } function _registerOperator( address operator, - IDelegationManager.OperatorDetails memory operatorDetails, + address delegationApprover, string memory metadataURI ) internal filterFuzzedAddressInputs(operator) { - _filterOperatorDetails(operator, operatorDetails); cheats.prank(operator); - delegationManager.registerAsOperator(operatorDetails, metadataURI); - } - - function _filterOperatorDetails( - address operator, - IDelegationManager.OperatorDetails memory operatorDetails - ) internal view { - // filter out zero address since people can't delegate to the zero address and operators are delegated to themselves - cheats.assume(operator != address(0)); - // filter out disallowed stakerOptOutWindowBlocks values - cheats.assume(operatorDetails.stakerOptOutWindowBlocks <= delegationManager.MAX_STAKER_OPT_OUT_WINDOW_BLOCKS()); + delegationManager.registerAsOperator(delegationApprover, 0, metadataURI); } /** * @notice Using this helper function to fuzz withdrawalAmounts since fuzzing two dynamic sized arrays of equal lengths * reject too many inputs. */ - function _fuzzWithdrawalAmounts(uint256[] memory depositAmounts) internal view returns (uint256[] memory) { - uint256[] memory withdrawalAmounts = new uint256[](depositAmounts.length); - for (uint256 i = 0; i < depositAmounts.length; i++) { - cheats.assume(depositAmounts[i] > 0); + function _fuzzDepositWithdrawalAmounts( + Randomness r, + uint32 numStrategies + )internal returns ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + uint64[] memory prevMagnitudes, + uint64[] memory newMagnitudes + ) { + withdrawalAmounts = new uint256[](numStrategies); + depositAmounts = new uint256[](numStrategies); + prevMagnitudes = new uint64[](numStrategies); + newMagnitudes = new uint64[](numStrategies); + for (uint256 i = 0; i < numStrategies; i++) { + depositAmounts[i] = r.Uint256(1, MAX_STRATEGY_SHARES); // generate withdrawal amount within range s.t withdrawAmount <= depositAmount - withdrawalAmounts[i] = bound( - uint256(keccak256(abi.encodePacked(depositAmounts[i]))), - 0, - depositAmounts[i] - ); + withdrawalAmounts[i] = r.Uint256(1, depositAmounts[i]); + + + prevMagnitudes[i] = r.Uint64(2, WAD); + newMagnitudes[i] = r.Uint64(1, prevMagnitudes[i]); } - return withdrawalAmounts; + return (depositAmounts, withdrawalAmounts, prevMagnitudes, newMagnitudes); } function _setUpQueueWithdrawalsSingleStrat( address staker, address withdrawer, IStrategy strategy, - uint256 withdrawalAmount + uint256 depositSharesToWithdraw ) internal view returns ( - IDelegationManager.QueuedWithdrawalParams[] memory, - IDelegationManager.Withdrawal memory, + QueuedWithdrawalParams[] memory, + Withdrawal memory, bytes32 ) { - IStrategy[] memory strategyArray = new IStrategy[](1); - strategyArray[0] = strategy; - uint256[] memory withdrawalAmounts = new uint256[](1); - withdrawalAmounts[0] = withdrawalAmount; + IStrategy[] memory strategyArray = strategy.toArray(); + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + { + uint256[] memory withdrawalAmounts = depositSharesToWithdraw.toArrayU256(); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategyArray, + depositShares: withdrawalAmounts, + withdrawer: withdrawer + }); + } - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategyArray, - shares: withdrawalAmounts, - withdrawer: withdrawer - }); + // Get scaled shares to withdraw + uint256[] memory scaledSharesArray = _getScaledShares(staker, strategy, depositSharesToWithdraw).toArrayU256(); - IDelegationManager.Withdrawal memory withdrawal = IDelegationManager.Withdrawal({ + Withdrawal memory withdrawal = Withdrawal({ staker: staker, delegatedTo: delegationManager.delegatedTo(staker), withdrawer: withdrawer, nonce: delegationManager.cumulativeWithdrawalsQueued(staker), startBlock: uint32(block.number), strategies: strategyArray, - shares: withdrawalAmounts + scaledShares: scaledSharesArray }); bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal); @@ -375,33 +360,105 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address staker, address withdrawer, IStrategy[] memory strategies, - uint256[] memory withdrawalAmounts + uint256[] memory depositWithdrawalAmounts ) internal view returns ( - IDelegationManager.QueuedWithdrawalParams[] memory, - IDelegationManager.Withdrawal memory, + QueuedWithdrawalParams[] memory, + Withdrawal memory, bytes32 ) { - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategies, - shares: withdrawalAmounts, - withdrawer: withdrawer - }); + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + { + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategies, + depositShares: depositWithdrawalAmounts, + withdrawer: withdrawer + }); + } + + // Get scaled shares to withdraw + uint256[] memory scaledSharesArray = new uint256[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + scaledSharesArray[i] = _getScaledShares(staker, strategies[i], depositWithdrawalAmounts[i]); + } - IDelegationManager.Withdrawal memory withdrawal = IDelegationManager.Withdrawal({ + Withdrawal memory withdrawal = Withdrawal({ staker: staker, delegatedTo: delegationManager.delegatedTo(staker), withdrawer: withdrawer, nonce: delegationManager.cumulativeWithdrawalsQueued(staker), startBlock: uint32(block.number), strategies: strategies, - shares: withdrawalAmounts + scaledShares: scaledSharesArray }); bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal); return (queuedWithdrawalParams, withdrawal, withdrawalRoot); } + /// @notice Call queue withdrawals and push the Withdrawal to storage for testing purposes and + /// later assertions + function _queueWithdrawals( + address staker, + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal + ) internal { + stakerQueuedWithdrawals[staker].push(withdrawal); + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + } + + function _getScaledShares(address staker, IStrategy strategy, uint256 depositSharesToWithdraw) internal view returns (uint256) { + // Setup vars + address operator = delegationManager.delegatedTo(staker); + IStrategy[] memory strategyArray = new IStrategy[](1); + strategyArray[0] = strategy; + + // Calculate the amount of slashing to apply + uint64 maxMagnitude = allocationManagerMock.getMaxMagnitudes(operator, strategyArray)[0]; + uint256 slashingFactor = _getSlashingFactor(staker, strategy, maxMagnitude); + + DepositScalingFactor memory _dsf = DepositScalingFactor(delegationManager.depositScalingFactor(staker, strategy)); + uint256 sharesToWithdraw = _dsf.calcWithdrawable(depositSharesToWithdraw, slashingFactor); + + uint256 scaledShares = SlashingLib.scaleForQueueWithdrawal({ + sharesToWithdraw: sharesToWithdraw, + slashingFactor: slashingFactor + }); + + return scaledShares; + } + + /// @notice get the shares expected to be withdrawn given the staker, strategy, maxMagnitude, and depositSharesToWithdraw + function _getWithdrawableShares( + address staker, + IStrategy[] memory strategies, + uint64[] memory maxMagnitudes, + uint256[] memory depositSharesToWithdraw + ) internal view returns (uint256[] memory) { + require(strategies.length == depositSharesToWithdraw.length, "DelegationManagerUnitTests: length mismatch"); + uint256[] memory withdrawnShares = new uint256[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + DepositScalingFactor memory _dsf = DepositScalingFactor({ + _scalingFactor: delegationManager.depositScalingFactor(staker, strategies[i]) + }); + withdrawnShares[i] = _dsf.calcWithdrawable(depositSharesToWithdraw[i], maxMagnitudes[i]); + } + return withdrawnShares; + } + + function _getSlashingFactor( + address staker, + IStrategy strategy, + uint64 operatorMaxMagnitude + ) internal view returns (uint256) { + if (strategy == beaconChainETHStrategy) { + uint64 beaconChainSlashingFactor = eigenPodManagerMock.beaconChainSlashingFactor(staker); + return operatorMaxMagnitude.mulWad(beaconChainSlashingFactor); + } + + return operatorMaxMagnitude; + } + /** * Deploy and deposit staker into a single strategy, then set up a queued withdrawal for the staker * Assumptions: @@ -412,71 +469,92 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address staker, address withdrawer, uint256 depositAmount, - uint256 withdrawalAmount - ) internal returns (IDelegationManager.Withdrawal memory, IERC20[] memory, bytes32) { + uint256 withdrawalAmount, + bool isBeaconChainStrategy + ) internal returns (IDelegationManagerTypes.Withdrawal memory, IERC20[] memory, bytes32) { uint256[] memory depositAmounts = new uint256[](1); depositAmounts[0] = depositAmount; - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); + IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts, isBeaconChainStrategy); ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ staker: staker, withdrawer: withdrawer, strategy: strategies[0], - withdrawalAmount: withdrawalAmount + depositSharesToWithdraw: withdrawalAmount }); cheats.prank(staker); delegationManager.queueWithdrawals(queuedWithdrawalParams); // Set the current deposits to be the depositAmount - withdrawalAmount - uint256[] memory currentAmounts = new uint256[](1); - currentAmounts[0] = depositAmount - withdrawalAmount; + uint256[] memory currentAmounts = uint256(depositAmount - withdrawalAmount).toArrayU256(); strategyManagerMock.setDeposits(staker, strategies, currentAmounts); - IERC20[] memory tokens = new IERC20[](1); - tokens[0] = strategies[0].underlyingToken(); + IERC20[] memory tokens = new IERC20[](strategies.length); + for (uint i = 0; i < tokens.length; i++) { + tokens[i] = strategies[i].underlyingToken(); + } + return (withdrawal, tokens, withdrawalRoot); } - /** - * Deploy and deposit staker into a single strategy, then set up a queued withdrawal for the staker + /** + * Deploy and deposit staker into a single strategy, then set up multiple queued withdrawals for the staker * Assumptions: * - operator is already a registered operator. - * - withdrawalAmount <= depositAmount + * - total deposit amount = depositAmount * numWithdrawals + * - this will fully withdraw from the single strategy */ - function _setUpCompleteQueuedWithdrawalBeaconStrat( + function _setUpCompleteQueuedWithdrawalsSingleStrat( address staker, address withdrawer, uint256 depositAmount, - uint256 withdrawalAmount - ) internal returns (IDelegationManager.Withdrawal memory, IERC20[] memory, bytes32) { + uint256 numWithdrawals + ) internal returns ( + IDelegationManagerTypes.Withdrawal[] memory withdrawals, + IERC20[][] memory tokens, + bytes32[] memory withdrawalRoots + ) { uint256[] memory depositAmounts = new uint256[](1); - depositAmounts[0] = depositAmount; - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = beaconChainETHStrategy; - ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, - bytes32 withdrawalRoot - ) = _setUpQueueWithdrawalsSingleStrat({ - staker: staker, - withdrawer: withdrawer, - strategy: strategies[0], - withdrawalAmount: withdrawalAmount - }); + depositAmounts[0] = depositAmount * numWithdrawals; + IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts, false); + + withdrawals = new Withdrawal[](numWithdrawals); + tokens = new IERC20[][](numWithdrawals); + withdrawalRoots = new bytes32[](numWithdrawals); + + for (uint i = 0; i < numWithdrawals; i++) { + ( + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: withdrawer, + strategy: strategies[0], + depositSharesToWithdraw: depositAmount + }); + + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + withdrawals[i] = withdrawal; + tokens[i] = new IERC20[](1); + tokens[i][0] = strategies[0].underlyingToken(); + withdrawalRoots[i] = withdrawalRoot; + } - cheats.prank(staker); - delegationManager.queueWithdrawals(queuedWithdrawalParams); - // Set the current deposits to be the depositAmount - withdrawalAmount - uint256[] memory currentAmounts = new uint256[](1); - currentAmounts[0] = depositAmount - withdrawalAmount; - strategyManagerMock.setDeposits(staker, strategies, currentAmounts); + { + // Set the current deposits to be 0 + uint256[] memory currentAmounts = new uint256[](1); + currentAmounts[0] = 0; + strategyManagerMock.setDeposits(staker, strategies, currentAmounts); + } + - IERC20[] memory tokens; - // tokens[0] = strategies[0].underlyingToken(); - return (withdrawal, tokens, withdrawalRoot); + return (withdrawals, tokens, withdrawalRoots); } /** @@ -489,9 +567,10 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag address staker, address withdrawer, uint256[] memory depositAmounts, - uint256[] memory withdrawalAmounts - ) internal returns (IDelegationManager.Withdrawal memory, IERC20[] memory, bytes32) { - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); + uint256[] memory withdrawalAmounts, + bool depositBeaconChainShares + ) internal returns (IDelegationManagerTypes.Withdrawal memory, IERC20[] memory, bytes32) { + IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts, depositBeaconChainShares); IERC20[] memory tokens = new IERC20[](strategies.length); for (uint256 i = 0; i < strategies.length; i++) { @@ -499,14 +578,14 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag } ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawals({ staker: staker, withdrawer: withdrawer, strategies: strategies, - withdrawalAmounts: withdrawalAmounts + depositWithdrawalAmounts: withdrawalAmounts }); cheats.prank(staker); @@ -514,199 +593,395 @@ contract DelegationManagerUnitTests is EigenLayerUnitTestSetup, IDelegationManag return (withdrawal, tokens, withdrawalRoot); } -} -contract DelegationManagerUnitTests_Initialization_Setters is DelegationManagerUnitTests { - function test_initialization() public { - assertEq( - address(delegationManager.strategyManager()), - address(strategyManagerMock), - "constructor / initializer incorrect, strategyManager set wrong" - ); - assertEq( - address(delegationManager.slasher()), - address(slasherMock), - "constructor / initializer incorrect, slasher set wrong" - ); - assertEq( - address(delegationManager.pauserRegistry()), - address(pauserRegistry), - "constructor / initializer incorrect, pauserRegistry set wrong" - ); - assertEq(delegationManager.owner(), address(this), "constructor / initializer incorrect, owner set wrong"); - assertEq(delegationManager.paused(), 0, "constructor / initializer incorrect, paused status set wrong"); + function _setOperatorMagnitude( + address operator, + IStrategy strategy, + uint64 magnitude + ) internal { + allocationManagerMock.setMaxMagnitude(operator, strategy, magnitude); } - /// @notice Verifies that the DelegationManager cannot be iniitalized multiple times - function test_initialize_revert_reinitialization() public { - cheats.expectRevert("Initializable: contract is already initialized"); - delegationManager.initialize( - address(this), - pauserRegistry, - 0, - 0, // minWithdrawalDelayBlocks - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ); + function _setOperatorMagnitudes( + address operator, + IStrategy[] memory strategies, + uint64[] memory magnitudes + ) internal { + allocationManagerMock.setMaxMagnitudes(operator, strategies, magnitudes); } - function testFuzz_setMinWithdrawalDelayBlocks_revert_notOwner( - address invalidCaller - ) public filterFuzzedAddressInputs(invalidCaller) { - cheats.assume(invalidCaller != delegationManager.owner()); - cheats.prank(invalidCaller); - cheats.expectRevert("Ownable: caller is not the owner"); - delegationManager.setMinWithdrawalDelayBlocks(0); + struct RegisterAsOperatorEmitStruct { + address operator; + address delegationApprover; + string metadataURI; } - function testFuzz_setMinWithdrawalDelayBlocks_revert_tooLarge(uint256 newMinWithdrawalDelayBlocks) external { - // filter fuzzed inputs to disallowed amounts - cheats.assume(newMinWithdrawalDelayBlocks > delegationManager.MAX_WITHDRAWAL_DELAY_BLOCKS()); + function _registerOperator_expectEmit(RegisterAsOperatorEmitStruct memory params) internal { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit DelegationApproverUpdated(params.operator, params.delegationApprover); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit StakerDelegated(params.operator, params.operator); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorRegistered(params.operator, params.delegationApprover); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorMetadataURIUpdated(params.operator, params.metadataURI); + } - // attempt to set the `minWithdrawalDelayBlocks` variable - cheats.expectRevert("DelegationManager._setMinWithdrawalDelayBlocks: _minWithdrawalDelayBlocks cannot be > MAX_WITHDRAWAL_DELAY_BLOCKS"); - delegationManager.setMinWithdrawalDelayBlocks(newMinWithdrawalDelayBlocks); + struct DelegateToEmitStruct { + address staker; + address operator; + IStrategy[] strategies; + uint256[] depositShares; + uint256[] depositScalingFactors; } - function testFuzz_initialize_Revert_WhenWithdrawalDelayBlocksTooLarge( - uint256[] memory withdrawalDelayBlocks, - uint256 invalidStrategyIndex - ) public { - // set withdrawalDelayBlocks to be too large - cheats.assume(withdrawalDelayBlocks.length > 0); - uint256 numStrats = withdrawalDelayBlocks.length; - IStrategy[] memory strategiesToSetDelayBlocks = new IStrategy[](numStrats); - for (uint256 i = 0; i < numStrats; i++) { - strategiesToSetDelayBlocks[i] = IStrategy(address(uint160(uint256(keccak256(abi.encode(strategyMock, i)))))); + function _delegateTo_expectEmit(DelegateToEmitStruct memory params) internal { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit StakerDelegated(params.staker, params.operator); + for (uint256 i = 0; i < params.strategies.length; i++) { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit DepositScalingFactorUpdated(params.staker, params.strategies[i], params.depositScalingFactors[i]); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesIncreased(params.operator, params.staker, params.strategies[i], params.depositShares[i]); } - - // set at least one index to be too large for withdrawalDelayBlocks - invalidStrategyIndex = invalidStrategyIndex % numStrats; - withdrawalDelayBlocks[invalidStrategyIndex] = MAX_WITHDRAWAL_DELAY_BLOCKS + 1; - - // Deploy DelegationManager implmentation and proxy - delegationManagerImplementation = new DelegationManager(strategyManagerMock, slasherMock, eigenPodManagerMock); - cheats.expectRevert( - "DelegationManager._setStrategyWithdrawalDelayBlocks: _withdrawalDelayBlocks cannot be > MAX_WITHDRAWAL_DELAY_BLOCKS" - ); - delegationManager = DelegationManager( - address( - new TransparentUpgradeableProxy( - address(delegationManagerImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - address(this), - pauserRegistry, - 0, // 0 is initialPausedStatus - minWithdrawalDelayBlocks, - strategiesToSetDelayBlocks, - withdrawalDelayBlocks - ) - ) - ) - ); } -} - -contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerUnitTests { - function test_registerAsOperator_revert_paused() public { - // set the pausing flag - cheats.prank(pauser); - delegationManager.pause(2 ** PAUSED_NEW_DELEGATION); - cheats.expectRevert("Pausable: index is paused"); - delegationManager.registerAsOperator( - IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: defaultOperator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }), - emptyStringForMetadataURI - ); + struct DelegateToSingleStratEmitStruct { + address staker; + address operator; + IStrategy strategy; + uint256 depositShares; + uint256 depositScalingFactor; } - // @notice Verifies that someone cannot successfully call `DelegationManager.registerAsOperator(operatorDetails)` again after registering for the first time - function testFuzz_registerAsOperator_revert_cannotRegisterMultipleTimes( - address operator, - IDelegationManager.OperatorDetails memory operatorDetails - ) public filterFuzzedAddressInputs(operator) { - _filterOperatorDetails(operator, operatorDetails); - - // Register once - cheats.startPrank(operator); - delegationManager.registerAsOperator(operatorDetails, emptyStringForMetadataURI); + function _delegateTo_expectEmit_singleStrat(DelegateToSingleStratEmitStruct memory params) internal { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit StakerDelegated(params.staker, params.operator); + if (params.depositShares > 0) { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit DepositScalingFactorUpdated(params.staker, params.strategy, params.depositScalingFactor); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesIncreased(params.operator, params.staker, params.strategy, params.depositShares); + } + } - // Expect revert when register again - cheats.expectRevert("DelegationManager.registerAsOperator: caller is already actively delegated"); - delegationManager.registerAsOperator(operatorDetails, emptyStringForMetadataURI); - cheats.stopPrank(); + struct UndelegateEmitStruct { + address staker; + address operator; + IStrategy strategy; + uint256 depositSharesQueued; + uint256 operatorSharesDecreased; + IDelegationManagerTypes.Withdrawal withdrawal; + bytes32 withdrawalRoot; + uint256 depositScalingFactor; + bool forceUndelegated; } - /** - * @notice Verifies that an operator cannot register with `stakerOptOutWindowBlocks` set larger than `MAX_STAKER_OPT_OUT_WINDOW_BLOCKS` - */ - function testFuzz_registerAsOperator_revert_optOutBlocksTooLarge( - IDelegationManager.OperatorDetails memory operatorDetails - ) public { - // filter out *allowed* stakerOptOutWindowBlocks values - cheats.assume(operatorDetails.stakerOptOutWindowBlocks > delegationManager.MAX_STAKER_OPT_OUT_WINDOW_BLOCKS()); + /// @notice Assumes only single strategy for staker being withdrawn, only checks for single strategy if + /// param.strategy address is not 0x0 + function _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct memory params + ) internal { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit StakerUndelegated(params.staker, params.operator); + if (params.forceUndelegated) { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit StakerForceUndelegated(params.staker, params.operator); + } - cheats.prank(defaultOperator); - cheats.expectRevert("DelegationManager._setOperatorDetails: stakerOptOutWindowBlocks cannot be > MAX_STAKER_OPT_OUT_WINDOW_BLOCKS"); - delegationManager.registerAsOperator(operatorDetails, emptyStringForMetadataURI); + if (address(params.strategy) != address(0)) { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(params.operator, params.staker, params.strategy, params.operatorSharesDecreased); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalQueued(params.withdrawalRoot, params.withdrawal, params.operatorSharesDecreased.toArrayU256()); + } } - /** - * @notice `operator` registers via calling `DelegationManager.registerAsOperator(operatorDetails, metadataURI)` - * Should be able to set any parameters, other than too high value for `stakerOptOutWindowBlocks` - * The set parameters should match the desired parameters (correct storage update) - * Operator becomes delegated to themselves - * Properly emits events – especially the `OperatorRegistered` event, but also `StakerDelegated` & `OperatorDetailsModified` events - * Reverts appropriately if operator was already delegated to someone (including themselves, i.e. they were already an operator) - * @param operator and @param operatorDetails are fuzzed inputs - */ - function testFuzz_registerAsOperator( - address operator, - IDelegationManager.OperatorDetails memory operatorDetails, - string memory metadataURI - ) public filterFuzzedAddressInputs(operator) { - _filterOperatorDetails(operator, operatorDetails); + struct IncreaseDelegatedSharesEmitStruct { + address staker; + address operator; + IStrategy strategy; + uint256 sharesToIncrease; + uint256 depositScalingFactor; + } + function _increaseDelegatedShares_expectEmit(IncreaseDelegatedSharesEmitStruct memory params) internal { cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorDetailsModified(operator, operatorDetails); + emit DepositScalingFactorUpdated(params.staker, params.strategy, params.depositScalingFactor); cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(operator, operator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorRegistered(operator, operatorDetails); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorMetadataURIUpdated(operator, metadataURI); + emit OperatorSharesIncreased(params.operator, params.staker, params.strategy, params.sharesToIncrease); + } + + struct QueueWithdrawalsEmitStruct { + address staker; + address operator; + IDelegationManagerTypes.QueuedWithdrawalParams[] queuedWithdrawalParams; + IDelegationManagerTypes.Withdrawal withdrawal; + bytes32 withdrawalRoot; + } + + function _queueWithdrawals_expectEmit(QueueWithdrawalsEmitStruct memory params) internal { + for (uint256 i = 0; i < params.queuedWithdrawalParams.length; i++) { + uint256[] memory sharesToWithdraw = new uint256[](params.queuedWithdrawalParams[i].strategies.length); + for (uint256 j = 0; j < params.queuedWithdrawalParams[i].strategies.length; j++) { + DepositScalingFactor memory _dsf = DepositScalingFactor({ + _scalingFactor: delegationManager.depositScalingFactor(defaultStaker, params.queuedWithdrawalParams[i].strategies[j]) + }); + uint256 newMaxMagnitude = allocationManagerMock.getMaxMagnitudes(params.operator, params.queuedWithdrawalParams[i].strategies)[j]; + sharesToWithdraw[j] = _dsf.calcWithdrawable(params.queuedWithdrawalParams[i].depositShares[j], newMaxMagnitude); + + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased( + params.operator, + params.staker, + params.queuedWithdrawalParams[i].strategies[j], + _dsf.calcWithdrawable(params.queuedWithdrawalParams[i].depositShares[j], newMaxMagnitude) + ); + } + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalQueued(params.withdrawalRoot, params.withdrawal, sharesToWithdraw); + } + } + + + /// @notice Due to rounding, withdrawable shares and operator shares may not align even if the operator + /// only has the single staker with deposits. + function _assertWithdrawableAndOperatorShares( + uint256 withdrawableShares, + uint256 operatorShares, + string memory errorMessage + ) internal pure { + assertLe( + withdrawableShares, + operatorShares, + "withdrawableShares should be less than or equal to operatorShares" + ); + if (withdrawableShares < 1e18) { + // Note that the amount of "drift"/difference between staker withdrawable shares + // and operator shares is a result of the nested floor division in the calculation + // of withdrawable shares in calcWithdrawable. This is expected behavior. + assertApproxEqAbs( + withdrawableShares, + operatorShares, + 1, + errorMessage + ); + } else { + assertApproxEqRel( + withdrawableShares, + operatorShares, + APPROX_REL_DIFF, + errorMessage + ); + } + assertLe( + withdrawableShares, + operatorShares, + "withdrawableShares should be less than or equal to operatorShares" + ); + } + + /** + * @notice Assertion checks after queuing a withdrawal. Reads withdrawals set in storage in test + * - Asserts exact match of Withdrawal struct exists in storage + * - Asserts Withdrawal root is pending + */ + function _assertQueuedWithdrawalExists( + address staker + ) internal view { + for (uint256 i = 0; i < stakerQueuedWithdrawals[staker].length; ++i) { + Withdrawal memory withdrawal = stakerQueuedWithdrawals[staker][i]; + bytes32 withdrawalRootToCheck = delegationManager.calculateWithdrawalRoot(withdrawal); + assertTrue( + delegationManager.pendingWithdrawals(withdrawalRootToCheck), + "withdrawalRoot not pending" + ); + + (Withdrawal[] memory withdrawals, ) = delegationManager.getQueuedWithdrawals(staker); + for (uint256 j = 0; j < withdrawals.length; ++j) { + if (withdrawalRootToCheck == delegationManager.calculateWithdrawalRoot(withdrawals[j])) { + assertEq( + withdrawals[j].staker, + withdrawal.staker + ); + assertEq( + withdrawals[j].withdrawer, + withdrawal.withdrawer + ); + assertEq( + withdrawals[j].delegatedTo, + withdrawal.delegatedTo + ); + assertEq( + withdrawals[j].nonce, + withdrawal.nonce + ); + assertEq( + withdrawals[j].startBlock, + withdrawal.startBlock + ); + assertEq( + withdrawals[j].scaledShares.length, + withdrawal.scaledShares.length + ); + for (uint256 k = 0; k < withdrawal.scaledShares.length; ++k) { + assertEq( + withdrawals[j].scaledShares[k], + withdrawal.scaledShares[k] + ); + assertEq( + address(withdrawals[j].strategies[k]), + address(withdrawal.strategies[k]) + ); + } + } + } + } + } +} + +contract DelegationManagerUnitTests_Initialization_Setters is DelegationManagerUnitTests { + function test_initialization() public view { + assertEq( + address(delegationManager.strategyManager()), + address(strategyManagerMock), + "constructor / initializer incorrect, strategyManager set wrong" + ); + assertEq( + address(delegationManager.pauserRegistry()), + address(pauserRegistry), + "constructor / initializer incorrect, pauserRegistry set wrong" + ); + assertEq( + address(delegationManager.eigenPodManager()), + address(eigenPodManagerMock), + "constructor / initializer incorrect, eigenPodManager set wrong" + ); + assertEq( + address(delegationManager.allocationManager()), + address(allocationManagerMock), + "constructor / initializer incorrect, allocationManager set wrong" + ); + assertEq( + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS(), + MIN_WITHDRAWAL_DELAY_BLOCKS, + "constructor / initializer incorrect, MIN_WITHDRAWAL_DELAY set wrong" + ); + assertEq(delegationManager.owner(), address(this), "constructor / initializer incorrect, owner set wrong"); + assertEq(delegationManager.paused(), 0, "constructor / initializer incorrect, paused status set wrong"); + } + + /// @notice Verifies that the DelegationManager cannot be iniitalized multiple times + function test_initialize_revert_reinitialization() public { + cheats.expectRevert("Initializable: contract is already initialized"); + delegationManager.initialize(address(this), 0); + } +} + +contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerUnitTests { + function test_registerAsOperator_revert_paused() public { + // set the pausing flag + cheats.prank(pauser); + delegationManager.pause(2 ** PAUSED_NEW_DELEGATION); + + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + delegationManager.registerAsOperator( + address(0), + 0, + emptyStringForMetadataURI + ); + } + + // @notice Verifies that someone cannot successfully call `DelegationManager.registerAsOperator(delegationApprover)` again after registering for the first time + function testFuzz_registerAsOperator_revert_cannotRegisterMultipleTimes( + address delegationApprover + ) public { + // Register once + cheats.startPrank(defaultOperator); + delegationManager.registerAsOperator(delegationApprover, 0, emptyStringForMetadataURI); + + // Expect revert when register again + cheats.expectRevert(ActivelyDelegated.selector); + delegationManager.registerAsOperator(delegationApprover, 0, emptyStringForMetadataURI); + cheats.stopPrank(); + } + /** + * @notice `operator` registers via calling `DelegationManager.registerAsOperator(delegationApprover, metadataURI)` + * Should be able to set any parameters, other than too high value for `stakerOptOutWindowBlocks` + * The set parameters should match the desired parameters (correct storage update) + * Operator becomes delegated to themselves + * Properly emits events – especially the `OperatorRegistered` event, but also `StakerDelegated` & `DelegationApproverUpdated` events + * Reverts appropriately if operator was already delegated to someone (including themselves, i.e. they were already an operator) + * @param operator and @param delegationApprover are fuzzed inputs + */ + function testFuzz_registerAsOperator( + address operator, + address delegationApprover, + string memory metadataURI + ) public filterFuzzedAddressInputs(operator) { + _registerOperator_expectEmit( + RegisterAsOperatorEmitStruct({ + operator: operator, + delegationApprover: delegationApprover, + metadataURI: metadataURI + }) + ); cheats.prank(operator); - delegationManager.registerAsOperator(operatorDetails, metadataURI); + delegationManager.registerAsOperator(delegationApprover, 0, metadataURI); // Storage checks assertEq( - operatorDetails.delegationApprover, + delegationApprover, delegationManager.delegationApprover(operator), "delegationApprover not set correctly" ); - assertEq( - operatorDetails.stakerOptOutWindowBlocks, - delegationManager.stakerOptOutWindowBlocks(operator), - "stakerOptOutWindowBlocks not set correctly" - ); assertEq(delegationManager.delegatedTo(operator), operator, "operator not delegated to self"); } + /// @notice Register two separate operators shouldn't revert + function testFuzz_registerAsOperator_TwoSeparateOperatorsRegister( + address operator1, + address delegationApprover1, + address operator2, + address delegationApprover2 + ) public { + cheats.assume(operator1 != operator2); + // register operator1 with expected emits + _registerOperator_expectEmit( + RegisterAsOperatorEmitStruct({ + operator: operator1, + delegationApprover: delegationApprover1, + metadataURI: emptyStringForMetadataURI + }) + ); + _registerOperator(operator1, delegationApprover1, emptyStringForMetadataURI); + // register operator2 with expected emits + _registerOperator_expectEmit( + RegisterAsOperatorEmitStruct({ + operator: operator2, + delegationApprover: delegationApprover2, + metadataURI: emptyStringForMetadataURI + }) + ); + _registerOperator(operator2, delegationApprover2, emptyStringForMetadataURI); + assertTrue( + delegationManager.isOperator(operator1), + "operator1 not registered" + ); + assertTrue( + delegationManager.isOperator(operator2), + "operator2 not registered" + ); + } + + // @notice Verifies that a staker who is actively delegated to an operator cannot register as an operator (without first undelegating, at least) - function testFuzz_registerAsOperator_cannotRegisterWhileDelegated( + function testFuzz_Revert_registerAsOperator_cannotRegisterWhileDelegated( address staker, - IDelegationManager.OperatorDetails memory operatorDetails + address delegationApprover ) public filterFuzzedAddressInputs(staker) { cheats.assume(staker != defaultOperator); - // Staker becomes an operator, so filter against staker's address - _filterOperatorDetails(staker, operatorDetails); // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); @@ -717,70 +992,102 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); // expect revert if attempt to register as operator - cheats.expectRevert("DelegationManager.registerAsOperator: caller is already actively delegated"); - delegationManager.registerAsOperator(operatorDetails, emptyStringForMetadataURI); + cheats.expectRevert(ActivelyDelegated.selector); + delegationManager.registerAsOperator(delegationApprover, 0, emptyStringForMetadataURI); cheats.stopPrank(); } + + /// @notice Add test for registerAsOperator where the operator has existing deposits in strategies + /// Assert: + /// depositShares == operatorShares == withdrawableShares + function testFuzz_registerAsOperator_withDeposits(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + // Set staker shares in StrategyManager + IStrategy[] memory strategiesToReturn = new IStrategy[](1); + strategiesToReturn[0] = strategyMock; + uint256[] memory sharesToReturn = new uint256[](1); + sharesToReturn[0] = shares; + strategyManagerMock.setDeposits(defaultOperator, strategiesToReturn, sharesToReturn); + + // register operator, their own staker depositShares should increase their operatorShares + _registerOperator_expectEmit( + RegisterAsOperatorEmitStruct({ + operator: defaultOperator, + delegationApprover: address(0), + metadataURI: emptyStringForMetadataURI + }) + ); + _registerOperatorWithBaseDetails(defaultOperator); + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + + // check depositShares == operatorShares == withdrawableShares + assertEq(operatorSharesAfter, shares, "operator shares not set correctly"); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultOperator, strategiesToReturn); + assertEq( + withdrawableShares[0], + shares, + "withdrawable shares not set correctly" + ); + assertEq( + strategyManagerMock.stakerDepositShares(defaultOperator, strategyMock), + shares, + "staker deposit shares not set correctly" + ); + } /** * @notice Tests that an operator can modify their OperatorDetails by calling `DelegationManager.modifyOperatorDetails` * Should be able to set any parameters, other than setting their `earningsReceiver` to the zero address or too high value for `stakerOptOutWindowBlocks` * The set parameters should match the desired parameters (correct storage update) - * Properly emits an `OperatorDetailsModified` event + * Properly emits an `DelegationApproverUpdated` event * Reverts appropriately if the caller is not an operator * Reverts if operator tries to decrease their `stakerOptOutWindowBlocks` parameter - * @param initialOperatorDetails and @param modifiedOperatorDetails are fuzzed inputs + * @param delegationApprover1 and @param delegationApprover2 are fuzzed inputs */ function testFuzz_modifyOperatorParameters( - IDelegationManager.OperatorDetails memory initialOperatorDetails, - IDelegationManager.OperatorDetails memory modifiedOperatorDetails + address delegationApprover1, + address delegationApprover2 ) public { - _registerOperator(defaultOperator, initialOperatorDetails, emptyStringForMetadataURI); + _registerOperator_expectEmit( + RegisterAsOperatorEmitStruct({ + operator: defaultOperator, + delegationApprover: delegationApprover1, + metadataURI: emptyStringForMetadataURI + }) + ); + _registerOperator(defaultOperator, delegationApprover1, emptyStringForMetadataURI); cheats.startPrank(defaultOperator); - // either it fails for trying to set the stakerOptOutWindowBlocks - if (modifiedOperatorDetails.stakerOptOutWindowBlocks > delegationManager.MAX_STAKER_OPT_OUT_WINDOW_BLOCKS()) { - cheats.expectRevert( - "DelegationManager._setOperatorDetails: stakerOptOutWindowBlocks cannot be > MAX_STAKER_OPT_OUT_WINDOW_BLOCKS" - ); - delegationManager.modifyOperatorDetails(modifiedOperatorDetails); - // or the transition is allowed, - } else if ( - modifiedOperatorDetails.stakerOptOutWindowBlocks >= initialOperatorDetails.stakerOptOutWindowBlocks - ) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorDetailsModified(defaultOperator, modifiedOperatorDetails); - delegationManager.modifyOperatorDetails(modifiedOperatorDetails); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit DelegationApproverUpdated(defaultOperator, delegationApprover2); + delegationManager.modifyOperatorDetails(defaultOperator, delegationApprover2); - assertEq( - modifiedOperatorDetails.delegationApprover, - delegationManager.delegationApprover(defaultOperator), - "delegationApprover not set correctly" - ); - assertEq( - modifiedOperatorDetails.stakerOptOutWindowBlocks, - delegationManager.stakerOptOutWindowBlocks(defaultOperator), - "stakerOptOutWindowBlocks not set correctly" - ); - assertEq(delegationManager.delegatedTo(defaultOperator), defaultOperator, "operator not delegated to self"); - // or else the transition is disallowed - } else { - cheats.expectRevert("DelegationManager._setOperatorDetails: stakerOptOutWindowBlocks cannot be decreased"); - delegationManager.modifyOperatorDetails(modifiedOperatorDetails); - } + assertEq( + delegationApprover2, + delegationManager.delegationApprover(defaultOperator), + "delegationApprover not set correctly" + ); + assertEq(delegationManager.delegatedTo(defaultOperator), defaultOperator, "operator not delegated to self"); + // or else the transition is disallowed cheats.stopPrank(); } // @notice Tests that an address which is not an operator cannot successfully call `updateOperatorMetadataURI`. - function test_updateOperatorMetadataUri_notRegistered() public { + function test_Revert_updateOperatorMetadataUri_notRegistered() public { assertFalse(delegationManager.isOperator(defaultOperator), "bad test setup"); cheats.prank(defaultOperator); - cheats.expectRevert("DelegationManager.updateOperatorMetadataURI: caller must be an operator"); - delegationManager.updateOperatorMetadataURI(emptyStringForMetadataURI); + cheats.expectRevert(OperatorNotRegistered.selector); + delegationManager.updateOperatorMetadataURI(defaultOperator, emptyStringForMetadataURI); + } + + + function test_Revert_updateOperatorMetadataUri_notOperator() public { + cheats.expectRevert(OperatorNotRegistered.selector); + delegationManager.modifyOperatorDetails(defaultOperator, defaultOperator); } /** @@ -788,35 +1095,71 @@ contract DelegationManagerUnitTests_RegisterModifyOperator is DelegationManagerU * @dev This is an important check to ensure that our definition of 'operator' remains consistent, in particular for preserving the * invariant that 'operators' are always delegated to themselves */ - function testFuzz_updateOperatorMetadataUri_revert_notOperator( - IDelegationManager.OperatorDetails memory operatorDetails + function testFuzz_UpdateOperatorMetadataURI(string memory metadataURI) public { + _registerOperatorWithBaseDetails(defaultOperator); + + // call `updateOperatorMetadataURI` and check for event + cheats.prank(defaultOperator); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorMetadataURIUpdated(defaultOperator, metadataURI); + delegationManager.updateOperatorMetadataURI(defaultOperator, metadataURI); + } + + function testFuzz_UAM_modifyOperatorDetails( + address delegationApprover ) public { - cheats.expectRevert("DelegationManager.modifyOperatorDetails: caller must be an operator"); - delegationManager.modifyOperatorDetails(operatorDetails); + // Set admin + cheats.prank(defaultOperator); + permissionController.setAppointee( + defaultOperator, + address(this), + address(delegationManager), + IDelegationManager.modifyOperatorDetails.selector + ); + + _registerOperatorWithBaseDetails(defaultOperator); + + // Modify operator details + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit DelegationApproverUpdated(defaultOperator, delegationApprover); + delegationManager.modifyOperatorDetails(defaultOperator, delegationApprover); + + // Check storage + assertEq( + delegationApprover, + delegationManager.delegationApprover(defaultOperator), + "delegationApprover not set correctly" + ); } - // @notice Tests that an operator who calls `updateOperatorMetadataURI` will correctly see an `OperatorMetadataURIUpdated` event emitted with their input - function testFuzz_UpdateOperatorMetadataURI(string memory metadataURI) public { - // register *this contract* as an operator + function testFuzz_UAM_updateOperatorMetadataURI(string memory metadataURI) public { + // Set admin + cheats.prank(defaultOperator); + permissionController.setAppointee( + defaultOperator, + address(this), + address(delegationManager), + IDelegationManager.updateOperatorMetadataURI.selector + ); + _registerOperatorWithBaseDetails(defaultOperator); // call `updateOperatorMetadataURI` and check for event - cheats.prank(defaultOperator); cheats.expectEmit(true, true, true, true, address(delegationManager)); emit OperatorMetadataURIUpdated(defaultOperator, metadataURI); - delegationManager.updateOperatorMetadataURI(metadataURI); + delegationManager.updateOperatorMetadataURI(defaultOperator, metadataURI); } } contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + using SlashingLib for *; + function test_Revert_WhenPaused() public { cheats.prank(defaultOperator); delegationManager.registerAsOperator( - IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: defaultOperator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }), + address(0), + 0, emptyStringForMetadataURI ); @@ -826,7 +1169,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; cheats.prank(defaultStaker); - cheats.expectRevert("Pausable: index is paused"); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); } @@ -834,39 +1177,34 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * @notice Delegates from `staker` to an operator, then verifies that the `staker` cannot delegate to another `operator` (at least without first undelegating) */ function testFuzz_Revert_WhenDelegateWhileDelegated( - address staker, - address operator, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 salt - ) public filterFuzzedAddressInputs(staker) filterFuzzedAddressInputs(operator) { - // filter out input since if the staker tries to delegate again after registering as an operator, we will revert earlier than this test is designed to check - cheats.assume(staker != operator); + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + address operator = r.Address(); + bytes32 salt = r.Bytes32(); // delegate from the staker to an operator - cheats.assume(operator != address(this)); _registerOperatorWithBaseDetails(operator); _delegateToOperatorWhoAcceptsAllStakers(staker, operator); // try to delegate again and check that the call reverts - cheats.startPrank(staker); - cheats.expectRevert("DelegationManager.delegateTo: staker is already actively delegated"); + cheats.prank(staker); + cheats.expectRevert(ActivelyDelegated.selector); delegationManager.delegateTo(operator, approverSignatureAndExpiry, salt); - cheats.stopPrank(); } - // @notice Verifies that `staker` cannot delegate to an unregistered `operator` - function testFuzz_Revert_WhenDelegateToUnregisteredOperator( - address staker, - address operator - ) public filterFuzzedAddressInputs(staker) filterFuzzedAddressInputs(operator) { + /// @notice Verifies that `staker` cannot delegate to an unregistered `operator` + function testFuzz_Revert_WhenDelegateToUnregisteredOperator(Randomness r) public { + address staker = r.Address(); + address operator = r.Address(); assertFalse(delegationManager.isOperator(operator), "incorrect test input?"); // try to delegate and check that the call reverts - cheats.startPrank(staker); - cheats.expectRevert("DelegationManager.delegateTo: operator is not registered in EigenLayer"); + cheats.prank(staker); + cheats.expectRevert(OperatorNotRegistered.selector); ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; delegationManager.delegateTo(operator, approverSignatureAndExpiry, emptySalt); - cheats.stopPrank(); } /** @@ -879,14 +1217,12 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Reverts if the ‘operator’ is not actually registered as an operator */ function testFuzz_OperatorWhoAcceptsAllStakers_StrategyManagerShares( - address staker, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 salt, - uint256 shares - ) public filterFuzzedAddressInputs(staker) { - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); _registerOperatorWithBaseDetails(defaultOperator); @@ -899,20 +1235,20 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); + strategyManagerMock.addDeposit(staker, strategyMock, shares); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); // delegate from the `staker` to the operator - cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, strategyMock, shares); + cheats.prank(staker); + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategyMock, + depositShares: shares, + depositScalingFactor: WAD + }) + ); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); - cheats.stopPrank(); uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); @@ -931,21 +1267,62 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { /** * @notice `staker` delegates to an operator who does not require any signature verification (i.e. the operator’s `delegationApprover` address is set to the zero address) - * via the `staker` calling `DelegationManager.delegateTo` + * but it should revert as the strategy has been fully slashed for the operator. + */ + function testFuzz_Revert_OperatorWhoAcceptsAllStakers_AlreadySlashed100Percent_StrategyManagerShares( + Randomness r + ) public { + address staker = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + + // Set empty sig+salt + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + bytes32 salt; + + _registerOperatorWithBaseDetails(defaultOperator); + + // Set staker shares in StrategyManager + IStrategy[] memory strategiesToReturn = strategyMock.toArray(); + uint256[] memory sharesToReturn = shares.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); + + // Set the operators magnitude to be 0 + _setOperatorMagnitude(defaultOperator, strategyMock, 0); + + // delegate from the `staker` to the operator + cheats.prank(staker); + cheats.expectRevert(FullySlashed.selector); + delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); + + assertTrue(delegationManager.delegatedTo(staker) != defaultOperator, "staker should not be delegated to the operator"); + assertFalse(delegationManager.isDelegated(staker), "staker should not be delegated"); + assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + // verify that the salt is still marked as unused (since it wasn't checked or used) + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + } + + /** + * @notice `staker` delegates to an operator who does not require any signature verification (i.e. the operator’s `delegationApprover` address is set to the zero address) + * but it should revert as the beaconChainStrategy has been fully slashed for the operator. * The function should pass with any `operatorSignature` input (since it should be unused) * Properly emits a `StakerDelegated` event * Staker is correctly delegated after the call (i.e. correct storage update) * OperatorSharesIncreased event should only be emitted if beaconShares is > 0. Since a staker can have negative shares nothing should happen in that case */ - function testFuzz_OperatorWhoAcceptsAllStakers_BeaconChainStrategyShares( - address staker, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 salt, - int256 beaconShares - ) public filterFuzzedAddressInputs(staker) { - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + function testFuzz_Revert_OperatorWhoAcceptsAllStakers_AlreadySlashed100Percent_BeaconChainStrategyShares( + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + int256 beaconShares = r.Int256(); + cheats.assume(beaconShares > 0); _registerOperatorWithBaseDetails(defaultOperator); @@ -960,21 +1337,200 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // Set staker shares in BeaconChainStrategy eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); + + // Set the operators magnitude for native restaking to be 0 + _setOperatorMagnitude(defaultOperator, beaconChainETHStrategy, 0); + // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); - if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, beaconChainETHStrategy, uint256(beaconShares)); - } + cheats.expectRevert(FullySlashed.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); - cheats.stopPrank(); uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - if (beaconShares <= 0) { - assertEq( - beaconSharesBefore, - beaconSharesAfter, + + assertEq( + beaconSharesBefore, + beaconSharesAfter, + "operator beaconchain shares should not have increased with negative shares" + ); + assertTrue(delegationManager.delegatedTo(staker) != defaultOperator, "staker should not be delegated to the operator"); + assertFalse(delegationManager.isDelegated(staker), "staker should not be delegated"); + assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + // verify that the salt is still marked as unused (since it wasn't checked or used) + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + } + + /// @notice Same test as above, except operator has a magnitude < WAD for the given strategies + function testFuzz_OperatorWhoAcceptsAllStakers_AlreadySlashed_StrategyManagerShares( + Randomness r + ) public { + address staker = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 maxMagnitude = r.Uint64(1, WAD); + + // Set empty sig+salt + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + bytes32 salt; + + _registerOperatorWithBaseDetails(defaultOperator); + + // Set staker shares in StrategyManager + strategyManagerMock.addDeposit(staker, strategyMock, shares); + (IStrategy[] memory strategiesToReturn, ) = strategyManagerMock.getDeposits(staker); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); + + // Set the operators magnitude + _setOperatorMagnitude(defaultOperator, strategyMock, maxMagnitude); + + // Expected staker scaling factor + uint256 stakerScalingFactor = uint256(WAD).divWad(maxMagnitude); + + // delegate from the `staker` to the operator + cheats.prank(staker); + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategyMock, + depositShares: shares, + depositScalingFactor: stakerScalingFactor + }) + ); + delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + + assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); + assertTrue(delegationManager.isOperator(defaultOperator), "staker not registered as operator"); + assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker delegated to the wrong address"); + assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + // verify that the salt is still marked as unused (since it wasn't checked or used) + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + _assertWithdrawableAndOperatorShares(withdrawableShares[0], operatorSharesAfter, "withdrawableShares not set correctly"); + } + + /** + * @notice `staker` delegates to an operator who does not require any signature verification (i.e. the operator’s `delegationApprover` address is set to the zero address) + * via the `staker` calling `DelegationManager.delegateTo` + * The function should pass with any `operatorSignature` input (since it should be unused) + * Properly emits a `StakerDelegated` event + * Staker is correctly delegated after the call (i.e. correct storage update) + * OperatorSharesIncreased event should only be emitted if beaconShares is > 0. Since a staker can have negative shares nothing should happen in that case + */ + function testFuzz_OperatorWhoAcceptsAllStakers_BeaconChainStrategyShares( + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + int256 beaconShares = r.Int256(); + cheats.assume(beaconShares > 0); + + _registerOperatorWithBaseDetails(defaultOperator); + // Set the operators magnitude + _setOperatorMagnitude(defaultOperator, beaconChainETHStrategy, WAD); + + // verify that the salt hasn't been used before + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + // Set staker shares in BeaconChainStrategy + eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); + + // delegate from the `staker` to the operator + cheats.startPrank(staker); + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: beaconChainETHStrategy, + depositShares: beaconShares > 0 ? uint256(beaconShares) : 0, + depositScalingFactor: WAD + }) + ); + delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); + uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + if (beaconShares <= 0) { + assertEq( + beaconSharesBefore, + beaconSharesAfter, + "operator beaconchain shares should not have increased with negative shares" + ); + } else { + assertEq( + beaconSharesBefore + uint256(beaconShares), + beaconSharesAfter, + "operator beaconchain shares not increased correctly" + ); + } + assertTrue(delegationManager.isOperator(defaultOperator), "staker not registered as operator"); + assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker delegated to the wrong address"); + assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + // verify that the salt is still marked as unused (since it wasn't checked or used) + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + } + + /// @notice Same test as above, except operator has a magnitude < WAD for the given strategies + function testFuzz_OperatorWhoAcceptsAllStakers_AlreadySlashed_BeaconChainStrategyShares( + Randomness r + ) public { + address staker = r.Address(); + uint64 maxMagnitude = r.Uint64(1, WAD); + // Bound and ensure beaconShares rounded down to gwei + int256 beaconShares = int256(bound(r.Uint256(), 1 gwei, MAX_ETH_SUPPLY)); + + // Set empty sig+salt + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + bytes32 salt; + + // Register and set operator's magnitude + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, beaconChainETHStrategy, maxMagnitude); + + // Set staker shares in BeaconChainStrategy + eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); + + // delegate from the `staker` to the operator, check for events emitted + cheats.startPrank(staker); + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: beaconChainETHStrategy, + depositShares: beaconShares > 0 ? uint256(beaconShares) : 0, + depositScalingFactor: uint256(WAD).divWad(maxMagnitude) + }) + ); + delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); + uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + if (beaconShares <= 0) { + assertEq( + beaconSharesBefore, + beaconSharesAfter, "operator beaconchain shares should not have increased with negative shares" ); } else { @@ -995,6 +1551,18 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ), "salt somehow spent too early?" ); + + IStrategy[] memory strategiesToReturn = beaconChainETHStrategy.toArray(); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + if (beaconShares > 0) { + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + beaconSharesAfter, + "withdrawableShares not set correctly" + ); + } else { + assertEq(withdrawableShares[0], 0, "staker shares not set correctly"); + } } /** @@ -1003,15 +1571,13 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Similar to tests above but now with staker who has both EigenPod and StrategyManager shares. */ function testFuzz_OperatorWhoAcceptsAllStakers_BeaconChainAndStrategyManagerShares( - address staker, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 salt, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(staker) { - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + int256 beaconShares = int256(bound(r.Uint256(), 1 gwei, MAX_ETH_SUPPLY)); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); _registerOperatorWithBaseDetails(defaultOperator); @@ -1024,28 +1590,42 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent too early?" ); // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); + strategyManagerMock.addDeposit(staker, strategyMock, shares); eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + ( + IStrategy[] memory strategiesToReturn, + uint256[] memory sharesToReturn + ) = delegationManager.getDepositedShares(staker); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, strategyMock, shares); + uint256[] memory depositScalingFactors = new uint256[](1); + depositScalingFactors[0] = uint256(WAD); if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, beaconChainETHStrategy, uint256(beaconShares)); + depositScalingFactors = new uint256[](2); + depositScalingFactors[0] = uint256(WAD); + depositScalingFactors[1] = uint256(WAD); } + _delegateTo_expectEmit( + DelegateToEmitStruct({ + staker: staker, + operator: defaultOperator, + strategies: strategiesToReturn, + depositShares: sharesToReturn, + depositScalingFactors: depositScalingFactors + }) + ); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + operatorSharesAfter, + "withdrawableShares not set correctly" + ); if (beaconShares <= 0) { assertEq( beaconSharesBefore, @@ -1053,6 +1633,11 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "operator beaconchain shares should not have increased with negative shares" ); } else { + _assertWithdrawableAndOperatorShares( + withdrawableShares[1], + beaconSharesAfter, + "withdrawableShares not set correctly" + ); assertEq( beaconSharesBefore + uint256(beaconShares), beaconSharesAfter, @@ -1073,21 +1658,122 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ); } + /** + * @notice `staker` delegates to an operator who does not require any signature verification (i.e. the operator’s `delegationApprover` address is set to the zero address) + * via the `staker` calling `DelegationManager.delegateTo` + * Similar to tests above but now with staker who has both EigenPod and StrategyManager shares. + */ + function testFuzz_OperatorWhoAcceptsAllStakers_AlreadySlashed_BeaconChainAndStrategyManagerShares( + Randomness r + ) public { + // 1. register operator and setup values, magnitudes + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + int256 beaconShares = int256(bound(r.Uint256(), 1 gwei, MAX_ETH_SUPPLY)); + uint64 maxMagnitudeBeacon = r.Uint64(1, WAD); + uint64 maxMagnitudeStrategy = r.Uint64(1, WAD); + + _registerOperatorWithBaseDetails(defaultOperator); + + // Set empty sig+salt + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; + bytes32 salt; + + // Set the operators magnitude to be 50% + _setOperatorMagnitude(defaultOperator, beaconChainETHStrategy, maxMagnitudeBeacon); + _setOperatorMagnitude(defaultOperator, strategyMock, maxMagnitudeStrategy); + + // 2. Set staker shares in BeaconChainStrategy and StrategyMananger + strategyManagerMock.addDeposit(defaultStaker, strategyMock, shares); + eigenPodManagerMock.setPodOwnerShares(defaultStaker, beaconShares); + ( + IStrategy[] memory strategiesToReturn, + uint256[] memory sharesToReturn + ) = delegationManager.getDepositedShares(defaultStaker); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 beaconSharesBefore = delegationManager.operatorShares(defaultStaker, beaconChainETHStrategy); + // 3. delegate from the `staker` to the operator with expected emitted events + cheats.startPrank(defaultStaker); + + uint256[] memory depositScalingFactors = new uint256[](1); + depositScalingFactors[0] = uint256(WAD).divWad(maxMagnitudeStrategy); + if (beaconShares > 0) { + depositScalingFactors = new uint256[](2); + depositScalingFactors[0] = uint256(WAD).divWad(maxMagnitudeStrategy); + depositScalingFactors[1] = uint256(WAD).divWad(maxMagnitudeBeacon); + } + _delegateTo_expectEmit( + DelegateToEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategies: strategiesToReturn, + depositShares: sharesToReturn, + depositScalingFactors: depositScalingFactors + }) + ); + delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); + cheats.stopPrank(); + + // 4. Assert correct end state values + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); + assertTrue(delegationManager.isOperator(defaultOperator), "defaultStaker not registered as operator"); + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "defaultStaker delegated to the wrong address"); + assertFalse(delegationManager.isOperator(defaultStaker), "staker incorrectly registered as operator"); + // verify that the salt is still marked as unused (since it wasn't checked or used) + assertFalse( + delegationManager.delegationApproverSaltIsSpent( + delegationManager.delegationApprover(defaultOperator), + salt + ), + "salt somehow spent too early?" + ); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategiesToReturn); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + operatorSharesAfter, + "withdrawable strategy shares not set correctly" + ); + if (beaconShares > 0) { + _assertWithdrawableAndOperatorShares( + withdrawableShares[1], + beaconSharesAfter, + "withdrawable beacon shares not set correctly" + ); + assertEq( + beaconSharesBefore + uint256(beaconShares), + beaconSharesAfter, + "operator beaconchain shares not increased correctly" + ); + } else { + assertEq(withdrawableShares[0], 0, "staker beacon chain shares not set correctly"); + assertEq( + beaconSharesBefore, + beaconSharesAfter, + "operator beaconchain shares should not have increased with negative shares" + ); + } + } + /** * @notice `staker` delegates to a operator who does not require any signature verification similar to test above. * In this scenario, staker doesn't have any delegatable shares and operator shares should not increase. Staker * should still be correctly delegated to the operator after the call. */ function testFuzz_OperatorWhoAcceptsAllStakers_ZeroDelegatableShares( - address staker, - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 salt - ) public filterFuzzedAddressInputs(staker) { + Randomness r, + ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint64 operatorMagnitude = r.Uint64(1, WAD); + // register *this contract* as an operator // filter inputs, since this will fail when the staker is already registered as an operator cheats.assume(staker != defaultOperator); _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); // verify that the salt hasn't been used before assertFalse( @@ -1146,7 +1832,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectRevert("DelegationManager._delegate: approver signature expired"); + cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -1199,7 +1885,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "salt somehow spent not spent?" ); delegationManager.undelegate(staker); - cheats.expectRevert("DelegationManager._delegate: approverSalt already spent"); + cheats.expectRevert(SaltSpent.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -1237,7 +1923,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer"); + cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -1323,15 +2009,12 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Reverts if the ‘operator’ is not actually registered as an operator */ function testFuzz_OperatorWhoRequiresECDSASignature_StrategyManagerShares( - address staker, - bytes32 salt, - uint256 expiry, - uint256 shares - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); _registerOperatorWithDelegationApprover(defaultOperator); @@ -1353,16 +2036,20 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ); // Set staker shares in StrategyManager - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); + strategyManagerMock.addDeposit(staker, strategyMock, shares); + (IStrategy[] memory strategiesToReturn, ) = strategyManagerMock.getDeposits(staker); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategyMock, + depositShares: shares, + depositScalingFactor: WAD + }) + ); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); @@ -1370,6 +2057,8 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker delegated to the wrong address"); assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + _assertWithdrawableAndOperatorShares(withdrawableShares[0], operatorSharesAfter, "withdrawableShares not set correctly"); if (staker == delegationManager.delegationApprover(defaultOperator)) { // verify that the salt is still marked as unused (since it wasn't checked or used) @@ -1403,15 +2092,12 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Reverts if the ‘operator’ is not actually registered as an operator */ function testFuzz_OperatorWhoRequiresECDSASignature_BeaconChainStrategyShares( - address staker, - bytes32 salt, - uint256 expiry, - int256 beaconShares - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); + int256 beaconShares = int256(bound(r.Uint256(), 1 gwei, MAX_ETH_SUPPLY)); _registerOperatorWithDelegationApprover(defaultOperator); @@ -1434,18 +2120,23 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // Set staker shares in BeaconChainStrategy eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + (IStrategy[] memory strategiesToReturn, ) = delegationManager.getDepositedShares(staker); uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); - if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, beaconChainETHStrategy, uint256(beaconShares)); - } + _delegateTo_expectEmit_singleStrat( + DelegateToSingleStratEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: beaconChainETHStrategy, + depositShares: uint256(beaconShares), + depositScalingFactor: WAD + }) + ); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); if (beaconShares <= 0) { assertEq( beaconSharesBefore, @@ -1453,6 +2144,11 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { "operator beaconchain shares should not have increased with negative shares" ); } else { + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + beaconSharesAfter, + "withdrawableShares not set correctly" + ); assertEq( beaconSharesBefore + uint256(beaconShares), beaconSharesAfter, @@ -1462,7 +2158,6 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker delegated to the wrong address"); assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); - if (staker == delegationManager.delegationApprover(defaultOperator)) { // verify that the salt is still marked as unused (since it wasn't checked or used) assertFalse( @@ -1496,17 +2191,15 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Reverts if the ‘operator’ is not actually registered as an operator */ function testFuzz_OperatorWhoRequiresECDSASignature_BeaconChainAndStrategyManagerShares( - address staker, - bytes32 salt, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); + Randomness r + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); + int256 beaconShares = int256(bound(r.Uint256(), 1 gwei, MAX_ETH_SUPPLY)); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); _registerOperatorWithDelegationApprover(defaultOperator); // verify that the salt hasn't been used before @@ -1527,47 +2220,67 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { ); // Set staker shares in BeaconChainStrategy and StrategyMananger - { - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(staker, strategiesToReturn, sharesToReturn); - eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); - } + uint256[] memory depositScalingFactors = new uint256[](1); + depositScalingFactors[0] = uint256(WAD); + strategyManagerMock.addDeposit(staker, strategyMock, shares); + eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + ( + IStrategy[] memory strategiesToReturn, + uint256[] memory sharesToReturn + ) = delegationManager.getDepositedShares(staker); uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); uint256 beaconSharesBefore = delegationManager.operatorShares(staker, beaconChainETHStrategy); // delegate from the `staker` to the operator cheats.startPrank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(staker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, strategyMock, shares); if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, beaconChainETHStrategy, uint256(beaconShares)); + depositScalingFactors = new uint256[](2); + depositScalingFactors[0] = uint256(WAD); + depositScalingFactors[1] = uint256(WAD); } + _delegateTo_expectEmit( + DelegateToEmitStruct({ + staker: staker, + operator: defaultOperator, + strategies: strategiesToReturn, + depositShares: sharesToReturn, + depositScalingFactors: depositScalingFactors + }) + ); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + if (beaconShares <= 0) { assertEq( beaconSharesBefore, - beaconSharesAfter, + delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy), "operator beaconchain shares should not have increased with negative shares" ); } else { assertEq( beaconSharesBefore + uint256(beaconShares), - beaconSharesAfter, + delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy), "operator beaconchain shares not increased correctly" ); } - assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); + assertEq( + operatorSharesBefore + shares, + delegationManager.operatorShares(defaultOperator, strategyMock), + "operator shares not increased correctly" + ); assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker delegated to the wrong address"); assertFalse(delegationManager.isOperator(staker), "staker incorrectly registered as operator"); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + delegationManager.operatorShares(defaultOperator, strategyMock), + "withdrawableShares for strategy not set correctly" + ); + _assertWithdrawableAndOperatorShares( + withdrawableShares[1], + delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy), + "withdrawableShares for beacon strategy not set correctly" + ); if (staker == delegationManager.delegationApprover(defaultOperator)) { // verify that the salt is still marked as unused (since it wasn't checked or used) @@ -1595,15 +2308,14 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * and check that reversion occurs when the signature is expired */ function testFuzz_Revert_WhenOperatorWhoRequiresEIP1271Signature_ExpiredDelegationApproverSignature( - address staker, - uint256 expiry - ) public filterFuzzedAddressInputs(staker) { - // roll to a very late timestamp - skip(type(uint256).max / 2); - // filter to only *invalid* `expiry` values - expiry = bound(expiry, 0, block.timestamp - 1); - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r + ) public { + address staker = r.Address(); + uint256 expiry = r.Uint256(0, block.timestamp - 1); + uint256 currTimestamp = r.Uint256(block.timestamp, type(uint256).max); + + // roll to a late timestamp + skip(currTimestamp); _registerOperatorWithDelegationApprover(defaultOperator); @@ -1613,7 +2325,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); - cheats.expectRevert("DelegationManager._delegate: approver signature expired"); + cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -1624,17 +2336,15 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Performed by delegating to operator, undelegating, and trying to reuse the same signature */ function testFuzz_Revert_WhenOperatorWhoRequiresEIP1271Signature_PreviouslyUsedSalt( - address staker, - bytes32 salt, - uint256 expiry - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); + Randomness r + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); // register *this contract* as an operator // filter inputs, since this will fail when the staker is already registered as an operator - ERC1271WalletMock wallet = _registerOperatorWith1271DelegationApprover(defaultOperator); - cheats.assume(staker != address(wallet) && staker != defaultOperator); + _registerOperatorWith1271DelegationApprover(defaultOperator); // calculate the delegationSigner's signature ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( @@ -1652,7 +2362,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); delegationManager.undelegate(staker); // Reusing same signature should revert with salt already being used - cheats.expectRevert("DelegationManager._delegate: approverSalt already spent"); + cheats.expectRevert(SaltSpent.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, salt); cheats.stopPrank(); } @@ -1662,29 +2372,14 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * is non compliant with EIP1271 */ function testFuzz_Revert_WhenOperatorWhoRequiresEIP1271Signature_NonCompliantWallet( - address staker, - uint256 expiry - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r + ) public { + address staker = r.Address(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); // deploy a ERC1271MaliciousMock contract that will return an incorrect value when called ERC1271MaliciousMock wallet = new ERC1271MaliciousMock(); - - // filter fuzzed input, since otherwise we can get a flaky failure here. if the caller itself is the 'delegationApprover' - // then we don't even trigger the signature verification call, so we won't get a revert as expected - cheats.assume(staker != address(wallet)); - - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: defaultOperator, - delegationApprover: address(wallet), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(defaultOperator, operatorDetails, emptyStringForMetadataURI); + _registerOperator(defaultOperator, address(wallet), emptyStringForMetadataURI); // create the signature struct ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; @@ -1703,31 +2398,16 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * returns a value other than the EIP1271 "magic bytes" and checking that reversion occurs appropriately */ function testFuzz_Revert_WhenOperatorWhoRequiresEIP1271Signature_IsValidSignatureFails( - address staker, - bytes32 salt, - uint256 expiry - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + Randomness r + ) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); // deploy a ERC1271WalletMock contract that will return an incorrect value when called // owner is the 0 address ERC1271WalletMock wallet = new ERC1271WalletMock(address(1)); - - // filter fuzzed input, since otherwise we can get a flaky failure here. if the caller itself is the 'delegationApprover' - // then we don't even trigger the signature verification call, so we won't get a revert as expected - cheats.assume(staker != address(wallet)); - - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: defaultOperator, - delegationApprover: address(wallet), - stakerOptOutWindowBlocks: 0 - }); - _registerOperator(defaultOperator, operatorDetails, emptyStringForMetadataURI); + _registerOperator(defaultOperator, address(wallet), emptyStringForMetadataURI); // calculate the delegationSigner's but this is not the correct signature from the wallet contract // since the wallet owner is address(1) @@ -1742,7 +2422,7 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { // try to delegate from the `staker` to the operator, and check reversion cheats.startPrank(staker); // Signature should fail as the wallet will not return EIP1271_MAGICVALUE - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: ERC1271 signature verification failed"); + cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); delegationManager.delegateTo(defaultOperator, approverSignatureAndExpiry, emptySalt); cheats.stopPrank(); } @@ -1757,17 +2437,10 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { * Reverts if the staker is already delegated (to the operator or to anyone else) * Reverts if the ‘operator’ is not actually registered as an operator */ - function testFuzz_OperatorWhoRequiresEIP1271Signature( - address staker, - bytes32 salt, - uint256 expiry - ) public filterFuzzedAddressInputs(staker) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - - // register *this contract* as an operator - // filter inputs, since this will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + function testFuzz_OperatorWhoRequiresEIP1271Signature(Randomness r) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + uint256 expiry = r.Uint256(block.timestamp, type(uint256).max); _registerOperatorWith1271DelegationApprover(defaultOperator); @@ -1822,863 +2495,593 @@ contract DelegationManagerUnitTests_delegateTo is DelegationManagerUnitTests { } } -contract DelegationManagerUnitTests_delegateToBySignature is DelegationManagerUnitTests { - function test_revert_paused() public { - cheats.prank(defaultOperator); - delegationManager.registerAsOperator( - IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: defaultOperator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }), - emptyStringForMetadataURI - ); - - // set the pausing flag - cheats.prank(pauser); - delegationManager.pause(2 ** PAUSED_NEW_DELEGATION); - - uint256 expiry = type(uint256).max; - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry - ); - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - cheats.expectRevert("Pausable: index is paused"); - delegationManager.delegateToBySignature( - defaultStaker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt - ); - } - - /// @notice Checks that `DelegationManager.delegateToBySignature` reverts if the staker's signature has expired - function testFuzz_Revert_WhenStakerSignatureExpired( - address staker, - address operator, - uint256 expiry, - bytes memory signature - ) public filterFuzzedAddressInputs(staker) filterFuzzedAddressInputs(operator) { - expiry = bound(expiry, 0, block.timestamp - 1); - cheats.expectRevert("DelegationManager.delegateToBySignature: staker signature expired"); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry = ISignatureUtils.SignatureWithExpiry({ - signature: signature, - expiry: expiry - }); - delegationManager.delegateToBySignature(staker, operator, signatureWithExpiry, signatureWithExpiry, emptySalt); +contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + using SlashingLib for *; + + /// @notice Verifies that `DelegationManager.increaseDelegatedShares` reverts if not called by the StrategyManager nor EigenPodManager + function testFuzz_Revert_increaseDelegatedShares_invalidCaller(Randomness r) public { + address invalidCaller = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + cheats.expectRevert(IDelegationManagerErrors.OnlyStrategyManagerOrEigenPodManager.selector); + delegationManager.increaseDelegatedShares(invalidCaller, strategyMock, 0, shares); } - /// @notice Checks that `DelegationManager.delegateToBySignature` reverts if the staker's ECDSA signature verification fails - function test_Revert_EOAStaker_WhenStakerSignatureVerificationFails() public { - address invalidStaker = address(1000); - address caller = address(2000); - uint256 expiry = type(uint256).max; + /** + * @notice Verifies that `DelegationManager.increaseDelegatedShares` reverts when operator slashed 100% for a strategy + * and the staker has deposits in that strategy + */ + function testFuzz_Revert_increaseDelegatedShares_slashedOperator100Percent( + Randomness r + ) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + address staker = r.Address(); + // Register operator _registerOperatorWithBaseDetails(defaultOperator); + // Set operator magnitude + _setOperatorMagnitude({ + operator: defaultOperator, + strategy: strategyMock, + magnitude: 0 + }); + // delegate from the `staker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry + uint256 _delegatedSharesBefore = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock ); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - // Should revert from invalid signature as staker is not set as the address of signer - cheats.startPrank(caller); - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer"); - // use an empty approver signature input since none is needed / the input is unchecked - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - delegationManager.delegateToBySignature( - invalidStaker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt + cheats.prank(address(strategyManagerMock)); + cheats.expectRevert(FullySlashed.selector); + delegationManager.increaseDelegatedShares(staker, strategyMock, 0, shares); + + uint256 delegatedSharesAfter = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock ); - cheats.stopPrank(); + + assertEq(delegatedSharesAfter, _delegatedSharesBefore, "delegated shares incremented incorrectly"); + assertEq(_delegatedSharesBefore, 0, "nonzero shares delegated to zero address!"); } - /// @notice Checks that `DelegationManager.delegateToBySignature` reverts if the staker's contract signature verification fails - function test_Revert_ERC1271Staker_WhenStakerSignatureVerficationFails() public { - address staker = address(new ERC1271WalletMock(address(1))); - address caller = address(2000); - uint256 expiry = type(uint256).max; + /** + * @notice Verifies that `DelegationManager.increaseDelegatedShares` reverts when operator slashed 100% for a strategy + * and the staker has deposits in that strategy. In this test case, the staker was initially deposited and delegated + * to the operator before the operator was slashed 100%. + * @dev Checks that withdrawable shares after 100% slashed is 0 + * @dev Checks that as a staker, redepositing after 100% slashed reverts + */ + function testFuzz_Revert_increaseDelegatedShares_slashedOperator100PercentWithExistingStaker( + Randomness r + ) public { + address staker = r.Address(); + uint64 initialMagnitude = r.Uint64(1, WAD); + uint256 existingShares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 shares = r.Uint256(existingShares, MAX_STRATEGY_SHARES); + // 1. Register operator with initial operator magnitude and delegate staker to operator _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude({ + operator: defaultOperator, + strategy: strategyMock, + magnitude: initialMagnitude + }); + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + // 2. set staker initial shares and increase delegated shares + IStrategy[] memory strategiesDeposited = strategyMock.toArray(); + uint256[] memory sharesToReturn = existingShares.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategiesDeposited, sharesToReturn); - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(staker, strategyMock, 0, existingShares); + + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesDeposited); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + delegationManager.operatorShares(defaultOperator, strategyMock), + "Shares not increased correctly" ); + // 3. Now set operator magnitude to 0 (100% slashed) + _setOperatorMagnitude({ + operator: defaultOperator, + strategy: strategyMock, + magnitude: 0 + }); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - // Should revert from invalid signature as staker is not set as the address of signer - cheats.startPrank(caller); - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: ERC1271 signature verification failed"); - // use an empty approver signature input since none is needed / the input is unchecked - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - delegationManager.delegateToBySignature( - staker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt + // 4. Try to "redeposit" and expect a revert since strategy is 100% slashed + // staker's withdrawable shares should also be 0 now + cheats.prank(address(strategyManagerMock)); + cheats.expectRevert(FullySlashed.selector); + delegationManager.increaseDelegatedShares(staker, strategyMock, existingShares, shares); + + (withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategiesDeposited); + assertEq( + withdrawableShares[0], + 0, + "All existing shares should be slashed" ); - cheats.stopPrank(); } - /// @notice Checks that `DelegationManager.delegateToBySignature` reverts when the staker is already delegated - function test_Revert_Staker_WhenAlreadyDelegated() public { - address staker = cheats.addr(stakerPrivateKey); - address caller = address(2000); - uint256 expiry = type(uint256).max; - + // @notice Verifies that there is no change in shares if the staker is not delegated + function testFuzz_increaseDelegatedShares_noop(Randomness r) public { + address staker = r.Address(); _registerOperatorWithBaseDetails(defaultOperator); + assertFalse(delegationManager.isDelegated(staker), "bad test setup"); - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry - ); - - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - // Should revert as `staker` has already delegated to `operator` - cheats.startPrank(caller); - cheats.expectRevert("DelegationManager.delegateToBySignature: staker is already actively delegated"); - // use an empty approver signature input since none is needed / the input is unchecked - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - delegationManager.delegateToBySignature( - staker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt - ); - cheats.stopPrank(); + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(staker, strategyMock, 0, 0); + assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "shares should not have changed"); } - /// @notice Checks that `delegateToBySignature` reverts when operator is not registered after successful staker signature verification - function test_Revert_EOAStaker_OperatorNotRegistered() public { - address staker = cheats.addr(stakerPrivateKey); - address caller = address(2000); - uint256 expiry = type(uint256).max; + /** + * @notice Verifies that `DelegationManager.increaseDelegatedShares` properly increases the delegated `shares` that the operator + * who the `staker` is delegated to has in the strategy + * @dev Checks that there is no change if the staker is not delegated + */ + function testFuzz_increaseDelegatedShares(Randomness r) public { + address staker = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + bool delegateFromStakerToOperator = r.Boolean(); - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry + // Register operator + _registerOperatorWithBaseDetails(defaultOperator); + // delegate from the `staker` to the operator *if `delegateFromStakerToOperator` is 'true'* + if (delegateFromStakerToOperator) { + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + } + uint256 _delegatedSharesBefore = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock ); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - // Should revert as `operator` is not registered - cheats.startPrank(caller); - cheats.expectRevert("DelegationManager.delegateToBySignature: operator is not registered in EigenLayer"); - // use an empty approver signature input since none is needed / the input is unchecked - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry; - delegationManager.delegateToBySignature( - staker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt + // deposit and increase delegated shares + strategyManagerMock.addDeposit(staker, strategyMock, shares); + if (delegationManager.isDelegated(staker)) { + _increaseDelegatedShares_expectEmit( + IncreaseDelegatedSharesEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategyMock, + sharesToIncrease: shares, + depositScalingFactor: WAD + }) + ); + } + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(staker, strategyMock, 0, shares); + + // Assert correct end state values + uint256 delegatedSharesAfter = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock ); - cheats.stopPrank(); + IStrategy[] memory strategy = new IStrategy[](1); + strategy[0] = strategyMock; + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategy); + if (delegationManager.isDelegated(staker)) { + assertEq( + delegatedSharesAfter, + _delegatedSharesBefore + shares, + "delegated shares did not increment correctly" + ); + assertEq( + withdrawableShares[0], + delegatedSharesAfter, + "Invalid withdrawable shares" + ); + } else { + assertEq(delegatedSharesAfter, _delegatedSharesBefore, "delegated shares incremented incorrectly"); + assertEq(_delegatedSharesBefore, 0, "nonzero shares delegated to zero address!"); + } } /** - * @notice Checks that `DelegationManager.delegateToBySignature` reverts if the delegationApprover's signature has expired - * after successful staker signature verification + * @notice Verifies that `DelegationManager.increaseDelegatedShares` properly increases the delegated `shares` that the operator + * who the `staker` is delegated to has in the strategy + * @dev Checks that there is no change if the staker is not delegated */ - function testFuzz_Revert_WhenDelegationApproverSignatureExpired( - address caller, - uint256 stakerExpiry, - uint256 delegationApproverExpiry - ) public filterFuzzedAddressInputs(caller) { - cheats.assume(caller != defaultOperator); - - // roll to a very late timestamp - skip(type(uint256).max / 2); + function testFuzz_increaseDelegatedShares_slashedOperator(Randomness r) public { + address staker = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 magnitude = r.Uint64(1, WAD); + bool delegateFromStakerToOperator = r.Boolean(); - // filter to only valid `stakerExpiry` values - stakerExpiry = bound(stakerExpiry, block.timestamp + 1, type(uint256).max); - // filter to only *invalid* `delegationApproverExpiry` values - delegationApproverExpiry = bound(delegationApproverExpiry, 0, block.timestamp - 1); + // Register operator + _registerOperatorWithBaseDetails(defaultOperator); + + // Set operator magnitude + _setOperatorMagnitude(defaultOperator, strategyMock, magnitude); - console.log("timestamp: %s", block.timestamp); - console.log(stakerExpiry); - console.log(delegationApproverExpiry); + // delegate from the `staker` to the operator *if `delegateFromStakerToOperator` is 'true'* + if (delegateFromStakerToOperator) { + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + } + uint256 _delegatedSharesBefore = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock + ); - _registerOperatorWithDelegationApprover(defaultOperator); + if (delegationManager.isDelegated(staker)) { + uint256 slashingFactor = _getSlashingFactor(staker, strategyMock, magnitude); + dsf.update(0, shares, slashingFactor); + _increaseDelegatedShares_expectEmit( + IncreaseDelegatedSharesEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategyMock, + sharesToIncrease: shares, + depositScalingFactor: dsf.scalingFactor() + }) + ); + } - // calculate the delegationSigner's signature - ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry = _getApproverSignature( - delegationSignerPrivateKey, - defaultStaker, - defaultOperator, - emptySalt, - delegationApproverExpiry - ); + strategyManagerMock.addDeposit(staker, strategyMock, shares); + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(staker, strategyMock, 0, shares); - // calculate the staker signature - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - stakerExpiry + // Assert correct values + uint256 delegatedSharesAfter = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategyMock ); + IStrategy[] memory strategy = new IStrategy[](1); + strategy[0] = strategyMock; + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategy); - // try delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature`, and check for reversion - cheats.startPrank(caller); - cheats.expectRevert("DelegationManager._delegate: approver signature expired"); - delegationManager.delegateToBySignature( - defaultStaker, - defaultOperator, - stakerSignatureAndExpiry, - approverSignatureAndExpiry, - emptySalt - ); - cheats.stopPrank(); + if (delegationManager.isDelegated(staker)) { + assertEq( + delegatedSharesAfter, + _delegatedSharesBefore + shares, + "delegated shares did not increment correctly" + ); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + delegatedSharesAfter, + "Invalid withdrawable shares" + ); + } else { + assertEq(delegatedSharesAfter, _delegatedSharesBefore, "delegated shares incremented incorrectly"); + assertEq(_delegatedSharesBefore, 0, "nonzero shares delegated to zero address!"); + } } /** - * @notice `staker` becomes delegated to an operator who does not require any signature verification (i.e. the operator’s `delegationApprover` address is set to the zero address) - * via the `caller` calling `DelegationManager.delegateToBySignature` - * The function should pass with any `operatorSignature` input (since it should be unused) - * The function should pass only with a valid `stakerSignatureAndExpiry` input - * Properly emits a `StakerDelegated` event - * Staker is correctly delegated after the call (i.e. correct storage update) - * BeaconChainStrategy and StrategyManager operator shares should increase for operator - * Reverts if the staker is already delegated (to the operator or to anyone else) - * Reverts if the ‘operator’ is not actually registered as an operator + * @notice Verifies that `DelegationManager.increaseDelegatedShares` doesn't revert when operator slashed 100% for a strategy + * and the staker has deposits in a separate strategy */ - function testFuzz_EOAStaker_OperatorWhoAcceptsAllStakers( - address caller, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - cheats.assume(expiry >= block.timestamp); - cheats.assume(shares > 0); + function testFuzz_increaseDelegatedShares_slashedOperator100Percent(Randomness r) public { + address staker = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 magnitude = r.Uint64(1, WAD); + IStrategy[] memory strategyArray = r.StrategyArray(1); + IStrategy strategy = strategyArray[0]; + // Register operator _registerOperatorWithBaseDetails(defaultOperator); + // Set operator magnitude for 100% slashed strategy + _setOperatorMagnitude({ + operator: defaultOperator, + strategy: strategyMock, + magnitude: 0 + }); + // Set operator magnitude for non-100% slashed strategy + _setOperatorMagnitude({ + operator: defaultOperator, + strategy: strategy, + magnitude: magnitude + }); + // delegate from the `staker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - // verify that the salt hasn't been used before - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - emptySalt - ), - "salt somehow spent too early?" + uint256 _delegatedSharesBefore = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategy ); - { - // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(defaultStaker, strategiesToReturn, sharesToReturn); - eigenPodManagerMock.setPodOwnerShares(defaultStaker, beaconShares); - } - uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesBefore = delegationManager.operatorShares(defaultStaker, beaconChainETHStrategy); - // fetch the staker's current nonce - uint256 currentStakerNonce = delegationManager.stakerNonce(defaultStaker); - // calculate the staker signature - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry + // deposit and increaseDelegatedShares + strategyManagerMock.addDeposit(staker, strategy, shares); + uint256 slashingFactor = _getSlashingFactor(staker, strategy, magnitude); + dsf.update(0, shares, slashingFactor); + _increaseDelegatedShares_expectEmit( + IncreaseDelegatedSharesEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: strategy, + sharesToIncrease: shares, + depositScalingFactor: dsf.scalingFactor() + }) ); + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(staker, strategy, 0, shares); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(defaultStaker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, strategyMock, shares); - if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, beaconChainETHStrategy, uint256(beaconShares)); - } - _delegateToBySignatureOperatorWhoAcceptsAllStakers( - defaultStaker, - caller, - defaultOperator, - stakerSignatureAndExpiry, - emptySalt + // Assert correct end state values + uint256 delegatedSharesAfter = delegationManager.operatorShares( + delegationManager.delegatedTo(staker), + strategy ); - - // Check operator shares increases - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - if (beaconShares <= 0) { - assertEq( - beaconSharesBefore, - beaconSharesAfter, - "operator beaconchain shares should not have increased with negative shares" - ); - } else { - assertEq( - beaconSharesBefore + uint256(beaconShares), - beaconSharesAfter, - "operator beaconchain shares not increased correctly" - ); - } - assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); - // check all the delegation status changes - assertTrue(delegationManager.isDelegated(defaultStaker), "staker not delegated correctly"); - assertEq( - delegationManager.delegatedTo(defaultStaker), - defaultOperator, - "staker delegated to the wrong address" + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(staker, strategyArray); + _assertWithdrawableAndOperatorShares( + withdrawableShares[0], + delegatedSharesAfter, + "Invalid withdrawable shares" ); - assertFalse(delegationManager.isOperator(defaultStaker), "staker incorrectly registered as operator"); - // check that the staker nonce incremented appropriately assertEq( - delegationManager.stakerNonce(defaultStaker), - currentStakerNonce + 1, - "staker nonce did not increment" - ); - // verify that the salt is still marked as unused (since it wasn't checked or used) - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - emptySalt - ), - "salt somehow spent too incorrectly?" + delegatedSharesAfter, + _delegatedSharesBefore + shares, + "delegated shares did not increment correctly" ); } /** - * @notice `staker` becomes delegated to an operator who requires signature verification through an EOA (i.e. the operator’s `delegationApprover` address is set to a nonzero EOA) - * via the `caller` calling `DelegationManager.delegateToBySignature` - * The function should pass *only with a valid ECDSA signature from the `delegationApprover`, OR if called by the operator or their delegationApprover themselves - * AND with a valid `stakerSignatureAndExpiry` input - * Properly emits a `StakerDelegated` event - * Staker is correctly delegated after the call (i.e. correct storage update) - * BeaconChainStrategy and StrategyManager operator shares should increase for operator - * Reverts if the staker is already delegated (to the operator or to anyone else) - * Reverts if the ‘operator’ is not actually registered as an operator + * @notice A unique test setup where impact of rounding can clearly be observed here. + * After making the initial deposit of 44182209037560531097078597505 shares, and the operator's magnitude is set to 999999999999990009, + * Each subsequent deposit amount of 1000 actually results in LESS withdrawable shares for the staker. There in an increasing drift + * between the operator's shares and the staker's withdrawable shares. + * The test below results in a drift difference of 4.418e13 */ - function testFuzz_EOAStaker_OperatorWhoRequiresECDSASignature( - address caller, - bytes32 salt, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - // filter to only valid `expiry` values - cheats.assume(expiry >= block.timestamp); - cheats.assume(shares > 0); - - _registerOperatorWithDelegationApprover(defaultOperator); + function test_increaseDelegatedShares_depositRepeatedly() public { + uint64 initialMagnitude = 999999999999990009; + uint256 shares = 44182209037560531097078597505; - // verify that the salt hasn't been used before - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent too early?" - ); - { - // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(defaultStaker, strategiesToReturn, sharesToReturn); - eigenPodManagerMock.setPodOwnerShares(defaultStaker, beaconShares); - } + // register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, initialMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + strategyManagerMock.addDeposit(defaultStaker, strategyMock, shares); - uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesBefore = delegationManager.operatorShares(defaultStaker, beaconChainETHStrategy); - // fetch the staker's current nonce - uint256 currentStakerNonce = delegationManager.stakerNonce(defaultStaker); - // calculate the staker signature - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry - ); + // delegate from the `defaultStaker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(defaultStaker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, strategyMock, shares); - if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, beaconChainETHStrategy, uint256(beaconShares)); - } - _delegateToBySignatureOperatorWhoRequiresSig( - defaultStaker, - caller, - defaultOperator, - stakerSignatureAndExpiry, - salt - ); { - // Check operator shares increases - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - if (beaconShares <= 0) { - assertEq( - beaconSharesBefore, - beaconSharesAfter, - "operator beaconchain shares should not have increased with negative shares" - ); - } else { - assertEq( - beaconSharesBefore + uint256(beaconShares), - beaconSharesAfter, - "operator beaconchain shares not increased correctly" - ); + for (uint256 i = 0; i < 1000; ++i) { + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(defaultStaker, strategyMock, shares, 1000); + shares += 1000; + uint256[] memory newDepositSharesArray = new uint256[](1); + newDepositSharesArray[0] = shares; + + strategyManagerMock.setDeposits(defaultStaker, strategies, newDepositSharesArray); } - assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); } - assertTrue(delegationManager.isDelegated(defaultStaker), "staker not delegated correctly"); + + ( + uint256[] memory withdrawableShares, + uint256[] memory depositShares + ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertEq(depositShares[0], shares, "staker deposit shares not reset correctly"); assertEq( - delegationManager.delegatedTo(defaultStaker), - defaultOperator, - "staker delegated to the wrong address" + delegationManager.operatorShares(defaultOperator, strategyMock) - withdrawableShares[0], + 44182209037566, + "drift should be 4.418e13 from previous tests" ); - assertFalse(delegationManager.isOperator(defaultStaker), "staker incorrectly registered as operator"); + } - // check that the delegationApprover nonce incremented appropriately - if (caller == defaultOperator || caller == delegationManager.delegationApprover(defaultOperator)) { - // verify that the salt is still marked as unused (since it wasn't checked or used) - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent too incorrectly?" - ); - } else { - // verify that the salt is marked as used - assertTrue( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent not spent?" - ); - } + /// @notice Verifies that `DelegationManager.burnOperatorShares` reverts if not called by the AllocationManager + function testFuzz_Revert_burnOperatorShares_invalidCaller(Randomness r) public { + address invalidCaller = r.Address(); - // check that the staker nonce incremented appropriately - assertEq( - delegationManager.stakerNonce(defaultStaker), - currentStakerNonce + 1, - "staker nonce did not increment" - ); + cheats.startPrank(invalidCaller); + cheats.expectRevert(IDelegationManagerErrors.OnlyAllocationManager.selector); + delegationManager.burnOperatorShares(defaultOperator, strategyMock, 0, 0); + } + + /// @notice Verifies that there is no change in shares if the staker is not delegatedd + function testFuzz_Revert_burnOperatorShares_noop() public { + _registerOperatorWithBaseDetails(defaultOperator); + + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, WAD/2); + assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "shares should not have changed"); } /** - * @notice `staker` becomes delegated to an operatorwho requires signature verification through an EIP1271-compliant contract (i.e. the operator’s `delegationApprover` address is - * set to a nonzero and code-containing address) via the `caller` calling `DelegationManager.delegateToBySignature` - * The function uses OZ's ERC1271WalletMock contract, and thus should pass *only when a valid ECDSA signature from the `owner` of the ERC1271WalletMock contract, - * OR if called by the operator or their delegationApprover themselves - * AND with a valid `stakerSignatureAndExpiry` input - * Properly emits a `StakerDelegated` event - * Staker is correctly delegated after the call (i.e. correct storage update) - * Reverts if the staker is already delegated (to the operator or to anyone else) - * Reverts if the ‘operator’ is not actually registered as an operator + * @notice Verifies that `DelegationManager.burnOperatorShares` properly decreases the delegated `shares` that the operator + * who the `defaultStaker` is delegated to has in the strategies */ - function testFuzz_EOAStaker_OperatorWhoRequiresEIP1271Signature( - address caller, - bytes32 salt, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - cheats.assume(expiry >= block.timestamp); - cheats.assume(shares > 0); + function testFuzz_burnOperatorShares_slashedOperator(Randomness r) public { + // sanity-filtering on fuzzed input length & staker + IStrategy[] memory strategies = r.StrategyArray(16); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 prevMaxMagnitude = r.Uint64(2, WAD); + uint64 newMaxMagnitude = r.Uint64(1, prevMaxMagnitude); + bool hasBeaconChainStrategy = r.Boolean(); + if (hasBeaconChainStrategy) { + // Set last strategy in array as beacon chain strategy + strategies[strategies.length - 1] = beaconChainETHStrategy; + } - _registerOperatorWith1271DelegationApprover(defaultOperator); + // Register operator + _registerOperatorWithBaseDetails(defaultOperator); - // verify that the salt hasn't been used before - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent too early?" - ); - { - // Set staker shares in BeaconChainStrategy and StrategyMananger - IStrategy[] memory strategiesToReturn = new IStrategy[](1); - strategiesToReturn[0] = strategyMock; - uint256[] memory sharesToReturn = new uint256[](1); - sharesToReturn[0] = shares; - strategyManagerMock.setDeposits(defaultStaker, strategiesToReturn, sharesToReturn); - eigenPodManagerMock.setPodOwnerShares(defaultStaker, beaconShares); + // Set the staker deposits in the strategies + uint256[] memory sharesToSet = new uint256[](strategies.length); + uint256[] memory depositScalingFactors = new uint256[](strategies.length); + for(uint256 i = 0; i < strategies.length; i++) { + strategies[i] = IStrategy(random().Address()); + sharesToSet[i] = shares; + depositScalingFactors[i] = uint256(WAD).divWad(uint256(prevMaxMagnitude)); + _setOperatorMagnitude(defaultOperator, strategies[i], prevMaxMagnitude); } - uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesBefore = delegationManager.operatorShares(defaultStaker, beaconChainETHStrategy); - // fetch the staker's current nonce - uint256 currentStakerNonce = delegationManager.stakerNonce(defaultStaker); - // calculate the staker signature - ISignatureUtils.SignatureWithExpiry memory stakerSignatureAndExpiry = _getStakerSignature( - stakerPrivateKey, - defaultOperator, - expiry + // Okay to set beacon chain shares in SM mock, wont' be called by DM + strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); + if (hasBeaconChainStrategy) { + eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(shares))); + } + + // events expected emitted for each strategy + _delegateTo_expectEmit( + DelegateToEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategies: strategies, + depositShares: sharesToSet, + depositScalingFactors: depositScalingFactors + }) ); + // delegate from the `staker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + address delegatedTo = delegationManager.delegatedTo(defaultStaker); - // delegate from the `staker` to the operator, via having the `caller` call `DelegationManager.delegateToBySignature` - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerDelegated(defaultStaker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, strategyMock, shares); - if (beaconShares > 0) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, defaultStaker, beaconChainETHStrategy, uint256(beaconShares)); + // check shares before call to `burnOperatorShares` + for (uint256 i = 0; i < strategies.length; ++i) { + // store delegated shares in a mapping + delegatedSharesBefore[strategies[i]] = delegationManager.operatorShares(delegatedTo, strategies[i]); + // also construct an array which we'll use in another loop + totalSharesForStrategyInArray[address(strategies[i])] += shares; } - _delegateToBySignatureOperatorWhoRequiresSig( - defaultStaker, - caller, - defaultOperator, - stakerSignatureAndExpiry, - salt - ); + // for each strategy in `strategies`, decrease delegated shares by `shares` { - // Check operator shares increases - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); - uint256 beaconSharesAfter = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); - if (beaconShares <= 0) { - assertEq( - beaconSharesBefore, - beaconSharesAfter, - "operator beaconchain shares should not have increased with negative shares" - ); - } else { - assertEq( - beaconSharesBefore + uint256(beaconShares), - beaconSharesAfter, - "operator beaconchain shares not increased correctly" + cheats.startPrank(address(allocationManagerMock)); + for (uint256 i = 0; i < strategies.length; ++i) { + uint256 currentShares = delegationManager.operatorShares(defaultOperator, strategies[i]); + uint256 sharesToDecrease = SlashingLib.calcSlashedAmount({ + operatorShares: currentShares, + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased( + defaultOperator, + address(0), + strategies[i], + sharesToDecrease ); + delegationManager.burnOperatorShares(defaultOperator, strategies[i], prevMaxMagnitude, newMaxMagnitude); + + // Also update maxMagnitude in ALM mock + allocationManagerMock.setMaxMagnitude(defaultOperator, strategies[i], newMaxMagnitude); + + totalSharesDecreasedForStrategy[strategies[i]] += sharesToDecrease; } - assertEq(operatorSharesBefore + shares, operatorSharesAfter, "operator shares not increased correctly"); + cheats.stopPrank(); } - assertTrue(delegationManager.isDelegated(defaultStaker), "staker not delegated correctly"); - assertEq( - delegationManager.delegatedTo(defaultStaker), - defaultOperator, - "staker delegated to the wrong address" - ); - assertFalse(delegationManager.isOperator(defaultStaker), "staker incorrectly registered as operator"); - // check that the delegationApprover nonce incremented appropriately - if (caller == defaultOperator || caller == delegationManager.delegationApprover(defaultOperator)) { - // verify that the salt is still marked as unused (since it wasn't checked or used) - assertFalse( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent too incorrectly?" + // check shares after call to `burnOperatorShares` + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + for (uint256 i = 0; i < strategies.length; ++i) { + uint256 delegatedSharesAfter = delegationManager.operatorShares(delegatedTo, strategies[i]); + assertEq( + delegatedSharesAfter, + delegatedSharesBefore[strategies[i]] - totalSharesDecreasedForStrategy[strategies[i]], + "delegated shares did not decrement correctly" ); - } else { - // verify that the salt is marked as used - assertTrue( - delegationManager.delegationApproverSaltIsSpent( - delegationManager.delegationApprover(defaultOperator), - salt - ), - "salt somehow spent not spent?" + + _assertWithdrawableAndOperatorShares( + withdrawableShares[i], + delegatedSharesAfter, + "withdrawable and operator shares not decremented correctly" ); } - - // check that the staker nonce incremented appropriately - assertEq( - delegationManager.stakerNonce(defaultStaker), - currentStakerNonce + 1, - "staker nonce did not increment" - ); } - /** - * @notice Calls same delegateToBySignature test but with the staker address being a ERC1271WalletMock - * Generates valid signatures from the staker to delegate to operator `defaultOperator` - */ - function testFuzz_ERC1271Staker_OperatorWhoAcceptsAllStakers( - address caller, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - defaultStaker = address(ERC1271WalletMock(cheats.addr(stakerPrivateKey))); - testFuzz_EOAStaker_OperatorWhoAcceptsAllStakers(caller, expiry, beaconShares, shares); - } /** - * @notice Calls same delegateToBySignature test but with the staker address being a ERC1271WalletMock - * Generates valid signatures from the staker to delegate to operator `defaultOperator` who has - * a delegationApprover address set to a nonzero EOA + * @notice This test demonstrates that the rate that withdrawable shares decrease from slashing is at LEAST + * greater than or equal to the rate that the operator shares decrease from slashing. + * We want this property otherwise undelegating/queue withdrawing all shares as a staker could lead to a underflow revert. + * Note: If the SlashingLib.calcSlashedAmount function were to round down (overslash) then this test would fail. */ - function testFuzz_ERC1271Staker_OperatorWhoRequiresECDSASignature( - address caller, - bytes32 salt, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - // Call same test but with the staker address being a ERC1271WalletMock - defaultStaker = address(ERC1271WalletMock(cheats.addr(stakerPrivateKey))); - testFuzz_EOAStaker_OperatorWhoRequiresECDSASignature(caller, salt, expiry, beaconShares, shares); - } + function test_burnOperatorShares_slashedRepeatedly() public { + uint64 initialMagnitude = 90009; + uint256 shares = 40000000004182209037560531097078597505; - /** - * @notice Calls same delegateToBySignature test but with the staker address being a ERC1271WalletMock - * Generates valid signatures from the staker to delegate to operator `defaultOperator` who has - * a delegationApprover address set to a nonzero ERC1271 compliant contract - */ - function testFuzz_ERC1271Staker_OperatorWhoRequiresEIP1271Signature( - address caller, - bytes32 salt, - uint256 expiry, - int256 beaconShares, - uint256 shares - ) public filterFuzzedAddressInputs(caller) { - // Call same test but with the staker address being a ERC1271WalletMock - defaultStaker = address(ERC1271WalletMock(cheats.addr(stakerPrivateKey))); - testFuzz_EOAStaker_OperatorWhoRequiresEIP1271Signature(caller, salt, expiry, beaconShares, shares); + // register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, initialMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + strategyManagerMock.addDeposit(defaultStaker, strategyMock, shares); + + // delegate from the `defaultStaker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Set operator magnitude + uint64 newOperatorMagnitude = initialMagnitude; + + for (uint256 i = 0; i < 100; ++i) { + uint64 slashMagnitude = 100; + newOperatorMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, newOperatorMagnitude); + + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares( + defaultOperator, + strategyMock, + newOperatorMagnitude + slashMagnitude, + newOperatorMagnitude + ); + + uint256 operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategyMock); + ( + uint256[] memory withdrawableShares, + uint256[] memory depositShares + ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertEq(depositShares[0], shares, "staker deposit shares not reset correctly"); + assertLe( + withdrawableShares[0], + operatorSharesAfterSlash, + "withdrawable should always be <= operatorShares even after rounding" + ); + } } } -contract DelegationManagerUnitTests_ShareAdjustment is DelegationManagerUnitTests { - // @notice Verifies that `DelegationManager.increaseDelegatedShares` reverts if not called by the StrategyManager nor EigenPodManager - function testFuzz_increaseDelegatedShares_revert_invalidCaller( - address invalidCaller, - uint256 shares - ) public filterFuzzedAddressInputs(invalidCaller) { - cheats.assume(invalidCaller != address(strategyManagerMock)); - cheats.assume(invalidCaller != address(eigenPodManagerMock)); - cheats.assume(invalidCaller != address(eigenLayerProxyAdmin)); +contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { + using SlashingLib for uint256; + using SingleItemArrayLib for *; + using Math for uint256; + + // @notice Verifies that undelegating is not possible when the "undelegation paused" switch is flipped + function testFuzz_Revert_undelegate_paused(Randomness r) public { + address staker = r.Address(); + // set the pausing flag + cheats.prank(pauser); + delegationManager.pause(2 ** PAUSED_ENTER_WITHDRAWAL_QUEUE); - cheats.expectRevert("DelegationManager: onlyStrategyManagerOrEigenPodManager"); - delegationManager.increaseDelegatedShares(invalidCaller, strategyMock, shares); + cheats.prank(staker); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + delegationManager.undelegate(staker); } - // @notice Verifies that there is no change in shares if the staker is not delegated - function testFuzz_increaseDelegatedShares_noop(address staker) public { - cheats.assume(staker != defaultOperator); - _registerOperatorWithBaseDetails(defaultOperator); - assertFalse(delegationManager.isDelegated(staker), "bad test setup"); + function testFuzz_Revert_undelegate_notDelegated(Randomness r) public { + address undelegatedStaker = r.Address(); + assertFalse(delegationManager.isDelegated(undelegatedStaker), "bad test setup"); - cheats.prank(address(strategyManagerMock)); - delegationManager.increaseDelegatedShares(staker, strategyMock, 1); - assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "shares should not have changed"); + cheats.prank(undelegatedStaker); + cheats.expectRevert(NotActivelyDelegated.selector); + delegationManager.undelegate(undelegatedStaker); + } + + // @notice Verifies that an operator cannot undelegate from themself (this should always be forbidden) + function testFuzz_Revert_undelegate_stakerIsOperator(Randomness r) public { + address operator = r.Address(); + _registerOperatorWithBaseDetails(operator); + + cheats.prank(operator); + cheats.expectRevert(OperatorsCannotUndelegate.selector); + delegationManager.undelegate(operator); } /** - * @notice Verifies that `DelegationManager.increaseDelegatedShares` properly increases the delegated `shares` that the operator - * who the `staker` is delegated to has in the strategy - * @dev Checks that there is no change if the staker is not delegated + * @notice verifies that `DelegationManager.undelegate` reverts if trying to undelegate an operator from themselves */ - function testFuzz_increaseDelegatedShares( - address staker, - uint256 shares, - bool delegateFromStakerToOperator - ) public filterFuzzedAddressInputs(staker) { - // filter inputs, since delegating to the operator will fail when the staker is already registered as an operator - cheats.assume(staker != defaultOperator); + function testFuzz_Revert_undelegate_operatorCannotForceUndelegateThemself(Randomness r) public { + address delegationApprover = r.Address(); + bool callFromOperatorOrApprover = r.Boolean(); - // Register operator - _registerOperatorWithBaseDetails(defaultOperator); - - // delegate from the `staker` to the operator *if `delegateFromStakerToOperator` is 'true'* - if (delegateFromStakerToOperator) { - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - } - - uint256 _delegatedSharesBefore = delegationManager.operatorShares( - delegationManager.delegatedTo(staker), - strategyMock - ); - - if (delegationManager.isDelegated(staker)) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesIncreased(defaultOperator, staker, strategyMock, shares); - } - - cheats.prank(address(strategyManagerMock)); - delegationManager.increaseDelegatedShares(staker, strategyMock, shares); - - uint256 delegatedSharesAfter = delegationManager.operatorShares( - delegationManager.delegatedTo(staker), - strategyMock - ); - - if (delegationManager.isDelegated(staker)) { - assertEq( - delegatedSharesAfter, - _delegatedSharesBefore + shares, - "delegated shares did not increment correctly" - ); - } else { - assertEq(delegatedSharesAfter, _delegatedSharesBefore, "delegated shares incremented incorrectly"); - assertEq(_delegatedSharesBefore, 0, "nonzero shares delegated to zero address!"); - } - } - - // @notice Verifies that `DelegationManager.decreaseDelegatedShares` reverts if not called by the StrategyManager nor EigenPodManager - function testFuzz_decreaseDelegatedShares_revert_invalidCaller( - address invalidCaller, - uint256 shares - ) public filterFuzzedAddressInputs(invalidCaller) { - cheats.assume(invalidCaller != address(strategyManagerMock)); - cheats.assume(invalidCaller != address(eigenPodManagerMock)); - - cheats.startPrank(invalidCaller); - cheats.expectRevert("DelegationManager: onlyStrategyManagerOrEigenPodManager"); - delegationManager.decreaseDelegatedShares(invalidCaller, strategyMock, shares); - } - - // @notice Verifies that there is no change in shares if the staker is not delegated - function testFuzz_decreaseDelegatedShares_noop(address staker) public { - cheats.assume(staker != defaultOperator); - _registerOperatorWithBaseDetails(defaultOperator); - assertFalse(delegationManager.isDelegated(staker), "bad test setup"); - - cheats.prank(address(strategyManagerMock)); - delegationManager.decreaseDelegatedShares(staker, strategyMock, 1); - assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "shares should not have changed"); - } - - /** - * @notice Verifies that `DelegationManager.decreaseDelegatedShares` properly decreases the delegated `shares` that the operator - * who the `staker` is delegated to has in the strategies - * @dev Checks that there is no change if the staker is not delegated - */ - function testFuzz_decreaseDelegatedShares( - address staker, - IStrategy[] memory strategies, - uint128 shares, - bool delegateFromStakerToOperator - ) public filterFuzzedAddressInputs(staker) { - // sanity-filtering on fuzzed input length & staker - cheats.assume(strategies.length <= 32); - cheats.assume(staker != defaultOperator); - - // Register operator - _registerOperatorWithBaseDetails(defaultOperator); - - // delegate from the `staker` to the operator *if `delegateFromStakerToOperator` is 'true'* - if (delegateFromStakerToOperator) { - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - } - - uint256[] memory sharesInputArray = new uint256[](strategies.length); - - address delegatedTo = delegationManager.delegatedTo(staker); - - // for each strategy in `strategies`, increase delegated shares by `shares` - // noop if the staker is not delegated - cheats.startPrank(address(strategyManagerMock)); - for (uint256 i = 0; i < strategies.length; ++i) { - delegationManager.increaseDelegatedShares(staker, strategies[i], shares); - // store delegated shares in a mapping - delegatedSharesBefore[strategies[i]] = delegationManager.operatorShares(delegatedTo, strategies[i]); - // also construct an array which we'll use in another loop - sharesInputArray[i] = shares; - totalSharesForStrategyInArray[address(strategies[i])] += sharesInputArray[i]; - } - cheats.stopPrank(); - - bool isDelegated = delegationManager.isDelegated(staker); - - // for each strategy in `strategies`, decrease delegated shares by `shares` - { - cheats.startPrank(address(strategyManagerMock)); - address operatorToDecreaseSharesOf = delegationManager.delegatedTo(staker); - if (isDelegated) { - for (uint256 i = 0; i < strategies.length; ++i) { - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit OperatorSharesDecreased( - operatorToDecreaseSharesOf, - staker, - strategies[i], - sharesInputArray[i] - ); - delegationManager.decreaseDelegatedShares(staker, strategies[i], sharesInputArray[i]); - } - } - cheats.stopPrank(); - } - - // check shares after call to `decreaseDelegatedShares` - for (uint256 i = 0; i < strategies.length; ++i) { - uint256 delegatedSharesAfter = delegationManager.operatorShares(delegatedTo, strategies[i]); - - if (isDelegated) { - assertEq( - delegatedSharesAfter + totalSharesForStrategyInArray[address(strategies[i])], - delegatedSharesBefore[strategies[i]], - "delegated shares did not decrement correctly" - ); - assertEq(delegatedSharesAfter, 0, "nonzero shares delegated to"); - } else { - assertEq( - delegatedSharesAfter, - delegatedSharesBefore[strategies[i]], - "delegated shares decremented incorrectly" - ); - assertEq(delegatedSharesBefore[strategies[i]], 0, "nonzero shares delegated to zero address!"); - } - } - } -} - -contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { - // @notice Verifies that undelegating is not possible when the "undelegation paused" switch is flipped - function test_undelegate_revert_paused(address staker) public filterFuzzedAddressInputs(staker) { - // set the pausing flag - cheats.prank(pauser); - delegationManager.pause(2 ** PAUSED_ENTER_WITHDRAWAL_QUEUE); - - cheats.prank(staker); - cheats.expectRevert("Pausable: index is paused"); - delegationManager.undelegate(staker); - } - - function testFuzz_undelegate_revert_notDelgated( - address undelegatedStaker - ) public filterFuzzedAddressInputs(undelegatedStaker) { - cheats.assume(undelegatedStaker != defaultOperator); - assertFalse(delegationManager.isDelegated(undelegatedStaker), "bad test setup"); - - cheats.prank(undelegatedStaker); - cheats.expectRevert("DelegationManager.undelegate: staker must be delegated to undelegate"); - delegationManager.undelegate(undelegatedStaker); - } - - // @notice Verifies that an operator cannot undelegate from themself (this should always be forbidden) - function testFuzz_undelegate_revert_stakerIsOperator(address operator) public filterFuzzedAddressInputs(operator) { - _registerOperatorWithBaseDetails(operator); - - cheats.prank(operator); - cheats.expectRevert("DelegationManager.undelegate: operators cannot be undelegated"); - delegationManager.undelegate(operator); - } - - /** - * @notice verifies that `DelegationManager.undelegate` reverts if trying to undelegate an operator from themselves - * @param callFromOperatorOrApprover -- calls from the operator if 'false' and the 'approver' if true - */ - function testFuzz_undelegate_operatorCannotForceUndelegateThemself( - address delegationApprover, - bool callFromOperatorOrApprover - ) public filterFuzzedAddressInputs(delegationApprover) { - // register *this contract* as an operator with the default `delegationApprover` - _registerOperatorWithDelegationApprover(defaultOperator); + // register *this contract* as an operator with the default `delegationApprover` + _registerOperatorWithDelegationApprover(defaultOperator); address caller; if (callFromOperatorOrApprover) { @@ -2689,17 +3092,16 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { // try to call the `undelegate` function and check for reversion cheats.prank(caller); - cheats.expectRevert("DelegationManager.undelegate: operators cannot be undelegated"); + cheats.expectRevert(OperatorsCannotUndelegate.selector); delegationManager.undelegate(defaultOperator); } - //TODO: verify that this check is even needed - function test_undelegate_revert_zeroAddress() public { + function test_Revert_undelegate_zeroAddress() public { _registerOperatorWithBaseDetails(defaultOperator); _delegateToOperatorWhoAcceptsAllStakers(address(0), defaultOperator); cheats.prank(address(0)); - cheats.expectRevert("DelegationManager.undelegate: cannot undelegate zero address"); + cheats.expectRevert(IPausable.InputAddressZero.selector); delegationManager.undelegate(address(0)); } @@ -2720,7 +3122,7 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { _delegateToOperatorWhoRequiresSig(staker, defaultOperator); cheats.prank(invalidCaller); - cheats.expectRevert("DelegationManager.undelegate: caller cannot undelegate staker"); + cheats.expectRevert(CallerCannotUndelegate.selector); delegationManager.undelegate(staker); } @@ -2731,8 +3133,8 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { * Properly undelegates the staker, i.e. the staker becomes “delegated to” the zero address, and `isDelegated(staker)` returns ‘false’ * Emits a `StakerUndelegated` event */ - function testFuzz_undelegate_noDelegateableShares(address staker) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); + function testFuzz_undelegate_noDelegateableShares(Randomness r) public { + address staker = r.Address(); // register *this contract* as an operator and delegate from the `staker` to them _registerOperatorWithBaseDetails(defaultOperator); @@ -2755,12 +3157,10 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { /** * @notice Verifies that the `undelegate` function allows for a force undelegation */ - function testFuzz_undelegate_forceUndelegation_noDelegateableShares( - address staker, - bytes32 salt, - bool callFromOperatorOrApprover - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); + function testFuzz_undelegate_forceUndelegation_noDelegateableShares(Randomness r) public { + address staker = r.Address(); + bytes32 salt = r.Bytes32(); + bool callFromOperatorOrApprover = r.Boolean(); _registerOperatorWithDelegationApprover(defaultOperator); _delegateToOperatorWhoRequiresSig(staker, defaultOperator, salt); @@ -2772,10 +3172,20 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { caller = defaultOperator; } - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerForceUndelegated(staker, defaultOperator); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit StakerUndelegated(staker, defaultOperator); + IDelegationManagerTypes.Withdrawal memory withdrawal; + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: staker, + operator: defaultOperator, + strategy: IStrategy(address(0)), + depositSharesQueued: 0, + operatorSharesDecreased: 0, + withdrawal: withdrawal, + withdrawalRoot: bytes32(0), + depositScalingFactor: WAD, + forceUndelegated: true + }) + ); cheats.prank(caller); bytes32[] memory withdrawalRoots = delegationManager.undelegate(staker); @@ -2787,538 +3197,3083 @@ contract DelegationManagerUnitTests_Undelegate is DelegationManagerUnitTests { ); assertFalse(delegationManager.isDelegated(staker), "staker not undelegated"); } -} -contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTests { - function test_Revert_WhenEnterQueueWithdrawalsPaused() public { - cheats.prank(pauser); - delegationManager.pause(2 ** PAUSED_ENTER_WITHDRAWAL_QUEUE); - (IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - strategy: strategyMock, - withdrawalAmount: 100 - }); - cheats.expectRevert("Pausable: index is paused"); - delegationManager.queueWithdrawals(queuedWithdrawalParams); - } + function testFuzz_undelegate_UAM(address staker, bytes32 salt) public { + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoRequiresSig(staker, defaultOperator, salt); - function test_Revert_WhenQueueWithdrawalParamsLengthMismatch() public { - IStrategy[] memory strategyArray = new IStrategy[](1); - strategyArray[0] = strategyMock; - uint256[] memory shareAmounts = new uint256[](2); - shareAmounts[0] = 100; - shareAmounts[1] = 100; + // Set delegate + cheats.prank(defaultOperator); + permissionController.setAppointee( + defaultOperator, + address(this), + address(delegationManager), + IDelegationManager.undelegate.selector + ); - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategyArray, - shares: shareAmounts, - withdrawer: defaultStaker - }); + // Undelegate + delegationManager.undelegate(staker); - cheats.expectRevert("DelegationManager.queueWithdrawal: input length mismatch"); - delegationManager.queueWithdrawals(queuedWithdrawalParams); + // Checks + assertEq( + delegationManager.delegatedTo(staker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(staker), "staker not undelegated"); } - function test_Revert_WhenNotStakerWithdrawer(address withdrawer) public { - cheats.assume(withdrawer != defaultStaker); + /** + * @notice Verifies that the `undelegate` function properly queues a withdrawal for all shares of the staker + */ + function testFuzz_undelegate_nonSlashedOperator(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + IStrategy[] memory strategyArray = r.StrategyArray(1); + IStrategy strategy = strategyArray[0]; - (IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ + // Set the staker deposits in the strategies + strategyManagerMock.addDeposit(defaultStaker, strategy, shares); + + // register *this contract* as an operator and delegate from the `staker` to them + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Format queued withdrawal + ( + , + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ staker: defaultStaker, - withdrawer: withdrawer, - strategy: strategyMock, - withdrawalAmount: 100 + withdrawer: defaultStaker, + strategy: strategy, + depositSharesToWithdraw: shares }); - cheats.expectRevert("DelegationManager.queueWithdrawal: withdrawer must be staker"); - cheats.prank(defaultStaker); - delegationManager.queueWithdrawals(queuedWithdrawalParams); - } - function test_Revert_WhenEmptyStrategiesArray() public { - IStrategy[] memory strategyArray = new IStrategy[](0); - uint256[] memory shareAmounts = new uint256[](0); - address withdrawer = defaultOperator; + // Undelegate the staker + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategy: strategy, + depositSharesQueued: shares, + operatorSharesDecreased: shares, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + cheats.prank(defaultStaker); + delegationManager.undelegate(defaultStaker); - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1); - queuedWithdrawalParams[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: strategyArray, - shares: shareAmounts, - withdrawer: withdrawer - }); + // Checks - delegation status + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); - cheats.expectRevert("DelegationManager._removeSharesAndQueueWithdrawal: strategies cannot be empty"); - delegationManager.queueWithdrawals(queuedWithdrawalParams); + // Checks - operator & staker shares + assertEq(delegationManager.operatorShares(defaultOperator, strategyMock), 0, "operator shares not decreased correctly"); + (uint256[] memory stakerWithdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); + assertEq(stakerWithdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); } /** - * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` - * from the `strategy` for the `sharesAmount`. - * - Asserts that staker is delegated to the operator - * - Asserts that shares for delegatedTo operator are decreased by `sharesAmount` - * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented - * - Checks that event was emitted with correct withdrawalRoot and withdrawal + * @notice Verifies that the `undelegate` function properly queues a withdrawal for all shares of the staker + * @notice The operator should have its shares slashed prior to the staker's deposit */ - function testFuzz_queueWithdrawal_SingleStrat( - address staker, - uint256 depositAmount, - uint256 withdrawalAmount - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); - uint256[] memory sharesAmounts = new uint256[](1); - sharesAmounts[0] = depositAmount; - // sharesAmounts is single element so returns single strategy - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, sharesAmounts); + function testFuzz_undelegate_preSlashedOperator(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 operatorMagnitude = r.Uint64(1, WAD); + IStrategy[] memory strategyArray = r.StrategyArray(1); + IStrategy strategy = strategyArray[0]; + + // register *this contract* as an operator & set its slashed magnitude _registerOperatorWithBaseDetails(defaultOperator); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + _setOperatorMagnitude(defaultOperator, strategy, operatorMagnitude); + + // Set the staker deposits in the strategies + strategyManagerMock.addDeposit(defaultStaker, strategy, shares); + + // delegate from the `staker` to them + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Format queued withdrawal ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, + , + Withdrawal memory withdrawal, bytes32 withdrawalRoot ) = _setUpQueueWithdrawalsSingleStrat({ - staker: staker, - withdrawer: staker, - strategy: strategies[0], - withdrawalAmount: withdrawalAmount + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategy, + depositSharesToWithdraw: shares }); - assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker should be delegated to operator"); - uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(staker); - uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategies[0]); - // queueWithdrawals - cheats.prank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit WithdrawalQueued(withdrawalRoot, withdrawal); - delegationManager.queueWithdrawals(queuedWithdrawalParams); + // Calculate operatorShares decreased, may be off of shares due to rounding + uint256 depositScalingFactor = delegationManager.depositScalingFactor(defaultStaker, strategy); + assertTrue(depositScalingFactor > WAD, "bad test setup"); + DepositScalingFactor memory dsf = DepositScalingFactor({ + _scalingFactor: depositScalingFactor + }); + uint256 operatorSharesDecreased = dsf.calcWithdrawable(shares, operatorMagnitude); + assertLe(operatorSharesDecreased, shares, "operatorSharesDecreased should be <= shares"); + + // Undelegate the staker + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategy: strategy, + depositSharesQueued: shares, + operatorSharesDecreased: operatorSharesDecreased, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + cheats.prank(defaultStaker); + delegationManager.undelegate(defaultStaker); - uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(staker); - uint256 delegatedSharesAfter = delegationManager.operatorShares(defaultOperator, strategies[0]); - assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); - assertEq(delegatedSharesBefore - withdrawalAmount, delegatedSharesAfter, "delegated shares not decreased correctly"); + // Checks - delegation status + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); + + // Checks - operator & staker shares + assertEq( + delegationManager.operatorShares(defaultOperator, strategy), + shares - operatorSharesDecreased, + "operator shares not decreased correctly" + ); + (uint256[] memory stakerWithdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); + assertEq(stakerWithdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); } /** - * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` - * with multiple strategies and sharesAmounts. Depending on length sharesAmounts, deploys corresponding number of strategies - * and deposits sharesAmounts into each strategy for the staker and delegates to operator. - * For each strategy, withdrawAmount <= depositAmount - * - Asserts that staker is delegated to the operator - * - Asserts that shares for delegatedTo operator are decreased by `sharesAmount` - * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented - * - Checks that event was emitted with correct withdrawalRoot and withdrawal + * @notice Verifies that the `undelegate` function properly queues a withdrawal for all shares of the staker + * @notice The operator should have its shares slashed prior to the staker's deposit */ - function testFuzz_queueWithdrawal_MultipleStrats( - address staker, - uint256[] memory depositAmounts - ) public filterFuzzedAddressInputs(staker){ - cheats.assume(staker != defaultOperator); - cheats.assume(depositAmounts.length > 0 && depositAmounts.length <= 32); - uint256[] memory withdrawalAmounts = _fuzzWithdrawalAmounts(depositAmounts); + function testFuzz_undelegate_slashedWhileStaked(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + uint64 prevMaxMagnitude = r.Uint64(2, WAD); + uint64 newMaxMagnitude = r.Uint64(1, prevMaxMagnitude - 1); + IStrategy[] memory strategyArray = r.StrategyArray(1); + IStrategy strategy = strategyArray[0]; - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); + // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, - bytes32 withdrawalRoot - ) = _setUpQueueWithdrawals({ - staker: staker, - withdrawer: staker, - strategies: strategies, - withdrawalAmounts: withdrawalAmounts - }); - // Before queueWithdrawal state values - uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(staker); - assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker should be delegated to operator"); - uint256[] memory delegatedSharesBefore = new uint256[](strategies.length); - for (uint256 i = 0; i < strategies.length; i++) { - delegatedSharesBefore[i] = delegationManager.operatorShares(defaultOperator, strategies[i]); + _setOperatorMagnitude(defaultOperator, strategy, prevMaxMagnitude); + + // Set the staker deposits in the strategies + strategyManagerMock.addDeposit(defaultStaker, strategy, shares); + + // delegate from the `defaultStaker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + assertEq( + delegationManager.operatorShares(defaultOperator, strategy), + shares, + "operatorShares should increment correctly" + ); + + // Set operator magnitude + uint256 operatorSharesAfterSlash; + uint256 sharesToDecrement; + { + sharesToDecrement = SlashingLib.calcSlashedAmount({ + operatorShares: shares, + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + _setOperatorMagnitude(defaultOperator, strategy, newMaxMagnitude); + + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategy, prevMaxMagnitude, newMaxMagnitude); + operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategy); + assertEq( + shares - sharesToDecrement, + operatorSharesAfterSlash + ); } - // queueWithdrawals - cheats.prank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit WithdrawalQueued(withdrawalRoot, withdrawal); - delegationManager.queueWithdrawals(queuedWithdrawalParams); + uint256 depositScalingFactor = delegationManager.depositScalingFactor(defaultStaker, strategy); + assertEq(depositScalingFactor, uint256(WAD).divWad(prevMaxMagnitude), "bad test setup"); + assertEq( + sharesToDecrement + operatorSharesAfterSlash, + shares, + "operatorShares should decrement correctly" + ); - // Post queueWithdrawal state values - for (uint256 i = 0; i < strategies.length; i++) { + // Get withdrawable shares + (uint256[] memory withdrawableShares, uint256[] memory depositShares) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); + _assertWithdrawableAndOperatorShares(withdrawableShares[0], operatorSharesAfterSlash, "Invalid withdrawable shares"); + assertEq(depositShares[0], shares, "Invalid deposit shares"); + + // Format queued withdrawal + ( + , + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategy, + depositSharesToWithdraw: shares + }); + + // Undelegate the staker + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategy: strategy, + depositSharesQueued: shares, + operatorSharesDecreased: withdrawableShares[0], + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + cheats.prank(defaultStaker); + delegationManager.undelegate(defaultStaker); + + // Checks - delegation status + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); + + // Checks - operator & staker shares + assertEq( + delegationManager.operatorShares(defaultOperator, strategy), + operatorSharesAfterSlash - withdrawableShares[0], // Note that this is not exactly 0 due to rounding + "operator shares not decreased correctly" + ); + + (withdrawableShares, depositShares) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); + assertEq(withdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); + assertEq(depositShares[0], 0, "staker deposit shares not reset correctly"); + } + + /** + * @notice Verifies that the `undelegate` function properly undelegates a staker even though their shares + * were slashed entirely. + */ + function testFuzz_undelegate_slashedOperator100PercentWhileStaked(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + IStrategy[] memory strategyArray = r.StrategyArray(1); + IStrategy strategy = strategyArray[0]; + + // register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + + // Set the staker deposits in the strategies + strategyManagerMock.addDeposit(defaultStaker, strategy, shares); + + // delegate from the `defaultStaker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Set operator magnitude + uint64 operatorMagnitude = 0; + uint256 operatorSharesAfterSlash; + { + _setOperatorMagnitude(defaultOperator, strategy, operatorMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategy, WAD, 0); + operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategy); + assertEq(operatorSharesAfterSlash, 0, "operator shares not fully slashed"); + } + + ( + , + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategy, + depositSharesToWithdraw: shares + }); + + uint256 depositScalingFactor = delegationManager.depositScalingFactor(defaultStaker, strategy); + assertEq(depositScalingFactor, WAD, "bad test setup"); + // Get withdrawable and deposit shares + { + ( + uint256[] memory withdrawableSharesBefore, + uint256[] memory depositSharesBefore + ) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); assertEq( - delegatedSharesBefore[i] - withdrawalAmounts[i], // Shares before - withdrawal amount - delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after - "delegated shares not decreased correctly" + withdrawableSharesBefore[0], + 0, + "withdrawable shares should be 0 after being slashed fully" + ); + assertEq( + depositSharesBefore[0], + shares, + "deposit shares should be unchanged after being slashed fully" ); } - uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(staker); - assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); + + // Undelegate the staker + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategy: strategy, + depositSharesQueued: shares, + operatorSharesDecreased: 0, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + cheats.prank(defaultStaker); + delegationManager.undelegate(defaultStaker); + + // Checks - delegation status + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); + + // Checks - operator & staker shares + assertEq(delegationManager.operatorShares(defaultOperator, strategy), 0, "operator shares not decreased correctly"); + ( + uint256[] memory stakerWithdrawableShares, + uint256[] memory depositShares + ) = delegationManager.getWithdrawableShares(defaultStaker, strategyArray); + assertEq(stakerWithdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); + assertEq(depositShares[0], 0, "staker deposit shares not reset correctly"); + } + + function testFuzz_undelegate_slashedOperatorCloseTo100(Randomness r) public { + uint32 numStakers = r.Uint32(1, 8); + address[] memory stakers = r.StakerArray(numStakers); + uint64 prevMaxMagnitude = r.Uint64(2, WAD); + uint64 newMaxMagnitude = 1; + + // 1. register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, prevMaxMagnitude); + + // 2. Stakers deposits in the strategyMock + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + { + for (uint256 i = 0; i < numStakers; ++i) { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + strategyManagerMock.addDeposit( + stakers[i], + strategyMock, + shares + ); + stakerDepositShares[stakers[i]] = shares; + } + } + + // 3. Delegate from the `stakers` to the operator + { + uint256 totalWithdrawable = 0; + for (uint256 i = 0; i < numStakers; ++i) { + _delegateToOperatorWhoAcceptsAllStakers(stakers[i], defaultOperator); + ( + uint256[] memory withdrawableSharesBefore, + uint256[] memory depositSharesBefore + ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + assertEq(depositSharesBefore[0], stakerDepositShares[stakers[i]], "deposit shares not set correctly"); + totalWithdrawable += withdrawableSharesBefore[0]; + } + assertLe( + totalWithdrawable, delegationManager.operatorShares(defaultOperator, strategyMock), "should be <= op shares due to rounding" + ); + } + + // 4. Slash operator - Set operator magnitude and call burnOperatorShares + uint256 operatorSharesAfterSlash; + { + _setOperatorMagnitude(defaultOperator, strategyMock, newMaxMagnitude); + + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategyMock, prevMaxMagnitude, newMaxMagnitude); + operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategyMock); + } + + // 5. Undelegate the stakers with expected events + uint256 totalOperatorSharesDecreased = 0; + for (uint256 i = 0; i < numStakers; ++i) { + ( + , + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: stakers[i], + withdrawer: stakers[i], + strategy: strategyMock, + depositSharesToWithdraw: stakerDepositShares[stakers[i]] + }); + dsf = DepositScalingFactor({ + _scalingFactor: delegationManager.depositScalingFactor(stakers[i], strategyMock) + }); + uint256 operatorSharesDecreased = dsf.calcWithdrawable(stakerDepositShares[stakers[i]], newMaxMagnitude); + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: stakers[i], + operator: defaultOperator, + strategy: strategyMock, + depositSharesQueued: stakerDepositShares[stakers[i]], + operatorSharesDecreased: operatorSharesDecreased, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + + cheats.prank(stakers[i]); + delegationManager.undelegate(stakers[i]); + + totalOperatorSharesDecreased += operatorSharesDecreased; + } + + // 6. Checks - delegation status and staker,operator shares + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); + assertEq( + delegationManager.operatorShares(defaultOperator, strategyMock) + totalOperatorSharesDecreased, + operatorSharesAfterSlash, + "operator shares not decreased correctly" + ); + for (uint256 i = 0; i < numStakers; ++i) { + ( + uint256[] memory stakerWithdrawableShares, + uint256[] memory stakerDepositShares + ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + assertEq(stakerWithdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); + assertEq(stakerDepositShares[0], 0, "staker deposit shares not reset correctly"); + } + } + + /** + * @notice Given an operator with slashed magnitude, delegate, undelegate, and then delegate back to the same operator with + * completing withdrawals as shares. This should result in the operatorShares after the second delegation being <= the shares from the first delegation. + */ + function testFuzz_undelegate_delegateAgainWithRounding(Randomness r) public { + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + // set magnitude to 66% to ensure rounding when calculating `toShares` + uint64 operatorMagnitude = 333333333333333333; + + // register *this contract* as an operator & set its slashed magnitude + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = strategyMock.toArray(); + { + uint256[] memory sharesToSet = shares.toArrayU256(); + strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); + } + + // delegate from the `staker` to them + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + uint256 depositScalingFactor = delegationManager.depositScalingFactor(defaultStaker, strategyMock); + assertEq(depositScalingFactor, uint256(WAD).divWad(uint256(operatorMagnitude)), "first deposit should result in k value of (1 / magnitude)"); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); + + // Format queued withdrawal + ( + , + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: shares + }); + + DepositScalingFactor memory _dsf = DepositScalingFactor(depositScalingFactor); + uint256 slashingFactor = _getSlashingFactor(defaultStaker, strategyMock, operatorMagnitude); + uint256 operatorSharesDecreased = _dsf.calcWithdrawable(shares, slashingFactor); + + // Undelegate the staker + cheats.prank(defaultStaker); + _undelegate_expectEmit_singleStrat( + UndelegateEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + strategy: strategyMock, + depositSharesQueued: shares, + operatorSharesDecreased: operatorSharesDecreased, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot, + depositScalingFactor: WAD, + forceUndelegated: false + }) + ); + delegationManager.undelegate(defaultStaker); + + // Checks - delegation status + assertEq( + delegationManager.delegatedTo(defaultStaker), + address(0), + "undelegated staker should be delegated to zero address" + ); + assertFalse(delegationManager.isDelegated(defaultStaker), "staker not undelegated"); + + // Checks - operator & staker shares + (uint256[] memory stakerWithdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertEq(stakerWithdrawableShares[0], 0, "staker withdrawable shares not calculated correctly"); + + // // Re-delegate the staker to the operator again. The shares should have increased but may be less than from before due to rounding + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + // complete withdrawal as shares, should add back delegated shares to operator due to delegating again + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(strategies[0].underlyingToken()); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + assertLe(operatorSharesAfter, operatorSharesBefore, "operator shares should be less than or equal to before due to potential rounding"); + } + + /** + * @notice This function tests to ensure that a delegator can re-delegate to an operator after undelegating. + * Asserts the shares after re-delegating are the same as originally. No slashing is done in this test. + */ + function testFuzz_undelegate_redelegateWithSharesBack(Randomness r) public { + address staker = r.Address(); + address operator = r.Address(); + uint256 strategyShares = r.Uint256(1, MAX_STRATEGY_SHARES); + int256 beaconShares = int256(r.Uint256(1, MAX_ETH_SUPPLY)); + bool completeAsShares = r.Boolean(); + + // 1. Set staker shares + strategyManagerMock.addDeposit(staker, strategyMock, strategyShares); + eigenPodManagerMock.setPodOwnerShares(staker, beaconShares); + ( + IStrategy[] memory strategiesToReturn, + ) = delegationManager.getDepositedShares(staker); + // 2. register operator and delegate staker to operator + _registerOperatorWithBaseDetails(operator); + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + // 3. Setup queued withdrawals from `undelegate` + // queued withdrawals done for single strat as this is how undelegate queue withdraws + ( + , + IDelegationManagerTypes.Withdrawal memory strategyWithdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: strategyShares + }); + ( + , + IDelegationManagerTypes.Withdrawal memory beaconWithdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: IStrategy(address(beaconChainETHStrategy)), + depositSharesToWithdraw: uint256(beaconShares) + }); + beaconWithdrawal.nonce = 1; // Ensure nonce is greater for second withdrawal + cheats.prank(staker); + delegationManager.undelegate(staker); + // 4. Delegate to operator again with shares added back + { + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + IERC20[] memory strategyTokens = new IERC20[](1); + strategyTokens[0] = IERC20(strategyMock.underlyingToken()); + IERC20[] memory beaconTokens = new IERC20[](1); + beaconTokens[0] = IERC20(address(beaconChainETHStrategy)); + if (completeAsShares) { + // delegate first and complete withdrawal + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + cheats.startPrank(staker); + delegationManager.completeQueuedWithdrawal(strategyWithdrawal, strategyTokens, false); + delegationManager.completeQueuedWithdrawal(beaconWithdrawal, beaconTokens, false); + cheats.stopPrank(); + } else { + // complete withdrawal first and then delegate + cheats.prank(staker); + delegationManager.completeQueuedWithdrawal(strategyWithdrawal, strategyTokens, false); + delegationManager.completeQueuedWithdrawal(beaconWithdrawal, beaconTokens, false); + cheats.stopPrank(); + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + } + } + + // 5. assert correct shares and delegation state + assertTrue( + delegationManager.isDelegated(staker), + "staker should be delegated" + ); + assertEq( + delegationManager.delegatedTo(staker), + operator, + "staker should be delegated to operator" + ); + (uint256[] memory stakerShares, ) = delegationManager.getWithdrawableShares(staker, strategiesToReturn); + assertEq( + delegationManager.operatorShares(operator, strategyMock), + stakerShares[0], + "operator shares should be equal to strategyShares" + ); + assertEq( + uint256(eigenPodManagerMock.podOwnerDepositShares(staker)), + stakerShares[1], + "beacon shares should be equal to beaconShares" + ); + } +} + +contract DelegationManagerUnitTests_queueWithdrawals is DelegationManagerUnitTests { + using SlashingLib for *; + using SingleItemArrayLib for *; + + function test_Revert_WhenEnterQueueWithdrawalsPaused() public { + cheats.prank(pauser); + delegationManager.pause(2 ** PAUSED_ENTER_WITHDRAWAL_QUEUE); + (QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: 100 + }); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + } + + function test_Revert_WhenQueueWithdrawalParamsLengthMismatch() public { + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory shareAmounts = new uint256[](2); + shareAmounts[0] = 100; + shareAmounts[1] = 100; + + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategyArray, + depositShares: shareAmounts, + withdrawer: defaultStaker + }); + + cheats.expectRevert(InputArrayLengthMismatch.selector); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + } + + function testFuzz_Revert_WhenNotStakerWithdrawer(address withdrawer) public { + cheats.assume(withdrawer != defaultStaker); + + (QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: withdrawer, + strategy: strategyMock, + depositSharesToWithdraw: 100 + }); + cheats.expectRevert(WithdrawerNotStaker.selector); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + } + + function test_Revert_WhenEmptyStrategiesArray() public { + IStrategy[] memory strategyArray = new IStrategy[](0); + uint256[] memory shareAmounts = new uint256[](0); + address withdrawer = defaultOperator; + + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategyArray, + depositShares: shareAmounts, + withdrawer: withdrawer + }); + + cheats.expectRevert(InputArrayLengthZero.selector); + delegationManager.queueWithdrawals(queuedWithdrawalParams); } /** * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` - * with multiple strategies and sharesAmounts and with thirdPartyTransfersForbidden for one of the strategies. - * Queuing a withdrawal should pass as the `withdrawer` address is the same as the staker. - * - * Depending on length sharesAmounts, deploys corresponding number of strategies - * and deposits sharesAmounts into each strategy for the staker and delegates to operator. - * For each strategy, withdrawAmount <= depositAmount + * from the `strategy` for the `sharesAmount`. * - Asserts that staker is delegated to the operator * - Asserts that shares for delegatedTo operator are decreased by `sharesAmount` * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented * - Checks that event was emitted with correct withdrawalRoot and withdrawal */ - function testFuzz_queueWithdrawal_ThirdPartyTransfersForbidden( - address staker, - uint256[] memory depositAmounts, - uint256 randSalt - ) public filterFuzzedAddressInputs(staker){ - cheats.assume(depositAmounts.length > 0 && depositAmounts.length <= 32); - cheats.assume(staker != defaultOperator); - uint256[] memory withdrawalAmounts = _fuzzWithdrawalAmounts(depositAmounts); + function testFuzz_queueWithdrawal_SingleStrat_nonSlashedOperator(Randomness r) public { + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawalAmount = r.Uint256(1, depositAmount); + uint256[] memory sharesAmounts = new uint256[](1); + sharesAmounts[0] = depositAmount; + bool depositBeaconChainShares = r.Boolean(); + // sharesAmounts is single element so returns single strategy + IStrategy[] memory strategies = _deployAndDepositIntoStrategies(defaultStaker, sharesAmounts, depositBeaconChainShares); + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategies[0], + depositSharesToWithdraw: withdrawalAmount + }); + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategies[0]); + + // queueWithdrawals + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + uint256 delegatedSharesAfter = delegationManager.operatorShares(defaultOperator, strategies[0]); + _assertQueuedWithdrawalExists(defaultStaker); + assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); + assertEq(delegatedSharesBefore - withdrawalAmount, delegatedSharesAfter, "delegated shares not decreased correctly"); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` + * from the `strategy` for the `sharesAmount`. Operator is slashed prior to the staker's deposit + * - Asserts that staker is delegated to the operator + * - Asserts that shares for delegatedTo operator are decreased by `sharesAmount` + * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_SingleStrat_preSlashedOperator(Randomness r) public { + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawalAmount = r.Uint256(1, depositAmount); + uint64 prevMaxMagnitude = r.Uint64(2, WAD); + uint64 newMaxMagnitude = r.Uint64(1, prevMaxMagnitude - 1); + + // Slash the operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, newMaxMagnitude); + + // Deposit for staker & delegate + strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: withdrawalAmount + }); + + dsf = DepositScalingFactor({ + _scalingFactor: delegationManager.depositScalingFactor(defaultStaker, strategyMock) + }); + uint256 expectedWithdrawnShares = dsf.calcWithdrawable(withdrawalAmount, newMaxMagnitude); + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); + + // queueWithdrawals + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + uint256 delegatedSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); + _assertQueuedWithdrawalExists(defaultStaker); + assertApproxEqRel( + delegatedSharesBefore - expectedWithdrawnShares, + delegatedSharesAfter, + 1e16, // max delta of 1%, given shares amount > 1000 + "delegated shares not decreased correctly" + ); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` + * from the `strategy` for the `sharesAmount`. Operator is slashed while the staker is deposited + * - Asserts that staker is delegated to the operator + * - Asserts that shares for delegatedTo operator are decreased by `sharesAmount` + * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_SingleStrat_slashedWhileStaked(Randomness r) public { + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawalAmount = r.Uint256(1, depositAmount); + uint64 prevMaxMagnitude = r.Uint64(2, WAD); + uint64 newMaxMagnitude = r.Uint64(1, prevMaxMagnitude - 1); + + // Register operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, prevMaxMagnitude); + + + // Deposit for staker & delegate + strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Slash the operator + _setOperatorMagnitude(defaultOperator, strategyMock, newMaxMagnitude); + _setOperatorMagnitude(defaultOperator, strategyMock, newMaxMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategyMock, prevMaxMagnitude, newMaxMagnitude); + + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: withdrawalAmount + }); + + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + uint256 delegatedSharesBefore = delegationManager.operatorShares(defaultOperator, strategyMock); + + // queueWithdrawals + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + uint256 delegatedSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + + uint256 slashingFactor = _getSlashingFactor(defaultStaker, strategyMock, newMaxMagnitude); + dsf = DepositScalingFactor(delegationManager.depositScalingFactor(defaultStaker, strategyMock)); + + uint256 sharesWithdrawn = dsf.calcWithdrawable(withdrawalAmount, slashingFactor); + uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); + _assertQueuedWithdrawalExists(defaultStaker); + assertEq( + delegatedSharesBefore - sharesWithdrawn, + delegatedSharesAfter, + "delegated shares not decreased correctly" + ); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` queues an empty withdrawal for the `withdrawer` + * from the `strategy` for the `sharesAmount` since the Operator is slashed 100% while the staker is deposited + * - Asserts that queuing a withdrawal results in an empty withdrawal when the operator is slashed 100% + * - Asserts that staker withdrawableShares after is 0 + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_SingleStrat_slashed100PercentWhileStaked(Randomness r) public { + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + + // Register operator, deposit for staker & delegate + _registerOperatorWithBaseDetails(defaultOperator); + strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + ( + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: 0 // expected 0 since slashed 100% + }); + + // Slash the operator + uint64 operatorMagnitude = 0; + _setOperatorMagnitude(defaultOperator, strategyMock, operatorMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, strategyMock, WAD, 0); + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); + + // queueWithdrawals should result in an empty withdrawal + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + (IStrategy[] memory strategies, ) = delegationManager.getDepositedShares(defaultStaker); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertEq( + withdrawableShares[0], + 0, + "withdrawable shares should be 0 after being slashed fully" + ); + _assertQueuedWithdrawalExists(defaultStaker); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` + * with multiple strategies and sharesAmounts. Operator has default WAD maxMagnitude for all strategies. + * Depending on number of strategies randomized, deposits sharesAmounts into each strategy for the staker and delegates to operator. + * For each strategy, + * - Asserts that staker is delegated to the operator + * - Asserts that the staker withdrawal is queued both with the root and actual Withdrawal struct in storage + * - Asserts that the operator shares decrease by the expected withdrawn shares + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_MultipleStrats_nonSlashedOperator( + Randomness r + ) public { + uint32 numStrategies = r.Uint32(1, 32); + bool depositBeaconChainShares = r.Boolean(); + + ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + , + ) = _fuzzDepositWithdrawalAmounts({ r: r, numStrategies: numStrategies }); + IStrategy[] memory strategies = _deployAndDepositIntoStrategies(defaultStaker, depositAmounts, depositBeaconChainShares); + + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawals({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategies: strategies, + depositWithdrawalAmounts: withdrawalAmounts + }); + // Before queueWithdrawal state values + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + assertEq(delegationManager.delegatedTo(defaultStaker), defaultOperator, "staker should be delegated to operator"); + uint256[] memory delegatedSharesBefore = new uint256[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + delegatedSharesBefore[i] = delegationManager.operatorShares(defaultOperator, strategies[i]); + } + + // queueWithdrawals + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + // Post queueWithdrawal state values + for (uint256 i = 0; i < strategies.length; i++) { + assertEq( + delegatedSharesBefore[i] - withdrawalAmounts[i], // Shares before - withdrawal amount + delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after + "delegated shares not decreased correctly" + ); + // assert staker deposit shares decremented correctly + assertEq( + strategyManagerMock.stakerDepositShares(defaultStaker, strategies[i]), + depositAmounts[i] - withdrawalAmounts[i], + "staker deposit shares not decreased correctly" + ); + } + assertEq( + delegationManager.delegatedTo(defaultStaker), + defaultOperator, + "staker should be delegated to operator" + ); + uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); + _assertQueuedWithdrawalExists(defaultStaker); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` + * with multiple strategies and sharesAmounts. Operator has random maxMagnitudes for each strategy. + * Depending on number of strategies randomized, deposits sharesAmounts into each strategy for the staker and delegates to operator. + * For each strategy, + * - Asserts that staker is delegated to the operator + * - Asserts that shares for delegatedTo operator are decreased by `depositAmount` + * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_MultipleStrats_preSlashedOperator(Randomness r) public { + // 1. Setup + // - fuzz numbers of strategies, deposit and withdraw amounts, and prev/new magnitudes for each strategy respectively + // - deposit into strategies, delegate to operator + uint32 numStrats = r.Uint32(1, 32); + bool depositBeaconChainShares = r.Boolean(); + IStrategy[] memory strategies = r.StrategyArray(numStrats); + if (depositBeaconChainShares) { + strategies[numStrats - 1] = beaconChainETHStrategy; + } + + ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + uint64[] memory prevMaxMagnitudes, + ) = _fuzzDepositWithdrawalAmounts({ r: r, numStrategies: numStrats }); + _registerOperatorWithBaseDetails(defaultOperator); + allocationManagerMock.setMaxMagnitudes(defaultOperator, strategies, prevMaxMagnitudes); + _depositIntoStrategies(defaultStaker, strategies, depositAmounts); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + uint256[] memory expectedWithdrawnShares = _getWithdrawableShares({ + staker: defaultStaker, + strategies: strategies, + maxMagnitudes: prevMaxMagnitudes, + depositSharesToWithdraw: withdrawalAmounts + }); + + + // 2. Setup and call queued withdrawals + ( + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawals({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategies: strategies, + depositWithdrawalAmounts: withdrawalAmounts + }); + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + // expected events emitted + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + // 3. call `DelegationManager.queueWithdrawals` + _queueWithdrawals(defaultStaker, queuedWithdrawalParams, withdrawal); + + // 4. Post queueWithdrawal state values + // Post queueWithdrawal state values + for (uint256 i = 0; i < strategies.length; i++) { + // assert operator shares decreased properly + assertEq( + depositAmounts[i] - expectedWithdrawnShares[i], // Shares before - withdrawal amount + delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after + "delegated shares not decreased correctly" + ); + // assert staker deposit shares decremented correctly + assertEq( + strategyManagerMock.stakerDepositShares(defaultStaker, strategies[i]), + depositAmounts[i] - withdrawalAmounts[i], + "staker deposit shares not decreased correctly" + ); + } + assertEq( + delegationManager.delegatedTo(defaultStaker), + defaultOperator, + "staker should be delegated to operator" + ); + assertEq( + nonceBefore + 1, + delegationManager.cumulativeWithdrawalsQueued(defaultStaker), + "staker nonce should have incremented" + ); + _assertQueuedWithdrawalExists(defaultStaker); + } + + /** + * @notice Verifies that `DelegationManager.queueWithdrawals` properly queues a withdrawal for the `withdrawer` + * with multiple strategies and sharesAmounts. Operator has random maxMagnitudes for each strategy. + * Depending on number of strategies randomized, deposits sharesAmounts into each strategy for the staker and delegates to operator. + * After depositing, the operator gets slashed for each of the strategies and has new maxMagnitudes set. + * For each strategy, + * - Asserts that staker is delegated to the operator + * - Asserts that shares for delegatedTo operator are decreased by `depositAmount` + * - Asserts that staker cumulativeWithdrawalsQueued nonce is incremented + * - Checks that event was emitted with correct withdrawalRoot and withdrawal + */ + function testFuzz_queueWithdrawal_MultipleStrats_slashedWhileStaked(Randomness r) public { + // 1. Setup + // - fuzz numbers of strategies, deposit and withdraw amounts, and prev/new magnitudes for each strategy respectively + // - deposit into strategies, delegate to operator + uint32 numStrats = r.Uint32(1, 32); + IStrategy[] memory strategies = r.StrategyArray(numStrats); + bool depositBeaconChainShares = r.Boolean(); + if (depositBeaconChainShares) { + strategies[numStrats - 1] = beaconChainETHStrategy; + } + ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + uint64[] memory prevMaxMagnitudes, + uint64[] memory newMaxMagnitudes + ) = _fuzzDepositWithdrawalAmounts({ r: r, numStrategies: numStrats }); + _registerOperatorWithBaseDetails(defaultOperator); + allocationManagerMock.setMaxMagnitudes(defaultOperator, strategies, prevMaxMagnitudes); + _depositIntoStrategies(defaultStaker, strategies, depositAmounts); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + uint256[] memory expectedWithdrawnShares = _getWithdrawableShares({ + staker: defaultStaker, + strategies: strategies, + maxMagnitudes: newMaxMagnitudes, + depositSharesToWithdraw: withdrawalAmounts + }); + + // 2. Slash operator while staker is delegated and staked + allocationManagerMock.setMaxMagnitudes(defaultOperator, strategies, newMaxMagnitudes); + cheats.startPrank(address(allocationManagerMock)); + for (uint256 i = 0; i < strategies.length; i++) { + delegationManager.burnOperatorShares(defaultOperator, strategies[i], prevMaxMagnitudes[i], newMaxMagnitudes[i]); + delegatedSharesBefore[strategies[i]] = delegationManager.operatorShares(defaultOperator, strategies[i]); + } + cheats.stopPrank(); + + // 3. Setup and call queued withdrawals + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + { + ( + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawals({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategies: strategies, + depositWithdrawalAmounts: withdrawalAmounts + }); + // expected events emitted + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + // 4. call `DelegationManager.queueWithdrawals` + _queueWithdrawals(defaultStaker, queuedWithdrawalParams, withdrawal); + } + + // 5. Post queueWithdrawal state values + for (uint256 i = 0; i < strategies.length; i++) { + // assert operator shares decreased properly + assertEq( + delegatedSharesBefore[strategies[i]] - expectedWithdrawnShares[i], // Shares before - withdrawal amount + delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after + "delegated shares not decreased correctly" + ); + // assert staker deposit shares decremented correctly + assertEq( + strategyManagerMock.stakerDepositShares(defaultStaker, strategies[i]), + depositAmounts[i] - withdrawalAmounts[i], + "staker deposit shares not decreased correctly" + ); + } + assertEq( + delegationManager.delegatedTo(defaultStaker), + defaultOperator, + "staker should be delegated to operator" + ); + assertEq( + nonceBefore + 1, + delegationManager.cumulativeWithdrawalsQueued(defaultStaker), + "staker nonce should have incremented" + ); + _assertQueuedWithdrawalExists(defaultStaker); + } + + /** + * @notice Same test as `testFuzz_queueWithdrawal_MultipleStrats_slashedWhileStaked` but with one strategy having 0 newMaxMagnitude + * - Asserts that the strategy with 0 newMaxMagnitude has 0 delegated shares before and after withdrawal + * - Asserts that the staker withdrawn shares for the strategy with 0 newMaxMagnitude is 0 + */ + function testFuzz_queueWithdrawal_MultipleStrats__slashed100PercentWhileStaked(Randomness r) public { + // 1. Setup + // - fuzz numbers of strategies, deposit and withdraw amounts, and prev/new magnitudes for each strategy respectively + // - deposit into strategies, delegate to operator + uint32 numStrats = r.Uint32(1, 32); + IStrategy[] memory strategies = r.StrategyArray(numStrats); + bool depositBeaconChainShares = r.Boolean(); + if (depositBeaconChainShares) { + strategies[numStrats - 1] = beaconChainETHStrategy; + } + ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + uint64[] memory prevMaxMagnitudes, + uint64[] memory newMaxMagnitudes + ) = _fuzzDepositWithdrawalAmounts({ r: r, numStrategies: numStrats }); + // randomly choose strategy to have 0 newMaxMagnitude + uint256 zeroMagnitudeIndex = r.Uint256(0, numStrats - 1); + newMaxMagnitudes[zeroMagnitudeIndex] = 0; + + _registerOperatorWithBaseDetails(defaultOperator); + allocationManagerMock.setMaxMagnitudes(defaultOperator, strategies, prevMaxMagnitudes); + _depositIntoStrategies(defaultStaker, strategies, depositAmounts); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + uint256[] memory expectedWithdrawnShares = _getWithdrawableShares({ + staker: defaultStaker, + strategies: strategies, + maxMagnitudes: newMaxMagnitudes, + depositSharesToWithdraw: withdrawalAmounts + }); + + // 2. Slash operator while staker is delegated and staked + allocationManagerMock.setMaxMagnitudes(defaultOperator, strategies, newMaxMagnitudes); + cheats.startPrank(address(allocationManagerMock)); + for (uint256 i = 0; i < strategies.length; i++) { + delegationManager.burnOperatorShares(defaultOperator, strategies[i], prevMaxMagnitudes[i], newMaxMagnitudes[i]); + delegatedSharesBefore[strategies[i]] = delegationManager.operatorShares(defaultOperator, strategies[i]); + } + cheats.stopPrank(); + + // 3. Setup and call queued withdrawals + uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(defaultStaker); + { + ( + IDelegationManagerTypes.QueuedWithdrawalParams[] memory queuedWithdrawalParams, + IDelegationManagerTypes.Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawals({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategies: strategies, + depositWithdrawalAmounts: withdrawalAmounts + }); + // expected events emitted + _queueWithdrawals_expectEmit( + QueueWithdrawalsEmitStruct({ + staker: defaultStaker, + operator: defaultOperator, + queuedWithdrawalParams: queuedWithdrawalParams, + withdrawal: withdrawal, + withdrawalRoot: withdrawalRoot + }) + ); + // 4. call `DelegationManager.queueWithdrawals` + _queueWithdrawals(defaultStaker, queuedWithdrawalParams, withdrawal); + } + + // 5. Post queueWithdrawal state values + for (uint256 i = 0; i < strategies.length; i++) { + // assert operator shares decreased properly + assertEq( + delegatedSharesBefore[strategies[i]] - expectedWithdrawnShares[i], // Shares before - withdrawal amount + delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after + "delegated shares not decreased correctly" + ); + // assert staker deposit shares decremented correctly + assertEq( + strategyManagerMock.stakerDepositShares(defaultStaker, strategies[i]), + depositAmounts[i] - withdrawalAmounts[i], + "staker deposit shares not decreased correctly" + ); + } + assertEq( + delegationManager.delegatedTo(defaultStaker), + defaultOperator, + "staker should be delegated to operator" + ); + assertEq( + expectedWithdrawnShares[zeroMagnitudeIndex], + delegatedSharesBefore[strategies[zeroMagnitudeIndex]], + "expected withdrawn shares and delegated shares before withdrawal should be 0" + ); + assertEq( + delegatedSharesBefore[strategies[zeroMagnitudeIndex]], + 0, + "expected withdrawn shares and delegated shares before withdrawal should be 0" + ); + assertEq( + nonceBefore + 1, + delegationManager.cumulativeWithdrawalsQueued(defaultStaker), + "staker nonce should have incremented" + ); + _assertQueuedWithdrawalExists(defaultStaker); + } +} + +contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + using SlashingLib for *; + using Math for uint256; + + function test_Revert_WhenExitWithdrawalQueuePaused() public { + cheats.prank(pauser); + delegationManager.pause(2 ** PAUSED_EXIT_WITHDRAWAL_QUEUE); + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + /* bytes32 withdrawalRoot */ + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + depositAmount: 100, + withdrawalAmount: 100, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); + + IERC20[][] memory tokensArray = new IERC20[][](1); + tokensArray[0] = tokens; + + bool[] memory receiveAsTokens = new bool[](1); + receiveAsTokens[0] = false; + + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + delegationManager.completeQueuedWithdrawals(tokensArray, receiveAsTokens, 1); + } + + function test_Revert_WhenInputArrayLengthMismatch() public { + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + /* bytes32 withdrawalRoot */ + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + depositAmount: 100, + withdrawalAmount: 100, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + // Roll to completion block + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + + // resize tokens array + IERC20[] memory newTokens = new IERC20[](0); + + cheats.prank(defaultStaker); + cheats.expectRevert(InputArrayLengthMismatch.selector); + delegationManager.completeQueuedWithdrawal(withdrawal, newTokens, false); + + IERC20[][] memory tokensArray = new IERC20[][](1); + tokensArray[0] = newTokens; + + bool[] memory receiveAsTokens = new bool[](1); + receiveAsTokens[0] = true; + + cheats.prank(defaultStaker); + cheats.expectRevert(InputArrayLengthMismatch.selector); + delegationManager.completeQueuedWithdrawals(tokensArray, receiveAsTokens, 1); + + // check that the withdrawal completes otherwise + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + } + + function test_Revert_WhenWithdrawerNotCaller(address invalidCaller) filterFuzzedAddressInputs(invalidCaller) public { + cheats.assume(invalidCaller != defaultStaker); + + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + depositAmount: 100, + withdrawalAmount: 100, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + cheats.expectRevert(WithdrawerNotCaller.selector); + cheats.prank(invalidCaller); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); + } + + function test_Revert_WhenInvalidWithdrawalRoot() public { + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + bytes32 withdrawalRoot + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + depositAmount: 100, + withdrawalAmount: 100, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + + cheats.expectRevert(WithdrawalNotQueued.selector); + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); + } + + /** + * @notice should revert if minWithdrawalDelayBlocks has not passed, and if + * delegationManager.getCompletableTimestamp returns a value greater than minWithdrawalDelayBlocks + * then it should revert if the validBlockNumber has not passed either. + */ + function test_Revert_WhenWithdrawalDelayNotPassed( + Randomness r + ) public { + uint32 numStrategies = r.Uint32(1, 32); + bool receiveAsTokens = r.Boolean(); + ( + uint256[] memory depositAmounts, + uint256[] memory withdrawalAmounts, + , + ) = _fuzzDepositWithdrawalAmounts(r, numStrategies); + + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + /* bytes32 withdrawalRoot */ + ) = _setUpCompleteQueuedWithdrawal({ + staker: defaultStaker, + withdrawer: defaultStaker, + depositAmounts: depositAmounts, + withdrawalAmounts: withdrawalAmounts, + depositBeaconChainShares: false + }); + + // prank as withdrawer address + cheats.roll(withdrawal.startBlock + minWithdrawalDelayBlocks - 1); + cheats.expectRevert(WithdrawalDelayNotElapsed.selector); + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); + + IERC20[][] memory tokensArray = new IERC20[][](1); + tokensArray[0] = tokens; + + bool[] memory receiveAsTokensArray = new bool[](1); + receiveAsTokensArray[0] = false; + + cheats.expectRevert(WithdrawalDelayNotElapsed.selector); + cheats.prank(defaultStaker); + delegationManager.completeQueuedWithdrawals(tokensArray, receiveAsTokensArray, 1); + } + + /** + * Test completing multiple queued withdrawals for a single strategy by passing in the withdrawals + */ + function test_completeQueuedWithdrawals_MultipleWithdrawals( + address staker, + uint64 depositAmount, + uint numWithdrawals + ) public filterFuzzedAddressInputs(staker) { + cheats.assume(staker != defaultOperator); + cheats.assume(depositAmount > 0); + cheats.assume(numWithdrawals > 1 && numWithdrawals < 20); + + ( + IDelegationManagerTypes.Withdrawal[] memory withdrawals, + IERC20[][] memory tokens, + bytes32[] memory withdrawalRoots + ) = _setUpCompleteQueuedWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + depositAmount: depositAmount, + numWithdrawals: numWithdrawals + }); + + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawals[0].strategies[0]); + + for (uint i = 0; i < withdrawalRoots.length; i++) { + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoots[i]), "withdrawalRoots should be pending"); + } + + bool[] memory receiveAsTokens = new bool[](withdrawals.length); + for (uint i = 0; i < withdrawals.length; i++) { + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoots[i]); + receiveAsTokens[i] = true; + } + + // completeQueuedWithdrawal + cheats.roll(withdrawals[0].startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(staker); + delegationManager.completeQueuedWithdrawals(withdrawals, tokens, receiveAsTokens); + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawals[0].strategies[0]); + assertEq(operatorSharesAfter, operatorSharesBefore, "operator shares should be unchanged"); + + for (uint i = 0; i < withdrawals.length; i++) { + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoots[i]), "withdrawalRoot should be completed and marked false now"); + } + } + + /** + * Test completing multiple queued withdrawals for a single strategy without passing in the withdrawals + */ + function test_completeQueuedWithdrawals_NumToComplete( + address staker, + uint64 depositAmount, + uint numWithdrawals, + uint numToComplete + ) public filterFuzzedAddressInputs(staker) { + cheats.assume(staker != defaultOperator); + cheats.assume(depositAmount > 0); + numWithdrawals = bound(numWithdrawals, 2, 20); + numToComplete = bound(numToComplete, 1, numWithdrawals); + + ( + IDelegationManagerTypes.Withdrawal[] memory withdrawals, + IERC20[][] memory tokens, + bytes32[] memory withdrawalRoots + ) = _setUpCompleteQueuedWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + depositAmount: depositAmount, + numWithdrawals: numWithdrawals + }); + + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawals[0].strategies[0]); + + for (uint i = 0; i < withdrawalRoots.length; i++) { + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoots[i]), "withdrawalRoots should be pending"); + } + + bool[] memory receiveAsTokens = new bool[](withdrawals.length); + for (uint i = 0; i < numToComplete; i++) { + // cheats.expectEmit(true, true, true, true, address(delegationManager)); + // emit SlashingWithdrawalCompleted(withdrawalRoots[i]); + receiveAsTokens[i] = true; + } + + // completeQueuedWithdrawal + cheats.roll(withdrawals[0].startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(staker); + delegationManager.completeQueuedWithdrawals(tokens, receiveAsTokens, numToComplete); + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawals[0].strategies[0]); + assertEq(operatorSharesAfter, operatorSharesBefore, "operator shares should be unchanged"); + + for (uint i = 0; i < numToComplete; i++) { + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoots[i]), "withdrawalRoot should be completed and marked false now"); + } + + for (uint i = numToComplete; i < numWithdrawals; i++) { + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoots[i]), "withdrawalRoot should still be pending"); + } + } + + /** + * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` + * for a single strategy. Withdraws as tokens so there are no operator shares increase. + * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after + * - Asserts operatorShares is unchanged after `completeQueuedWithdrawal` + * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + */ + function test_completeQueuedWithdrawal_SingleStratWithdrawAsTokens(Randomness r) public { + address staker = r.Address(); + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawalAmount = r.Uint256(1, depositAmount); + + _registerOperatorWithBaseDetails(defaultOperator); + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + bytes32 withdrawalRoot + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: staker, + withdrawer: staker, + depositAmount: depositAmount, + withdrawalAmount: withdrawalAmount, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + + // completeQueuedWithdrawal + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(staker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertEq(operatorSharesAfter, operatorSharesBefore, "operator shares should be unchanged"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + } + + /** + * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` + * for a single strategy. Withdraws as tokens so there are no operator shares increase. + * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after + * - Asserts operatorShares is decreased after the operator is slashed + * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + * - Asserts that the shares the staker completed withdrawal for are less than what is expected since its operator is slashed + */ + function test_completeQueuedWithdrawal_SingleStratWithdrawAsTokens_slashOperatorDuringQueue( + uint256 depositAmount, + uint256 withdrawalAmount, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) public { + depositAmount = bound(depositAmount, 1, MAX_STRATEGY_SHARES); + withdrawalAmount = bound(withdrawalAmount, 1, depositAmount); + prevMaxMagnitude = uint64(bound(prevMaxMagnitude, 2, WAD)); + newMaxMagnitude = uint64(bound(newMaxMagnitude, 1, prevMaxMagnitude - 1)); + + // Deposit Staker + strategyManagerMock.addDeposit(defaultStaker, strategyMock, depositAmount); + + // Register operator and delegate to it + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + uint256 operatorSharesBeforeQueue = delegationManager.operatorShares(defaultOperator, strategyMock); + + // Queue withdrawal + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: strategyMock, + depositSharesToWithdraw: withdrawalAmount + }); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + uint256 operatorSharesAfterQueue = delegationManager.operatorShares(defaultOperator, strategyMock); + + assertEq(operatorSharesAfterQueue, operatorSharesBeforeQueue - withdrawalAmount, "1 shares should be decreased after queue"); + + // Slash operator while staker has queued withdrawal + uint256 sharesToDecrement = SlashingLib.calcSlashedAmount({ + operatorShares: operatorSharesAfterQueue, + prevMaxMagnitude: prevMaxMagnitude, + newMaxMagnitude: newMaxMagnitude + }); + _setOperatorMagnitude(defaultOperator, strategyMock, newMaxMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, withdrawal.strategies[0], prevMaxMagnitude, newMaxMagnitude); + uint256 operatorSharesAfterSlash = delegationManager.operatorShares(defaultOperator, strategyMock); + assertEq(operatorSharesAfterSlash, operatorSharesAfterQueue - sharesToDecrement, "operator shares should be decreased after slash"); + + // Complete queue withdrawal + { + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(strategyMock.underlyingToken()); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + } + + // Checks: operator shares + uint256 operatorSharesAfterWithdrawalComplete = delegationManager.operatorShares(defaultOperator, strategyMock); + assertEq(operatorSharesAfterWithdrawalComplete, operatorSharesAfterSlash, "operator shares should be unchanged from slash to withdrawal completion"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + + // Checks: staker shares: + uint256 stakerSharesWithdrawn = strategyManagerMock.strategySharesWithdrawn(defaultStaker, strategyMock); + { + dsf = DepositScalingFactor({ + _scalingFactor: delegationManager.depositScalingFactor(defaultStaker, strategyMock) + }); + } + + uint256 actualSharesWithdrawn = dsf.calcWithdrawable(withdrawalAmount, newMaxMagnitude); + assertEq(stakerSharesWithdrawn, actualSharesWithdrawn, "staker shares withdrawn not calculated correctly"); + } + + /** + * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` + * for the BeaconChainStrategy. Withdraws as tokens so there are no operator shares increase. + * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after + * - Asserts operatorShares is decreased after staker is slashed + * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + * - Asserts that the shares the staker completed withdrawal for are less than what is expected since the staker is slashed during queue + */ + // TODO: fuzz the beacon chain magnitude + function test_completeQueuedWithdrawal_BeaconStratWithdrawAsTokens_slashStakerDuringQueue( + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + + // Deposit Staker + eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(depositAmount))); + + // Register operator and delegate to it + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + uint256 operatorSharesBeforeQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + + // Queue withdrawal + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: beaconChainETHStrategy, + depositSharesToWithdraw: withdrawalAmount + }); + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + uint256 operatorSharesAfterQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterQueue, operatorSharesBeforeQueue - withdrawalAmount, "operator shares should be decreased after queue"); + + { + // Slash the staker for beacon chain shares while it has queued a withdrawal + // simulate the operations done in EigenPodManager._reduceSlashingFactor + uint256 beaconSharesBeforeSlash = uint256(eigenPodManagerMock.podOwnerShares(defaultStaker)); + uint64 prevBeaconChainSlashingFactor = eigenPodManagerMock.beaconChainSlashingFactor(defaultStaker); + uint256 beaconSharesAfterSlash = beaconSharesBeforeSlash / 2; + uint256 balanceRemainingWad = beaconSharesAfterSlash.divWadRoundUp(beaconSharesBeforeSlash); + uint64 newBeaconChainSlashingFactor = uint64(prevBeaconChainSlashingFactor.mulWad(balanceRemainingWad)); + + eigenPodManagerMock.setBeaconChainSlashingFactor(defaultStaker, newBeaconChainSlashingFactor); + uint256 wadSlashed = uint256(WAD) - balanceRemainingWad; + + cheats.prank(address(eigenPodManagerMock)); + delegationManager.decreaseDelegatedShares(defaultStaker, beaconSharesBeforeSlash, prevBeaconChainSlashingFactor, wadSlashed); + } + + uint256 operatorSharesAfterBeaconSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterBeaconSlash, operatorSharesAfterQueue.ceilDiv(2), "operator shares should be decreased after beaconChain slash"); + + // Complete queue withdrawal + IERC20[] memory tokens = new IERC20[](1); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + + // Checks: operator shares + uint256 operatorSharesAfterWithdrawalComplete = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertEq(operatorSharesAfterWithdrawalComplete, operatorSharesAfterBeaconSlash, "operator shares should be unchanged from slash to withdrawal completion"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + + // Checks: staker shares + uint256 stakerBeaconSharesWithdrawn = eigenPodManagerMock.podOwnerSharesWithdrawn(defaultStaker); + assertEq(stakerBeaconSharesWithdrawn, withdrawalAmount / 2, "staker shares withdrawn should be half of expected it is slashed by half"); + } + + /** + * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` + * for the BeaconChainStrategy. Withdraws as tokens so there are no operator shares increase. + * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after + * - Asserts operatorShares is decreased after staker is slashed and after the operator is slashed + * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + * - Asserts that the shares the staker completed withdrawal for are less than what is expected since both the staker and its operator are slashed during queue + */ + // TODO: fuzz the beacon chain magnitude & operator magnitude + function test_completeQueuedWithdrawal_BeaconStratWithdrawAsTokens_slashStakerAndOperator( + Randomness r + ) public rand(r) { + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + + // Deposit Staker + eigenPodManagerMock.setPodOwnerShares(defaultStaker, int256(uint256(depositAmount))); + + // Register operator and delegate to it + _registerOperatorWithBaseDetails(defaultOperator); + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + uint256 operatorSharesBeforeQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + + // Queue withdrawal + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + bytes32 withdrawalRoot + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: defaultStaker, + withdrawer: defaultStaker, + strategy: beaconChainETHStrategy, + depositSharesToWithdraw: withdrawalAmount + }); + + uint256 operatorSharesAfterAVSSlash; + { + cheats.prank(defaultStaker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + uint256 operatorSharesAfterQueue = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterQueue, operatorSharesBeforeQueue - withdrawalAmount, "operator shares should be decreased after queue"); + + // Slash the staker for beacon chain shares while it has queued a withdrawal + // simulate the operations done in EigenPodManager._reduceSlashingFactor + uint256 beaconSharesBeforeSlash = uint256(eigenPodManagerMock.podOwnerShares(defaultStaker)); + uint64 prevBeaconChainSlashingFactor = eigenPodManagerMock.beaconChainSlashingFactor(defaultStaker); + uint256 beaconSharesAfterSlash = beaconSharesBeforeSlash / 2; + + uint256 balanceRemainingWad = beaconSharesAfterSlash.divWadRoundUp(beaconSharesBeforeSlash); + uint64 newBeaconChainSlashingFactor = uint64(prevBeaconChainSlashingFactor.mulWad(balanceRemainingWad)); + + eigenPodManagerMock.setBeaconChainSlashingFactor(defaultStaker, newBeaconChainSlashingFactor); + uint256 wadSlashed = uint256(WAD) - balanceRemainingWad; + + cheats.prank(address(eigenPodManagerMock)); + delegationManager.decreaseDelegatedShares(defaultStaker, beaconSharesBeforeSlash, prevBeaconChainSlashingFactor, wadSlashed); + uint256 operatorSharesAfterBeaconSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertEq(operatorSharesAfterBeaconSlash, operatorSharesAfterQueue.ceilDiv(2), "operator shares should be decreased after beaconChain slash"); + + // Slash the operator for beacon chain shares + uint64 operatorMagnitude = 5e17; + _setOperatorMagnitude(defaultOperator, withdrawal.strategies[0], operatorMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares(defaultOperator, withdrawal.strategies[0], WAD, operatorMagnitude); + operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + assertApproxEqAbs(operatorSharesAfterAVSSlash, operatorSharesAfterBeaconSlash / 2, 1, "operator shares should be decreased after AVS slash"); + } + operatorSharesAfterAVSSlash = delegationManager.operatorShares(defaultOperator, beaconChainETHStrategy); + + // Complete queue withdrawal + IERC20[] memory tokens = new IERC20[](1); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(defaultStaker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true); + + // Checks: operator shares + uint256 operatorSharesAfterWithdrawalComplete = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertEq(operatorSharesAfterWithdrawalComplete, operatorSharesAfterAVSSlash, "operator shares should be unchanged from slash to withdrawal completion"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + + // Checks: staker shares + uint256 stakerBeaconSharesWithdrawn = eigenPodManagerMock.podOwnerSharesWithdrawn(defaultStaker); + assertEq(stakerBeaconSharesWithdrawn, withdrawalAmount / 4, "staker shares withdrawn should be 1/4th of expected it is slashed by half twice"); + } + + + /** + * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` + * for a single strategy. Withdraws as shares so if the withdrawer is delegated, operator shares increase. In the test case, this only + * happens if staker and withdrawer are fuzzed the same address (i.e. staker == withdrawer) + * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after + * - Asserts if staker == withdrawer, operatorShares increase, otherwise operatorShares are unchanged + * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + */ + function testFuzz_completeQueuedWithdrawal_SingleStratWithdrawAsShares_nonSlashedOperator( + Randomness r + ) public rand(r) { + address staker = r.Address(); + uint128 depositAmount = r.Uint128(); + uint128 withdrawalAmount = r.Uint128(1, depositAmount); + + _registerOperatorWithBaseDetails(defaultOperator); + + ( + Withdrawal memory withdrawal, + IERC20[] memory tokens, + bytes32 withdrawalRoot + ) = _setUpCompleteQueuedWithdrawalSingleStrat({ + staker: staker, + withdrawer: staker, + depositAmount: depositAmount, + withdrawalAmount: withdrawalAmount, + isBeaconChainStrategy: false + }); + _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); + uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + + // Set delegationManager on strategyManagerMock so it can call back into delegationManager + strategyManagerMock.setDelegationManager(delegationManager); + + // completeQueuedWithdrawal + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + cheats.prank(staker); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit SlashingWithdrawalCompleted(withdrawalRoot); + delegationManager.completeQueuedWithdrawal(withdrawal, tokens, false); + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + // Since staker is delegated, operatorShares get incremented + assertEq(operatorSharesAfter, operatorSharesBefore + withdrawalAmount, "operator shares not increased correctly"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + } +} + +contract DelegationManagerUnitTests_burningShares is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + + /** + * @notice Test burning shares for an operator with no queued withdrawals + * - Asserts slashable shares before and after in queue is 0 + * - Asserts operator shares are decreased by half + */ + function testFuzz_burnOperatorShares_NoQueuedWithdrawals(Randomness r) public { + address operator = r.Address(); + address staker = r.Address(); + uint64 initMagnitude = WAD; + uint64 newMagnitude = 5e17; + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + + // register *this contract* as an operator + _registerOperatorWithBaseDetails(operator); + _setOperatorMagnitude(operator, strategyMock, initMagnitude); + // Set the staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory sharesArray = shares.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategyArray, sharesArray); + // delegate from the `staker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + // calculate burned shares, should be halved + uint256 sharesToBurn = shares/2; + + // Burn shares + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToBurn); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: initMagnitude, + newMaxMagnitude: newMagnitude + }); + + uint256 queuedSlashableSharesAfter = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + uint256 operatorSharesAfter = delegationManager.operatorShares(operator, strategyMock); + assertEq(queuedSlashableSharesBefore, 0, "there should be no slashable shares in queue"); + assertEq(queuedSlashableSharesAfter, 0, "there should be no slashable shares in queue"); + assertEq(operatorSharesAfter, operatorSharesBefore - sharesToBurn, "operator shares should be decreased by sharesToBurn"); + } + + /** + * @notice Test burning shares for an operator with no slashable queued withdrawals in past MIN_WITHDRAWAL_DELAY_BLOCKS window. + * There does exist past queued withdrawals but nothing in the queue is slashable. + * - Asserts slashable shares in queue right after queuing a withdrawal is the withdrawal amount + * and then checks that after the withdrawal window the slashable shares is 0 again. + * - Asserts operator shares are decreased by half after burning + * - Asserts that the slashable shares in queue before/after burning are 0 + */ + function testFuzz_burnOperatorShares_NoQueuedWithdrawalsInWindow(Randomness r) public { + // 1. Randomize operator and staker info + // Operator info + address operator = r.Address(); + uint64 newMagnitude = 5e17; + // First staker + address staker1 = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + // Second Staker, will queue withdraw shares + address staker2 = r.Address(); + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawAmount = r.Uint256(1, depositAmount); + + // 2. Register the operator, set the staker deposits, and delegate the 2 stakers to them + _registerOperatorWithBaseDetails(operator); + { + // Set the first staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory sharesArray = shares.toArrayU256(); + uint256[] memory depositArray = depositAmount.toArrayU256(); + strategyManagerMock.setDeposits(staker1, strategyArray, sharesArray); + // Set the second staker's deposits in the strategies + strategyManagerMock.setDeposits(staker2, strategyArray, depositArray); + } + _delegateToOperatorWhoAcceptsAllStakers(staker1, operator); + _delegateToOperatorWhoAcceptsAllStakers(staker2, operator); + + // 3. Queue withdrawal for staker2 and roll blocks forward so that the withdrawal is not slashable + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker2, + withdrawer: staker2, + strategy: strategyMock, + depositSharesToWithdraw: withdrawAmount + }); + cheats.prank(staker2); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + withdrawAmount, + "there should be withdrawAmount slashable shares in queue" + ); + cheats.roll(withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); + } + + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + // calculate burned shares, should be halved + // staker2 queue withdraws shares and we roll blocks to after the withdrawal is no longer slashable. + // Therefore amount of shares to burn should be what the staker still has remaining + staker1 shares and then + // divided by 2 since the operator was slashed 50% + uint256 sharesToBurn = (shares + depositAmount - withdrawAmount) / 2; + + // 4. Burn shares + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToBurn); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: WAD, + newMaxMagnitude: newMagnitude + }); + + // 5. Assert expected values + uint256 queuedSlashableSharesAfter = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + uint256 operatorSharesAfter = delegationManager.operatorShares(operator, strategyMock); + assertEq(queuedSlashableSharesBefore, 0, "there should be no slashable shares in queue"); + assertEq(queuedSlashableSharesAfter, 0, "there should be no slashable shares in queue"); + assertEq(operatorSharesAfter, operatorSharesBefore - sharesToBurn, "operator shares should be decreased by sharesToBurn"); + } + + /** + * @notice Test burning shares for an operator with slashable queued withdrawals in past MIN_WITHDRAWAL_DELAY_BLOCKS window. + * There exists a single withdrawal that is slashable. + */ + function testFuzz_burnOperatorShares_SingleSlashableWithdrawal(Randomness r) public { + // 1. Randomize operator and staker info + // Operator info + address operator = r.Address(); + uint64 newMagnitude = 25e16; + // First staker + address staker1 = r.Address(); + uint256 shares = r.Uint256(1, MAX_STRATEGY_SHARES); + // Second Staker, will queue withdraw shares + address staker2 = r.Address(); + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + uint256 withdrawAmount = r.Uint256(1, depositAmount); + + // 2. Register the operator, set the staker deposits, and delegate the 2 stakers to them + _registerOperatorWithBaseDetails(operator); + { + // Set the first staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory sharesArray = shares.toArrayU256(); + uint256[] memory depositArray = depositAmount.toArrayU256(); + strategyManagerMock.setDeposits(staker1, strategyArray, sharesArray); + // Set the second staker's deposits in the strategies + strategyManagerMock.setDeposits(staker2, strategyArray, depositArray); + } + _delegateToOperatorWhoAcceptsAllStakers(staker1, operator); + _delegateToOperatorWhoAcceptsAllStakers(staker2, operator); + + // 3. Queue withdrawal for staker2 so that the withdrawal is slashable + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams,, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker2, + withdrawer: staker2, + strategy: strategyMock, + depositSharesToWithdraw: withdrawAmount + }); + cheats.prank(staker2); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + withdrawAmount, + "there should be withdrawAmount slashable shares in queue" + ); + } + + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + // calculate burned shares, should be 3/4 of the original shares + // staker2 queue withdraws shares + // Therefore amount of shares to burn should be what the staker still has remaining + staker1 shares and then + // divided by 2 since the operator was slashed 50% + uint256 sharesToDecrease = (shares + depositAmount - withdrawAmount) * 3 / 4; + uint256 sharesToBurn = sharesToDecrease + withdrawAmount * 3 / 4; + + // 4. Burn shares + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToDecrease); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: WAD, + newMaxMagnitude: newMagnitude + }); + + // 5. Assert expected values + uint256 queuedSlashableSharesAfter = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + uint256 operatorSharesAfter = delegationManager.operatorShares(operator, strategyMock); + assertEq(queuedSlashableSharesBefore, withdrawAmount, "Slashable shares in queue should be full withdraw amount"); + assertEq(queuedSlashableSharesAfter, withdrawAmount / 4, "Slashable shares in queue should be 1/4 withdraw amount after slashing"); + assertEq(operatorSharesAfter, operatorSharesBefore - sharesToDecrease, "operator shares should be decreased by sharesToBurn"); + } + + /** + * @notice Test burning shares for an operator with slashable queued withdrawals in past MIN_WITHDRAWAL_DELAY_BLOCKS window. + * There exists multiple withdrawals that are slashable. + */ + function testFuzz_burnOperatorShares_MultipleSlashableWithdrawals(Randomness r) public { + // 1. Randomize operator and staker info + // Operator info + address operator = r.Address(); + uint64 newMagnitude = 25e16; + // Staker and withdrawing amounts + address staker = r.Address(); + uint256 depositAmount = r.Uint256(3, MAX_STRATEGY_SHARES); + uint256 withdrawAmount1 = r.Uint256(2, depositAmount); + uint256 withdrawAmount2 = r.Uint256(1, depositAmount - withdrawAmount1); + + // 2. Register the operator, set the staker deposits, and delegate the 2 stakers to them + _registerOperatorWithBaseDetails(operator); + { + // Set the first staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory sharesArray = depositAmount.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategyArray, sharesArray); + } + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + + // 3. Queue withdrawal for staker and roll blocks forward so that the withdrawal is not slashable + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: withdrawAmount1 + }); + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + withdrawAmount1, + "there should be withdrawAmount slashable shares in queue" + ); + + ( + queuedWithdrawalParams, + withdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: withdrawAmount2 + }); + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + withdrawAmount2 + withdrawAmount1, + "there should be withdrawAmount slashable shares in queue" + ); + } + + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + // calculate burned shares, should be halved for both operatorShares and slashable shares in queue + // staker queue withdraws shares twice and both withdrawals should be slashed 75%. + uint256 sharesToDecrease = (depositAmount - withdrawAmount1 - withdrawAmount2) * 3 / 4; + uint256 sharesToBurn = sharesToDecrease + (delegationManager.getSlashableSharesInQueue(operator, strategyMock) * 3 / 4); + + // 4. Burn shares + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToDecrease); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: WAD, + newMaxMagnitude: newMagnitude + }); + + // 5. Assert expected values + uint256 queuedSlashableSharesAfter = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + uint256 operatorSharesAfter = delegationManager.operatorShares(operator, strategyMock); + assertEq(queuedSlashableSharesBefore, (withdrawAmount1 + withdrawAmount2), "Slashable shares in queue should be full withdraw amount"); + assertEq(queuedSlashableSharesAfter, (withdrawAmount1 + withdrawAmount2) / 4, "Slashable shares in queue should be 1/4 withdraw amount after slashing"); + assertEq(operatorSharesAfter, operatorSharesBefore - sharesToDecrease, "operator shares should be decreased by sharesToBurn"); + } + + /** + * @notice TODO Test burning shares for an operator with slashable queued withdrawals in past MIN_WITHDRAWAL_DELAY_BLOCKS window. + * There exists multiple withdrawals that are slashable but queued with different maxMagnitudes at + * time of queuing. + * + * Test Setup: + * - staker1 deposits, queues withdrawal for some amount, + * - operator slashed 50% + * - staker 2 deposits, queues withdrawal for some amount + * - operator is then slashed another 50% + * slashed amount for staker 1 should be 75% and staker 2 should be 50% where the total + * slashed amount is the sum of both + */ + function testFuzz_burnOperatorShares_MultipleWithdrawalsMultipleSlashings(Randomness r) public { + address operator = r.Address(); + address staker = r.Address(); + uint256 depositAmount = r.Uint256(3, MAX_STRATEGY_SHARES); + uint256 depositSharesToWithdraw1 = r.Uint256(1, depositAmount); + uint256 depositSharesToWithdraw2 = r.Uint256(1, depositAmount - depositSharesToWithdraw1); + + uint64 newMagnitude = 5e17; + + // 2. Register the operator, set the staker deposits, and delegate the 2 stakers to them + _registerOperatorWithBaseDetails(operator); + { + // Set the first staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory depositArray = depositAmount.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategyArray, depositArray); + } + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + + // 3. Queue withdrawal for staker and slash operator for 50% + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams,, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: depositSharesToWithdraw1 + }); + + // 3.1 queue a withdrawal for the staker + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + uint256 sharesToDecrease = (depositAmount - depositSharesToWithdraw1) / 2; + uint256 sharesToBurn = sharesToDecrease + depositSharesToWithdraw1/2; + + // 3.2 Burn shares + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToDecrease); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: WAD, + newMaxMagnitude: newMagnitude + }); + + // 3.3 Assert slashable shares and operator shares + assertEq( + queuedSlashableSharesBefore, + depositSharesToWithdraw1, + "Slashable shares in queue should be full withdraw1 amount" + ); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + depositSharesToWithdraw1 / 2, + "Slashable shares in queue should be 1/2 withdraw1 amount after slashing" + ); + assertEq( + delegationManager.operatorShares(operator, strategyMock), + operatorSharesBefore - sharesToDecrease, + "operator shares should be decreased by sharesToBurn" + ); + } + + // 4. Queue withdrawal for staker and slash operator for 50% again + newMagnitude = newMagnitude/2; + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams,, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: depositSharesToWithdraw2 + }); + + // actual withdrawn shares are half of the deposit shares because of first slashing + uint256 withdrawAmount2 = depositSharesToWithdraw2 / 2; + + // 4.1 queue a withdrawal for the staker + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + uint256 queuedSlashableSharesBefore = delegationManager.getSlashableSharesInQueue(operator, strategyMock); + + uint256 sharesToDecrease = operatorSharesBefore / 2; + uint256 sharesToBurn = sharesToDecrease + (withdrawAmount2 + depositSharesToWithdraw1/2)/2; + + // 4.2 Burn shares + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, sharesToDecrease); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, sharesToBurn); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: newMagnitude*2, + newMaxMagnitude: newMagnitude + }); + + // 4.3 Assert slashable shares and operator shares + assertEq( + queuedSlashableSharesBefore, + withdrawAmount2 + depositSharesToWithdraw1/2, + "Slashable shares in queue before should be withdrawAmount1 / 2 + withdrawAmount2" + ); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + (withdrawAmount2 + depositSharesToWithdraw1/2)/2, + "Slashable shares in queue should be (withdrawAmount2 + depositSharesToWithdraw1/2)/2 after slashing" + ); + assertEq( + delegationManager.operatorShares(operator, strategyMock), + operatorSharesBefore - sharesToDecrease, + "operator shares should be decreased by sharesToBurn" + ); + } + + } + + /** + * @notice Ensure that when a withdrawal is completable then there are no slashable shares in the queue. + * However if the withdrawal is not completable and the withdrawal delay hasn't elapsed, then the withdrawal + * should be counted as slashable. + */ + function testFuzz_burnOperatorShares_Timings(Randomness r) public { + // 1. Randomize operator and staker info + // Operator info + address operator = r.Address(); + uint64 newMagnitude = 25e16; + // staker + address staker = r.Address(); + uint256 depositAmount = r.Uint256(1, MAX_STRATEGY_SHARES); + + // 2. Register the operator, set the staker deposits, and delegate the staker to them + _registerOperatorWithBaseDetails(operator); + { + // Set the first staker deposits in the strategies + IStrategy[] memory strategyArray = strategyMock.toArray(); + uint256[] memory depositArray = depositAmount.toArrayU256(); + strategyManagerMock.setDeposits(staker, strategyArray, depositArray); + } + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + + // 3. Queue withdrawal for staker and roll blocks forward so that the withdrawal is completable + uint256 completableBlock; + { + ( + QueuedWithdrawalParams[] memory queuedWithdrawalParams, + Withdrawal memory withdrawal, + ) = _setUpQueueWithdrawalsSingleStrat({ + staker: staker, + withdrawer: staker, + strategy: strategyMock, + depositSharesToWithdraw: depositAmount + }); + cheats.startPrank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + // 3.1 after queuing the withdrawal, check that there are slashable shares in queue + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + depositAmount, + "there should be depositAmount slashable shares in queue" + ); + // Check slashable shares in queue before and when the withdrawal is completable + completableBlock = withdrawal.startBlock + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS(); + IERC20[] memory tokenArray = strategyMock.underlyingToken().toArray(); + + // 3.2 roll to right before withdrawal is completable, check that slashable shares are still there + // attempting to complete a withdrawal should revert + cheats.roll(completableBlock - 1); + cheats.expectRevert(WithdrawalDelayNotElapsed.selector); + delegationManager.completeQueuedWithdrawal(withdrawal, tokenArray, true); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + depositAmount, + "there should still be depositAmount slashable shares in queue" + ); + + // 3.3 roll to blocknumber that the withdrawal is completable, there should be no slashable shares in queue + cheats.roll(completableBlock); + delegationManager.completeQueuedWithdrawal(withdrawal, tokenArray, true); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + 0, + "there should be no slashable shares in queue when the withdrawal is completable" + ); + + cheats.stopPrank(); + + } + + uint256 operatorSharesBefore = delegationManager.operatorShares(operator, strategyMock); + + // 4. Burn 0 shares when new magnitude is set + _setOperatorMagnitude(operator, strategyMock, newMagnitude); + cheats.prank(address(allocationManagerMock)); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesDecreased(operator, address(0), strategyMock, 0); + cheats.expectEmit(true, true, true, true, address(delegationManager)); + emit OperatorSharesBurned(operator, strategyMock, 0); + delegationManager.burnOperatorShares({ + operator: operator, + strategy: strategyMock, + prevMaxMagnitude: WAD, + newMaxMagnitude: newMagnitude + }); + + // 5. Assert expected values + uint256 operatorSharesAfter = delegationManager.operatorShares(operator, strategyMock); + assertEq( + delegationManager.getSlashableSharesInQueue(operator, strategyMock), + 0, + "there should still be no slashable shares in queue after burning 0 shares" + ); + assertEq(operatorSharesAfter, operatorSharesBefore, "operator shares should be unchanged and equal to 0"); + assertEq(operatorSharesBefore, 0, "operator shares should be unchanged and equal to 0"); + } +} + +/// @notice Fuzzed Unit tests to compare totalWitdrawable shares for an operator vs their actual operatorShares. +/// Requires the WRITE_CSV_TESTS env variable to be set to true to output to a test file +contract DelegationManagerUnitTests_SharesUnderflowChecks is DelegationManagerUnitTests { + using SlashingLib for *; + + /** + * @notice Fuzzed tests + * Single staker with fuzzed starting shares and magnitude. + * Slash 100 magnitude and deposit 100 shares for 100 iterations. + */ + /// forge-config: default.fuzz.runs = 50 + function testFuzz_slashDepositRepeatedly( + uint64 initMagnitude, + uint256 shares + ) public { + initMagnitude = uint64(bound(initMagnitude, 10000, WAD)); + shares = bound(shares, 1, MAX_STRATEGY_SHARES); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + + // register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + { + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; + + strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); + } + + // delegate from the `defaultStaker` to the operator + _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); - // Randomly set strategy true for thirdPartyTransfersForbidden - uint256 randStrategyIndex = randSalt % strategies.length; - strategyManagerMock.setThirdPartyTransfersForbidden(strategies[randStrategyIndex], true); - _registerOperatorWithBaseDetails(defaultOperator); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - ( - IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, - IDelegationManager.Withdrawal memory withdrawal, - bytes32 withdrawalRoot - ) = _setUpQueueWithdrawals({ - staker: staker, - withdrawer: staker, - strategies: strategies, - withdrawalAmounts: withdrawalAmounts - }); - // Before queueWithdrawal state values - uint256 nonceBefore = delegationManager.cumulativeWithdrawalsQueued(staker); - assertEq(delegationManager.delegatedTo(staker), defaultOperator, "staker should be delegated to operator"); - uint256[] memory delegatedSharesBefore = new uint256[](strategies.length); - for (uint256 i = 0; i < strategies.length; i++) { - delegatedSharesBefore[i] = delegationManager.operatorShares(defaultOperator, strategies[i]); + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + uint256 newDepositShares = shares; + for (uint256 i = 0; i < 100; ++i) { + + // 1. slash operator for 100 magnitude + uint64 slashMagnitude = 100; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + + // 2. deposit again + uint256 sharesIncrease = 1000; + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(defaultStaker, strategyMock, newDepositShares, sharesIncrease); + newDepositShares += sharesIncrease; + + uint256[] memory newDepositSharesArray = new uint256[](1); + newDepositSharesArray[0] = newDepositShares; + + strategyManagerMock.setDeposits(defaultStaker, strategies, newDepositSharesArray); + } } - // queueWithdrawals - cheats.prank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit WithdrawalQueued(withdrawalRoot, withdrawal); - delegationManager.queueWithdrawals(queuedWithdrawalParams); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertLe( + withdrawableShares[0], + delegationManager.operatorShares(defaultOperator, strategyMock), + "withdrawableShares should be less than or equal to operatorShares" + ); - // Post queueWithdrawal state values - for (uint256 i = 0; i < strategies.length; i++) { - assertEq( - delegatedSharesBefore[i] - withdrawalAmounts[i], // Shares before - withdrawal amount - delegationManager.operatorShares(defaultOperator, strategies[i]), // Shares after - "delegated shares not decreased correctly" + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", + cheats.toString(shares), ", ", + cheats.toString(delegationManager.operatorShares(defaultOperator, strategyMock)), ", ", + cheats.toString(withdrawableShares[0]), ", ", + cheats.toString(stdMath.delta(delegationManager.operatorShares(defaultOperator, strategyMock), withdrawableShares[0])) + )) ); } - uint256 nonceAfter = delegationManager.cumulativeWithdrawalsQueued(staker); - assertEq(nonceBefore + 1, nonceAfter, "staker nonce should have incremented"); } /** - * @notice Randomly selects one of the strategies to set thirdPartyTransfersForbidden to true. - * Verifies that `DelegationManager.queueWithdrawals` properly reverts a queuedWithdrawal since the `withdrawer` - * is not the same as the `staker`. + * @notice Fuzzed tests + * Single staker with fuzzed starting shares and magnitude. + * Slash 100 magnitude and fuzz deposit amount for 100 iterations. */ - function testFuzz_queueWithdrawal_Revert_WhenThirdPartyTransfersForbidden( - address staker, - address withdrawer, - uint256[] memory depositAmounts, - uint256 randSalt - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != withdrawer && staker != defaultOperator); - cheats.assume(depositAmounts.length > 0 && depositAmounts.length <= 32); - uint256[] memory withdrawalAmounts = _fuzzWithdrawalAmounts(depositAmounts); - - IStrategy[] memory strategies = _deployAndDepositIntoStrategies(staker, depositAmounts); - // Randomly set strategy true for thirdPartyTransfersForbidden - uint256 randStrategyIndex = randSalt % strategies.length; - strategyManagerMock.setThirdPartyTransfersForbidden(strategies[randStrategyIndex], true); + /// forge-config: default.fuzz.runs = 50 + function testFuzz_slashDepositRepeatedly_randDeposits( + uint64 initMagnitude, + uint256 shares, + uint256 depositAmount + ) public { + initMagnitude = uint64(bound(initMagnitude, 10000, WAD)); + depositAmount = bound(depositAmount, 1, 1e34); + shares = bound(shares, 1, MAX_STRATEGY_SHARES / 1e4); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + + // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - (IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams, , ) = _setUpQueueWithdrawals({ - staker: staker, - withdrawer: withdrawer, - strategies: strategies, - withdrawalAmounts: withdrawalAmounts - }); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + { + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; - // queueWithdrawals - // NOTE: Originally, you could queue a withdrawal to a different address, which would fail with a specific error - // if third party transfers were forbidden. Now, withdrawing to a different address is forbidden regardless - // of third party transfer status. - cheats.expectRevert( - "DelegationManager.queueWithdrawal: withdrawer must be staker" - ); - cheats.prank(staker); - delegationManager.queueWithdrawals(queuedWithdrawalParams); - } -} + strategyManagerMock.setDeposits(defaultStaker, strategies, sharesToSet); + } -contract DelegationManagerUnitTests_completeQueuedWithdrawal is DelegationManagerUnitTests { - function test_Revert_WhenExitWithdrawalQueuePaused() public { - cheats.prank(pauser); - delegationManager.pause(2 ** PAUSED_EXIT_WITHDRAWAL_QUEUE); - _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - /* bytes32 withdrawalRoot */ - ) = _setUpCompleteQueuedWithdrawalSingleStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmount: 100, - withdrawalAmount: 100 - }); + // delegate from the `defaultStaker` to the operator _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); - cheats.expectRevert("Pausable: index is paused"); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); - } - function test_Revert_WhenInvalidWithdrawalRoot() public { - _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - bytes32 withdrawalRoot - ) = _setUpCompleteQueuedWithdrawalSingleStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmount: 100, - withdrawalAmount: 100 - }); - _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + uint256 newDepositShares = shares; + for (uint256 i = 0; i < 100; ++i) { + + // 1. slash operator for 100 magnitude + uint64 slashMagnitude = 100; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + + // 2. deposit again + cheats.prank(address(strategyManagerMock)); + delegationManager.increaseDelegatedShares(defaultStaker, strategyMock, newDepositShares, depositAmount); + newDepositShares += depositAmount; + + uint256[] memory newDepositSharesArray = new uint256[](1); + newDepositSharesArray[0] = newDepositShares; + + strategyManagerMock.setDeposits(defaultStaker, strategies, newDepositSharesArray); + } + } - assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); - cheats.prank(defaultStaker); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); - assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(defaultStaker, strategies); + assertLe( + withdrawableShares[0], + delegationManager.operatorShares(defaultOperator, strategyMock), + "withdrawableShares should be less than or equal to operatorShares" + ); - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); - cheats.expectRevert("DelegationManager._completeQueuedWithdrawal: action is not in queue"); - cheats.prank(defaultStaker); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test2.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", + cheats.toString(shares), ", ", + cheats.toString(depositAmount), ", ", + cheats.toString(delegationManager.operatorShares(defaultOperator, strategyMock)), ", ", + cheats.toString(withdrawableShares[0]), ", ", + cheats.toString(stdMath.delta(delegationManager.operatorShares(defaultOperator, strategyMock), withdrawableShares[0])) + )) + ); + } } + /** - * @notice should revert if minWithdrawalDelayBlocks has not passed, and if - * delegationManager.getWithdrawalDelay returns a value greater than minWithdrawalDelayBlocks - * then it should revert if the validBlockNumber has not passed either. + * @notice Fuzzed tests + * For 500 stakers, deposit `shares` amount and delegate to the operator. After each staker delegates, + * slash 100 magnitude. */ - function test_Revert_WhenWithdrawalDelayBlocksNotPassed( - uint256[] memory depositAmounts, - bool receiveAsTokens + /// forge-config: default.fuzz.runs = 50 + function testFuzz_depositMultipleStakers_slash_repeatedly( + uint64 initMagnitude, + uint256 shares ) public { - cheats.assume(depositAmounts.length > 0 && depositAmounts.length <= 32); - uint256[] memory withdrawalAmounts = _fuzzWithdrawalAmounts(depositAmounts); - + initMagnitude = uint64(bound(initMagnitude, 50000, WAD)); + shares = bound(shares, MAX_STRATEGY_SHARES / 1e7, MAX_STRATEGY_SHARES / 1e4); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + + // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - /* bytes32 withdrawalRoot */ - ) = _setUpCompleteQueuedWithdrawal({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmounts: depositAmounts, - withdrawalAmounts: withdrawalAmounts - }); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; - // prank as withdrawer address - cheats.startPrank(defaultStaker); + uint256 numStakers = 500; + + address[] memory stakers = new address[](numStakers); + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + for (uint256 i = 0; i < numStakers; ++i) { + // 1. deposit and delegate new staker + stakers[i] = random().Address(); + strategyManagerMock.setDeposits(stakers[i], strategies, sharesToSet); + _delegateToOperatorWhoAcceptsAllStakers(stakers[i], defaultOperator); + + // 2. slash operator for 100 magnitude + uint64 slashMagnitude = 100; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + } + } - cheats.expectRevert( - "DelegationManager._completeQueuedWithdrawal: minWithdrawalDelayBlocks period has not yet passed" + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 totalWithdrawableShares = 0; + for (uint256 i = 0; i < numStakers; ++i) { + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + totalWithdrawableShares += withdrawableShares[0]; + } + assertLe( + totalWithdrawableShares, + operatorSharesAfter, + "withdrawableShares should be less than or equal to operatorShares" ); - cheats.roll(block.number + minWithdrawalDelayBlocks - 1); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, receiveAsTokens); - uint256 validBlockNumber = delegationManager.getWithdrawalDelay(withdrawal.strategies); - if (validBlockNumber > minWithdrawalDelayBlocks) { - cheats.expectRevert( - "DelegationManager._completeQueuedWithdrawal: withdrawalDelayBlocks period has not yet passed for this strategy" + + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test3.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", // initial magnitude + cheats.toString(shares), ", ", // amount each staker deposits + cheats.toString(operatorSharesAfter), ", ", // operator shares after all slashing and deposits + cheats.toString(totalWithdrawableShares), ", ", // total withdrawable shares from all stakers + cheats.toString(stdMath.delta(operatorSharesAfter, totalWithdrawableShares)) // delta difference between opShares and total withdrawable + )) ); - cheats.roll(validBlockNumber - 1); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, receiveAsTokens); } - - cheats.stopPrank(); } /** - * @notice should revert when the withdrawalDelayBlocks period has not yet passed for the - * beacon chain strategy + * @notice Fuzzed tests + * For 500 stakers, deposit `shares` amount and delegate to the operator. After each staker delegates, + * slash 1000 magnitude. Initial magnitude is very small so this will slash larger proportions. */ - function test_Revert_WhenWithdrawalDelayBlocksNotPassed_BeaconStrat( - uint256 depositAmount, - uint256 withdrawalAmount, - uint256 beaconWithdrawalDelay + /// forge-config: default.fuzz.runs = 50 + function testFuzz_depositMultipleStakers_slashLargeMagnitudes( + uint64 initMagnitude, + uint256 shares ) public { - cheats.assume(depositAmount > 1 && withdrawalAmount <= depositAmount); - beaconWithdrawalDelay = bound(beaconWithdrawalDelay, minWithdrawalDelayBlocks, MAX_WITHDRAWAL_DELAY_BLOCKS); - _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - - ) = _setUpCompleteQueuedWithdrawalBeaconStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmount: depositAmount, - withdrawalAmount: withdrawalAmount - }); + initMagnitude = uint64(bound(initMagnitude, 50000, WAD)); + shares = bound(shares, MAX_STRATEGY_SHARES / 1e7, MAX_STRATEGY_SHARES / 1e4); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + // register *this contract* as an operator + _registerOperatorWithBaseDetails(defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = beaconChainETHStrategy; - uint256[] memory withdrawalDelayBlocks = new uint256[](1); - delegationManager.setStrategyWithdrawalDelayBlocks(withdrawal.strategies, withdrawalDelayBlocks); + strategies[0] = strategyMock; + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; - // prank as withdrawer address - cheats.startPrank(defaultStaker); + uint256 numStakers = 500; + + address[] memory stakers = new address[](numStakers); + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + for (uint256 i = 0; i < numStakers; ++i) { + + // 1. deposit and delegate new staker + stakers[i] = random().Address(); + strategyManagerMock.setDeposits(stakers[i], strategies, sharesToSet); + _delegateToOperatorWhoAcceptsAllStakers(stakers[i], defaultOperator); + + // 2. slash operator for 100 magnitude + uint64 slashMagnitude = 100; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + } + } - cheats.expectRevert( - "DelegationManager._completeQueuedWithdrawal: minWithdrawalDelayBlocks period has not yet passed" + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 totalWithdrawableShares = 0; + for (uint256 i = 0; i < numStakers; ++i) { + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + totalWithdrawableShares += withdrawableShares[0]; + } + assertLe( + totalWithdrawableShares, + operatorSharesAfter, + "withdrawableShares should be less than or equal to operatorShares" ); - cheats.roll(block.number + minWithdrawalDelayBlocks - 1); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); - uint256 validBlockNumber = delegationManager.getWithdrawalDelay(withdrawal.strategies); - if (validBlockNumber > minWithdrawalDelayBlocks) { - cheats.expectRevert( - "DelegationManager._completeQueuedWithdrawal: withdrawalDelayBlocks period has not yet passed for this strategy" + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test4.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", // initial magnitude + cheats.toString(shares), ", ", // amount each staker deposits + cheats.toString(operatorSharesAfter), ", ", // operator shares after all slashing and deposits + cheats.toString(totalWithdrawableShares), ", ", // total withdrawable shares from all stakers + cheats.toString(stdMath.delta(operatorSharesAfter, totalWithdrawableShares)) // delta difference between opShares and total withdrawable + )) ); - cheats.roll(validBlockNumber - 1); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); } - - cheats.stopPrank(); } - function test_Revert_WhenNotCalledByWithdrawer() public { + /** + * @notice Same as above `testFuzz_depositMultipleStakers_slashLargeMagnitudes` test but with slashing + * 1 magnitude instead of 100. + */ + /// forge-config: default.fuzz.runs = 50 + function testFuzz_depositMultipleStakers_slashSmallMagnitudes( + uint64 initMagnitude, + uint256 shares + ) public { + initMagnitude = uint64(bound(initMagnitude, 1000, WAD)); + shares = bound(shares, MAX_STRATEGY_SHARES / 1e7, MAX_STRATEGY_SHARES / 1e4); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + + // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - /*bytes32 withdrawalRoot*/ - ) = _setUpCompleteQueuedWithdrawalSingleStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmount: 100, - withdrawalAmount: 100 - }); - _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); - cheats.expectRevert("DelegationManager._completeQueuedWithdrawal: only withdrawer can complete action"); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); - } + uint256 numStakers = 500; - function test_Revert_WhenTokensArrayLengthMismatch() public { - _registerOperatorWithBaseDetails(defaultOperator); - (IDelegationManager.Withdrawal memory withdrawal, , ) = _setUpCompleteQueuedWithdrawalSingleStrat({ - staker: defaultStaker, - withdrawer: defaultStaker, - depositAmount: 100, - withdrawalAmount: 100 - }); - _delegateToOperatorWhoAcceptsAllStakers(defaultStaker, defaultOperator); + address[] memory stakers = new address[](numStakers); + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + for (uint256 i = 0; i < numStakers; ++i) { + + // 1. deposit and delegate new staker + stakers[i] = random().Address(); + strategyManagerMock.setDeposits(stakers[i], strategies, sharesToSet); + _delegateToOperatorWhoAcceptsAllStakers(stakers[i], defaultOperator); + + // 2. slash operator for 100 magnitude + uint64 slashMagnitude = 1; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + } + } - IERC20[] memory tokens = new IERC20[](0); - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); - cheats.expectRevert("DelegationManager._completeQueuedWithdrawal: input length mismatch"); - cheats.prank(defaultStaker); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, true); + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 totalWithdrawableShares = 0; + for (uint256 i = 0; i < numStakers; ++i) { + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + totalWithdrawableShares += withdrawableShares[0]; + } + assertLe( + totalWithdrawableShares, + operatorSharesAfter, + "withdrawableShares should be less than or equal to operatorShares" + ); + + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test5.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", // initial magnitude + cheats.toString(shares), ", ", // amount each staker deposits + cheats.toString(operatorSharesAfter), ", ", // operator shares after all slashing and deposits + cheats.toString(totalWithdrawableShares), ", ", // total withdrawable shares from all stakers + cheats.toString(stdMath.delta(operatorSharesAfter, totalWithdrawableShares)) // delta difference between opShares and total withdrawable + )) + ); + } } /** - * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` - * for a single strategy. Withdraws as tokens so there are no operator shares increase. - * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after - * - Asserts operatorShares is unchanged after `completeQueuedWithdrawal` - * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot + * @notice Setup 500 delegated stakers who each deposit `shares` amount. + * Then slash 1 magnitude 500 times and then compare amount of shares that can be withdrawn vs operatorShares */ - function test_completeQueuedWithdrawal_SingleStratWithdrawAsTokens( - address staker, - uint256 depositAmount, - uint256 withdrawalAmount - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); + /// forge-config: default.fuzz.runs = 50 + function testFuzz_depositMultipleStakersOnce_slashSmallMagnitudes( + uint64 initMagnitude, + uint256 shares + ) public { + initMagnitude = uint64(bound(initMagnitude, 1000, WAD)); + shares = bound(shares, MAX_STRATEGY_SHARES / 1e7, MAX_STRATEGY_SHARES / 1e4); + cheats.assume(initMagnitude % 2 != 0); + cheats.assume(shares % 2 != 0); + + // register *this contract* as an operator _registerOperatorWithBaseDetails(defaultOperator); - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - bytes32 withdrawalRoot - ) = _setUpCompleteQueuedWithdrawalSingleStrat({ - staker: staker, - withdrawer: staker, - depositAmount: depositAmount, - withdrawalAmount: withdrawalAmount - }); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); - assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + _setOperatorMagnitude(defaultOperator, strategyMock, initMagnitude); + + // Set the staker deposits in the strategies + IStrategy[] memory strategies = new IStrategy[](1); + strategies[0] = strategyMock; + uint256[] memory sharesToSet = new uint256[](1); + sharesToSet[0] = shares; - // completeQueuedWithdrawal - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); - cheats.prank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit WithdrawalCompleted(withdrawalRoot); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, true); + uint256 numStakers = 500; - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); - assertEq(operatorSharesAfter, operatorSharesBefore, "operator shares should be unchanged"); - assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + address[] memory stakers = new address[](numStakers); + // deposit all stakers one time + for (uint256 i = 0; i < numStakers; ++i) { + + // 1. deposit and delegate new staker + stakers[i] = random().Address(); + strategyManagerMock.setDeposits(stakers[i], strategies, sharesToSet); + _delegateToOperatorWhoAcceptsAllStakers(stakers[i], defaultOperator); + } + + // Slash and deposit more for each iteration + uint64 currMagnitude = initMagnitude; + { + for (uint256 i = 0; i < numStakers; ++i) { + + // 2. slash operator for 100 magnitude + uint64 slashMagnitude = 1; + currMagnitude -= slashMagnitude; + _setOperatorMagnitude(defaultOperator, strategyMock, currMagnitude); + cheats.prank(address(allocationManagerMock)); + delegationManager.burnOperatorShares({ + operator: defaultOperator, + strategy: strategyMock, + prevMaxMagnitude: currMagnitude + slashMagnitude, + newMaxMagnitude: currMagnitude + }); + } + } + + uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, strategyMock); + uint256 totalWithdrawableShares = 0; + for (uint256 i = 0; i < numStakers; ++i) { + (uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(stakers[i], strategies); + totalWithdrawableShares += withdrawableShares[0]; + } + assertLe( + totalWithdrawableShares, + operatorSharesAfter, + "withdrawableShares should be less than or equal to operatorShares" + ); + + if (cheats.envOr("WRITE_CSV_TESTS", false)) { + cheats.writeLine( + "./test6.csv", + string(abi.encodePacked( + cheats.toString(initMagnitude), ", ", // initial magnitude + cheats.toString(shares), ", ", // amount each staker deposits + cheats.toString(operatorSharesAfter), ", ", // operator shares after all slashing and deposits + cheats.toString(totalWithdrawableShares), ", ", // total withdrawable shares from all stakers + cheats.toString(stdMath.delta(operatorSharesAfter, totalWithdrawableShares)) // delta difference between opShares and total withdrawable + )) + ); + } } +} - /** - * @notice Verifies that `DelegationManager.completeQueuedWithdrawal` properly completes a queued withdrawal for the `withdrawer` - * for a single strategy. Withdraws as shares so if the withdrawer is delegated, operator shares increase. In the test case, this only - * happens if staker and withdrawer are fuzzed the same address (i.e. staker == withdrawer) - * - Asserts that the withdrawalRoot is True before `completeQueuedWithdrawal` and False after - * - Asserts if staker == withdrawer, operatorShares increase, otherwise operatorShares are unchanged - * - Checks that event `WithdrawalCompleted` is emitted with withdrawalRoot - */ - function test_completeQueuedWithdrawal_SingleStratWithdrawAsShares( - address staker, - uint256 depositAmount, - uint256 withdrawalAmount - ) public filterFuzzedAddressInputs(staker) { - cheats.assume(staker != defaultOperator); - cheats.assume(withdrawalAmount > 0 && withdrawalAmount <= depositAmount); - _registerOperatorWithBaseDetails(defaultOperator); +/** + * @notice TODO Lifecycle tests - These tests combine multiple functionalities of the DelegationManager + 1. Old SigP test - registerAsOperator, separate staker delegate to operator, as operator undelegate (reverts), + checks that staker is still delegated and operator still registered, staker undelegates, checks staker not delegated and operator + is still registered + 2. RegisterOperator, Deposit, Delegate, Queue, Complete + 3. RegisterOperator, Mock Slash(set maxMagnitudes), Deposit/Delegate, Queue, Complete + 4. RegisterOperator, Deposit/Delegate, Mock Slash(set maxMagnitudes), Queue, Complete + 5. RegisterOperator, Mock Slash(set maxMagnitudes), Deposit/Delegate, Queue, Mock Slash(set maxMagnitudes), Complete + 7. RegisterOperator, Deposit/Delegate, Mock Slash 100% (set maxMagnitudes), Undelegate, Complete non 100% slashed strategies + 8. RegisterOperator, Deposit/Delegate, Undelegate, Re delegate to another operator, Mock Slash 100% (set maxMagnitudes), Complete as shares + (withdrawals should have been slashed even though delegated to a new operator) + 9. Invariant check getWithdrawableShares = sum(deposits), Multiple deposits with operator who has never been slashed + 10. Invariant check getWithdrawableShares = sum(deposits), Multiple deposits with operator who HAS been been slashed + */ - ( - IDelegationManager.Withdrawal memory withdrawal, - IERC20[] memory tokens, - bytes32 withdrawalRoot - ) = _setUpCompleteQueuedWithdrawalSingleStrat({ +contract DelegationManagerUnitTests_Lifecycle is DelegationManagerUnitTests { + using SingleItemArrayLib for *; + + // 2. RegisterOperator, Deposit, Delegate, Queue, Complete + function test_register_operator_deposit_delegate_queue_complete(Randomness r) public rand(r) { + address operator = r.Address(); + address staker = r.Address(); + IStrategy[] memory strategies = strategyMock.toArray(); + uint256[] memory depositShares = uint256(100 ether).toArrayU256(); + + // 1) Register operator. + _registerOperatorWithBaseDetails(operator); + + // 2) Mock deposit into SM. + strategyManagerMock.setDeposits(staker, strategies, depositShares); + + // 3) Staker delegates to operator. + _delegateToOperatorWhoAcceptsAllStakers(staker, operator); + + // 3) Staker queues withdrawals. + QueuedWithdrawalParams[] memory queuedWithdrawalParams = new QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = QueuedWithdrawalParams({ + strategies: strategies, + depositShares: depositShares, + withdrawer: staker + }); + cheats.prank(staker); + delegationManager.queueWithdrawals(queuedWithdrawalParams); + + // 4) Complete queued withdrawals. + Withdrawal memory withdrawal = Withdrawal({ staker: staker, + delegatedTo: operator, withdrawer: staker, - depositAmount: depositAmount, - withdrawalAmount: withdrawalAmount + nonce: 0, + startBlock: uint32(block.number), + strategies: strategies, + scaledShares: depositShares }); - _delegateToOperatorWhoAcceptsAllStakers(staker, defaultOperator); - uint256 operatorSharesBefore = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); + + bytes32 withdrawalRoot = keccak256(abi.encode(withdrawal)); assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be pending"); + cheats.roll(block.number + delegationManager.MIN_WITHDRAWAL_DELAY_BLOCKS()); - // completeQueuedWithdrawal - cheats.roll(block.number + delegationManager.getWithdrawalDelay(withdrawal.strategies)); cheats.prank(staker); - cheats.expectEmit(true, true, true, true, address(delegationManager)); - emit WithdrawalCompleted(withdrawalRoot); - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, 0 /* middlewareTimesIndex */, false); + delegationManager.completeQueuedWithdrawal(withdrawal, tokenMock.toArray(), false); - uint256 operatorSharesAfter = delegationManager.operatorShares(defaultOperator, withdrawal.strategies[0]); - // Since staker is delegated, operatorShares get incremented - assertEq(operatorSharesAfter, operatorSharesBefore + withdrawalAmount, "operator shares not increased correctly"); - assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should be completed and marked false now"); + assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), "withdrawalRoot should not be pending"); + + // Checks + assertEq(delegationManager.cumulativeWithdrawalsQueued(staker), 1, "staker nonce should have incremented"); + assertEq(delegationManager.operatorShares(operator, strategies[0]), 100 ether, "operator shares should be 0 after withdrawal"); } -} +} \ No newline at end of file diff --git a/src/test/unit/EigenPodManagerUnit.t.sol b/src/test/unit/EigenPodManagerUnit.t.sol index b31d1d404..4f9bd7b18 100644 --- a/src/test/unit/EigenPodManagerUnit.t.sol +++ b/src/test/unit/EigenPodManagerUnit.t.sol @@ -1,18 +1,17 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "src/contracts/pods/EigenPodManager.sol"; import "src/contracts/pods/EigenPodPausingConstants.sol"; -import "src/test/events/IEigenPodManagerEvents.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; import "src/test/harnesses/EigenPodManagerWrapper.sol"; import "src/test/mocks/EigenPodMock.sol"; import "src/test/mocks/ETHDepositMock.sol"; -contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { +contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup, IEigenPodManagerEvents { // Contracts Under Test: EigenPodManager EigenPodManager public eigenPodManagerImplementation; EigenPodManager public eigenPodManager; @@ -30,6 +29,8 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { IEigenPod public defaultPod; address public initialOwner = address(this); + IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + function setUp() virtual override public { EigenLayerUnitTestSetup.setUp(); @@ -42,9 +43,9 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { eigenPodManagerImplementation = new EigenPodManager( ethPOSMock, eigenPodBeacon, - strategyManagerMock, - slasherMock, - delegationManagerMock + IStrategyManager(address(strategyManagerMock)), + IDelegationManager(address(delegationManagerMock)), + pauserRegistry ); eigenPodManager = EigenPodManager( address( @@ -54,7 +55,6 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { abi.encodeWithSelector( EigenPodManager.initialize.selector, initialOwner, - pauserRegistry, 0 /*initialPausedStatus*/ ) ) @@ -65,8 +65,8 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { defaultPod = eigenPodManager.getPod(defaultStaker); // Exclude the zero address, and the eigenPodManager itself from fuzzed inputs - addressIsExcludedFromFuzzedInputs[address(0)] = true; - addressIsExcludedFromFuzzedInputs[address(eigenPodManager)] = true; + isExcludedFuzzAddress[address(0)] = true; + isExcludedFuzzAddress[address(eigenPodManager)] = true; } /******************************************************************************* @@ -75,11 +75,14 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { function _initializePodWithShares(address podOwner, int256 shares) internal { // Deploy pod - IEigenPod deployedPod = _deployAndReturnEigenPodForStaker(podOwner); + _deployAndReturnEigenPodForStaker(podOwner); - // Set shares - cheats.prank(address(deployedPod)); - eigenPodManager.recordBeaconChainETHBalanceUpdate(podOwner, shares); + if (shares >= 0) { + cheats.prank(address(delegationManagerMock)); + eigenPodManager.addShares(podOwner, beaconChainETHStrategy, IERC20(address(0)), uint256(shares)); + } else { + EigenPodManagerWrapper(address(eigenPodManager)).setPodOwnerShares(podOwner, shares); + } } @@ -95,19 +98,19 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { return deployedPod; } - function _checkPodDeployed(address staker, address expectedPod, uint256 numPodsBefore) internal { + function _checkPodDeployed(address staker, address expectedPod, uint256 numPodsBefore) internal view { assertEq(address(eigenPodManager.ownerToPod(staker)), expectedPod, "Expected pod not deployed"); assertEq(eigenPodManager.numPods(), numPodsBefore + 1, "Num pods not incremented"); } } -contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitTests, IEigenPodManagerEvents { +contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitTests { /******************************************************************************* Initialization Tests *******************************************************************************/ - function test_initialization() public { + function test_initialization() public view { // Check max pods, beacon chain, owner, and pauser assertEq(eigenPodManager.owner(), initialOwner, "Initialization: owner incorrect"); assertEq(address(eigenPodManager.pauserRegistry()), address(pauserRegistry), "Initialization: pauser registry incorrect"); @@ -117,7 +120,6 @@ contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitT assertEq(address(eigenPodManager.ethPOS()), address(ethPOSMock), "Initialization: ethPOS incorrect"); assertEq(address(eigenPodManager.eigenPodBeacon()), address(eigenPodBeacon), "Initialization: eigenPodBeacon incorrect"); assertEq(address(eigenPodManager.strategyManager()), address(strategyManagerMock), "Initialization: strategyManager incorrect"); - assertEq(address(eigenPodManager.slasher()), address(slasherMock), "Initialization: slasher incorrect"); assertEq(address(eigenPodManager.delegationManager()), address(delegationManagerMock), "Initialization: delegationManager incorrect"); } @@ -125,12 +127,11 @@ contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitT cheats.expectRevert("Initializable: contract is already initialized"); eigenPodManager.initialize( initialOwner, - pauserRegistry, 0 /*initialPausedStatus*/); } } -contract EigenPodManagerUnitTests_CreationTests is EigenPodManagerUnitTests, IEigenPodManagerEvents { +contract EigenPodManagerUnitTests_CreationTests is EigenPodManagerUnitTests { function test_createPod() public { // Get expected pod address and pods before @@ -147,7 +148,7 @@ contract EigenPodManagerUnitTests_CreationTests is EigenPodManagerUnitTests, IEi } function test_createPod_revert_alreadyCreated() public deployPodForStaker(defaultStaker) { - cheats.expectRevert("EigenPodManager.createPod: Sender already has a pod"); + cheats.expectRevert(IEigenPodManagerErrors.EigenPodAlreadyExists.selector); eigenPodManager.createPod(); } } @@ -193,29 +194,21 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { function testFuzz_addShares_revert_notDelegationManager(address notDelegationManager) public filterFuzzedAddressInputs(notDelegationManager){ cheats.assume(notDelegationManager != address(delegationManagerMock)); cheats.prank(notDelegationManager); - cheats.expectRevert("EigenPodManager.onlyDelegationManager: not the DelegationManager"); - eigenPodManager.addShares(defaultStaker, 0); + cheats.expectRevert(IEigenPodManagerErrors.OnlyDelegationManager.selector); + eigenPodManager.addShares(defaultStaker, IStrategy(address(0)), IERC20(address(0)), 0); } function test_addShares_revert_podOwnerZeroAddress() public { cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.addShares: podOwner cannot be zero address"); - eigenPodManager.addShares(address(0), 0); + cheats.expectRevert(IEigenPodErrors.InputAddressZero.selector); + eigenPodManager.addShares(address(0), beaconChainETHStrategy, IERC20(address(0)), 0); } function testFuzz_addShares_revert_sharesNegative(int256 shares) public { cheats.assume(shares < 0); cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.addShares: shares cannot be negative"); - eigenPodManager.addShares(defaultStaker, uint256(shares)); - } - - function testFuzz_addShares_revert_sharesNotWholeGwei(uint256 shares) public { - cheats.assume(int256(shares) >= 0); - cheats.assume(shares % GWEI_TO_WEI != 0); - cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.addShares: shares must be a whole Gwei amount"); - eigenPodManager.addShares(defaultStaker, shares); + cheats.expectRevert(IEigenPodManagerErrors.SharesNegative.selector); + eigenPodManager.addShares(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), uint256(shares)); } function testFuzz_addShares(uint256 shares) public { @@ -226,51 +219,43 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { // Add shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.addShares(defaultStaker, shares); + eigenPodManager.addShares(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), shares); // Check storage update - assertEq(eigenPodManager.podOwnerShares(defaultStaker), int256(shares), "Incorrect number of shares added"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), int256(shares), "Incorrect number of shares added"); } /******************************************************************************* Remove Shares Tests ******************************************************************************/ - function testFuzz_removeShares_revert_notDelegationManager(address notDelegationManager) public filterFuzzedAddressInputs(notDelegationManager) { + function testFuzz_removeDepositShares_revert_notDelegationManager(address notDelegationManager) public filterFuzzedAddressInputs(notDelegationManager) { cheats.assume(notDelegationManager != address(delegationManagerMock)); cheats.prank(notDelegationManager); - cheats.expectRevert("EigenPodManager.onlyDelegationManager: not the DelegationManager"); - eigenPodManager.removeShares(defaultStaker, 0); + cheats.expectRevert(IEigenPodManagerErrors.OnlyDelegationManager.selector); + eigenPodManager.removeDepositShares(defaultStaker, beaconChainETHStrategy, 0); } - function testFuzz_removeShares_revert_sharesNegative(int256 shares) public { - cheats.assume(shares < 0); + function testFuzz_removeDepositShares_revert_sharesNegative(uint224 sharesToRemove) public { + cheats.assume(sharesToRemove > 0); cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.removeShares: shares cannot be negative"); - eigenPodManager.removeShares(defaultStaker, uint256(shares)); - } - - function testFuzz_removeShares_revert_sharesNotWholeGwei(uint256 shares) public { - cheats.assume(int256(shares) >= 0); - cheats.assume(shares % GWEI_TO_WEI != 0); - cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.removeShares: shares must be a whole Gwei amount"); - eigenPodManager.removeShares(defaultStaker, shares); + cheats.expectRevert(IEigenPodManagerErrors.SharesNegative.selector); + eigenPodManager.removeDepositShares(defaultStaker, beaconChainETHStrategy, sharesToRemove); } - function testFuzz_removeShares_revert_tooManySharesRemoved(uint224 sharesToAdd, uint224 sharesToRemove) public { + function testFuzz_removeDepositShares_revert_tooManySharesRemoved(uint224 sharesToAdd, uint224 sharesToRemove) public { // Constrain inputs cheats.assume(sharesToRemove > sharesToAdd); uint256 sharesAdded = sharesToAdd * GWEI_TO_WEI; uint256 sharesRemoved = sharesToRemove * GWEI_TO_WEI; // Initialize pod with shares - _initializePodWithShares(defaultStaker, int256(sharesAdded)); + _initializePodWithShares(defaultStaker, int256(sharesAdded)); // Remove shares cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.removeShares: cannot result in pod owner having negative shares"); - eigenPodManager.removeShares(defaultStaker, sharesRemoved); + cheats.expectRevert(IEigenPodManagerErrors.SharesNegative.selector); + eigenPodManager.removeDepositShares(defaultStaker, beaconChainETHStrategy, sharesRemoved); } function testFuzz_removeShares(uint224 sharesToAdd, uint224 sharesToRemove) public { @@ -284,13 +269,13 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { // Remove shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.removeShares(defaultStaker, sharesRemoved); + eigenPodManager.removeDepositShares(defaultStaker, beaconChainETHStrategy, sharesRemoved); // Check storage - assertEq(eigenPodManager.podOwnerShares(defaultStaker), int256(sharesAdded - sharesRemoved), "Incorrect number of shares removed"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), int256(sharesAdded - sharesRemoved), "Incorrect number of shares removed"); } - function testFuzz_removeShares_zeroShares(address podOwner, uint256 shares) public filterFuzzedAddressInputs(podOwner) { + function testFuzz_removeDepositShares_zeroShares(address podOwner, uint256 shares) public filterFuzzedAddressInputs(podOwner) { // Constrain inputs cheats.assume(podOwner != address(0)); cheats.assume(shares < type(uint256).max / 2); @@ -302,79 +287,111 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { // Remove shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.removeShares(podOwner, shares); + eigenPodManager.removeDepositShares(podOwner, beaconChainETHStrategy, shares); // Check storage update - assertEq(eigenPodManager.podOwnerShares(podOwner), 0, "Shares not reset to zero"); + assertEq(eigenPodManager.podOwnerDepositShares(podOwner), 0, "Shares not reset to zero"); } +} + +contract EigenPodManagerUnitTests_WithdrawSharesAsTokensTests is EigenPodManagerUnitTests { + // Wrapper contract that exposes the internal `_calculateChangeInDelegatableShares` function + EigenPodManagerWrapper public eigenPodManagerWrapper; + + function setUp() virtual override public { + super.setUp(); + // Upgrade eigenPodManager to wrapper + eigenPodManagerWrapper = new EigenPodManagerWrapper( + ethPOSMock, + eigenPodBeacon, + IStrategyManager(address(strategyManagerMock)), + IDelegationManager(address(delegationManagerMock)), + pauserRegistry + ); + eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); + } /******************************************************************************* WithdrawSharesAsTokens Tests ******************************************************************************/ - function test_withdrawSharesAsTokens_revert_podOwnerZeroAddress() public { + function test_withdrawSharesAsTokens_revert_invalidStrategy() public { cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.withdrawSharesAsTokens: podOwner cannot be zero address"); - eigenPodManager.withdrawSharesAsTokens(address(0), address(0), 0); + cheats.expectRevert(IEigenPodManagerErrors.InvalidStrategy.selector); + eigenPodManager.withdrawSharesAsTokens(defaultStaker, IStrategy(address(0)), IERC20(address(0)), 0); } - function test_withdrawSharesAsTokens_revert_destinationZeroAddress() public { + function test_withdrawSharesAsTokens_revert_podOwnerZeroAddress() public { cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.withdrawSharesAsTokens: destination cannot be zero address"); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, address(0), 0); + cheats.expectRevert(IEigenPodErrors.InputAddressZero.selector); + eigenPodManager.withdrawSharesAsTokens(address(0), beaconChainETHStrategy, IERC20(address(0)), 0); } function testFuzz_withdrawSharesAsTokens_revert_sharesNegative(int256 shares) public { cheats.assume(shares < 0); cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.withdrawSharesAsTokens: shares cannot be negative"); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, defaultStaker, uint256(shares)); - } - - function testFuzz_withdrawSharesAsTokens_revert_sharesNotWholeGwei(uint256 shares) public { - cheats.assume(int256(shares) >= 0); - cheats.assume(shares % GWEI_TO_WEI != 0); - - cheats.prank(address(delegationManagerMock)); - cheats.expectRevert("EigenPodManager.withdrawSharesAsTokens: shares must be a whole Gwei amount"); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, defaultStaker, shares); + cheats.expectRevert(IEigenPodManagerErrors.SharesNegative.selector); + eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), uint256(shares)); } /** * @notice The `withdrawSharesAsTokens` is called in the `completeQueuedWithdrawal` function from the - * delegationManager. When a withdrawal is queued in the delegationManager, `removeShares is called` + * delegationManager. When a withdrawal is queued in the delegationManager, `removeDepositShares is called` */ - function test_withdrawSharesAsTokens_reduceEntireDeficit() public { + function test_withdrawSharesAsTokens_m2NegativeShares_reduceEntireDeficit() public { // Shares to initialize & withdraw int256 sharesBeginning = -100e18; uint256 sharesToWithdraw = 101e18; // Deploy Pod And initialize with negative shares _initializePodWithShares(defaultStaker, sharesBeginning); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), sharesBeginning, "Shares not initialized correctly"); // Withdraw shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, defaultStaker, sharesToWithdraw); + cheats.expectEmit(true, true, true, true); + emit PodSharesUpdated(defaultStaker, 100e18); + cheats.expectEmit(true, true, true, true); + emit NewTotalShares(defaultStaker, 0); + // Expect call to EigenPod for the withdrawal + cheats.expectCall( + address(defaultPod), + abi.encodeWithSelector(IEigenPod.withdrawRestakedBeaconChainETH.selector, defaultStaker, 1e18), + 1 + ); + eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw); // Check storage update - assertEq(eigenPodManager.podOwnerShares(defaultStaker), int256(0), "Shares not reduced to 0"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), int256(0), "Shares not reduced to 0"); } - function test_withdrawSharesAsTokens_partialDefecitReduction() public { + function test_withdrawSharesAsTokens_m2NegativeShares_partialDefecitReduction() public { // Shares to initialize & withdraw int256 sharesBeginning = -100e18; uint256 sharesToWithdraw = 50e18; // Deploy Pod And initialize with negative shares _initializePodWithShares(defaultStaker, sharesBeginning); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), sharesBeginning, "Shares not initialized correctly"); // Withdraw shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, defaultStaker, sharesToWithdraw); + cheats.expectEmit(true, true, true, true); + emit PodSharesUpdated(defaultStaker, 50e18); + cheats.expectEmit(true, true, true, true); + emit NewTotalShares(defaultStaker, -50e18); + // Assert that no call is made by passing in zero for the count + bytes memory emptyBytes; + cheats.expectCall( + address(defaultPod), + emptyBytes, // Cheatcode checks a partial match starting at the first byte of the calldata + 0 + ); + eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw); // Check storage update int256 expectedShares = sharesBeginning + int256(sharesToWithdraw); - assertEq(eigenPodManager.podOwnerShares(defaultStaker), expectedShares, "Shares not reduced to expected amount"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), expectedShares, "Shares not reduced to expected amount"); } function test_withdrawSharesAsTokens_withdrawPositive() public { @@ -387,104 +404,125 @@ contract EigenPodManagerUnitTests_ShareUpdateTests is EigenPodManagerUnitTests { // Withdraw shares cheats.prank(address(delegationManagerMock)); - eigenPodManager.withdrawSharesAsTokens(defaultStaker, defaultStaker, sharesToWithdraw); + // Expect call to EigenPod for the withdrawal + cheats.expectCall( + address(defaultPod), + abi.encodeWithSelector(IEigenPod.withdrawRestakedBeaconChainETH.selector, defaultStaker, sharesToWithdraw), + 1 + ); + eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw); // Check storage remains the same - assertEq(eigenPodManager.podOwnerShares(defaultStaker), sharesBeginning, "Shares should not be adjusted"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), sharesBeginning, "Shares should not be adjusted"); } } -contract EigenPodManagerUnitTests_BeaconChainETHBalanceUpdateTests is EigenPodManagerUnitTests, IEigenPodManagerEvents { +contract EigenPodManagerUnitTests_BeaconChainETHBalanceUpdateTests is EigenPodManagerUnitTests { + // Wrapper contract that exposes the internal `_calculateChangeInDelegatableShares` function + EigenPodManagerWrapper public eigenPodManagerWrapper; + + function setUp() virtual override public { + super.setUp(); - function testFuzz_recordBalanceUpdate_revert_notPod(address invalidCaller) public filterFuzzedAddressInputs(invalidCaller) deployPodForStaker(defaultStaker) { + // Upgrade eigenPodManager to wrapper + eigenPodManagerWrapper = new EigenPodManagerWrapper( + ethPOSMock, + eigenPodBeacon, + IStrategyManager(address(strategyManagerMock)), + IDelegationManager(address(delegationManagerMock)), + pauserRegistry + ); + eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); + } + + function testFuzz_revert_notPod(address invalidCaller) public filterFuzzedAddressInputs(invalidCaller) deployPodForStaker(defaultStaker) { cheats.assume(invalidCaller != address(defaultPod)); cheats.prank(invalidCaller); - cheats.expectRevert("EigenPodManager.onlyEigenPod: not a pod"); - eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, 0); + cheats.expectRevert(IEigenPodManagerErrors.OnlyEigenPod.selector); + eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, 0, 0); } - function test_recordBalanceUpdate_revert_zeroAddress() public { + function test_revert_zeroAddress() public { IEigenPod zeroAddressPod = _deployAndReturnEigenPodForStaker(address(0)); cheats.prank(address(zeroAddressPod)); - cheats.expectRevert("EigenPodManager.recordBeaconChainETHBalanceUpdate: podOwner cannot be zero address"); - eigenPodManager.recordBeaconChainETHBalanceUpdate(address(0), 0); + cheats.expectRevert(IEigenPodErrors.InputAddressZero.selector); + eigenPodManager.recordBeaconChainETHBalanceUpdate(address(0), 0, 0); } - function testFuzz_recordBalanceUpdate_revert_nonWholeGweiAmount(int256 sharesDelta) public deployPodForStaker(defaultStaker) { + function testFuzz_revert_nonWholeGweiAmount(int256 sharesDelta) public deployPodForStaker(defaultStaker) { cheats.assume(sharesDelta % int256(GWEI_TO_WEI) != 0); cheats.prank(address(defaultPod)); - cheats.expectRevert("EigenPodManager.recordBeaconChainETHBalanceUpdate: sharesDelta must be a whole Gwei amount"); - eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, sharesDelta); + cheats.expectRevert(IEigenPodManagerErrors.SharesNotMultipleOfGwei.selector); + eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, 0, sharesDelta); } - function testFuzz_recordBalanceUpdateX(int224 sharesBefore, int224 sharesDelta) public { + function testFuzz_revert_negativeDepositShares(int224 sharesBefore) public { + cheats.assume(sharesBefore < 0); + + // Initialize shares + _initializePodWithShares(defaultStaker, sharesBefore); + + // Record balance update + cheats.prank(address(defaultPod)); + cheats.expectRevert(IEigenPodManagerErrors.LegacyWithdrawalsNotCompleted.selector); + eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, 0, 0); + } + + function testFuzz_recordPositiveBalanceUpdate( + uint256 sharesBefore, + uint256 sharesDelta, + uint256 prevRestakedBalanceWei + ) public { // Constrain inputs - int256 scaledSharesBefore = sharesBefore * int256(GWEI_TO_WEI); - int256 scaledSharesDelta = sharesDelta * int256(GWEI_TO_WEI); + sharesBefore = bound(sharesBefore, 0, type(uint224).max) * uint(GWEI_TO_WEI); + sharesDelta = bound(sharesDelta, 0, type(uint224).max) * uint(GWEI_TO_WEI); + prevRestakedBalanceWei = bound(prevRestakedBalanceWei, 0, type(uint256).max); // Initialize shares - _initializePodWithShares(defaultStaker, scaledSharesBefore); + _initializePodWithShares(defaultStaker, int(sharesBefore)); + + uint64 prevSlashingFactor = eigenPodManager.beaconChainSlashingFactor(defaultStaker); - // Update balance + // Add shares cheats.expectEmit(true, true, true, true); - emit PodSharesUpdated(defaultStaker, scaledSharesDelta); + emit PodSharesUpdated(defaultStaker, int(sharesDelta)); cheats.expectEmit(true, true, true, true); - emit NewTotalShares(defaultStaker, scaledSharesBefore + scaledSharesDelta); + emit NewTotalShares(defaultStaker, int(sharesBefore + sharesDelta)); + cheats.prank(address(defaultPod)); - eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, scaledSharesDelta); + eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, prevRestakedBalanceWei, int(sharesDelta)); // Check storage - assertEq(eigenPodManager.podOwnerShares(defaultStaker), scaledSharesBefore + scaledSharesDelta, "Shares not updated correctly"); + // Note that this is a unit test, we don't validate that the withdrawable shares are updated correctly + // See the integration tests for checking scaling factors and withdrawable shares + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), int(sharesBefore + sharesDelta), "Shares not updated correctly"); + assertEq(eigenPodManager.beaconChainSlashingFactor(defaultStaker), prevSlashingFactor, "bcsf should not change"); } -} -contract EigenPodManagerUnitTests_ShareAdjustmentCalculationTests is EigenPodManagerUnitTests { - // Wrapper contract that exposes the internal `_calculateChangeInDelegatableShares` function - EigenPodManagerWrapper public eigenPodManagerWrapper; - - function setUp() virtual override public { - super.setUp(); + function testFuzz_recordNegativeBalanceUpdate( + uint256 sharesBefore, + uint256 sharesDelta, + uint256 prevRestakedBalanceWei + ) public { + // Constrain inputs + sharesBefore = bound(sharesBefore, 0, type(uint224).max) * uint(GWEI_TO_WEI); + prevRestakedBalanceWei = bound(prevRestakedBalanceWei, 1, type(uint224).max); + sharesDelta = bound(sharesDelta, 1, prevRestakedBalanceWei) * uint(GWEI_TO_WEI); + prevRestakedBalanceWei *= GWEI_TO_WEI; - // Upgrade eigenPodManager to wrapper - eigenPodManagerWrapper = new EigenPodManagerWrapper( - ethPOSMock, - eigenPodBeacon, - strategyManagerMock, - slasherMock, - delegationManagerMock - ); - eigenLayerProxyAdmin.upgrade(TransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerWrapper)); - } + // Initialize shares + _initializePodWithShares(defaultStaker, int(sharesBefore)); - function testFuzz_shareAdjustment_negativeToNegative(int256 sharesBefore, int256 sharesAfter) public { - cheats.assume(sharesBefore <= 0); - cheats.assume(sharesAfter <= 0); - - int256 sharesDelta = eigenPodManagerWrapper.calculateChangeInDelegatableShares(sharesBefore, sharesAfter); - assertEq(sharesDelta, 0, "Shares delta must be 0"); - } + uint64 prevSlashingFactor = eigenPodManager.beaconChainSlashingFactor(defaultStaker); - function testFuzz_shareAdjustment_negativeToPositive(int256 sharesBefore, int256 sharesAfter) public { - cheats.assume(sharesBefore <= 0); - cheats.assume(sharesAfter > 0); - - int256 sharesDelta = eigenPodManagerWrapper.calculateChangeInDelegatableShares(sharesBefore, sharesAfter); - assertEq(sharesDelta, sharesAfter, "Shares delta must be equal to sharesAfter"); - } + // Not checking the new slashing factor - just checking the invariant that new <= prev + cheats.expectEmit(true, true, true, false); + emit BeaconChainSlashingFactorDecreased(defaultStaker, 0, 0); - function testFuzz_shareAdjustment_positiveToNegative(int256 sharesBefore, int256 sharesAfter) public { - cheats.assume(sharesBefore > 0); - cheats.assume(sharesAfter <= 0); - - int256 sharesDelta = eigenPodManagerWrapper.calculateChangeInDelegatableShares(sharesBefore, sharesAfter); - assertEq(sharesDelta, -sharesBefore, "Shares delta must be equal to the negative of sharesBefore"); - } + cheats.prank(address(defaultPod)); + eigenPodManager.recordBeaconChainETHBalanceUpdate(defaultStaker, prevRestakedBalanceWei, -int(sharesDelta)); - function testFuzz_shareAdjustment_positiveToPositive(int256 sharesBefore, int256 sharesAfter) public { - cheats.assume(sharesBefore > 0); - cheats.assume(sharesAfter > 0); - - int256 sharesDelta = eigenPodManagerWrapper.calculateChangeInDelegatableShares(sharesBefore, sharesAfter); - assertEq(sharesDelta, sharesAfter - sharesBefore, "Shares delta must be equal to the difference between sharesAfter and sharesBefore"); + assertEq(eigenPodManager.podOwnerDepositShares(defaultStaker), int(sharesBefore), "Shares should not be adjusted"); + assertTrue(eigenPodManager.beaconChainSlashingFactor(defaultStaker) <= prevSlashingFactor, "bcsf should always decrease"); } -} +} \ No newline at end of file diff --git a/src/test/unit/EigenPodUnit.t.sol b/src/test/unit/EigenPodUnit.t.sol index 6314a107c..15798afac 100644 --- a/src/test/unit/EigenPodUnit.t.sol +++ b/src/test/unit/EigenPodUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "@openzeppelin/contracts/utils/Create2.sol"; @@ -12,16 +12,12 @@ import "src/test/mocks/ERC20Mock.sol"; import "src/test/harnesses/EigenPodHarness.sol"; import "src/test/utils/ProofParsing.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; -import "src/test/events/IEigenPodEvents.sol"; import "src/test/integration/mocks/BeaconChainMock.t.sol"; import "src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol"; import "src/test/utils/EigenPodUser.t.sol"; -import "src/test/events/IEigenPodEvents.sol"; - contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, IEigenPodEvents { - using Strings for *; using BytesLib for bytes; using BeaconChainProofs for *; @@ -62,7 +58,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, // Deploy EigenPod podImplementation = new EigenPod( ethPOSDepositMock, - eigenPodManagerMock, + IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL ); @@ -114,7 +110,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, EigenPodUser staker; - stakerName = string.concat("Staker", numStakers.toString()); + stakerName = string.concat("Staker", cheats.toString(numStakers)); staker = new EigenPodUser(stakerName); uint256 amount = bound(rand, 1 ether, 640 ether); @@ -194,12 +190,12 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, ) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(addedValidators); - IEigenPod.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); - IEigenPod.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); for (uint i = 0; i < curStatuses.length; i++) { - assertTrue(prevStatuses[i] == IEigenPod.VALIDATOR_STATUS.INACTIVE, err); - assertTrue(curStatuses[i] == IEigenPod.VALIDATOR_STATUS.ACTIVE, err); + assertTrue(prevStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.INACTIVE, err); + assertTrue(curStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.ACTIVE, err); } } @@ -210,18 +206,18 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, ) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(removedValidators); - IEigenPod.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); - IEigenPod.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); + IEigenPodTypes.VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); for (uint i = 0; i < curStatuses.length; i++) { - assertTrue(prevStatuses[i] == IEigenPod.VALIDATOR_STATUS.ACTIVE, err); - assertTrue(curStatuses[i] == IEigenPod.VALIDATOR_STATUS.WITHDRAWN, err); + assertTrue(prevStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.ACTIVE, err); + assertTrue(curStatuses[i] == IEigenPodTypes.VALIDATOR_STATUS.WITHDRAWN, err); } } - function _getValidatorStatuses(EigenPodUser staker, bytes32[] memory pubkeyHashes) internal view returns (IEigenPod.VALIDATOR_STATUS[] memory) { + function _getValidatorStatuses(EigenPodUser staker, bytes32[] memory pubkeyHashes) internal view returns (IEigenPodTypes.VALIDATOR_STATUS[] memory) { EigenPod pod = staker.pod(); - IEigenPod.VALIDATOR_STATUS[] memory statuses = new IEigenPod.VALIDATOR_STATUS[](pubkeyHashes.length); + IEigenPodTypes.VALIDATOR_STATUS[] memory statuses = new IEigenPodTypes.VALIDATOR_STATUS[](pubkeyHashes.length); for (uint i = 0; i < statuses.length; i++) { statuses[i] = pod.validatorStatus(pubkeyHashes[i]); @@ -230,7 +226,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, return statuses; } - function _getPrevValidatorStatuses(EigenPodUser staker, bytes32[] memory pubkeyHashes) internal timewarp() returns (IEigenPod.VALIDATOR_STATUS[] memory) { + function _getPrevValidatorStatuses(EigenPodUser staker, bytes32[] memory pubkeyHashes) internal timewarp() returns (IEigenPodTypes.VALIDATOR_STATUS[] memory) { return _getValidatorStatuses(staker, pubkeyHashes); } @@ -248,7 +244,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, function assert_ProofsRemainingEqualsActive( EigenPodUser staker, string memory err - ) internal { + ) internal view { EigenPod pod = staker.pod(); assertEq(pod.currentCheckpoint().proofsRemaining, pod.activeValidatorCount(), err); } @@ -287,7 +283,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, int256 totalBalanceDeltaGWei = 0; uint64 checkpointTimestamp = pod.currentCheckpointTimestamp(); for (uint i = 0; i < validators.length; i++) { - IEigenPod.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(proofs[i].pubkeyHash); + IEigenPodTypes.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(proofs[i].pubkeyHash); uint64 prevBalanceGwei = info.restakedBalanceGwei; uint64 newBalanceGwei = BeaconChainProofs.getBalanceAtIndex(proofs[i].balanceRoot, validators[i]); int128 balanceDeltaGwei = _calcBalanceDelta({ @@ -328,10 +324,10 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, contract EigenPodUnitTests_Initialization is EigenPodUnitTests { function test_constructor() public { - EigenPod pod = new EigenPod(ethPOSDepositMock, eigenPodManagerMock, GENESIS_TIME_LOCAL); + EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); assertTrue(pod.ethPOS() == ethPOSDepositMock, "should have set ethPOS correctly"); - assertTrue(pod.eigenPodManager() == eigenPodManagerMock, "should have set eigenpodmanager correctly"); + assertTrue(address(pod.eigenPodManager()) == address(eigenPodManagerMock), "should have set eigenpodmanager correctly"); assertTrue(pod.GENESIS_TIME() == GENESIS_TIME_LOCAL, "should have set genesis time correctly"); } @@ -356,11 +352,11 @@ contract EigenPodUnitTests_Initialization is EigenPodUnitTests { } function test_initialize_revert_emptyPodOwner() public { - EigenPod pod = new EigenPod(ethPOSDepositMock, eigenPodManagerMock, GENESIS_TIME_LOCAL); + EigenPod pod = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); // un-initialize pod cheats.store(address(pod), 0, 0); - cheats.expectRevert("EigenPod.initialize: podOwner cannot be zero address"); + cheats.expectRevert(IEigenPodErrors.InputAddressZero.selector); pod.initialize(address(0)); } @@ -370,7 +366,7 @@ contract EigenPodUnitTests_Initialization is EigenPodUnitTests { cheats.assume(invalidCaller != address(staker)); cheats.prank(invalidCaller); - cheats.expectRevert("EigenPod.onlyEigenPodOwner: not podOwner"); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodOwner.selector); pod.setProofSubmitter(invalidCaller); } @@ -405,7 +401,7 @@ contract EigenPodUnitTests_EPMFunctions is EigenPodUnitTests { cheats.deal(invalidCaller, 32 ether); cheats.prank(invalidCaller); - cheats.expectRevert("EigenPod.onlyEigenPodManager: not eigenPodManager"); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodManager.selector); eigenPod.stake{value: 32 ether}(pubkey, signature, depositDataRoot); } @@ -415,7 +411,7 @@ contract EigenPodUnitTests_EPMFunctions is EigenPodUnitTests { cheats.deal(address(eigenPodManagerMock), value); cheats.prank(address(eigenPodManagerMock)); - cheats.expectRevert("EigenPod.stake: must initially stake for any validator with 32 ether"); + cheats.expectRevert(IEigenPodErrors.MsgValueNot32ETH.selector); eigenPod.stake{value: value}(pubkey, signature, depositDataRoot); } @@ -450,7 +446,7 @@ contract EigenPodUnitTests_EPMFunctions is EigenPodUnitTests { // ensure invalid caller causing revert cheats.assume(invalidCaller != address(eigenPodManagerMock)); cheats.prank(invalidCaller); - cheats.expectRevert("EigenPod.onlyEigenPodManager: not eigenPodManager"); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodManager.selector); pod.withdrawRestakedBeaconChainETH(recipient, randAmount); } @@ -469,7 +465,7 @@ contract EigenPodUnitTests_EPMFunctions is EigenPodUnitTests { // ensure amount is not a full gwei randAmount = (randAmount % 1 gwei) + bound(randAmount, 1, 1 gwei - 1); - cheats.expectRevert("EigenPod.withdrawRestakedBeaconChainETH: amountWei must be a whole Gwei amount"); + cheats.expectRevert(IEigenPodErrors.AmountMustBeMultipleOfGwei.selector); cheats.prank(address(eigenPodManagerMock)); pod.withdrawRestakedBeaconChainETH(recipient, randAmount); } @@ -492,9 +488,7 @@ contract EigenPodUnitTests_EPMFunctions is EigenPodUnitTests { uint64 withdrawableRestakedExecutionLayerGwei = pod.withdrawableRestakedExecutionLayerGwei(); randAmountWei = randAmountWei - (randAmountWei % 1 gwei); cheats.assume((randAmountWei / 1 gwei) > withdrawableRestakedExecutionLayerGwei); - cheats.expectRevert( - "EigenPod.withdrawRestakedBeaconChainETH: amountGwei exceeds withdrawableRestakedExecutionLayerGwei" - ); + cheats.expectRevert(IEigenPodErrors.InsufficientWithdrawableBalance.selector); cheats.prank(address(eigenPodManagerMock)); pod.withdrawRestakedBeaconChainETH(recipient, randAmountWei); } @@ -556,7 +550,7 @@ contract EigenPodUnitTests_recoverTokens is EigenPodUnitTests { amounts[0] = 1; cheats.prank(invalidCaller); - cheats.expectRevert("EigenPod.onlyEigenPodOwner: not podOwner"); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodOwner.selector); pod.recoverTokens(tokens, amounts, podOwner); } @@ -575,7 +569,7 @@ contract EigenPodUnitTests_recoverTokens is EigenPodUnitTests { eigenPodManagerMock.pause(1 << PAUSED_NON_PROOF_WITHDRAWALS); cheats.prank(podOwner); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); pod.recoverTokens(tokens, amounts, podOwner); } @@ -591,7 +585,7 @@ contract EigenPodUnitTests_recoverTokens is EigenPodUnitTests { amounts[1] = 1; cheats.startPrank(podOwner); - cheats.expectRevert("EigenPod.recoverTokens: tokenList and amountsToWithdraw must be same length"); + cheats.expectRevert(IEigenPodErrors.InputArrayLengthMismatch.selector); pod.recoverTokens(tokens, amounts, podOwner); cheats.stopPrank(); } @@ -638,9 +632,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro cheats.assume(invalidCaller != podOwner && invalidCaller != proofSubmitter); cheats.prank(invalidCaller); - cheats.expectRevert( - "EigenPod.onlyOwnerOrProofSubmitter: caller is not pod owner or proof submitter" - ); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodOwnerOrProofSubmitter.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, @@ -659,7 +651,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro cheats.prank(pauser); eigenPodManagerMock.pause(2 ** PAUSED_EIGENPODS_VERIFY_CREDENTIALS); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); staker.verifyWithdrawalCredentials(validators); } @@ -679,7 +671,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro staker.startCheckpoint(); // Try to verify withdrawal credentials at the current block - cheats.expectRevert("EigenPod.verifyWithdrawalCredentials: specified timestamp is too far in past"); + cheats.expectRevert(IEigenPodErrors.BeaconTimestampTooFarInPast.selector); staker.verifyWithdrawalCredentials(validators); } @@ -695,7 +687,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro bytes32[][] memory invalidValidatorFields = new bytes32[][](proofs.validatorFields.length + 1); cheats.startPrank(address(staker)); - cheats.expectRevert("EigenPod.verifyWithdrawalCredentials: validatorIndices and proofs must be same length"); + cheats.expectRevert(IEigenPodErrors.InputArrayLengthMismatch.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -704,7 +696,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro validatorFields: proofs.validatorFields }); - cheats.expectRevert("EigenPod.verifyWithdrawalCredentials: validatorIndices and proofs must be same length"); + cheats.expectRevert(IEigenPodErrors.InputArrayLengthMismatch.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -713,7 +705,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro validatorFields: proofs.validatorFields }); - cheats.expectRevert("EigenPod.verifyWithdrawalCredentials: validatorIndices and proofs must be same length"); + cheats.expectRevert(IEigenPodErrors.InputArrayLengthMismatch.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -738,9 +730,8 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro proof: proofWithInvalidLength }); - cheats.startPrank(address(staker)); - cheats.expectRevert("BeaconChainProofs.verifyStateRoot: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: invalidStateRootProof, @@ -754,7 +745,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro uint256 proofLength = proofs.stateRootProof.proof.length; uint256 randIndex = bound(rand, 0, proofLength - 1); proofs.stateRootProof.proof[randIndex] = randValue; - cheats.expectRevert("BeaconChainProofs.verifyStateRoot: Invalid state root merkle proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -773,9 +764,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro staker.verifyWithdrawalCredentials(validators); // now that validators are ACTIVE, ensure we can't verify them again - cheats.expectRevert( - "EigenPod._verifyWithdrawalCredentials: validator must be inactive to prove withdrawal credentials" - ); + cheats.expectRevert(IEigenPodErrors.CredentialsAlreadyVerified.selector); staker.verifyWithdrawalCredentials(validators); staker.exitValidators(validators); @@ -786,9 +775,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro beaconChain.advanceEpoch_NoRewards(); // now that validators are WITHDRAWN, ensure we can't verify them again - cheats.expectRevert( - "EigenPod._verifyWithdrawalCredentials: validator must be inactive to prove withdrawal credentials" - ); + cheats.expectRevert(IEigenPodErrors.CredentialsAlreadyVerified.selector); staker.verifyWithdrawalCredentials(validators); } @@ -803,9 +790,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro beaconChain.advanceEpoch(); // now that validators are exited, ensure we can't verify them - cheats.expectRevert( - "EigenPod._verifyWithdrawalCredentials: validator must not be exiting" - ); + cheats.expectRevert(IEigenPodErrors.ValidatorIsExitingBeaconChain.selector); staker.verifyWithdrawalCredentials(validators); } @@ -821,7 +806,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro proofs.validatorFields[0][VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX] = invalidWithdrawalCredentials; cheats.startPrank(address(staker)); - cheats.expectRevert("EigenPod._verifyWithdrawalCredentials: proof is not for this EigenPod"); + cheats.expectRevert(IEigenPodErrors.WithdrawalCredentialsNotForEigenPod.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -847,7 +832,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro proofs.validatorFields[0] = invalidValidatorFields; cheats.startPrank(address(staker)); - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidValidatorFieldsLength.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -869,7 +854,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro = _toLittleEndianUint64(BeaconChainProofs.FAR_FUTURE_EPOCH); cheats.startPrank(address(staker)); - cheats.expectRevert("EigenPod._verifyWithdrawalCredentials: validator must be in the process of activating"); + cheats.expectRevert(IEigenPodErrors.ValidatorInactiveOnBeaconChain.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -891,7 +876,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro proofs.validatorFieldsProofs[0] = new bytes(proofs.validatorFieldsProofs[0].length + 32); cheats.startPrank(address(staker)); - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -914,7 +899,7 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro proofs.validatorFields[0][VALIDATOR_PUBKEY_INDEX] = randPubkey; cheats.startPrank(address(staker)); - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Invalid merkle proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyWithdrawalCredentials({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -963,9 +948,9 @@ contract EigenPodUnitTests_verifyWithdrawalCredentials is EigenPodUnitTests, Pro bytes32 pubkeyHash = beaconChain.pubkeyHash(validators[i]); bytes memory pubkey = beaconChain.pubkey(validators[i]); - IEigenPod.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); - IEigenPod.ValidatorInfo memory pkInfo = pod.validatorPubkeyToInfo(pubkey); - assertTrue(pod.validatorStatus(pubkey) == IEigenPod.VALIDATOR_STATUS.ACTIVE, "validator status should be active"); + IEigenPodTypes.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); + IEigenPodTypes.ValidatorInfo memory pkInfo = pod.validatorPubkeyToInfo(pubkey); + assertTrue(pod.validatorStatus(pubkey) == IEigenPodTypes.VALIDATOR_STATUS.ACTIVE, "validator status should be active"); assertEq(keccak256(abi.encode(info)), keccak256(abi.encode(pkInfo)), "validator info should be identical"); assertEq(info.validatorIndex, validators[i], "should have assigned correct validator index"); assertEq(info.restakedBalanceGwei, beaconChain.effectiveBalance(validators[i]), "should have restaked full effective balance"); @@ -992,9 +977,7 @@ contract EigenPodUnitTests_startCheckpoint is EigenPodUnitTests { cheats.assume(invalidCaller != podOwner && invalidCaller != proofSubmitter); cheats.prank(invalidCaller); - cheats.expectRevert( - "EigenPod.onlyOwnerOrProofSubmitter: caller is not pod owner or proof submitter" - ); + cheats.expectRevert(IEigenPodErrors.OnlyEigenPodOwnerOrProofSubmitter.selector); pod.startCheckpoint({ revertIfNoBalance: false }); } @@ -1007,7 +990,7 @@ contract EigenPodUnitTests_startCheckpoint is EigenPodUnitTests { cheats.prank(pauser); eigenPodManagerMock.pause(2 ** PAUSED_START_CHECKPOINT); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); staker.startCheckpoint(); } @@ -1018,7 +1001,7 @@ contract EigenPodUnitTests_startCheckpoint is EigenPodUnitTests { (uint40[] memory validators,) = staker.startValidators(); staker.verifyWithdrawalCredentials(validators); staker.startCheckpoint(); - cheats.expectRevert("EigenPod._startCheckpoint: must finish previous checkpoint before starting another"); + cheats.expectRevert(IEigenPodErrors.CheckpointAlreadyActive.selector); staker.startCheckpoint(); } @@ -1031,7 +1014,7 @@ contract EigenPodUnitTests_startCheckpoint is EigenPodUnitTests { staker.startCheckpoint(); staker.completeCheckpoint(); - cheats.expectRevert("EigenPod._startCheckpoint: cannot checkpoint twice in one block"); + cheats.expectRevert(IEigenPodErrors.CannotCheckpointTwiceInSingleBlock.selector); staker.startCheckpoint(); } @@ -1045,7 +1028,7 @@ contract EigenPodUnitTests_startCheckpoint is EigenPodUnitTests { beaconChain.advanceEpoch_NoRewards(); cheats.prank(pod.podOwner()); - cheats.expectRevert("EigenPod._startCheckpoint: no balance available to checkpoint"); + cheats.expectRevert(IEigenPodErrors.NoBalanceToCheckpoint.selector); pod.startCheckpoint({ revertIfNoBalance: true }); } @@ -1099,7 +1082,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { cheats.prank(pauser); eigenPodManagerMock.pause(2 ** PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1117,9 +1100,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { validators, pod.currentCheckpointTimestamp() ); - cheats.expectRevert( - "EigenPod.verifyCheckpointProofs: must have active checkpoint to perform checkpoint proof" - ); + cheats.expectRevert(IEigenPodErrors.NoActiveCheckpoint.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1143,7 +1124,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { // change the length of balanceContainerProof to cause a revert proofs.balanceContainerProof.proof = new bytes(proofs.balanceContainerProof.proof.length + 1); - cheats.expectRevert("BeaconChainProofs.verifyBalanceContainer: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1169,7 +1150,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { bytes1 randValue = bytes1(keccak256(abi.encodePacked(proofs.balanceContainerProof.proof[0]))); proofs.balanceContainerProof.proof[0] = randValue; - cheats.expectRevert("BeaconChainProofs.verifyBalanceContainer: invalid balance container proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1193,7 +1174,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { // change the length of balance proof to cause a revert proofs.balanceProofs[0].proof = new bytes(proofs.balanceProofs[0].proof.length + 1); - cheats.expectRevert("BeaconChainProofs.verifyValidatorBalance: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1218,7 +1199,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { bytes1 randValue = bytes1(keccak256(abi.encodePacked(proofs.balanceProofs[0].proof[0]))); proofs.balanceProofs[0].proof[0] = randValue; - cheats.expectRevert("BeaconChainProofs.verifyValidatorBalance: Invalid merkle proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs @@ -1352,7 +1333,7 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { for (uint i = 0; i < validators.length; i++) { bytes32 pubkeyHash = beaconChain.pubkeyHash(validators[i]); - IEigenPod.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); + IEigenPodTypes.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); assertEq(info.restakedBalanceGwei, beaconChain.currentBalance(validators[i]), "should have restaked full current balance"); assertEq(info.lastCheckpointedAt, pod.lastCheckpointTimestamp(), "should have recorded correct update time"); } @@ -1395,10 +1376,10 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { for (uint i = 0; i < validators.length; i++) { bytes32 pubkeyHash = beaconChain.pubkeyHash(validators[i]); - IEigenPod.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); + IEigenPodTypes.ValidatorInfo memory info = pod.validatorPubkeyHashToInfo(pubkeyHash); assertEq(info.restakedBalanceGwei, 0, "should have 0 restaked balance"); assertEq(info.lastCheckpointedAt, pod.lastCheckpointTimestamp(), "should have recorded correct update time"); - assertTrue(info.status == IEigenPod.VALIDATOR_STATUS.WITHDRAWN, "should have recorded correct update time"); + assertTrue(info.status == IEigenPodTypes.VALIDATOR_STATUS.WITHDRAWN, "should have recorded correct update time"); } } @@ -1435,7 +1416,6 @@ contract EigenPodUnitTests_verifyCheckpointProofs is EigenPodUnitTests { } } -/// @notice TODO contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { /// @notice test verifyStaleBalance reverts when paused function testFuzz_revert_verifyStaleBalancePaused(uint256 rand) public { @@ -1446,7 +1426,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { cheats.prank(pauser); eigenPodManagerMock.pause(2 ** PAUSED_VERIFY_STALE_BALANCE); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1463,7 +1443,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { cheats.prank(pauser); eigenPodManagerMock.pause(2 ** PAUSED_START_CHECKPOINT); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); + cheats.expectRevert(IEigenPodErrors.CurrentlyPaused.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1487,7 +1467,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { uint64 lastCheckpointTimestamp = pod.lastCheckpointTimestamp(); // proof for given beaconTimestamp is not yet stale, this should revert StaleBalanceProofs memory proofs = beaconChain.getStaleBalanceProofs(validator); - cheats.expectRevert("EigenPod.verifyStaleBalance: proof is older than last checkpoint"); + cheats.expectRevert(IEigenPodErrors.BeaconTimestampTooFarInPast.selector); pod.verifyStaleBalance({ beaconTimestamp: lastCheckpointTimestamp, stateRootProof: proofs.stateRootProof, @@ -1508,7 +1488,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { // proof for given beaconTimestamp is not yet stale, this should revert StaleBalanceProofs memory proofs = beaconChain.getStaleBalanceProofs(validator); - cheats.expectRevert("EigenPod.verifyStaleBalance: proof is older than last checkpoint"); + cheats.expectRevert(IEigenPodErrors.BeaconTimestampTooFarInPast.selector); pod.verifyStaleBalance({ beaconTimestamp: 0, stateRootProof: proofs.stateRootProof, @@ -1529,7 +1509,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { beaconChain.advanceEpoch(); StaleBalanceProofs memory proofs = beaconChain.getStaleBalanceProofs(validator); - cheats.expectRevert("EigenPod.verifyStaleBalance: validator is not active"); + cheats.expectRevert(IEigenPodErrors.ValidatorNotActiveInPod.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1551,7 +1531,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { beaconChain.advanceEpoch(); StaleBalanceProofs memory proofs = beaconChain.getStaleBalanceProofs(validator); - cheats.expectRevert("EigenPod.verifyStaleBalance: validator must be slashed to be marked stale"); + cheats.expectRevert(IEigenPodErrors.ValidatorNotSlashedOnBeaconChain.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1580,7 +1560,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { proof: proofWithInvalidLength }); - cheats.expectRevert("BeaconChainProofs.verifyStateRoot: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: invalidStateRootProof, @@ -1608,7 +1588,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { uint256 randIndex = bound(rand, 0, proofLength - 1); proofs.stateRootProof.proof[randIndex] = randValue; - cheats.expectRevert("BeaconChainProofs.verifyStateRoot: Invalid state root merkle proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1639,7 +1619,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { validatorFields: proofs.validatorProof.validatorFields, proof: invalidProof }); - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Proof has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidProofLength.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1653,7 +1633,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { } proofs.validatorProof.validatorFields = validatorFieldsInvalidLength; - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length"); + cheats.expectRevert(BeaconChainProofs.InvalidValidatorFieldsLength.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1682,7 +1662,7 @@ contract EigenPodUnitTests_verifyStaleBalance is EigenPodUnitTests { uint256 VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1; proofs.validatorProof.validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX] = randWithdrawalCredentials; - cheats.expectRevert("BeaconChainProofs.verifyValidatorFields: Invalid merkle proof"); + cheats.expectRevert(BeaconChainProofs.InvalidProof.selector); pod.verifyStaleBalance({ beaconTimestamp: proofs.beaconTimestamp, stateRootProof: proofs.stateRootProof, @@ -1727,7 +1707,7 @@ contract EigenPodHarnessSetup is EigenPodUnitTests { // Deploy EP Harness eigenPodHarnessImplementation = new EigenPodHarness( ethPOSDepositMock, - eigenPodManagerMock, + IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL ); @@ -1750,9 +1730,9 @@ contract EigenPodUnitTests_proofParsingTests is EigenPodHarnessSetup, ProofParsi bytes validatorFieldsProof; bytes32[] validatorFields; - function _assertWithdrawalCredentialsSet(uint256 restakedBalanceGwei) internal { - IEigenPod.ValidatorInfo memory validatorInfo = eigenPodHarness.validatorPubkeyHashToInfo(validatorFields[0]); - assertEq(uint8(validatorInfo.status), uint8(IEigenPod.VALIDATOR_STATUS.ACTIVE), "Validator status should be active"); + function _assertWithdrawalCredentialsSet(uint256 restakedBalanceGwei) internal view { + IEigenPodTypes.ValidatorInfo memory validatorInfo = eigenPodHarness.validatorPubkeyHashToInfo(validatorFields[0]); + assertEq(uint8(validatorInfo.status), uint8(IEigenPodTypes.VALIDATOR_STATUS.ACTIVE), "Validator status should be active"); assertEq(validatorInfo.validatorIndex, validatorIndex, "Validator index incorrectly set"); assertEq(validatorInfo.lastCheckpointedAt, oracleTimestamp, "Last checkpointed at timestamp incorrectly set"); assertEq(validatorInfo.restakedBalanceGwei, restakedBalanceGwei, "Restaked balance gwei not set correctly"); @@ -1792,4 +1772,4 @@ contract EigenPodUnitTests_proofParsingTests is EigenPodHarnessSetup, ProofParsi ); _; } -} +} \ No newline at end of file diff --git a/src/test/unit/PausableUnit.t.sol b/src/test/unit/PausableUnit.t.sol index bb7c4c60d..866595226 100644 --- a/src/test/unit/PausableUnit.t.sol +++ b/src/test/unit/PausableUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -17,7 +17,7 @@ contract PausableUnitTests is Test { address public unpauser = address(999); uint256 public initPausedStatus = 0; - mapping(address => bool) public addressIsExcludedFromFuzzedInputs; + mapping(address => bool) public isExcludedFuzzAddress; /// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`. event Paused(address indexed account, uint256 newPausedStatus); @@ -29,22 +29,10 @@ contract PausableUnitTests is Test { address[] memory pausers = new address[](1); pausers[0] = pauser; pauserRegistry = new PauserRegistry(pausers, unpauser); - pausable = new PausableHarness(); - pausable.initializePauser(pauserRegistry, initPausedStatus); + pausable = new PausableHarness(pauserRegistry); + pausable.initializePauser(initPausedStatus); } - - function testCannotReinitialize(address _pauserRegistry, uint256 _initPausedStatus) public { - cheats.expectRevert(bytes("Pausable._initializePauser: _initializePauser() can only be called once")); - pausable.initializePauser(PauserRegistry(_pauserRegistry), _initPausedStatus); - } - - function testCannotInitializeWithZeroAddress(uint256 _initPausedStatus) public { - address _pauserRegistry = address(0); - pausable = new PausableHarness(); - cheats.expectRevert(bytes("Pausable._initializePauser: _initializePauser() can only be called once")); - pausable.initializePauser(PauserRegistry(_pauserRegistry), _initPausedStatus); - } - + function testPause(uint256 previousPausedStatus, uint256 newPausedStatus) public { // filter out any fuzzed inputs which would (improperly) flip any bits to '0'. cheats.assume(previousPausedStatus & newPausedStatus == previousPausedStatus); @@ -70,7 +58,7 @@ contract PausableUnitTests is Test { cheats.assume(notPauser != pauser); cheats.startPrank(notPauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as pauser")); + cheats.expectRevert(IPausable.OnlyPauser.selector); pausable.pause(newPausedStatus); cheats.stopPrank(); } @@ -97,7 +85,7 @@ contract PausableUnitTests is Test { cheats.assume(notPauser != pauser); cheats.startPrank(notPauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as pauser")); + cheats.expectRevert(IPausable.OnlyPauser.selector); pausable.pauseAll(); cheats.stopPrank(); } @@ -115,7 +103,7 @@ contract PausableUnitTests is Test { require(pausable.paused() == previousPausedStatus, "previousPausedStatus not set correctly"); cheats.startPrank(pauser); - cheats.expectRevert(bytes("Pausable.pause: invalid attempt to unpause functionality")); + cheats.expectRevert(IPausable.InvalidNewPausedStatus.selector); pausable.pause(newPausedStatus); cheats.stopPrank(); } @@ -151,7 +139,7 @@ contract PausableUnitTests is Test { cheats.assume(notUnpauser != pausable.pauserRegistry().unpauser()); cheats.startPrank(notUnpauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); + cheats.expectRevert(IPausable.OnlyUnpauser.selector); pausable.unpause(newPausedStatus); cheats.stopPrank(); } @@ -168,9 +156,8 @@ contract PausableUnitTests is Test { require(pausable.paused() == previousPausedStatus, "previousPausedStatus not set correctly"); cheats.startPrank(pausable.pauserRegistry().unpauser()); - cheats.expectRevert(bytes("Pausable.unpause: invalid attempt to pause functionality")); + cheats.expectRevert(IPausable.InvalidNewPausedStatus.selector); pausable.unpause(newPausedStatus); cheats.stopPrank(); } - } diff --git a/src/test/unit/PauserRegistryUnit.t.sol b/src/test/unit/PauserRegistryUnit.t.sol index 9005db5a7..f83b9aca8 100644 --- a/src/test/unit/PauserRegistryUnit.t.sol +++ b/src/test/unit/PauserRegistryUnit.t.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; +import "../../contracts/interfaces/IPausable.sol"; import "../../contracts/permissions/PauserRegistry.sol"; contract PauserRegistryUnitTests is Test { @@ -14,7 +15,7 @@ contract PauserRegistryUnitTests is Test { address public pauser = address(555); address public unpauser = address(999); - mapping(address => bool) public addressIsExcludedFromFuzzedInputs; + mapping(address => bool) public isExcludedFuzzAddress; event PauserStatusChanged(address pauser, bool canPause); @@ -66,7 +67,7 @@ contract PauserRegistryUnitTests is Test { cheats.assume(newPauser != address(0)); cheats.startPrank(notUnpauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); + cheats.expectRevert(IPausable.OnlyUnpauser.selector); pauserRegistry.setIsPauser(newPauser, true); cheats.stopPrank(); } @@ -76,7 +77,7 @@ contract PauserRegistryUnitTests is Test { cheats.assume(newUnpauser != address(0)); cheats.startPrank(notUnpauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); + cheats.expectRevert(IPausable.OnlyUnpauser.selector); pauserRegistry.setUnpauser(newUnpauser); cheats.stopPrank(); } @@ -85,7 +86,7 @@ contract PauserRegistryUnitTests is Test { address newPauser = address(0); cheats.startPrank(pauserRegistry.unpauser()); - cheats.expectRevert(bytes("PauserRegistry._setPauser: zero address input")); + cheats.expectRevert(IPauserRegistry.InputAddressZero.selector); pauserRegistry.setIsPauser(newPauser, true); cheats.stopPrank(); } @@ -94,7 +95,7 @@ contract PauserRegistryUnitTests is Test { address newUnpauser = address(0); cheats.startPrank(pauserRegistry.unpauser()); - cheats.expectRevert(bytes("PauserRegistry._setUnpauser: zero address input")); + cheats.expectRevert(IPauserRegistry.InputAddressZero.selector); pauserRegistry.setUnpauser(newUnpauser); cheats.stopPrank(); } diff --git a/src/test/unit/PermissionControllerUnit.t.sol b/src/test/unit/PermissionControllerUnit.t.sol new file mode 100644 index 000000000..43088a4a3 --- /dev/null +++ b/src/test/unit/PermissionControllerUnit.t.sol @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "forge-std/Test.sol"; + +import "src/contracts/permissions/PermissionController.sol"; +import "src/contracts/interfaces/IPermissionController.sol"; + +import "src/test/utils/EigenLayerUnitTestSetup.sol"; + +contract PermissionControllerUnitTests is EigenLayerUnitTestSetup, IPermissionControllerEvents, IPermissionControllerErrors { + address account = address(0x1); + address admin = address(0x2); + address admin2 = address(0x3); + address appointee1 = address(0x4); + address appointee2 = address(0x5); + + address target1; + address target2; + bytes4 selector1 = IDelegationManager.updateOperatorMetadataURI.selector; + bytes4 selector2 = IAllocationManager.modifyAllocations.selector; + + function setUp() virtual public override { + // Setup - already deploys permissionController + EigenLayerUnitTestSetup.setUp(); + + // Set targets + target1 = address(delegationManagerMock); + target2 = address(allocationManagerMock); + } +} + +contract PermissionControllerUnitTests_AddPendingAdmin is PermissionControllerUnitTests { + function testFuzz_getAdmin_notSet(address account) public view filterFuzzedAddressInputs(account) { + address[] memory admins = permissionController.getAdmins(account); + assertEq(admins[0], account, "Account is not admin"); + assertTrue(permissionController.isAdmin(account, account), "Account is not admin"); + } + + /// @notice Tests the setAdmin function when it has not been initialized + function test_revert_caller_not_account() public { + cheats.expectRevert(IPermissionControllerErrors.NotAdmin.selector); + permissionController.addPendingAdmin(account, admin); + } + + function test_revert_adminPending() public { + // Set admin to be pending + cheats.startPrank(account); + permissionController.addPendingAdmin(account, admin); + + // Expect revert + cheats.expectRevert(IPermissionControllerErrors.AdminAlreadyPending.selector); + permissionController.addPendingAdmin(account, admin); + } + + function test_addPendingAdmin_initialSet() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit PendingAdminAdded(account, admin); + + cheats.prank(account); + permissionController.addPendingAdmin(account, admin); + + // Check storage + address[] memory pendingAdmins = permissionController.getPendingAdmins(account); + assertEq(pendingAdmins[0], admin, "Admin not set to pending"); + assertTrue(permissionController.isPendingAdmin(account, admin), "Pending admin not set correctly"); + assertFalse(permissionController.isAdmin(account, admin), "Pending admin not set correctly"); + } +} + +contract PermissionControllerUnitTests_RemovePendingAdmin is PermissionControllerUnitTests { + function setUp() virtual public override { + // Setup + PermissionControllerUnitTests.setUp(); + + // Set admin to be pending + cheats.prank(account); + permissionController.addPendingAdmin(account, admin); + } + + function test_revert_notAdmin() public { + cheats.expectRevert(IPermissionControllerErrors.NotAdmin.selector); + permissionController.removePendingAdmin(account, admin); + } + + function test_revert_notPending() public { + // Expect revert + cheats.prank(account); + cheats.expectRevert(IPermissionControllerErrors.AdminNotPending.selector); + permissionController.removePendingAdmin(account, admin2); + } + + function test_removePendingAdmin() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit PendingAdminRemoved(account, admin); + + cheats.prank(account); + permissionController.removePendingAdmin(account, admin); + + // Check storage + address[] memory pendingAdmins = permissionController.getPendingAdmins(account); + assertEq(pendingAdmins.length, 0, "Pending admin not removed"); + } +} + +contract PermissionControllerUnitTests_AcceptAdmin is PermissionControllerUnitTests { + function setUp() virtual public override { + // Setup + PermissionControllerUnitTests.setUp(); + + // Set admin + cheats.prank(account); + permissionController.addPendingAdmin(account, admin); + } + + function test_revert_adminNotPending() public { + cheats.prank(admin2); + cheats.expectRevert(IPermissionControllerErrors.AdminNotPending.selector); + permissionController.acceptAdmin(account); + } + + function test_acceptAdmin() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit AdminSet(account, admin); + + cheats.prank(admin); + permissionController.acceptAdmin(account); + + // Check storage + address[] memory admins = permissionController.getAdmins(account); + address[] memory pendingAdmins = permissionController.getPendingAdmins(account); + assertEq(pendingAdmins.length, 0, "Pending admin not removed"); + assertEq(admins.length, 1, "Additional admin not added"); + assertFalse(permissionController.isAdmin(account, account), "Account should no longer be admin"); + assertTrue(permissionController.isAdmin(account, admin), "Admin not set"); + assertTrue(permissionController.canCall(account, admin, address(0), bytes4(0)), "Admin cannot call"); + } + + function test_addMultipleAdmin_fromAccount() public { + // Add another pending admin + cheats.prank(account); + permissionController.addPendingAdmin(account, admin2); + + // Assert pending admins length + address[] memory pendingAdmins = permissionController.getPendingAdmins(account); + assertEq(pendingAdmins.length, 2, "Additional pending admin not added"); + + // Accept admins + cheats.prank(admin); + permissionController.acceptAdmin(account); + cheats.prank(admin2); + permissionController.acceptAdmin(account); + + // Check storage + address[] memory admins = permissionController.getAdmins(account); + assertEq(admins.length, 2, "Additional admin not added"); + assertTrue(permissionController.isAdmin(account, admin), "Old admin should still be admin"); + assertTrue(permissionController.isAdmin(account, admin2), "New admin not set correctly"); + assertTrue(permissionController.canCall(account, admin, address(0), bytes4(0)), "Admin cannot call"); + assertTrue(permissionController.canCall(account, admin2, address(0), bytes4(0)), "Admin cannot call"); + } + + function test_addMultipleAdmin_newAdminAdds() public { + // Accept admin + cheats.startPrank(admin); + permissionController.acceptAdmin(account); + + // Add another pending admin + permissionController.addPendingAdmin(account, admin2); + cheats.stopPrank(); + + // Accept admins + cheats.prank(admin2); + permissionController.acceptAdmin(account); + + // Check storage + address[] memory admins = permissionController.getAdmins(account); + assertEq(admins.length, 2, "Additional admin not added"); + assertTrue(permissionController.isAdmin(account, admin), "Old admin should still be admin"); + assertTrue(permissionController.isAdmin(account, admin2), "New admin not set correctly"); + assertTrue(permissionController.canCall(account, admin, address(0), bytes4(0)), "Admin cannot call"); + assertTrue(permissionController.canCall(account, admin2, address(0), bytes4(0)), "Admin cannot call"); + } +} + +contract PermissionControllerUnitTests_RemoveAdmin is PermissionControllerUnitTests { + function setUp() virtual public override { + // Setup + PermissionControllerUnitTests.setUp(); + + // Set admins + cheats.startPrank(account); + permissionController.addPendingAdmin(account, admin); + permissionController.addPendingAdmin(account, admin2); + cheats.stopPrank(); + + // Accept admins + cheats.prank(admin); + permissionController.acceptAdmin(account); + cheats.prank(admin2); + permissionController.acceptAdmin(account); + } + + function test_revert_notAdmin() public { + cheats.prank(appointee1); + cheats.expectRevert(IPermissionControllerErrors.NotAdmin.selector); + permissionController.removeAdmin(account, admin); + } + + function test_revert_adminNotSet() public { + cheats.prank(admin); + cheats.expectRevert(IPermissionControllerErrors.AdminNotSet.selector); + permissionController.removeAdmin(account, appointee1); + } + + function test_revert_cannotHaveZeroAdmins() public { + // Remove admin2 + cheats.startPrank(admin); + permissionController.removeAdmin(account, admin2); + + // Remove admin + cheats.expectRevert(IPermissionControllerErrors.CannotHaveZeroAdmins.selector); + permissionController.removeAdmin(account, admin); + } + + function test_removeAdmin() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit AdminRemoved(account, admin); + + cheats.prank(admin); + permissionController.removeAdmin(account, admin); + + // Check storage + assertFalse(permissionController.isAdmin(account, admin), "Admin not removed"); + assertFalse(permissionController.canCall(account, admin, address(0), bytes4(0)), "Admin can still call"); + + // Assert that admin2 is now the only admin + address[] memory admins = permissionController.getAdmins(account); + assertEq(admins[0], admin2, "Account is not admin"); + assertTrue(permissionController.isAdmin(account, admin2), "Admin2 is not admin"); + assertFalse(permissionController.isAdmin(account, admin), "Account should not be admin"); + } +} + +contract PermissionControllerUnitTests_SetAppointee is PermissionControllerUnitTests { + function setUp() virtual public override { + // Setup + PermissionControllerUnitTests.setUp(); + + // Set & accept admin + cheats.prank(account); + permissionController.addPendingAdmin(account, admin); + cheats.prank(admin); + permissionController.acceptAdmin(account); + } + + function test_revert_notAdmin() public { + cheats.expectRevert(IPermissionControllerErrors.NotAdmin.selector); + permissionController.setAppointee(account, appointee1, address(0), bytes4(0)); + } + + function test_setAppointee() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit AppointeeSet(account, appointee1, target1, selector1); + + cheats.prank(admin); + permissionController.setAppointee(account, appointee1, target1, selector1); + + // Validate Permissions + _validateSetAppointee(account, appointee1, target1, selector1); + } + + function test_revert_appointeeAlreadySet() public { + // Set appointee + cheats.startPrank(admin); + permissionController.setAppointee(account, appointee1, target1, selector1); + + cheats.expectRevert(IPermissionControllerErrors.AppointeeAlreadySet.selector); + permissionController.setAppointee(account, appointee1, target1, selector1); + cheats.stopPrank(); + } + + function test_setMultipleAppointees() public { + // Set appointees + cheats.startPrank(admin); + permissionController.setAppointee(account, appointee1, target1, selector1); + permissionController.setAppointee(account, appointee1, target2, selector2); + permissionController.setAppointee(account, appointee2, target1, selector1); + cheats.stopPrank(); + + // Validate Permissions + _validateSetAppointee(account, appointee1, target1, selector1); + _validateSetAppointee(account, appointee1, target2, selector2); + _validateSetAppointee(account, appointee2, target1, selector1); + } + + function _validateSetAppointee(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + assertTrue(permissionController.canCall(accountToCheck, appointee, target, selector)); + _validateAppointeePermissions(accountToCheck, appointee, target, selector); + _validateGetAppointees(accountToCheck, appointee, target, selector); + } + + function _validateAppointeePermissions(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + (address[] memory targets, bytes4[] memory selectors) = permissionController.getAppointeePermissions(accountToCheck, appointee); + bool foundTargetSelector = false; + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == target) { + assertEq(selectors[i], selector, "Selector does not match target"); + foundTargetSelector = true; + break; + } + } + assertTrue(foundTargetSelector, "Appointee does not have permission for given target and selector"); + } + + function _validateGetAppointees(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + (address[] memory appointees) = permissionController.getAppointees(accountToCheck, target, selector); + bool foundAppointee = false; + for (uint256 i = 0; i < appointees.length; ++i) { + if (appointees[i] == appointee) { + foundAppointee = true; + break; + } + } + assertTrue(foundAppointee, "Appointee not in list of appointees for given target and selector"); + } +} + +contract PermissionControllerUnitTests_RemoveAppointee is PermissionControllerUnitTests { + function setUp() virtual public override { + // Setup + PermissionControllerUnitTests.setUp(); + + // Set & accept admin + cheats.prank(account); + permissionController.addPendingAdmin(account, admin); + cheats.prank(admin); + permissionController.acceptAdmin(account); + + // Set appointees + cheats.startPrank(admin); + permissionController.setAppointee(account, appointee1, target1, selector1); + permissionController.setAppointee(account, appointee1, target2, selector2); + permissionController.setAppointee(account, appointee2, target1, selector1); + cheats.stopPrank(); + } + + function test_revert_notAdmin() public { + cheats.expectRevert(IPermissionControllerErrors.NotAdmin.selector); + permissionController.removeAppointee(account, appointee1, target1, selector1); + } + + function test_removeAppointee() public { + // Expect emit + cheats.expectEmit(true, true, true, true); + emit AppointeeRemoved(account, appointee1, target1, selector1); + + cheats.prank(admin); + permissionController.removeAppointee(account, appointee1, target1, selector1); + + // Validate Permissions + _validateRemoveAppointee(account, appointee1, target1, selector1); + } + + function test_revert_appointeeNotSet() public { + cheats.expectRevert(IPermissionControllerErrors.AppointeeNotSet.selector); + cheats.prank(admin); + permissionController.removeAppointee(account, appointee2, target2, selector2); + } + + function test_removeMultipleAppointees() public { + // Remove appointees + cheats.startPrank(admin); + permissionController.removeAppointee(account, appointee1, target1, selector1); + permissionController.removeAppointee(account, appointee1, target2, selector2); + permissionController.removeAppointee(account, appointee2, target1, selector1); + cheats.stopPrank(); + + // Validate Permissions + _validateRemoveAppointee(account, appointee1, target1, selector1); + _validateRemoveAppointee(account, appointee1, target2, selector2); + _validateRemoveAppointee(account, appointee2, target1, selector1); + } + + // Tests that the encoding from adding an appointee is properly decoded + function test_symmetricalTargetSelector() public { + // Test Decoding + (address[] memory targets, bytes4[] memory selectors) = permissionController.getAppointeePermissions(account, appointee2); + assertEq(targets.length, 1, "Incorrect number of targets"); + assertEq(selectors.length, 1, "Incorrect number of selectors"); + assertEq(targets[0], target1, "Incorrect target"); + assertEq(selectors[0], selector1, "Incorrect selector"); + } + + + function _validateRemoveAppointee(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + assertFalse(permissionController.canCall(accountToCheck, appointee, target, selector)); + _validateAppointeePermissionsRemoved(accountToCheck, appointee, target, selector); + _validateGetAppointeesRemoved(accountToCheck, appointee, target, selector); + } + + function _validateAppointeePermissionsRemoved(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + (address[] memory targets, bytes4[] memory selectors) = permissionController.getAppointeePermissions(accountToCheck, appointee); + bool foundTargetSelector = false; + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == target && selectors[i] == selector) { + foundTargetSelector = true; + break; + } + } + assertFalse(foundTargetSelector, "Appointee still has permission for given target and selector"); + } + + function _validateGetAppointeesRemoved(address accountToCheck, address appointee, address target, bytes4 selector) internal view { + (address[] memory appointees) = permissionController.getAppointees(accountToCheck, target, selector); + bool foundAppointee = false; + for (uint256 i = 0; i < appointees.length; ++i) { + if (appointees[i] == appointee) { + foundAppointee = true; + break; + } + } + assertFalse(foundAppointee, "Appointee still in list of appointees for given target and selector"); + } +} \ No newline at end of file diff --git a/src/test/unit/RewardsCoordinatorUnit.t.sol b/src/test/unit/RewardsCoordinatorUnit.t.sol index c23498a82..b072bd852 100644 --- a/src/test/unit/RewardsCoordinatorUnit.t.sol +++ b/src/test/unit/RewardsCoordinatorUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/mocks/ERC1271WalletMock.sol"; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; @@ -7,7 +7,6 @@ import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "src/contracts/core/RewardsCoordinator.sol"; import "src/contracts/strategies/StrategyBase.sol"; -import "src/test/events/IRewardsCoordinatorEvents.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; import "src/test/mocks/Reenterer.sol"; import "src/test/mocks/ERC20Mock.sol"; @@ -39,7 +38,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin IStrategy strategyMock3; StrategyBase strategyImplementation; uint256 mockTokenInitialSupply = 1e38 - 1; - IRewardsCoordinator.StrategyAndMultiplier[] defaultStrategyAndMultipliers; + IRewardsCoordinatorTypes.StrategyAndMultiplier[] defaultStrategyAndMultipliers; // Config Variables /// @notice intervals(epochs) are 1 weeks @@ -91,8 +90,11 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin // Deploy RewardsCoordinator proxy and implementation rewardsCoordinatorImplementation = new RewardsCoordinator( - delegationManagerMock, - strategyManagerMock, + IDelegationManager(address(delegationManagerMock)), + IStrategyManager(address(strategyManagerMock)), + IAllocationManager(address(allocationManagerMock)), + pauserRegistry, + IPermissionController(address(permissionController)), CALCULATION_INTERVAL_SECONDS, MAX_REWARDS_DURATION, MAX_RETROACTIVE_LENGTH, @@ -107,7 +109,6 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin abi.encodeWithSelector( RewardsCoordinator.initialize.selector, address(this), // initOwner - pauserRegistry, 0, // 0 is initialPausedStatus rewardsUpdater, activationDelay, @@ -122,13 +123,13 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin token2 = new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); token3 = new ERC20PresetFixedSupply("pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this)); - strategyImplementation = new StrategyBase(strategyManagerMock); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token1, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, token1) ) ) ); @@ -137,7 +138,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token2, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, token2) ) ) ); @@ -146,7 +147,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token3, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, token3) ) ) ); @@ -161,21 +162,21 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin strategyManagerMock.setStrategyWhitelist(strategies[2], true); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) ); rewardsCoordinator.setRewardsForAllSubmitter(rewardsForAllSubmitter, true); rewardsCoordinator.setRewardsUpdater(rewardsUpdater); // Exclude from fuzzed tests - addressIsExcludedFromFuzzedInputs[address(rewardsCoordinator)] = true; - addressIsExcludedFromFuzzedInputs[address(rewardsUpdater)] = true; + isExcludedFuzzAddress[address(rewardsCoordinator)] = true; + isExcludedFuzzAddress[address(rewardsUpdater)] = true; // Set the timestamp to some time after the genesis rewards timestamp cheats.warp(GENESIS_REWARDS_TIMESTAMP + 5 days); @@ -204,7 +205,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin return timestamp1 > timestamp2 ? timestamp1 : timestamp2; } - function _assertRewardsClaimedEvents(bytes32 root, IRewardsCoordinator.RewardsMerkleClaim memory claim, address recipient) internal { + function _assertRewardsClaimedEvents(bytes32 root, IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim, address recipient) internal { address earner = claim.earnerLeaf.earner; address claimer = rewardsCoordinator.claimerFor(earner); if (claimer == address(0)) { @@ -231,7 +232,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin /// @notice given address and array of reward tokens, return array of cumulativeClaimed amonts function _getCumulativeClaimed( address earner, - IRewardsCoordinator.RewardsMerkleClaim memory claim + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim ) internal view returns (uint256[] memory) { uint256[] memory totalClaimed = new uint256[](claim.tokenLeaves.length); @@ -244,7 +245,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin /// @notice given a claim, return the new cumulativeEarnings for each token function _getCumulativeEarnings( - IRewardsCoordinator.RewardsMerkleClaim memory claim + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim ) internal pure returns (uint256[] memory) { uint256[] memory earnings = new uint256[](claim.tokenLeaves.length); @@ -257,7 +258,7 @@ contract RewardsCoordinatorUnitTests is EigenLayerUnitTestSetup, IRewardsCoordin function _getClaimTokenBalances( address earner, - IRewardsCoordinator.RewardsMerkleClaim memory claim + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim ) internal view returns (uint256[] memory) { uint256[] memory balances = new uint256[](claim.tokenLeaves.length); @@ -294,6 +295,46 @@ contract RewardsCoordinatorUnitTests_initializeAndSetters is RewardsCoordinatorU cheats.stopPrank(); } + function test_setClaimerFor_UAM_revert_staker(address earner, address claimer) public filterFuzzedAddressInputs(earner) { + cheats.prank(earner); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidEarner.selector); + rewardsCoordinator.setClaimerFor(earner, claimer); + } + + function test_setCLaimerFor_UAM_AVS() public { + address avs = address(1000); + address claimer = address(1001); + + // Set AVS + allocationManagerMock.setAVSSetCount(avs, 1); + + // Set claimer for AVS + cheats.startPrank(avs); + cheats.expectEmit(true, true, true, true, address(rewardsCoordinator)); + emit ClaimerForSet(avs, rewardsCoordinator.claimerFor(avs), claimer); + rewardsCoordinator.setClaimerFor(avs, claimer); + cheats.stopPrank(); + + assertEq(claimer, rewardsCoordinator.claimerFor(avs), "claimerFor not set"); + } + + function test_setClaimerFor_UAM_Operator() public { + address operator = address(1000); + address claimer = address(1001); + + // Set operator + delegationManagerMock.setIsOperator(operator, true); + + // Set claimer for operator + cheats.startPrank(operator); + cheats.expectEmit(true, true, true, true, address(rewardsCoordinator)); + emit ClaimerForSet(operator, rewardsCoordinator.claimerFor(operator), claimer); + rewardsCoordinator.setClaimerFor(operator, claimer); + cheats.stopPrank(); + + assertEq(claimer, rewardsCoordinator.claimerFor(operator), "claimerFor not set"); + } + function testFuzz_setActivationDelay(uint32 activationDelay) public { cheats.startPrank(rewardsCoordinator.owner()); cheats.expectEmit(true, true, true, true, address(rewardsCoordinator)); @@ -386,9 +427,9 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi cheats.prank(pauser); rewardsCoordinator.pause(2 ** PAUSED_AVS_REWARDS_SUBMISSION); - cheats.expectRevert("Pausable: index is paused"); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions; + rewardsCoordinator.createAVSRewardsSubmission(defaultAVS, rewardsSubmissions); } // Revert from reentrancy @@ -403,8 +444,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi _deployMockRewardTokens(address(this), 1); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: IERC20(address(reenterer)), amount: amount, @@ -416,7 +457,7 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi reenterer.prepare(targetToUse, msgValueToUse, calldataToUse, bytes("ReentrancyGuard: reentrant call")); cheats.expectRevert(); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + rewardsCoordinator.createAVSRewardsSubmission(defaultAVS, rewardsSubmissions); } // Revert with 0 length strats and multipliers @@ -444,9 +485,9 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - IRewardsCoordinator.StrategyAndMultiplier[] memory emptyStratsAndMultipliers; - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory emptyStratsAndMultipliers; + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: emptyStratsAndMultipliers, token: rewardToken, amount: amount, @@ -456,8 +497,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: no strategies set"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.InputArrayLengthZero.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert when amount > 1e38-1 @@ -482,8 +523,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -493,8 +534,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. Call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: amount too large"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.AmountExceedsMax.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } function testFuzz_Revert_WhenDuplicateStrategies( @@ -518,12 +559,12 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - IRewardsCoordinator.StrategyAndMultiplier[] - memory dupStratsAndMultipliers = new IRewardsCoordinator.StrategyAndMultiplier[](2); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + IRewardsCoordinatorTypes.StrategyAndMultiplier[] + memory dupStratsAndMultipliers = new IRewardsCoordinatorTypes.StrategyAndMultiplier[](2); dupStratsAndMultipliers[0] = defaultStrategyAndMultipliers[0]; dupStratsAndMultipliers[1] = defaultStrategyAndMultipliers[0]; - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: dupStratsAndMultipliers, token: rewardToken, amount: amount, @@ -534,9 +575,9 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); cheats.expectRevert( - "RewardsCoordinator._validateRewardsSubmission: strategies must be in ascending order to handle duplicates" + IRewardsCoordinatorErrors.StrategiesNotInAscendingOrder.selector ); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert with exceeding max duration @@ -563,8 +604,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -574,8 +615,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: duration exceeds MAX_REWARDS_DURATION"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.DurationExceedsMax.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert with invalid interval seconds @@ -603,8 +644,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -614,10 +655,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert( - "RewardsCoordinator._validateRewardsSubmission: duration must be a multiple of CALCULATION_INTERVAL_SECONDS" - ); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidDurationRemainder.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert with retroactive rewards enabled and set too far in past @@ -649,8 +688,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -660,8 +699,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: startTimestamp too far in the past"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.StartTimestampTooFarInPast.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert with start timestamp past max future length @@ -687,8 +726,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -698,8 +737,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected revert cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: startTimestamp too far in the future"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.StartTimestampTooFarInFuture.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } // Revert with non whitelisted strategy @@ -727,9 +766,9 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); defaultStrategyAndMultipliers[0].strategy = IStrategy(address(999)); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -739,8 +778,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 3. call createAVSRewardsSubmission() with expected event emitted cheats.prank(avs); - cheats.expectRevert("RewardsCoordinator._validateRewardsSubmission: invalid strategy considered"); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + cheats.expectRevert(IRewardsCoordinatorErrors.StrategyNotWhitelisted.selector); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); } /** @@ -774,8 +813,8 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -794,7 +833,7 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi cheats.expectEmit(true, true, true, true, address(rewardsCoordinator)); emit AVSRewardsSubmissionCreated(avs, currSubmissionNonce, rewardsSubmissionHash, rewardsSubmissions[0]); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + rewardsCoordinator.createAVSRewardsSubmission(avs, rewardsSubmissions); cheats.stopPrank(); assertTrue(rewardsCoordinator.isAVSRewardsSubmissionHash(avs, rewardsSubmissionHash), "rewards submission hash not submitted"); @@ -826,7 +865,7 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi cheats.assume(param.avs != address(0)); cheats.prank(rewardsCoordinator.owner()); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](numSubmissions); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](numSubmissions); bytes32[] memory rewardsSubmissionHashes = new bytes32[](numSubmissions); uint256 startSubmissionNonce = rewardsCoordinator.submissionNonce(param.avs); _deployMockRewardTokens(param.avs, numSubmissions); @@ -855,7 +894,7 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi param.startTimestamp = param.startTimestamp - (param.startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission memory rewardsSubmission = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardTokens[i], amount: amounts[i], @@ -872,7 +911,7 @@ contract RewardsCoordinatorUnitTests_createAVSRewardsSubmission is RewardsCoordi // 4. call createAVSRewardsSubmission() cheats.prank(param.avs); - rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + rewardsCoordinator.createAVSRewardsSubmission(param.avs, rewardsSubmissions); // 5. Check for submissionNonce() and rewardsSubmissionHashes being set assertEq( @@ -906,8 +945,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo cheats.prank(pauser); rewardsCoordinator.pause(2 ** PAUSED_REWARDS_FOR_ALL_SUBMISSION); - cheats.expectRevert("Pausable: index is paused"); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions; rewardsCoordinator.createRewardsForAllSubmission(rewardsSubmissions); } @@ -922,8 +961,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo _deployMockRewardTokens(address(this), 1); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: IERC20(address(reenterer)), amount: amount, @@ -944,8 +983,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo ) public filterFuzzedAddressInputs(invalidSubmitter) { cheats.assume(invalidSubmitter != rewardsForAllSubmitter); - cheats.expectRevert("RewardsCoordinator: caller is not a valid createRewardsForAllSubmission submitter"); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; + cheats.expectRevert(IRewardsCoordinatorErrors.UnauthorizedCaller.selector); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions; rewardsCoordinator.createRewardsForAllSubmission(rewardsSubmissions); } @@ -979,8 +1018,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -1034,7 +1073,7 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo cheats.assume(2 <= numSubmissions && numSubmissions <= 10); cheats.prank(rewardsCoordinator.owner()); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](numSubmissions); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](numSubmissions); bytes32[] memory rewardsSubmissionHashes = new bytes32[](numSubmissions); uint256 startSubmissionNonce = rewardsCoordinator.submissionNonce(rewardsForAllSubmitter); _deployMockRewardTokens(rewardsForAllSubmitter, numSubmissions); @@ -1063,7 +1102,7 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllSubmission is RewardsCoo param.startTimestamp = param.startTimestamp - (param.startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission memory rewardsSubmission = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardTokens[i], amount: amounts[i], @@ -1119,8 +1158,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi cheats.prank(pauser); rewardsCoordinator.pause(2 ** PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS); - cheats.expectRevert("Pausable: index is paused"); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions; rewardsCoordinator.createRewardsForAllEarners(rewardsSubmissions); } @@ -1135,8 +1174,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi _deployMockRewardTokens(address(this), 1); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: IERC20(address(reenterer)), amount: amount, @@ -1157,8 +1196,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi ) public filterFuzzedAddressInputs(invalidSubmitter) { cheats.assume(invalidSubmitter != rewardsForAllSubmitter); - cheats.expectRevert("RewardsCoordinator: caller is not a valid createRewardsForAllSubmission submitter"); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; + cheats.expectRevert(IRewardsCoordinatorErrors.UnauthorizedCaller.selector); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions; rewardsCoordinator.createRewardsForAllEarners(rewardsSubmissions); } @@ -1192,8 +1231,8 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -1247,7 +1286,7 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi cheats.assume(2 <= numSubmissions && numSubmissions <= 10); cheats.prank(rewardsCoordinator.owner()); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinator.RewardsSubmission[](numSubmissions); + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = new IRewardsCoordinatorTypes.RewardsSubmission[](numSubmissions); bytes32[] memory rewardsSubmissionHashes = new bytes32[](numSubmissions); uint256 startSubmissionNonce = rewardsCoordinator.submissionNonce(rewardsForAllSubmitter); _deployMockRewardTokens(rewardsForAllSubmitter, numSubmissions); @@ -1276,7 +1315,7 @@ contract RewardsCoordinatorUnitTests_createRewardsForAllEarners is RewardsCoordi param.startTimestamp = param.startTimestamp - (param.startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create rewards submission input param - IRewardsCoordinator.RewardsSubmission memory rewardsSubmission = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardTokens[i], amount: amounts[i], @@ -1333,7 +1372,7 @@ contract RewardsCoordinatorUnitTests_submitRoot is RewardsCoordinatorUnitTests { ) public filterFuzzedAddressInputs(invalidRewardsUpdater) { cheats.prank(invalidRewardsUpdater); - cheats.expectRevert("RewardsCoordinator: caller is not the rewardsUpdater"); + cheats.expectRevert(IRewardsCoordinatorErrors.UnauthorizedCaller.selector); rewardsCoordinator.submitRoot(bytes32(0), 0); } @@ -1341,7 +1380,7 @@ contract RewardsCoordinatorUnitTests_submitRoot is RewardsCoordinatorUnitTests { cheats.prank(pauser); rewardsCoordinator.pause(2 ** PAUSED_SUBMIT_ROOTS); - cheats.expectRevert("Pausable: index is paused"); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); rewardsCoordinator.submitRoot(bytes32(0), 0); } @@ -1456,8 +1495,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1505,8 +1544,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1554,8 +1593,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; // 1. Claim against first root { @@ -1680,8 +1719,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests cheats.startPrank(claimer); // rootIndex in claim is 0, which is disabled - IRewardsCoordinator.RewardsMerkleClaim memory claim; - cheats.expectRevert("RewardsCoordinator._checkClaim: root is disabled"); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim; + cheats.expectRevert(IRewardsCoordinatorErrors.RootDisabled.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); } @@ -1703,8 +1742,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; // 1. Claim against first root { @@ -1748,9 +1787,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests cheats.startPrank(claimer); assertTrue(rewardsCoordinator.checkClaim(claim), "RewardsCoordinator.checkClaim: claim not valid"); - cheats.expectRevert( - "RewardsCoordinator.processClaim: cumulativeEarnings must be gt than cumulativeClaimed" - ); + cheats.expectRevert(IRewardsCoordinatorErrors.EarningsNotGreaterThanClaimed.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); @@ -1774,8 +1811,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1788,10 +1825,10 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests // Check claim is not valid from both checkClaim() and processClaim() throwing a revert cheats.startPrank(claimer); - cheats.expectRevert("RewardsCoordinator._verifyTokenClaim: invalid token claim proof"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidClaimProof.selector); assertFalse(rewardsCoordinator.checkClaim(claim), "RewardsCoordinator.checkClaim: claim not valid"); - cheats.expectRevert("RewardsCoordinator._verifyTokenClaim: invalid token claim proof"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidClaimProof.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); @@ -1815,8 +1852,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1828,10 +1865,10 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests // Check claim is not valid from both checkClaim() and processClaim() throwing a revert cheats.startPrank(claimer); - cheats.expectRevert("RewardsCoordinator._verifyEarnerClaimProof: invalid earner claim proof"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidClaimProof.selector); assertFalse(rewardsCoordinator.checkClaim(claim), "RewardsCoordinator.checkClaim: claim not valid"); - cheats.expectRevert("RewardsCoordinator._verifyEarnerClaimProof: invalid earner claim proof"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidClaimProof.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); @@ -1854,8 +1891,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1871,7 +1908,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests .with_key(address(claim.tokenLeaves[0].token)) .checked_write(type(uint256).max); cheats.startPrank(claimer); - cheats.expectRevert("RewardsCoordinator.processClaim: cumulativeEarnings must be gt than cumulativeClaimed"); + cheats.expectRevert(IRewardsCoordinatorErrors.EarningsNotGreaterThanClaimed.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); } @@ -1895,8 +1932,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1909,7 +1946,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests uint8 proofLength = uint8(claim.tokenTreeProofs[0].length); claim.tokenIndices[0] = claim.tokenIndices[0] | uint32(1 << (numShift + proofLength / 32)); cheats.startPrank(claimer); - cheats.expectRevert("RewardsCoordinator._verifyTokenClaim: invalid tokenLeafIndex"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidTokenLeafIndex.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); } @@ -1933,8 +1970,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofs(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[2]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofs(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[2]; uint32 rootIndex = claim.rootIndex; IRewardsCoordinator.DistributionRoot memory distributionRoot = rewardsCoordinator.getDistributionRootAtIndex(rootIndex); @@ -1947,7 +1984,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests uint8 proofLength = uint8(claim.earnerTreeProof.length); claim.earnerIndex = claim.earnerIndex | uint32(1 << (numShift + proofLength / 32)); cheats.startPrank(claimer); - cheats.expectRevert("RewardsCoordinator._verifyEarnerClaimProof: invalid earnerLeafIndex"); + cheats.expectRevert(IRewardsCoordinatorErrors.InvalidEarnerLeafIndex.selector); rewardsCoordinator.processClaim(claim, claimer); cheats.stopPrank(); } @@ -1971,8 +2008,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofsMaxEarnerAndLeafIndices(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofsMaxEarnerAndLeafIndices(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; // 1. Claim against first root where earner tree is full tree and earner and token index is last index of that tree height { @@ -2036,8 +2073,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofsSingleTokenLeaf(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofsSingleTokenLeaf(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; // 1. Claim against first root where earner tree is full tree and earner and token index is last index of that tree height { @@ -2101,8 +2138,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } // Parse all 3 claim proofs for distributionRoots 0,1,2 respectively - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = _parseAllProofsSingleEarnerLeaf(); - IRewardsCoordinator.RewardsMerkleClaim memory claim = claims[0]; + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = _parseAllProofsSingleEarnerLeaf(); + IRewardsCoordinatorTypes.RewardsMerkleClaim memory claim = claims[0]; // 1. Claim against first root where earner tree is full tree and earner and token index is last index of that tree height { @@ -2155,7 +2192,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests } /// @notice parse proofs from json file and submitRoot() - function _parseProofData(string memory filePath) internal returns (IRewardsCoordinator.RewardsMerkleClaim memory) { + function _parseProofData(string memory filePath) internal returns (IRewardsCoordinatorTypes.RewardsMerkleClaim memory) { cheats.readFile(filePath); string memory claimProofData = cheats.readFile(filePath); @@ -2170,7 +2207,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests uint256 numTokenLeaves = stdJson.readUint(claimProofData, ".TokenLeavesNum"); uint256 numTokenTreeProofs = stdJson.readUint(claimProofData, ".TokenTreeProofsNum"); - IRewardsCoordinator.TokenTreeMerkleLeaf[] memory tokenLeaves = new IRewardsCoordinator.TokenTreeMerkleLeaf[]( + IRewardsCoordinatorTypes.TokenTreeMerkleLeaf[] memory tokenLeaves = new IRewardsCoordinatorTypes.TokenTreeMerkleLeaf[]( numTokenLeaves ); uint32[] memory tokenIndices = new uint32[](numTokenLeaves); @@ -2181,7 +2218,7 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests IERC20 token = IERC20(stdJson.readAddress(claimProofData, tokenKey)); uint256 cumulativeEarnings = stdJson.readUint(claimProofData, amountKey); - tokenLeaves[i] = IRewardsCoordinator.TokenTreeMerkleLeaf({ + tokenLeaves[i] = IRewardsCoordinatorTypes.TokenTreeMerkleLeaf({ token: token, cumulativeEarnings: cumulativeEarnings }); @@ -2207,11 +2244,11 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests cheats.prank(rewardsUpdater); rewardsCoordinator.submitRoot(merkleRoot, prevRootCalculationEndTimestamp); - IRewardsCoordinator.RewardsMerkleClaim memory newClaim = IRewardsCoordinator.RewardsMerkleClaim({ + IRewardsCoordinatorTypes.RewardsMerkleClaim memory newClaim = IRewardsCoordinatorTypes.RewardsMerkleClaim({ rootIndex: rootIndex, earnerIndex: earnerIndex, earnerTreeProof: earnerTreeProof, - earnerLeaf: IRewardsCoordinator.EarnerTreeMerkleLeaf({earner: earner, earnerTokenRoot: earnerTokenRoot}), + earnerLeaf: IRewardsCoordinatorTypes.EarnerTreeMerkleLeaf({earner: earner, earnerTokenRoot: earnerTokenRoot}), tokenIndices: tokenIndices, tokenTreeProofs: tokenTreeProofs, tokenLeaves: tokenLeaves @@ -2220,8 +2257,8 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests return newClaim; } - function _parseAllProofs() internal virtual returns (IRewardsCoordinator.RewardsMerkleClaim[] memory) { - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = new IRewardsCoordinator.RewardsMerkleClaim[](3); + function _parseAllProofs() internal virtual returns (IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory) { + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = new IRewardsCoordinatorTypes.RewardsMerkleClaim[](3); claims[0] = _parseProofData("src/test/test-data/rewardsCoordinator/processClaimProofs_Root1.json"); claims[1] = _parseProofData("src/test/test-data/rewardsCoordinator/processClaimProofs_Root2.json"); @@ -2230,27 +2267,27 @@ contract RewardsCoordinatorUnitTests_processClaim is RewardsCoordinatorUnitTests return claims; } - function _parseAllProofsMaxEarnerAndLeafIndices() internal virtual returns (IRewardsCoordinator.RewardsMerkleClaim[] memory) { - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = new IRewardsCoordinator.RewardsMerkleClaim[](1); + function _parseAllProofsMaxEarnerAndLeafIndices() internal virtual returns (IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory) { + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = new IRewardsCoordinatorTypes.RewardsMerkleClaim[](1); claims[0] = _parseProofData("src/test/test-data/rewardsCoordinator/processClaimProofs_MaxEarnerAndLeafIndices.json"); return claims; } - function _parseAllProofsSingleTokenLeaf() internal virtual returns (IRewardsCoordinator.RewardsMerkleClaim[] memory) { - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = new IRewardsCoordinator.RewardsMerkleClaim[](1); + function _parseAllProofsSingleTokenLeaf() internal virtual returns (IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory) { + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = new IRewardsCoordinatorTypes.RewardsMerkleClaim[](1); claims[0] = _parseProofData("src/test/test-data/rewardsCoordinator/processClaimProofs_SingleTokenLeaf.json"); return claims; } - function _parseAllProofsSingleEarnerLeaf() internal virtual returns (IRewardsCoordinator.RewardsMerkleClaim[] memory) { - IRewardsCoordinator.RewardsMerkleClaim[] memory claims = new IRewardsCoordinator.RewardsMerkleClaim[](1); + function _parseAllProofsSingleEarnerLeaf() internal virtual returns (IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory) { + IRewardsCoordinatorTypes.RewardsMerkleClaim[] memory claims = new IRewardsCoordinatorTypes.RewardsMerkleClaim[](1); claims[0] = _parseProofData("src/test/test-data/rewardsCoordinator/processClaimProofs_SingleEarnerLeaf.json"); return claims; } -} +} \ No newline at end of file diff --git a/src/test/unit/StrategyBaseTVLLimitsUnit.sol b/src/test/unit/StrategyBaseTVLLimitsUnit.sol index 6a2b1d8f9..797621b68 100644 --- a/src/test/unit/StrategyBaseTVLLimitsUnit.sol +++ b/src/test/unit/StrategyBaseTVLLimitsUnit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "./StrategyBaseUnit.t.sol"; @@ -24,7 +24,7 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { StrategyBaseUnitTests.setUp(); // depoloy the TVL-limited strategy - strategyBaseTVLLimitsImplementation = new StrategyBaseTVLLimits(strategyManager); + strategyBaseTVLLimitsImplementation = new StrategyBaseTVLLimits(strategyManager, pauserRegistry); strategyWithTVLLimits = StrategyBaseTVLLimits( address( new TransparentUpgradeableProxy( @@ -55,28 +55,25 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { function testSetTVLLimitsFailsWhenNotCalledByUnpauser(uint256 maxPerDepositFuzzedInput, uint256 maxTotalDepositsFuzzedInput, address notUnpauser) public { cheats.assume(notUnpauser != address(proxyAdmin)); cheats.assume(notUnpauser != unpauser); - cheats.startPrank(notUnpauser); - cheats.expectRevert(bytes("msg.sender is not permissioned as unpauser")); + cheats.prank(notUnpauser); + cheats.expectRevert(IPausable.OnlyUnpauser.selector); strategyWithTVLLimits.setTVLLimits(maxPerDepositFuzzedInput, maxTotalDepositsFuzzedInput); - cheats.stopPrank(); } function testSetInvalidMaxPerDepositAndMaxDeposits(uint256 maxPerDepositFuzzedInput, uint256 maxTotalDepositsFuzzedInput) public { cheats.assume(maxTotalDepositsFuzzedInput < maxPerDepositFuzzedInput); - cheats.startPrank(unpauser); - cheats.expectRevert(bytes("StrategyBaseTVLLimits._setTVLLimits: maxPerDeposit exceeds maxTotalDeposits")); + cheats.prank(unpauser); + cheats.expectRevert(IStrategyErrors.MaxPerDepositExceedsMax.selector); strategyWithTVLLimits.setTVLLimits(maxPerDepositFuzzedInput, maxTotalDepositsFuzzedInput); - cheats.stopPrank(); } function testDepositMoreThanMaxPerDeposit(uint256 maxPerDepositFuzzedInput, uint256 maxTotalDepositsFuzzedInput, uint256 amount) public { cheats.assume(amount > maxPerDepositFuzzedInput); _setTVLLimits(maxPerDepositFuzzedInput, maxTotalDepositsFuzzedInput); - cheats.startPrank(address(strategyManager)); - cheats.expectRevert(bytes("StrategyBaseTVLLimits: max per deposit exceeded")); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.MaxPerDepositExceedsMax.selector); strategyWithTVLLimits.deposit(underlyingToken, amount); - cheats.stopPrank(); } function testDepositMorethanMaxDeposits() public { @@ -97,10 +94,9 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { underlyingToken.transfer(address(strategyWithTVLLimits), maxPerDeposit); require(underlyingToken.balanceOf(address(strategyWithTVLLimits)) > maxTotalDeposits, "bad test setup"); - cheats.startPrank(address(strategyManager)); - cheats.expectRevert(bytes("StrategyBaseTVLLimits: max deposits exceeded")); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.BalanceExceedsMaxTotalDeposits.selector); strategyWithTVLLimits.deposit(underlyingToken, maxPerDeposit); - cheats.stopPrank(); } function testDepositValidAmount(uint256 depositAmount) public { @@ -115,9 +111,8 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { underlyingToken.transfer(address(strategyWithTVLLimits), depositAmount); uint256 sharesBefore = strategyWithTVLLimits.totalShares(); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategyWithTVLLimits.deposit(underlyingToken, depositAmount); - cheats.stopPrank(); require(strategyWithTVLLimits.totalShares() == depositAmount + sharesBefore, "total shares not updated correctly"); } @@ -126,30 +121,26 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { cheats.assume(maxTotalDepositsFuzzedInput > 0); cheats.assume(newMaxTotalDepositsFuzzedInput > maxTotalDepositsFuzzedInput); cheats.assume(newMaxTotalDepositsFuzzedInput < initialSupply); - cheats.startPrank(unpauser); + cheats.prank(unpauser); strategyWithTVLLimits.setTVLLimits(maxTotalDepositsFuzzedInput, maxTotalDepositsFuzzedInput); - cheats.stopPrank(); underlyingToken.transfer(address(strategyWithTVLLimits), maxTotalDepositsFuzzedInput); uint256 sharesBefore = strategyWithTVLLimits.totalShares(); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategyWithTVLLimits.deposit(underlyingToken, maxTotalDepositsFuzzedInput); - cheats.stopPrank(); require(strategyWithTVLLimits.totalShares() == maxTotalDepositsFuzzedInput + sharesBefore, "total shares not updated correctly"); - cheats.startPrank(unpauser); + cheats.prank(unpauser); strategyWithTVLLimits.setTVLLimits(newMaxTotalDepositsFuzzedInput, newMaxTotalDepositsFuzzedInput); - cheats.stopPrank(); underlyingToken.transfer(address(strategyWithTVLLimits), newMaxTotalDepositsFuzzedInput - maxTotalDepositsFuzzedInput); sharesBefore = strategyWithTVLLimits.totalShares(); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategyWithTVLLimits.deposit(underlyingToken, newMaxTotalDepositsFuzzedInput - maxTotalDepositsFuzzedInput); - cheats.stopPrank(); require(strategyWithTVLLimits.totalShares() == newMaxTotalDepositsFuzzedInput, "total shares not updated correctly"); } @@ -171,50 +162,43 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { underlyingToken.transfer(address(strategyWithTVLLimits), depositAmount); if (depositAmount > maxPerDepositFuzzedInput) { - cheats.startPrank(address(strategyManager)); - cheats.expectRevert("StrategyBaseTVLLimits: max per deposit exceeded"); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.MaxPerDepositExceedsMax.selector); strategyWithTVLLimits.deposit(underlyingToken, depositAmount); - cheats.stopPrank(); // transfer the tokens back from the strategy to not mess up the state - cheats.startPrank(address(strategyWithTVLLimits)); + cheats.prank(address(strategyWithTVLLimits)); underlyingToken.transfer(address(this), depositAmount); - cheats.stopPrank(); // return 'true' since the call to `deposit` reverted return true; } else if (underlyingToken.balanceOf(address(strategyWithTVLLimits)) > maxTotalDepositsFuzzedInput) { - cheats.startPrank(address(strategyManager)); - cheats.expectRevert("StrategyBaseTVLLimits: max deposits exceeded"); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.MaxPerDepositExceedsMax.selector); strategyWithTVLLimits.deposit(underlyingToken, depositAmount); - cheats.stopPrank(); // transfer the tokens back from the strategy to not mess up the state - cheats.startPrank(address(strategyWithTVLLimits)); + cheats.prank(address(strategyWithTVLLimits)); underlyingToken.transfer(address(this), depositAmount); - cheats.stopPrank(); // return 'true' since the call to `deposit` reverted return true; } else { uint256 totalSharesBefore = strategyWithTVLLimits.totalShares(); if (expectedSharesOut == 0) { - cheats.startPrank(address(strategyManager)); - cheats.expectRevert("StrategyBase.deposit: newShares cannot be zero"); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.NewSharesZero.selector); strategyWithTVLLimits.deposit(underlyingToken, depositAmount); - cheats.stopPrank(); // transfer the tokens back from the strategy to not mess up the state - cheats.startPrank(address(strategyWithTVLLimits)); + cheats.prank(address(strategyWithTVLLimits)); underlyingToken.transfer(address(this), depositAmount); - cheats.stopPrank(); // return 'true' since the call to `deposit` reverted return true; } else { - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategyWithTVLLimits.deposit(underlyingToken, depositAmount); - cheats.stopPrank(); require(strategyWithTVLLimits.totalShares() == expectedSharesOut + totalSharesBefore, "total shares not updated correctly"); @@ -228,12 +212,11 @@ contract StrategyBaseTVLLimitsUnitTests is StrategyBaseUnitTests { function _setTVLLimits(uint256 _maxPerDeposit, uint256 _maxTotalDeposits) internal { cheats.assume(_maxPerDeposit < _maxTotalDeposits); (uint256 _maxPerDepositBefore, uint256 _maxTotalDepositsBefore) = strategyWithTVLLimits.getTVLLimits(); - cheats.startPrank(unpauser); cheats.expectEmit(true, true, true, true, address(strategyWithTVLLimits)); + cheats.prank(unpauser); emit MaxPerDepositUpdated(_maxPerDepositBefore, _maxPerDeposit); emit MaxTotalDepositsUpdated(_maxTotalDepositsBefore, _maxTotalDeposits); strategyWithTVLLimits.setTVLLimits(_maxPerDeposit, _maxTotalDeposits); - cheats.stopPrank(); } /// OVERRIDING EXISTING TESTS TO FILTER INPUTS THAT WOULD FAIL DUE TO DEPOSIT-LIMITING diff --git a/src/test/unit/StrategyBaseUnit.t.sol b/src/test/unit/StrategyBaseUnit.t.sol index e721e9cef..13a80673b 100644 --- a/src/test/unit/StrategyBaseUnit.t.sol +++ b/src/test/unit/StrategyBaseUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; @@ -51,18 +51,18 @@ contract StrategyBaseUnitTests is Test { pausers[0] = pauser; pauserRegistry = new PauserRegistry(pausers, unpauser); - strategyManager = new StrategyManagerMock(); + strategyManager = IStrategyManager(address(new StrategyManagerMock(IDelegationManager(address(0))))); underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", initialSupply, initialOwner); - strategyImplementation = new StrategyBase(strategyManager); + strategyImplementation = new StrategyBase(strategyManager, pauserRegistry); strategy = StrategyBase( address( new TransparentUpgradeableProxy( address(strategyImplementation), address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); @@ -70,14 +70,14 @@ contract StrategyBaseUnitTests is Test { function testCannotReinitialize() public { cheats.expectRevert(bytes("Initializable: contract is already initialized")); - strategy.initialize(underlyingToken, pauserRegistry); + strategy.initialize(underlyingToken); } function testCannotReceiveZeroShares() public { uint256 amountToDeposit = 0; cheats.startPrank(address(strategyManager)); - cheats.expectRevert(bytes("StrategyBase.deposit: newShares cannot be zero")); + cheats.expectRevert(IStrategyErrors.NewSharesZero.selector); strategy.deposit(underlyingToken, amountToDeposit); cheats.stopPrank(); } @@ -91,11 +91,10 @@ contract StrategyBaseUnitTests is Test { underlyingToken.transfer(address(strategy), amountToDeposit); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); cheats.expectEmit(true, true, true, true, address(strategy)); emit ExchangeRateEmitted(1e18); uint256 newShares = strategy.deposit(underlyingToken, amountToDeposit); - cheats.stopPrank(); require(newShares == amountToDeposit, "newShares != amountToDeposit"); uint256 totalSharesAfter = strategy.totalShares(); @@ -115,10 +114,8 @@ contract StrategyBaseUnitTests is Test { underlyingToken.transfer(address(strategy), amountToDeposit); - cheats.startPrank(address(strategyManager)); - + cheats.prank(address(strategyManager)); uint256 newShares = strategy.deposit(underlyingToken, amountToDeposit); - cheats.stopPrank(); require(newShares == amountToDeposit, "newShares != amountToDeposit"); uint256 totalSharesAfter = strategy.totalShares(); @@ -127,17 +124,15 @@ contract StrategyBaseUnitTests is Test { function testDepositFailsWhenDepositsPaused() public { // pause deposits - cheats.startPrank(pauser); + cheats.prank(pauser); strategy.pause(1); - cheats.stopPrank(); uint256 amountToDeposit = 1e18; underlyingToken.transfer(address(strategy), amountToDeposit); - cheats.expectRevert(bytes("Pausable: index is paused")); - cheats.startPrank(address(strategyManager)); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + cheats.prank(address(strategyManager)); strategy.deposit(underlyingToken, amountToDeposit); - cheats.stopPrank(); } @@ -147,10 +142,9 @@ contract StrategyBaseUnitTests is Test { uint256 amountToDeposit = 1e18; underlyingToken.transfer(address(strategy), amountToDeposit); - cheats.expectRevert(bytes("StrategyBase.onlyStrategyManager")); - cheats.startPrank(caller); + cheats.expectRevert(IStrategyErrors.OnlyStrategyManager.selector); + cheats.prank(caller); strategy.deposit(underlyingToken, amountToDeposit); - cheats.stopPrank(); } function testDepositFailsWhenNotUsingUnderlyingToken(address notUnderlyingToken) public { @@ -158,24 +152,23 @@ contract StrategyBaseUnitTests is Test { uint256 amountToDeposit = 1e18; - cheats.expectRevert(bytes("StrategyBase.deposit: Can only deposit underlyingToken")); - cheats.startPrank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.OnlyUnderlyingToken.selector); + cheats.prank(address(strategyManager)); strategy.deposit(IERC20(notUnderlyingToken), amountToDeposit); - cheats.stopPrank(); } function testDepositFailForTooManyShares() public { // Deploy token with 1e39 total supply underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", 1e39, initialOwner); - strategyImplementation = new StrategyBase(strategyManager); + strategyImplementation = new StrategyBase(strategyManager, pauserRegistry); strategy = StrategyBase( address( new TransparentUpgradeableProxy( address(strategyImplementation), address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); @@ -187,7 +180,7 @@ contract StrategyBaseUnitTests is Test { // Deposit cheats.prank(address(strategyManager)); - cheats.expectRevert(bytes("StrategyBase.deposit: totalShares exceeds `MAX_TOTAL_SHARES`")); + cheats.expectRevert(IStrategyErrors.TotalSharesExceedsMax.selector); strategy.deposit(underlyingToken, amountToDeposit); } @@ -199,13 +192,11 @@ contract StrategyBaseUnitTests is Test { uint256 strategyBalanceBefore = underlyingToken.balanceOf(address(strategy)); uint256 tokenBalanceBefore = underlyingToken.balanceOf(address(this)); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); cheats.expectEmit(true, true, true, true, address(strategy)); emit ExchangeRateEmitted(1e18); strategy.withdraw(address(this), underlyingToken, sharesToWithdraw); - cheats.stopPrank(); - uint256 tokenBalanceAfter = underlyingToken.balanceOf(address(this)); uint256 totalSharesAfter = strategy.totalShares(); @@ -223,9 +214,8 @@ contract StrategyBaseUnitTests is Test { uint256 tokenBalanceBefore = underlyingToken.balanceOf(address(this)); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, sharesToWithdraw); - cheats.stopPrank(); uint256 tokenBalanceAfter = underlyingToken.balanceOf(address(this)); uint256 totalSharesAfter = strategy.totalShares(); @@ -243,9 +233,8 @@ contract StrategyBaseUnitTests is Test { uint256 sharesBefore = strategy.totalShares(); uint256 tokenBalanceBefore = underlyingToken.balanceOf(address(this)); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, amountToWithdraw); - cheats.stopPrank(); require(sharesBefore == strategy.totalShares(), "shares changed"); require(tokenBalanceBefore == underlyingToken.balanceOf(address(this)), "token balance changed"); @@ -256,16 +245,14 @@ contract StrategyBaseUnitTests is Test { testDepositWithZeroPriorBalanceAndZeroPriorShares(amountToDeposit); // pause withdrawals - cheats.startPrank(pauser); + cheats.prank(pauser); strategy.pause(2); - cheats.stopPrank(); uint256 amountToWithdraw = 1e18; - cheats.expectRevert(bytes("Pausable: index is paused")); - cheats.startPrank(address(strategyManager)); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, amountToWithdraw); - cheats.stopPrank(); } function testWithdrawalFailsWhenCallingFromNotStrategyManager(address caller) public { @@ -276,10 +263,9 @@ contract StrategyBaseUnitTests is Test { uint256 amountToWithdraw = 1e18; - cheats.expectRevert(bytes("StrategyBase.onlyStrategyManager")); - cheats.startPrank(caller); + cheats.expectRevert(IStrategyErrors.OnlyStrategyManager.selector); + cheats.prank(caller); strategy.withdraw(address(this), underlyingToken, amountToWithdraw); - cheats.stopPrank(); } function testWithdrawalFailsWhenNotUsingUnderlyingToken(address notUnderlyingToken) public { @@ -287,10 +273,9 @@ contract StrategyBaseUnitTests is Test { uint256 amountToWithdraw = 1e18; - cheats.expectRevert(bytes("StrategyBase.withdraw: Can only withdraw the strategy token")); - cheats.startPrank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.OnlyUnderlyingToken.selector); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), IERC20(notUnderlyingToken), amountToWithdraw); - cheats.stopPrank(); } function testWithdrawFailsWhenSharesGreaterThanTotalShares(uint256 amountToDeposit, uint256 sharesToWithdraw) public virtual { @@ -302,10 +287,9 @@ contract StrategyBaseUnitTests is Test { // since we are checking strictly greater than in this test cheats.assume(sharesToWithdraw > totalSharesBefore); - cheats.expectRevert(bytes("StrategyBase.withdraw: amountShares must be less than or equal to totalShares")); - cheats.startPrank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.WithdrawalAmountExceedsTotalDeposits.selector); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, sharesToWithdraw); - cheats.stopPrank(); } function testWithdrawalFailsWhenTokenTransferFails() public { @@ -316,7 +300,7 @@ contract StrategyBaseUnitTests is Test { new TransparentUpgradeableProxy( address(strategyImplementation), address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); @@ -328,9 +312,8 @@ contract StrategyBaseUnitTests is Test { ERC20_SetTransferReverting_Mock(address(underlyingToken)).setTransfersRevert(true); cheats.expectRevert(); - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, amountToWithdraw); - cheats.stopPrank(); } // uint240 input to prevent overflow @@ -343,10 +326,9 @@ contract StrategyBaseUnitTests is Test { } function testDeposit_ZeroAmount() public { - cheats.startPrank(address(strategyManager)); - cheats.expectRevert(bytes("StrategyBase.deposit: newShares cannot be zero")); + cheats.prank(address(strategyManager)); + cheats.expectRevert(IStrategyErrors.NewSharesZero.selector); strategy.deposit(underlyingToken, 0); - cheats.stopPrank(); } @@ -406,8 +388,7 @@ contract StrategyBaseUnitTests is Test { uint256 sharesToWithdraw = totalSharesBefore - sharesToLeave; - cheats.startPrank(address(strategyManager)); + cheats.prank(address(strategyManager)); strategy.withdraw(address(this), underlyingToken, sharesToWithdraw); - cheats.stopPrank(); } -} +} \ No newline at end of file diff --git a/src/test/unit/StrategyFactoryUnit.t.sol b/src/test/unit/StrategyFactoryUnit.t.sol index d8bd92858..577585116 100644 --- a/src/test/unit/StrategyFactoryUnit.t.sol +++ b/src/test/unit/StrategyFactoryUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; @@ -46,12 +46,12 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { underlyingToken = new ERC20PresetFixedSupply("Test Token", "TEST", initialSupply, initialOwner); - strategyImplementation = new StrategyBase(strategyManagerMock); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyBeacon = new UpgradeableBeacon(address(strategyImplementation)); strategyBeacon.transferOwnership(beaconProxyOwner); - strategyFactoryImplementation = new StrategyFactory(strategyManagerMock); + strategyFactoryImplementation = new StrategyFactory(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyFactory = StrategyFactory( address( @@ -60,7 +60,6 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { address(eigenLayerProxyAdmin), abi.encodeWithSelector(StrategyFactory.initialize.selector, initialOwner, - pauserRegistry, initialPausedStatus, strategyBeacon ) @@ -69,7 +68,7 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { ); } - function test_initialization() public { + function test_initialization() public view { assertEq( address(strategyFactory.strategyManager()), address(strategyManagerMock), @@ -99,7 +98,6 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { cheats.expectRevert("Initializable: contract is already initialized"); strategyFactory.initialize({ _initialOwner: initialOwner, - _pauserRegistry: pauserRegistry, _initialPausedStatus: initialPausedStatus, _strategyBeacon: strategyBeacon }); @@ -111,17 +109,16 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { StrategyBase newStrategy = StrategyBase(address(strategyFactory.deployNewStrategy(underlyingToken))); require(strategyFactory.deployedStrategies(underlyingToken) == newStrategy, "deployedStrategies mapping not set correctly"); - require(newStrategy.strategyManager() == strategyManagerMock, "strategyManager not set correctly"); + require(address(newStrategy.strategyManager()) == address(strategyManagerMock), "strategyManager not set correctly"); require(strategyBeacon.implementation() == address(strategyImplementation), "strategyImplementation not set correctly"); require(newStrategy.pauserRegistry() == pauserRegistry, "pauserRegistry not set correctly"); require(newStrategy.underlyingToken() == underlyingToken, "underlyingToken not set correctly"); require(strategyManagerMock.strategyIsWhitelistedForDeposit(newStrategy), "underlyingToken is not whitelisted"); - require(!strategyManagerMock.thirdPartyTransfersForbidden(newStrategy), "newStrategy has 3rd party transfers forbidden"); } function test_deployNewStrategy_revert_StrategyAlreadyExists() public { test_deployNewStrategy(); - cheats.expectRevert("StrategyFactory.deployNewStrategy: Strategy already exists for token"); + cheats.expectRevert(IStrategyFactory.StrategyAlreadyExists.selector); strategyFactory.deployNewStrategy(underlyingToken); } @@ -134,7 +131,7 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { emit TokenBlacklisted(token); strategyFactory.blacklistTokens(tokens); - cheats.expectRevert("StrategyFactory.deployNewStrategy: Token is blacklisted"); + cheats.expectRevert(IStrategyFactory.BlacklistedToken.selector); strategyFactory.deployNewStrategy(token); } @@ -159,38 +156,18 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { function test_whitelistStrategies() public { StrategyBase strategy = _deployStrategy(); IStrategy[] memory strategiesToWhitelist = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); strategiesToWhitelist[0] = strategy; - thirdPartyTransfersForbiddenValues[0] = true; - strategyFactory.whitelistStrategies(strategiesToWhitelist, thirdPartyTransfersForbiddenValues); + strategyFactory.whitelistStrategies(strategiesToWhitelist); assertTrue(strategyManagerMock.strategyIsWhitelistedForDeposit(strategy), "Strategy not whitelisted"); - require(strategyManagerMock.thirdPartyTransfersForbidden(strategy), "3rd party transfers forbidden not set correctly"); } function test_whitelistStrategies_revert_notOwner() public { IStrategy[] memory strategiesToWhitelist = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); cheats.expectRevert("Ownable: caller is not the owner"); cheats.prank(notOwner); - strategyFactory.whitelistStrategies(strategiesToWhitelist, thirdPartyTransfersForbiddenValues); - } - - function test_setThirdPartyTransfersForbidden_revert_notOwner() public { - IStrategy strategy; - - cheats.expectRevert("Ownable: caller is not the owner"); - cheats.prank(notOwner); - strategyFactory.setThirdPartyTransfersForbidden(strategy, true); - } - - function test_setThirdPartyTransfersFrobidden() public { - StrategyBase strategy = _deployStrategy(); - bool thirdPartyTransfersForbidden = true; - - strategyFactory.setThirdPartyTransfersForbidden(strategy, thirdPartyTransfersForbidden); - assertTrue(strategyManagerMock.thirdPartyTransfersForbidden(strategy), "3rd party transfers forbidden not set"); + strategyFactory.whitelistStrategies(strategiesToWhitelist); } function test_removeStrategiesFromWhitelist_revert_notOwner() public { @@ -216,7 +193,7 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup { new TransparentUpgradeableProxy( address(strategyImplementation), address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry) + abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); diff --git a/src/test/unit/StrategyManagerUnit.t.sol b/src/test/unit/StrategyManagerUnit.t.sol index 189c495cd..00d0d0928 100644 --- a/src/test/unit/StrategyManagerUnit.t.sol +++ b/src/test/unit/StrategyManagerUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/mocks/ERC1271WalletMock.sol"; import "src/contracts/core/StrategyManager.sol"; @@ -10,7 +10,6 @@ import "src/test/mocks/ERC20_SetTransferReverting_Mock.sol"; import "src/test/mocks/Reverter.sol"; import "src/test/mocks/Reenterer.sol"; import "src/test/mocks/MockDecimals.sol"; -import "src/test/events/IStrategyManagerEvents.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; /** @@ -37,7 +36,9 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv function setUp() public override { EigenLayerUnitTestSetup.setUp(); - strategyManagerImplementation = new StrategyManager(delegationManagerMock, eigenPodManagerMock, slasherMock); + strategyManagerImplementation = new StrategyManager( + IDelegationManager(address(delegationManagerMock)), pauserRegistry + ); strategyManager = StrategyManager( address( new TransparentUpgradeableProxy( @@ -47,7 +48,6 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv StrategyManager.initialize.selector, initialOwner, initialOwner, - pauserRegistry, 0 /*initialPausedStatus*/ ) ) @@ -66,19 +66,13 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv _strategies[0] = dummyStrat; _strategies[1] = dummyStrat2; _strategies[2] = dummyStrat3; - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](3); - _thirdPartyTransfersForbiddenValues[0] = false; - _thirdPartyTransfersForbiddenValues[1] = false; - _thirdPartyTransfersForbiddenValues[2] = false; for (uint256 i = 0; i < _strategies.length; ++i) { cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(_strategies[i]); - cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit UpdatedThirdPartyTransfersForbidden(_strategies[i], _thirdPartyTransfersForbiddenValues[i]); } - strategyManager.addStrategiesToDepositWhitelist(_strategies, _thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(_strategies); - addressIsExcludedFromFuzzedInputs[address(reenterer)] = true; + isExcludedFuzzAddress[address(reenterer)] = true; } // INTERNAL / HELPER FUNCTIONS @@ -88,9 +82,9 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv IPauserRegistry _pauserRegistry, address admin ) public returns (StrategyBase) { - StrategyBase newStrategy = new StrategyBase(_strategyManager); + StrategyBase newStrategy = new StrategyBase(_strategyManager, _pauserRegistry); newStrategy = StrategyBase(address(new TransparentUpgradeableProxy(address(newStrategy), address(admin), ""))); - newStrategy.initialize(_token, _pauserRegistry); + newStrategy.initialize(_token); return newStrategy; } @@ -108,22 +102,22 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv // sanity check / filter cheats.assume(amount <= token.balanceOf(address(this))); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); // needed for expecting an event with the right parameters - uint256 expectedShares = amount; + uint256 expectedDepositShares = amount; cheats.prank(staker); cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit Deposit(staker, token, strategy, expectedShares); + emit Deposit(staker, token, strategy, expectedDepositShares); uint256 shares = strategyManager.depositIntoStrategy(strategy, token, amount); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - assertEq(sharesAfter, sharesBefore + shares, "sharesAfter != sharesBefore + shares"); - if (sharesBefore == 0) { + assertEq(depositSharesAfter, depositSharesBefore + shares, "depositSharesAfter != depositSharesBefore + shares"); + if (depositSharesBefore == 0) { assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore + 1, @@ -142,7 +136,7 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv address staker, uint256 amount, uint256 expiry, - string memory expectedRevertMessage + bytes4 expectedRevertMessage ) internal returns (bytes memory) { // filter out zero case since it will revert with "StrategyManager._addShares: shares should not be zero!" cheats.assume(amount != 0); @@ -163,23 +157,18 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv signature = abi.encodePacked(r, s, v); } - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, dummyStrat); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, dummyStrat); - bool expectedRevertMessageIsempty; - { - string memory emptyString; - expectedRevertMessageIsempty = - keccak256(abi.encodePacked(expectedRevertMessage)) == keccak256(abi.encodePacked(emptyString)); - } + bool expectedRevertMessageIsempty = expectedRevertMessage == bytes4(0x00000000); if (!expectedRevertMessageIsempty) { - cheats.expectRevert(bytes(expectedRevertMessage)); + cheats.expectRevert(expectedRevertMessage); } else if (expiry < block.timestamp) { - cheats.expectRevert("StrategyManager.depositIntoStrategyWithSignature: signature expired"); + cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); } else { // needed for expecting an event with the right parameters - uint256 expectedShares = amount; + uint256 expectedDepositShares = amount; cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit Deposit(staker, dummyToken, dummyStrat, expectedShares); + emit Deposit(staker, dummyToken, dummyStrat, expectedDepositShares); } uint256 shares = strategyManager.depositIntoStrategyWithSignature( dummyStrat, @@ -190,11 +179,11 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv signature ); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, dummyStrat); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, dummyStrat); uint256 nonceAfter = strategyManager.nonces(staker); if (expiry >= block.timestamp && expectedRevertMessageIsempty) { - assertEq(sharesAfter, sharesBefore + shares, "sharesAfter != sharesBefore + shares"); + assertEq(depositSharesAfter, depositSharesBefore + shares, "depositSharesAfter != depositSharesBefore + shares"); assertEq(nonceAfter, nonceBefore + 1, "nonceAfter != nonceBefore + 1"); } return signature; @@ -219,7 +208,6 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv */ function _addStrategiesToWhitelist(uint8 numberOfStrategiesToAdd) internal returns (IStrategy[] memory) { IStrategy[] memory strategyArray = new IStrategy[](numberOfStrategiesToAdd); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](numberOfStrategiesToAdd); // loop that deploys a new strategy and adds it to the array for (uint256 i = 0; i < numberOfStrategiesToAdd; ++i) { IStrategy _strategy = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); @@ -232,7 +220,7 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(strategyArray[i]); } - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); for (uint256 i = 0; i < numberOfStrategiesToAdd; ++i) { assertTrue(strategyManager.strategyIsWhitelistedForDeposit(strategyArray[i]), "strategy not whitelisted"); @@ -245,10 +233,10 @@ contract StrategyManagerUnitTests is EigenLayerUnitTestSetup, IStrategyManagerEv contract StrategyManagerUnitTests_initialize is StrategyManagerUnitTests { function test_CannotReinitialize() public { cheats.expectRevert("Initializable: contract is already initialized"); - strategyManager.initialize(initialOwner, initialOwner, pauserRegistry, 0); + strategyManager.initialize(initialOwner, initialOwner, 0); } - function test_InitializedStorageProperly() public { + function test_InitializedStorageProperly() public view { assertEq(strategyManager.owner(), initialOwner, "strategyManager.owner() != initialOwner"); assertEq( strategyManager.strategyWhitelister(), @@ -281,22 +269,22 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest cheats.assume(amount <= token.balanceOf(address(this))); cheats.assume(amount >= 1); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); // needed for expecting an event with the right parameters - uint256 expectedShares = strategy.underlyingToShares(amount); + uint256 expectedDepositShares = strategy.underlyingToShares(amount); cheats.prank(staker); cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit Deposit(staker, token, strategy, expectedShares); - uint256 shares = strategyManager.depositIntoStrategy(strategy, token, amount); + emit Deposit(staker, token, strategy, expectedDepositShares); + uint256 depositedShares = strategyManager.depositIntoStrategy(strategy, token, amount); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - assertEq(sharesAfter, sharesBefore + shares, "sharesAfter != sharesBefore + shares"); - if (sharesBefore == 0) { + assertEq(depositSharesAfter, depositSharesBefore + depositedShares, "depositSharesAfter != depositSharesBefore + depositedShares"); + if (depositSharesBefore == 0) { assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore + 1, @@ -323,6 +311,320 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest testFuzz_depositIntoStrategySuccessfully(staker, amount); } + // TODO: test depositing into multiple strategies + // function testFuzz_depositIntoStrategy_MultipleStrategies() + // /// @notice deploys 'numStratsToAdd' strategies using '_testAddStrategy' and then deposits '1e18' to each of them from 'getOperatorAddress(0)' + // /// @param numStratsToAdd is the number of strategies being added and deposited into + // function testDepositStrategies(uint8 numStratsToAdd) public { + // _testDepositStrategies(getOperatorAddress(0), 1e18, numStratsToAdd); + // } + + // TODO: fix old stETH fork test + // /// @notice Shadow-forks mainnet and tests depositing stETH tokens into a "StrategyBase" contract. + // function testForkMainnetDepositSteth() public { + // // hard-coded inputs + // // address sender = address(this); + // uint64 amountToDeposit = 1e12; + + // // shadow-fork mainnet + // try cheats.createFork("mainnet") returns (uint256 forkId) { + // cheats.selectFork(forkId); + // // If RPC_MAINNET ENV not set, default to this mainnet RPC endpoint + // } catch { + // cheats.createSelectFork("https://eth.llamarpc.com"); + // } + + // // cast mainnet stETH address to IERC20 interface + // // IERC20 steth = IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); + // IERC20 underlyingToken = IERC20(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); + + // // deploy necessary contracts on the shadow-forked network + // // deploy proxy admin for ability to upgrade proxy contracts + // eigenLayerProxyAdmin = new ProxyAdmin(); + // //deploy pauser registry + // address[] memory pausers = new address[](1); + // pausers[0] = pauser; + // eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); + // /** + // * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are + // * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. + // */ + // emptyContract = new EmptyContract(); + // delegation = DelegationManager( + // address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + // ); + // strategyManager = StrategyManager( + // address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + // ); + // eigenPodManager = EigenPodManager( + // address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + // ); + + // ethPOSDeposit = new ETHPOSDepositMock(); + // pod = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); + + // eigenPodBeacon = new UpgradeableBeacon(address(pod)); + // // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs + // DelegationManager delegationImplementation = new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, MIN_WITHDRAWAL_DELAY); + // StrategyManager strategyManagerImplementation = new StrategyManager(delegation); + // EigenPodManager eigenPodManagerImplementation = new EigenPodManager(ethPOSDeposit, eigenPodBeacon, strategyManager, delegation); + // // Third, upgrade the proxy contracts to use the correct implementation contracts and initialize them. + // eigenLayerProxyAdmin.upgradeAndCall( + // ITransparentUpgradeableProxy(payable(address(delegation))), + // address(delegationImplementation), + // abi.encodeWithSelector( + // DelegationManager.initialize.selector, + // eigenLayerReputedMultisig, + // eigenLayerPauserReg, + // 0 /*initialPausedStatus*/, + // minWithdrawalDelayBlocks, + // initializeStrategiesToSetDelayBlocks, + // initializeWithdrawalDelayBlocks + // ) + // ); + // eigenLayerProxyAdmin.upgradeAndCall( + // ITransparentUpgradeableProxy(payable(address(strategyManager))), + // address(strategyManagerImplementation), + // abi.encodeWithSelector( + // StrategyManager.initialize.selector, + // eigenLayerReputedMultisig, + // eigenLayerReputedMultisig, + // eigenLayerPauserReg, + // 0/*initialPausedStatus*/ + // ) + // ); + // eigenLayerProxyAdmin.upgradeAndCall( + // ITransparentUpgradeableProxy(payable(address(eigenPodManager))), + // address(eigenPodManagerImplementation), + // abi.encodeWithSelector( + // EigenPodManager.initialize.selector, + // eigenLayerReputedMultisig, + // eigenLayerPauserReg, + // 0/*initialPausedStatus*/ + // ) + // ); + + // // cheat a bunch of ETH to this address + // cheats.deal(address(this), 1e20); + // // deposit a huge amount of ETH to get ample stETH + // { + // (bool success, bytes memory returnData) = address(underlyingToken).call{value: 1e20}(""); + // require(success, "depositing stETH failed"); + // returnData; + // } + + // // deploy StrategyBase contract implementation, then create upgradeable proxy that points to implementation and initialize it + // baseStrategyImplementation = new StrategyBase(strategyManager); + // IStrategy stethStrategy = StrategyBase( + // address( + // new TransparentUpgradeableProxy( + // address(baseStrategyImplementation), + // address(eigenLayerProxyAdmin), + // abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) + // ) + // ) + // ); + + // // REMAINDER OF CODE ADAPTED FROM `_testDepositToStrategy` + // // _testDepositToStrategy(sender, amountToDeposit, underlyingToken, stethStrategy); + + // // whitelist the strategy for deposit, in case it wasn't before + // { + // cheats.startPrank(strategyManager.strategyWhitelister()); + // IStrategy[] memory _strategy = new IStrategy[](1); + // _strategy[0] = stethStrategy; + // strategyManager.addStrategiesToDepositWhitelist(_strategy); + // cheats.stopPrank(); + // } + + // uint256 operatorSharesBefore = strategyManager.stakerDepositShares(address(this), stethStrategy); + // // check the expected output + // uint256 expectedSharesOut = stethStrategy.underlyingToShares(amountToDeposit); + + // underlyingToken.transfer(address(this), amountToDeposit); + // cheats.startPrank(address(this)); + // underlyingToken.approve(address(strategyManager), type(uint256).max); + // strategyManager.depositIntoStrategy(stethStrategy, underlyingToken, amountToDeposit); + + // //check if depositor has never used this strat, that it is added correctly to stakerStrategyList array. + // if (operatorSharesBefore == 0) { + // // check that strategy is appropriately added to dynamic array of all of sender's strategies + // assertTrue( + // strategyManager.stakerStrategyList(address(this), strategyManager.stakerStrategyListLength(address(this)) - 1) + // == stethStrategy, + // "_testDepositToStrategy: stakerStrategyList array updated incorrectly" + // ); + // } + // // check that the shares out match the expected amount out + // // the actual transfer in will be lower by 1-2 wei than expected due to stETH's internal rounding + // // to account for this we check approximate rather than strict equivalence here + // { + // uint256 actualSharesOut = strategyManager.stakerDepositShares(address(this), stethStrategy) - operatorSharesBefore; + // require(actualSharesOut >= expectedSharesOut, "too few shares"); + // require((actualSharesOut * 1000) / expectedSharesOut < 1003, "too many shares"); + + // // additional sanity check for deposit not increasing in value + // require(stethStrategy.sharesToUnderlying(actualSharesOut) <= amountToDeposit, "value cannot have increased"); + // // slippage check + // require((stethStrategy.sharesToUnderlying(actualSharesOut) * 1e6) / amountToDeposit >= (1e6 - 1), "bad slippage on first deposit"); + // } + // cheats.stopPrank(); + // } + + // TODO: fix old frontrun depositor test + // function testFrontrunFirstDepositor(/*uint256 depositAmount*/) public { + + // //setup addresses + // address attacker = address(100); + // address user = address(200); + + // //give 2 ether to attacker and user + // weth.transfer(attacker,2 ether); + // weth.transfer(user,2 ether); + + // //attacker FRONTRUN: deposit 1 wei (receive 1 share) + // StrategyManager _strategyManager = _whitelistStrategy(strategyManager, wethStrat); + + // cheats.startPrank(attacker); + // weth.approve(address(strategyManager), type(uint256).max); + // _strategyManager.depositIntoStrategy(wethStrat, weth, 1 wei); + // cheats.stopPrank(); + + // //attacker FRONTRUN: transfer 1 ether into strategy directly to manipulate the value of shares + // cheats.prank(attacker); + // weth.transfer(address(wethStrat),1 ether); + + // //user deposits 2 eth into strategy - only gets 1 share due to rounding + // cheats.startPrank(user); + // weth.approve(address(_strategyManager), type(uint256).max); + // _strategyManager.depositIntoStrategy(wethStrat, weth, 2 ether); + // cheats.stopPrank(); + + // //attacker deposited 1 ether and 1 wei - received 1 share + // //user deposited 2 ether - received X shares + // //user has lost 0.5 ether? + // (, uint256[] memory shares) = _strategyManager.getDeposits(attacker); + // uint256 attackerValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); + // require(attackerValueWeth >= (1), "attacker got zero shares"); + + // (, shares) = _strategyManager.getDeposits(user); + // uint256 userValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); + // require(userValueWeth >= (1900000000000000000), "user has lost more than 0.1 eth from frontrunning"); + + // uint256 attackerLossesWeth = (2 ether + 1 wei) - attackerValueWeth; + // uint256 userLossesWeth = 2 ether - userValueWeth; + // require(attackerLossesWeth > userLossesWeth, "griefing attack deals more damage than cost"); + // } + + // TODO: fix old testFrontrunFirstDepositorFuzzed + // function testFrontrunFirstDepositorFuzzed(uint96 firstDepositAmount, uint96 donationAmount, uint96 secondDepositAmount) public { + // // want to only use nonzero amounts or else we'll get reverts + // cheats.assume(firstDepositAmount != 0 && secondDepositAmount != 0); + + // // setup addresses + // address attacker = address(100); + // address user = address(200); + + // // attacker makes first deposit + // _testDepositToStrategy(attacker, firstDepositAmount, weth, wethStrat); + + // // transfer tokens into strategy directly to manipulate the value of shares + // weth.transfer(address(wethStrat), donationAmount); + + // // filter out calls that would revert for minting zero shares + // cheats.assume(wethStrat.underlyingToShares(secondDepositAmount) != 0); + + // // user makes 2nd deposit into strategy - gets diminished shares due to rounding + // _testDepositToStrategy(user, secondDepositAmount, weth, wethStrat); + + // // check for griefing + // (, uint256[] memory shares) = strategyManager.getDeposits(attacker); + // uint256 attackerValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); + // (, shares) = strategyManager.getDeposits(user); + // uint256 userValueWeth = wethStrat.sharesToUnderlyingView(shares[0]); + + // uint256 attackerCost = uint256(firstDepositAmount) + uint256(donationAmount); + // require(attackerCost >= attackerValueWeth, "attacker gained value?"); + // // uint256 attackerLossesWeth = attackerValueWeth > attackerCost ? 0 : (attackerCost - attackerValueWeth); + // uint256 attackerLossesWeth = attackerCost - attackerValueWeth; + // uint256 userLossesWeth = secondDepositAmount - userValueWeth; + + // emit log_named_uint("attackerLossesWeth", attackerLossesWeth); + // emit log_named_uint("userLossesWeth", userLossesWeth); + + // // use '+1' here to account for rounding. given the attack will cost ETH in the form of gas, this is fine. + // require(attackerLossesWeth + 1 >= userLossesWeth, "griefing attack deals more damage than cost"); + // } + + // TODO: testDepositTokenWithOneWeiFeeOnTransfer + // function testDepositTokenWithOneWeiFeeOnTransfer(address sender, uint64 amountToDeposit) public fuzzedAddress(sender) { + // cheats.assume(amountToDeposit != 0); + + // IERC20 underlyingToken; + + // { + // uint256 initSupply = 1e50; + // address initOwner = address(this); + // ERC20_OneWeiFeeOnTransfer oneWeiFeeOnTransferToken = new ERC20_OneWeiFeeOnTransfer(initSupply, initOwner); + // underlyingToken = IERC20(address(oneWeiFeeOnTransferToken)); + // } + + // // need to transfer extra here because otherwise the `sender` won't have enough tokens + // underlyingToken.transfer(sender, 1000); + + // IStrategy oneWeiFeeOnTransferTokenStrategy = StrategyBase( + // address( + // new TransparentUpgradeableProxy( + // address(baseStrategyImplementation), + // address(eigenLayerProxyAdmin), + // abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, eigenLayerPauserReg) + // ) + // ) + // ); + + // // REMAINDER OF CODE ADAPTED FROM `_testDepositToStrategy` + // // _testDepositToStrategy(sender, amountToDeposit, underlyingToken, oneWeiFeeOnTransferTokenStrategy); + + // // whitelist the strategy for deposit, in case it wasn't before + // { + // cheats.startPrank(strategyManager.strategyWhitelister()); + // IStrategy[] memory _strategy = new IStrategy[](1); + // _strategy[0] = oneWeiFeeOnTransferTokenStrategy; + // strategyManager.addStrategiesToDepositWhitelist(_strategy); + // cheats.stopPrank(); + // } + // uint256 operatorSharesBefore = strategyManager.stakerDepositShares(sender, oneWeiFeeOnTransferTokenStrategy); + // // check the expected output + // uint256 expectedSharesOut = oneWeiFeeOnTransferTokenStrategy.underlyingToShares(amountToDeposit); + + // underlyingToken.transfer(sender, amountToDeposit); + // cheats.startPrank(sender); + // underlyingToken.approve(address(strategyManager), type(uint256).max); + // strategyManager.depositIntoStrategy(oneWeiFeeOnTransferTokenStrategy, underlyingToken, amountToDeposit); + + // //check if depositor has never used this strat, that it is added correctly to stakerStrategyList array. + // if (operatorSharesBefore == 0) { + // // check that strategy is appropriately added to dynamic array of all of sender's strategies + // assertTrue( + // strategyManager.stakerStrategyList(sender, strategyManager.stakerStrategyListLength(sender) - 1) + // == oneWeiFeeOnTransferTokenStrategy, + // "_testDepositToStrategy: stakerStrategyList array updated incorrectly" + // ); + // } + // // check that the shares out match the expected amount out + // // the actual transfer in will be lower by 1 wei than expected due to stETH's internal rounding + // // to account for this we check approximate rather than strict equivalence here + // { + // uint256 actualSharesOut = strategyManager.stakerDepositShares(sender, oneWeiFeeOnTransferTokenStrategy) - operatorSharesBefore; + // require((actualSharesOut * 1000) / expectedSharesOut > 998, "too few shares"); + // require((actualSharesOut * 1000) / expectedSharesOut < 1002, "too many shares"); + + // // additional sanity check for deposit not increasing in value + // require(oneWeiFeeOnTransferTokenStrategy.sharesToUnderlying(actualSharesOut) <= amountToDeposit, "value cannot have increased"); + // } + // cheats.stopPrank(); + // } + function test_Revert_WhenDepositsPaused() public { uint256 amount = 1e18; @@ -330,7 +632,7 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest cheats.prank(pauser); strategyManager.pause(1); - cheats.expectRevert("Pausable: index is paused"); + cheats.expectRevert(IPausable.CurrentlyPaused.selector); strategyManager.depositIntoStrategy(dummyStrat, dummyToken, amount); } @@ -340,16 +642,14 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest reenterer = new Reenterer(); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); _strategy[0] = IStrategy(address(reenterer)); for (uint256 i = 0; i < _strategy.length; ++i) { cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(_strategy[i]); } - strategyManager.addStrategiesToDepositWhitelist(_strategy, thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); reenterer.prepareReturnData(abi.encode(amount)); @@ -372,13 +672,10 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest dummyStrat = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = address(this); IERC20 token = dummyToken; @@ -396,12 +693,10 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest dummyStrat = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = address(this); IERC20 token = dummyToken; @@ -418,12 +713,10 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest dummyStrat = StrategyBase(address(new Reverter())); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = address(this); IERC20 token = dummyToken; @@ -440,13 +733,10 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest dummyStrat = StrategyBase(address(5678)); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = address(this); IERC20 token = dummyToken; @@ -468,7 +758,7 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest IStrategy strategy = dummyStrat; cheats.prank(staker); - cheats.expectRevert("StrategyManager.onlyStrategiesWhitelistedForDeposit: strategy not whitelisted"); + cheats.expectRevert(IStrategyManagerErrors.StrategyNotWhitelisted.selector); strategyManager.depositIntoStrategy(strategy, token, amount); } @@ -478,13 +768,10 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest dummyStrat = StrategyBase(address(reenterer)); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = address(this); IStrategy strategy = dummyStrat; @@ -494,7 +781,7 @@ contract StrategyManagerUnitTests_depositIntoStrategy is StrategyManagerUnitTest reenterer.prepareReturnData(abi.encode(uint256(0))); cheats.prank(staker); - cheats.expectRevert("StrategyManager._addShares: shares should not be zero!"); + cheats.expectRevert(IStrategyManagerErrors.SharesAmountZero.selector); strategyManager.depositIntoStrategy(strategy, token, amount); } } @@ -521,17 +808,17 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa signature = abi.encodePacked(r, s, v); } - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer"); + cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); // call with `notStaker` as input instead of `staker` address address notStaker = address(3333); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, notStaker, expiry, signature); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); uint256 nonceAfter = strategyManager.nonces(staker); - assertEq(sharesAfter, sharesBefore, "sharesAfter != sharesBefore"); + assertEq(depositSharesAfter, depositSharesBefore, "depositSharesAfter != depositSharesBefore"); assertEq(nonceAfter, nonceBefore, "nonceAfter != nonceBefore"); } @@ -541,8 +828,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa address staker = cheats.addr(privateKey); // not expecting a revert, so input an empty string - string memory expectedRevertMessage; - _depositIntoStrategyWithSignature(staker, amount, expiry, expectedRevertMessage); + _depositIntoStrategyWithSignature(staker, amount, expiry, bytes4(0x00000000)); } function testFuzz_Revert_SignatureReplay(uint256 amount, uint256 expiry) public { @@ -554,7 +840,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa // not expecting a revert, so input an empty string bytes memory signature = _depositIntoStrategyWithSignature(staker, amount, expiry, ""); - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: signature not from signer"); + cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); strategyManager.depositIntoStrategyWithSignature(dummyStrat, dummyToken, amount, staker, expiry, signature); } @@ -594,7 +880,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa signature = abi.encodePacked(r, s, v); } - cheats.expectRevert("EIP1271SignatureUtils.checkSignature_EIP1271: ERC1271 signature verification failed"); + cheats.expectRevert(ISignatureUtils.InvalidSignature.selector); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, staker, expiry, signature); } @@ -665,8 +951,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa staker = address(wallet); // not expecting a revert, so input an empty string - string memory expectedRevertMessage; - _depositIntoStrategyWithSignature(staker, amount, expiry, expectedRevertMessage); + _depositIntoStrategyWithSignature(staker, amount, expiry, bytes4(0x00000000)); } function test_Revert_WhenDepositsPaused() public { @@ -676,8 +961,7 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa cheats.prank(pauser); strategyManager.pause(1); - string memory expectedRevertMessage = "Pausable: index is paused"; - _depositIntoStrategyWithSignature(staker, 1e18, type(uint256).max, expectedRevertMessage); + _depositIntoStrategyWithSignature(staker, 1e18, type(uint256).max, IPausable.CurrentlyPaused.selector); } /** @@ -690,18 +974,15 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa reenterer = new Reenterer(); // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = IStrategy(address(reenterer)); for (uint256 i = 0; i < _strategy.length; ++i) { cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(_strategy[i]); } - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); address staker = cheats.addr(privateKey); IStrategy strategy = IStrategy(address(reenterer)); @@ -763,15 +1044,15 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa signature = abi.encodePacked(r, s, v); } - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); - cheats.expectRevert("StrategyManager.depositIntoStrategyWithSignature: signature expired"); + cheats.expectRevert(ISignatureUtils.SignatureExpired.selector); strategyManager.depositIntoStrategyWithSignature(strategy, token, amount, staker, expiry, signature); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); uint256 nonceAfter = strategyManager.nonces(staker); - assertEq(sharesAfter, sharesBefore, "sharesAfter != sharesBefore"); + assertEq(depositSharesAfter, depositSharesBefore, "depositSharesAfter != depositSharesBefore"); assertEq(nonceAfter, nonceBefore, "nonceAfter != nonceBefore"); } @@ -782,37 +1063,22 @@ contract StrategyManagerUnitTests_depositIntoStrategyWithSignature is StrategyMa address staker = cheats.addr(privateKey); uint256 amount = 1e18; - string - memory expectedRevertMessage = "StrategyManager.onlyStrategiesWhitelistedForDeposit: strategy not whitelisted"; - _depositIntoStrategyWithSignature(staker, amount, type(uint256).max, expectedRevertMessage); - } - - function testFuzz_Revert_WhenThirdPartyTransfersForbidden(uint256 amount, uint256 expiry) public { - // min shares must be minted on strategy - cheats.assume(amount >= 1); - - cheats.prank(strategyManager.strategyWhitelister()); - strategyManager.setThirdPartyTransfersForbidden(dummyStrat, true); - - address staker = cheats.addr(privateKey); - // not expecting a revert, so input an empty string - string memory expectedRevertMessage = "StrategyManager.depositIntoStrategyWithSignature: third transfers disabled"; - _depositIntoStrategyWithSignature(staker, amount, expiry, expectedRevertMessage); + _depositIntoStrategyWithSignature(staker, amount, type(uint256).max, IStrategyManagerErrors.StrategyNotWhitelisted.selector); } } -contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { +contract StrategyManagerUnitTests_removeDepositShares is StrategyManagerUnitTests { /** * @notice Should revert if not called by DelegationManager */ function test_Revert_DelegationManagerModifier() external { DelegationManagerMock invalidDelegationManager = new DelegationManagerMock(); - cheats.expectRevert("StrategyManager.onlyDelegationManager: not the DelegationManager"); - invalidDelegationManager.removeShares(strategyManager, address(this), dummyStrat, 1); + cheats.expectRevert(IStrategyManagerErrors.OnlyDelegationManager.selector); + invalidDelegationManager.removeDepositShares(strategyManager, address(this), dummyStrat, 1); } /** - * @notice deposits a single strategy and tests removeShares() function reverts when sharesAmount is 0 + * @notice deposits a single strategy and tests removeDepositShares() function reverts when sharesAmount is 0 */ function testFuzz_Revert_ZeroShares( address staker, @@ -822,12 +1088,12 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { cheats.assume(depositAmount > 0 && depositAmount < dummyToken.totalSupply()); IStrategy strategy = dummyStrat; _depositIntoStrategySuccessfully(strategy, staker, depositAmount); - cheats.expectRevert("StrategyManager._removeShares: shareAmount should not be zero!"); - delegationManagerMock.removeShares(strategyManager, staker, strategy, 0); + cheats.expectRevert(IStrategyManagerErrors.SharesAmountZero.selector); + delegationManagerMock.removeDepositShares(strategyManager, staker, strategy, 0); } /** - * @notice deposits a single strategy and tests removeShares() function reverts when sharesAmount is + * @notice deposits a single strategy and tests removeDepositShares() function reverts when sharesAmount is * higher than depositAmount */ function testFuzz_Revert_ShareAmountTooHigh( @@ -840,12 +1106,12 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { cheats.assume(removeSharesAmount > depositAmount); IStrategy strategy = dummyStrat; _depositIntoStrategySuccessfully(strategy, staker, depositAmount); - cheats.expectRevert("StrategyManager._removeShares: shareAmount too high"); - delegationManagerMock.removeShares(strategyManager, staker, strategy, removeSharesAmount); + cheats.expectRevert(IStrategyManagerErrors.SharesAmountTooHigh.selector); + delegationManagerMock.removeDepositShares(strategyManager, staker, strategy, removeSharesAmount); } /** - * @notice deposit single strategy and removeShares() for less than the deposited amount + * @notice deposit single strategy and removeDepositShares() for less than the deposited amount * Shares should be updated correctly with stakerStrategyListLength unchanged */ function testFuzz_RemoveSharesLessThanDeposit( @@ -859,11 +1125,11 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { IStrategy strategy = dummyStrat; _depositIntoStrategySuccessfully(strategy, staker, depositAmount); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); - delegationManagerMock.removeShares(strategyManager, staker, strategy, removeSharesAmount); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); + delegationManagerMock.removeDepositShares(strategyManager, staker, strategy, removeSharesAmount); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); - assertEq(sharesBefore, sharesAfter + removeSharesAmount, "Remove incorrect amount of shares"); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); + assertEq(depositSharesBefore, depositSharesAfter + removeSharesAmount, "Remove incorrect amount of shares"); assertEq( stakerStrategyListLengthBefore, stakerStrategyListLengthAfter, @@ -872,7 +1138,7 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { } /** - * @notice testing removeShares() + * @notice testing removeDepositShares() * deposits 1 strategy and tests it is removed from staker strategy list after removing all shares */ function testFuzz_RemovesStakerStrategyListSingleStrat( @@ -885,23 +1151,23 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { _depositIntoStrategySuccessfully(strategy, staker, sharesAmount); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, strategy); - assertEq(sharesBefore, sharesAmount, "Staker has not deposited amount into strategy"); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, strategy); + assertEq(depositSharesBefore, sharesAmount, "Staker has not deposited amount into strategy"); - delegationManagerMock.removeShares(strategyManager, staker, strategy, sharesAmount); + delegationManagerMock.removeDepositShares(strategyManager, staker, strategy, sharesAmount); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, strategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, strategy); assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore - 1, "stakerStrategyListLengthAfter != stakerStrategyListLengthBefore - 1" ); - assertEq(sharesAfter, 0, "sharesAfter != 0"); + assertEq(depositSharesAfter, 0, "depositSharesAfter != 0"); assertFalse(_isDepositedStrategy(staker, strategy), "strategy should not be part of staker strategy list"); } /** - * @notice testing removeShares() function with 3 strategies deposited. + * @notice testing removeDepositShares() function with 3 strategies deposited. * Randomly selects one of the 3 strategies to be fully removed from staker strategy list. * Only callable by DelegationManager */ @@ -923,22 +1189,22 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { uint256 removeAmount = amounts[randStrategy % 3]; uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); - uint256[] memory sharesBefore = new uint256[](3); + uint256[] memory depositSharesBefore = new uint256[](3); for (uint256 i = 0; i < 3; ++i) { - sharesBefore[i] = strategyManager.stakerStrategyShares(staker, strategies[i]); - assertEq(sharesBefore[i], amounts[i], "Staker has not deposited amount into strategy"); + depositSharesBefore[i] = strategyManager.stakerDepositShares(staker, strategies[i]); + assertEq(depositSharesBefore[i], amounts[i], "Staker has not deposited amount into strategy"); assertTrue(_isDepositedStrategy(staker, strategies[i]), "strategy should be deposited"); } - delegationManagerMock.removeShares(strategyManager, staker, removeStrategy, removeAmount); + delegationManagerMock.removeDepositShares(strategyManager, staker, removeStrategy, removeAmount); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, removeStrategy); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, removeStrategy); assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore - 1, "stakerStrategyListLengthAfter != stakerStrategyListLengthBefore - 1" ); - assertEq(sharesAfter, 0, "sharesAfter != 0"); + assertEq(depositSharesAfter, 0, "depositSharesAfter != 0"); assertFalse( _isDepositedStrategy(staker, removeStrategy), "strategy should not be part of staker strategy list" @@ -946,7 +1212,7 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { } /** - * @notice testing removeShares() function with 3 strategies deposited. + * @notice testing removeDepositShares() function with 3 strategies deposited. * Removing Shares could result in removing from staker strategy list if depositAmounts[i] == sharesAmounts[i]. * Only callable by DelegationManager */ @@ -956,41 +1222,41 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { strategies[0] = dummyStrat; strategies[1] = dummyStrat2; strategies[2] = dummyStrat3; - uint256[] memory sharesBefore = new uint256[](3); + uint256[] memory depositSharesBefore = new uint256[](3); for (uint256 i = 0; i < 3; ++i) { depositAmounts[i] = bound(depositAmounts[i], 1, strategies[i].underlyingToken().totalSupply()); sharesAmounts[i] = bound(sharesAmounts[i], 1, depositAmounts[i]); _depositIntoStrategySuccessfully(strategies[i], staker, depositAmounts[i]); - sharesBefore[i] = strategyManager.stakerStrategyShares(staker, strategies[i]); - assertEq(sharesBefore[i], depositAmounts[i], "Staker has not deposited amount into strategy"); + depositSharesBefore[i] = strategyManager.stakerDepositShares(staker, strategies[i]); + assertEq(depositSharesBefore[i], depositAmounts[i], "Staker has not deposited amount into strategy"); assertTrue(_isDepositedStrategy(staker, strategies[i]), "strategy should be deposited"); } uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); uint256 numPoppedStrategies = 0; - uint256[] memory sharesAfter = new uint256[](3); + uint256[] memory depositSharesAfter = new uint256[](3); for (uint256 i = 0; i < 3; ++i) { - delegationManagerMock.removeShares(strategyManager, staker, strategies[i], sharesAmounts[i]); + delegationManagerMock.removeDepositShares(strategyManager, staker, strategies[i], sharesAmounts[i]); } for (uint256 i = 0; i < 3; ++i) { - sharesAfter[i] = strategyManager.stakerStrategyShares(staker, strategies[i]); + depositSharesAfter[i] = strategyManager.stakerDepositShares(staker, strategies[i]); if (sharesAmounts[i] == depositAmounts[i]) { ++numPoppedStrategies; assertFalse( _isDepositedStrategy(staker, strategies[i]), "strategy should not be part of staker strategy list" ); - assertEq(sharesAfter[i], 0, "sharesAfter != 0"); + assertEq(depositSharesAfter[i], 0, "depositSharesAfter != 0"); } else { assertTrue( _isDepositedStrategy(staker, strategies[i]), "strategy should be part of staker strategy list" ); assertEq( - sharesAfter[i], - sharesBefore[i] - sharesAmounts[i], - "sharesAfter != sharesBefore - sharesAmounts" + depositSharesAfter[i], + depositSharesBefore[i] - sharesAmounts[i], + "depositSharesAfter != depositSharesBefore - sharesAmounts" ); } } @@ -1005,18 +1271,18 @@ contract StrategyManagerUnitTests_removeShares is StrategyManagerUnitTests { contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { function test_Revert_DelegationManagerModifier() external { DelegationManagerMock invalidDelegationManager = new DelegationManagerMock(); - cheats.expectRevert("StrategyManager.onlyDelegationManager: not the DelegationManager"); + cheats.expectRevert(IStrategyManagerErrors.OnlyDelegationManager.selector); invalidDelegationManager.addShares(strategyManager, address(this), dummyToken, dummyStrat, 1); } function testFuzz_Revert_StakerZeroAddress(uint256 amount) external { - cheats.expectRevert("StrategyManager._addShares: staker cannot be zero address"); + cheats.expectRevert(IStrategyManagerErrors.StakerAddressZero.selector); delegationManagerMock.addShares(strategyManager, address(0), dummyToken, dummyStrat, amount); } function testFuzz_Revert_ZeroShares(address staker) external filterFuzzedAddressInputs(staker) { cheats.assume(staker != address(0)); - cheats.expectRevert("StrategyManager._addShares: shares should not be zero!"); + cheats.expectRevert(IStrategyManagerErrors.SharesAmountZero.selector); delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, 0); } @@ -1026,19 +1292,19 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { ) external filterFuzzedAddressInputs(staker) { cheats.assume(staker != address(0) && amount != 0); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, dummyStrat); - assertEq(sharesBefore, 0, "Staker has already deposited into this strategy"); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, dummyStrat); + assertEq(depositSharesBefore, 0, "Staker has already deposited into this strategy"); assertFalse(_isDepositedStrategy(staker, dummyStrat), "strategy should not be deposited"); delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, amount); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, dummyStrat); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, dummyStrat); assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore + 1, "stakerStrategyListLengthAfter != stakerStrategyListLengthBefore + 1" ); - assertEq(sharesAfter, amount, "sharesAfter != amount"); + assertEq(depositSharesAfter, amount, "depositSharesAfter != amount"); assertTrue(_isDepositedStrategy(staker, dummyStrat), "strategy should be deposited"); } @@ -1051,19 +1317,19 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { IStrategy strategy = dummyStrat; _depositIntoStrategySuccessfully(strategy, staker, initialAmount); uint256 stakerStrategyListLengthBefore = strategyManager.stakerStrategyListLength(staker); - uint256 sharesBefore = strategyManager.stakerStrategyShares(staker, dummyStrat); - assertEq(sharesBefore, initialAmount, "Staker has not deposited amount into strategy"); + uint256 depositSharesBefore = strategyManager.stakerDepositShares(staker, dummyStrat); + assertEq(depositSharesBefore, initialAmount, "Staker has not deposited amount into strategy"); assertTrue(_isDepositedStrategy(staker, strategy), "strategy should be deposited"); delegationManagerMock.addShares(strategyManager, staker, dummyToken, dummyStrat, sharesAmount); uint256 stakerStrategyListLengthAfter = strategyManager.stakerStrategyListLength(staker); - uint256 sharesAfter = strategyManager.stakerStrategyShares(staker, dummyStrat); + uint256 depositSharesAfter = strategyManager.stakerDepositShares(staker, dummyStrat); assertEq( stakerStrategyListLengthAfter, stakerStrategyListLengthBefore, "stakerStrategyListLengthAfter != stakerStrategyListLengthBefore" ); - assertEq(sharesAfter, sharesBefore + sharesAmount, "sharesAfter != sharesBefore + sharesAmount"); + assertEq(depositSharesAfter, depositSharesBefore + sharesAmount, "depositSharesAfter != depositSharesBefore + sharesAmount"); assertTrue(_isDepositedStrategy(staker, strategy), "strategy should be deposited"); } @@ -1080,21 +1346,17 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { // loop that deploys a new strategy and deposits into it for (uint256 i = 0; i < MAX_STAKER_STRATEGY_LIST_LENGTH; ++i) { - cheats.startPrank(staker); + cheats.prank(staker); strategyManager.depositIntoStrategy(strategy, token, amount); - cheats.stopPrank(); dummyStrat = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); strategy = dummyStrat; // whitelist the strategy for deposit - cheats.startPrank(strategyManager.owner()); + cheats.prank(strategyManager.owner()); IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = dummyStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); + strategyManager.addStrategiesToDepositWhitelist(_strategy); } assertEq( @@ -1104,10 +1366,10 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { ); cheats.prank(staker); - cheats.expectRevert("StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH"); + cheats.expectRevert(IStrategyManagerErrors.MaxStrategiesExceeded.selector); delegationManagerMock.addShares(strategyManager, staker, dummyToken, strategy, amount); - cheats.expectRevert("StrategyManager._addShares: deposit would exceed MAX_STAKER_STRATEGY_LIST_LENGTH"); + cheats.expectRevert(IStrategyManagerErrors.MaxStrategiesExceeded.selector); strategyManager.depositIntoStrategy(strategy, token, amount); } } @@ -1115,8 +1377,8 @@ contract StrategyManagerUnitTests_addShares is StrategyManagerUnitTests { contract StrategyManagerUnitTests_withdrawSharesAsTokens is StrategyManagerUnitTests { function test_Revert_DelegationManagerModifier() external { DelegationManagerMock invalidDelegationManager = new DelegationManagerMock(); - cheats.expectRevert("StrategyManager.onlyDelegationManager: not the DelegationManager"); - invalidDelegationManager.removeShares(strategyManager, address(this), dummyStrat, 1); + cheats.expectRevert(IStrategyManagerErrors.OnlyDelegationManager.selector); + invalidDelegationManager.removeDepositShares(strategyManager, address(this), dummyStrat, 1); } /** @@ -1133,7 +1395,7 @@ contract StrategyManagerUnitTests_withdrawSharesAsTokens is StrategyManagerUnitT IStrategy strategy = dummyStrat; IERC20 token = dummyToken; _depositIntoStrategySuccessfully(strategy, staker, depositAmount); - cheats.expectRevert("StrategyBase.withdraw: amountShares must be less than or equal to totalShares"); + cheats.expectRevert(IStrategyErrors.WithdrawalAmountExceedsTotalDeposits.selector); delegationManagerMock.withdrawSharesAsTokens(strategyManager, staker, strategy, sharesAmount, token); } @@ -1154,6 +1416,50 @@ contract StrategyManagerUnitTests_withdrawSharesAsTokens is StrategyManagerUnitT } } +contract StrategyManagerUnitTests_burnShares is StrategyManagerUnitTests { + function test_Revert_DelegationManagerModifier() external { + DelegationManagerMock invalidDelegationManager = new DelegationManagerMock(); + cheats.prank(address(invalidDelegationManager)); + cheats.expectRevert(IStrategyManagerErrors.OnlyDelegationManager.selector); + strategyManager.burnShares(dummyStrat, 1); + } + + /** + * @notice deposits a single strategy and withdrawSharesAsTokens() function reverts when sharesAmount is + * higher than depositAmount + */ + function testFuzz_Revert_ShareAmountTooHigh( + address staker, + uint256 depositAmount, + uint256 sharesToBurn + ) external filterFuzzedAddressInputs(staker) { + cheats.assume(staker != address(0)); + cheats.assume(depositAmount > 0 && depositAmount < dummyToken.totalSupply() && depositAmount < sharesToBurn); + IStrategy strategy = dummyStrat; + _depositIntoStrategySuccessfully(strategy, staker, depositAmount); + cheats.expectRevert(IStrategyErrors.WithdrawalAmountExceedsTotalDeposits.selector); + cheats.prank(address(delegationManagerMock)); + strategyManager.burnShares(strategy, sharesToBurn); + } + + function testFuzz_SingleStrategyDeposited( + address staker, + uint256 depositAmount, + uint256 sharesToBurn + ) external filterFuzzedAddressInputs(staker) { + cheats.assume(staker != address(0)); + cheats.assume(sharesToBurn > 0 && sharesToBurn < dummyToken.totalSupply() && depositAmount >= sharesToBurn); + IStrategy strategy = dummyStrat; + IERC20 token = dummyToken; + _depositIntoStrategySuccessfully(strategy, staker, depositAmount); + uint256 balanceBefore = token.balanceOf(strategyManager.DEFAULT_BURN_ADDRESS()); + cheats.prank(address(delegationManagerMock)); + strategyManager.burnShares(strategy, sharesToBurn); + uint256 balanceAfter = token.balanceOf(strategyManager.DEFAULT_BURN_ADDRESS()); + assertEq(balanceAfter, balanceBefore + sharesToBurn, "balanceAfter != balanceBefore + sharesAmount"); + } +} + contract StrategyManagerUnitTests_setStrategyWhitelister is StrategyManagerUnitTests { function testFuzz_SetStrategyWhitelister( address newWhitelister @@ -1184,43 +1490,41 @@ contract StrategyManagerUnitTests_addStrategiesToDepositWhitelist is StrategyMan ) external filterFuzzedAddressInputs(notStrategyWhitelister) { cheats.assume(notStrategyWhitelister != strategyManager.strategyWhitelister()); IStrategy[] memory strategyArray = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); + IStrategy _strategy = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); strategyArray[0] = _strategy; cheats.prank(notStrategyWhitelister); - cheats.expectRevert("StrategyManager.onlyStrategyWhitelister: not the strategyWhitelister"); - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + cheats.expectRevert(IStrategyManagerErrors.OnlyStrategyWhitelister.selector); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); } function test_AddSingleStrategyToWhitelist() external { IStrategy[] memory strategyArray = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); + IStrategy strategy = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); strategyArray[0] = strategy; assertFalse(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should not be whitelisted"); cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(strategy); - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); assertTrue(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should be whitelisted"); } function test_AddAlreadyWhitelistedStrategy() external { IStrategy[] memory strategyArray = new IStrategy[](1); - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); + IStrategy strategy = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); strategyArray[0] = strategy; assertFalse(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should not be whitelisted"); cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(strategy); - cheats.expectEmit(true, true, true, true, address(strategyManager)); - emit UpdatedThirdPartyTransfersForbidden(strategy, false); - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); assertTrue(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should be whitelisted"); // Make sure event not emitted by checking logs length cheats.recordLogs(); uint256 numLogsBefore = cheats.getRecordedLogs().length; - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); uint256 numLogsAfter = cheats.getRecordedLogs().length; assertEq(numLogsBefore, numLogsAfter, "event emitted when strategy already whitelisted"); assertTrue(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should still be whitelisted"); @@ -1241,7 +1545,7 @@ contract StrategyManagerUnitTests_removeStrategiesFromDepositWhitelist is Strate IStrategy[] memory strategyArray = _addStrategiesToWhitelist(1); cheats.prank(notStrategyWhitelister); - cheats.expectRevert("StrategyManager.onlyStrategyWhitelister: not the strategyWhitelister"); + cheats.expectRevert(IStrategyManagerErrors.OnlyStrategyWhitelister.selector); strategyManager.removeStrategiesFromDepositWhitelist(strategyArray); } @@ -1272,12 +1576,12 @@ contract StrategyManagerUnitTests_removeStrategiesFromDepositWhitelist is Strate IStrategy[] memory strategyArray = new IStrategy[](1); IStrategy strategy = _deployNewStrategy(dummyToken, strategyManager, pauserRegistry, dummyAdmin); strategyArray[0] = strategy; - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); + assertFalse(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should not be whitelisted"); // Add strategy to whitelist first cheats.expectEmit(true, true, true, true, address(strategyManager)); emit StrategyAddedToDepositWhitelist(strategy); - strategyManager.addStrategiesToDepositWhitelist(strategyArray, thirdPartyTransfersForbiddenValues); + strategyManager.addStrategiesToDepositWhitelist(strategyArray); assertTrue(strategyManager.strategyIsWhitelistedForDeposit(strategy), "strategy should be whitelisted"); // Now remove strategy from whitelist @@ -1328,4 +1632,4 @@ contract StrategyManagerUnitTests_removeStrategiesFromDepositWhitelist is Strate } } } -} +} \ No newline at end of file diff --git a/src/test/utils/BeaconChainProofsWrapper.sol b/src/test/utils/BeaconChainProofsWrapper.sol deleted file mode 100644 index d093848d4..000000000 --- a/src/test/utils/BeaconChainProofsWrapper.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/libraries/BeaconChainProofs.sol"; - -/// @notice This contract is used to test offchain proof generation -contract BeaconChainProofsWrapper { - - function verifyStateRoot( - bytes32 beaconBlockRoot, - BeaconChainProofs.StateRootProof calldata proof - ) external view { - BeaconChainProofs.verifyStateRoot(beaconBlockRoot, proof); - } - - function verifyValidatorFields( - bytes32 beaconStateRoot, - bytes32[] calldata validatorFields, - bytes calldata validatorFieldsProof, - uint40 validatorIndex - ) external view { - BeaconChainProofs.verifyValidatorFields(beaconStateRoot, validatorFields, validatorFieldsProof, validatorIndex); - } - - function verifyBalanceContainer( - bytes32 beaconBlockRoot, - BeaconChainProofs.BalanceContainerProof calldata proof - ) external view { - BeaconChainProofs.verifyBalanceContainer(beaconBlockRoot, proof); - } - - function verifyValidatorBalance( - bytes32 balanceContainerRoot, - uint40 validatorIndex, - BeaconChainProofs.BalanceProof calldata proof - ) external view { - BeaconChainProofs.verifyValidatorBalance(balanceContainerRoot, validatorIndex, proof); - } - - -} \ No newline at end of file diff --git a/src/test/utils/EigenLayerUnitTestBase.sol b/src/test/utils/EigenLayerUnitTestBase.sol deleted file mode 100644 index 1999bee02..000000000 --- a/src/test/utils/EigenLayerUnitTestBase.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "src/contracts/permissions/PauserRegistry.sol"; -import "forge-std/Test.sol"; - -abstract contract EigenLayerUnitTestBase is Test { - Vm cheats = Vm(VM_ADDRESS); - - PauserRegistry public pauserRegistry; - ProxyAdmin public eigenLayerProxyAdmin; - - mapping(address => bool) public addressIsExcludedFromFuzzedInputs; - - address public constant pauser = address(555); - address public constant unpauser = address(556); - - // Helper Functions/Modifiers - modifier filterFuzzedAddressInputs(address fuzzedAddress) { - cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); - _; - } - - function setUp() public virtual { - address[] memory pausers = new address[](1); - pausers[0] = pauser; - pauserRegistry = new PauserRegistry(pausers, unpauser); - eigenLayerProxyAdmin = new ProxyAdmin(); - - addressIsExcludedFromFuzzedInputs[address(pauserRegistry)] = true; - addressIsExcludedFromFuzzedInputs[address(eigenLayerProxyAdmin)] = true; - } -} diff --git a/src/test/utils/EigenLayerUnitTestSetup.sol b/src/test/utils/EigenLayerUnitTestSetup.sol index ee2664f23..71b9f9cd8 100644 --- a/src/test/utils/EigenLayerUnitTestSetup.sol +++ b/src/test/utils/EigenLayerUnitTestSetup.sol @@ -1,30 +1,101 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; +import "forge-std/Test.sol"; + +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; + +import "src/contracts/permissions/PauserRegistry.sol"; +import "src/contracts/permissions/PermissionController.sol"; +import "src/contracts/strategies/StrategyBase.sol"; + +import "src/test/mocks/AVSDirectoryMock.sol"; +import "src/test/mocks/AllocationManagerMock.sol"; import "src/test/mocks/StrategyManagerMock.sol"; import "src/test/mocks/DelegationManagerMock.sol"; -import "src/test/mocks/SlasherMock.sol"; import "src/test/mocks/EigenPodManagerMock.sol"; -import "src/test/utils/EigenLayerUnitTestBase.sol"; - -abstract contract EigenLayerUnitTestSetup is EigenLayerUnitTestBase { - // Declare Mocks - StrategyManagerMock public strategyManagerMock; - DelegationManagerMock public delegationManagerMock; - SlasherMock public slasherMock; - EigenPodManagerMock public eigenPodManagerMock; - - function setUp() public virtual override { - EigenLayerUnitTestBase.setUp(); - strategyManagerMock = new StrategyManagerMock(); - delegationManagerMock = new DelegationManagerMock(); - slasherMock = new SlasherMock(); - eigenPodManagerMock = new EigenPodManagerMock(pauserRegistry); - - addressIsExcludedFromFuzzedInputs[address(0)] = true; - addressIsExcludedFromFuzzedInputs[address(strategyManagerMock)] = true; - addressIsExcludedFromFuzzedInputs[address(delegationManagerMock)] = true; - addressIsExcludedFromFuzzedInputs[address(slasherMock)] = true; - addressIsExcludedFromFuzzedInputs[address(eigenPodManagerMock)] = true; +import "src/test/mocks/EmptyContract.sol"; + +import "src/test/utils/SingleItemArrayLib.sol"; +import "src/test/utils/Random.sol"; + +import "src/test/utils/SingleItemArrayLib.sol"; + +abstract contract EigenLayerUnitTestSetup is Test { + using SingleItemArrayLib for *; + + uint256 internal constant MAX_PRIVATE_KEY = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140; + + Vm cheats = Vm(VM_ADDRESS); + + address constant pauser = address(555); + address constant unpauser = address(556); + + PauserRegistry pauserRegistry; + ProxyAdmin eigenLayerProxyAdmin; + PermissionController permissionControllerImplementation; + PermissionController permissionController; + + AVSDirectoryMock avsDirectoryMock; + AllocationManagerMock allocationManagerMock; + StrategyManagerMock strategyManagerMock; + DelegationManagerMock delegationManagerMock; + EigenPodManagerMock eigenPodManagerMock; + EmptyContract emptyContract; + + + mapping(address => bool) public isExcludedFuzzAddress; + + modifier filterFuzzedAddressInputs(address addr) { + cheats.assume(!isExcludedFuzzAddress[addr]); + _; + } + + modifier rand(Randomness r) { + r.set(); + _; + } + + function random() internal returns (Randomness) { + return Randomness.wrap(Random.SEED).shuffle(); + } + + function setUp() public virtual { + address[] memory pausers = new address[](2); + pausers[0] = pauser; + pausers[1] = address(this); + + pauserRegistry = new PauserRegistry(pausers, unpauser); + eigenLayerProxyAdmin = new ProxyAdmin(); + + // Deploy permission controller + permissionControllerImplementation = new PermissionController(); + permissionController = PermissionController(address(new TransparentUpgradeableProxy( + address(permissionControllerImplementation), + address(eigenLayerProxyAdmin), + abi.encodeWithSelector( + PermissionController.initialize.selector + ) + ))); + + avsDirectoryMock = AVSDirectoryMock(payable(address(new AVSDirectoryMock()))); + allocationManagerMock = AllocationManagerMock(payable(address(new AllocationManagerMock()))); + strategyManagerMock = StrategyManagerMock(payable(address(new StrategyManagerMock(IDelegationManager(address(delegationManagerMock)))))); + delegationManagerMock = DelegationManagerMock(payable(address(new DelegationManagerMock()))); + eigenPodManagerMock = EigenPodManagerMock(payable(address(new EigenPodManagerMock(pauserRegistry)))); + emptyContract = new EmptyContract(); + + + isExcludedFuzzAddress[address(0)] = true; + isExcludedFuzzAddress[address(pauserRegistry)] = true; + isExcludedFuzzAddress[address(permissionController)] = true; + isExcludedFuzzAddress[address(eigenLayerProxyAdmin)] = true; + isExcludedFuzzAddress[address(avsDirectoryMock)] = true; + isExcludedFuzzAddress[address(allocationManagerMock)] = true; + isExcludedFuzzAddress[address(strategyManagerMock)] = true; + isExcludedFuzzAddress[address(delegationManagerMock)] = true; + isExcludedFuzzAddress[address(eigenPodManagerMock)] = true; } -} +} \ No newline at end of file diff --git a/src/test/utils/EigenPodUser.t.sol b/src/test/utils/EigenPodUser.t.sol index 862349e40..d0f2e80f1 100644 --- a/src/test/utils/EigenPodUser.t.sol +++ b/src/test/utils/EigenPodUser.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -10,7 +10,7 @@ import "src/contracts/interfaces/IStrategy.sol"; import "src/test/integration/TimeMachine.t.sol"; import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/integration/utils/PrintUtils.t.sol"; +import "src/test/utils/Logger.t.sol"; struct Validator { uint40 index; @@ -22,9 +22,7 @@ interface IUserDeployer { function eigenPodBeacon() external view returns (IBeacon); } -contract EigenPodUser is PrintUtils { - - Vm cheats = Vm(VM_ADDRESS); +contract EigenPodUser is Logger { TimeMachine timeMachine; BeaconChainMock beaconChain; @@ -37,10 +35,6 @@ contract EigenPodUser is PrintUtils { EigenPod public pod; uint40[] validators; - IStrategy constant BEACONCHAIN_ETH_STRAT = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - IERC20 constant NATIVE_ETH = IERC20(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - uint constant GWEI_TO_WEI = 1e9; - bytes internal constant beaconProxyBytecode = hex"608060405260405161090e38038061090e83398101604081905261002291610460565b61002e82826000610035565b505061058a565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610520565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610520565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108e7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053b565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c65782516103bf576001600160a01b0385163b6103bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d0565b6103d083836103d8565b949350505050565b8151156103e85781518083602001fd5b8060405162461bcd60e51b81526004016101699190610557565b80516001600160a01b038116811461041957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561044f578181015183820152602001610437565b838111156100f95750506000910152565b6000806040838503121561047357600080fd5b61047c83610402565b60208401519092506001600160401b038082111561049957600080fd5b818501915085601f8301126104ad57600080fd5b8151818111156104bf576104bf61041e565b604051601f8201601f19908116603f011681019083821181831017156104e7576104e761041e565b8160405282815288602084870101111561050057600080fd5b610511836020830160208801610434565b80955050505050509250929050565b60006020828403121561053257600080fd5b6102c882610402565b6000825161054d818460208701610434565b9190910192915050565b6020815260008251806020840152610576816040850160208701610434565b601f01601f19169190910160400192915050565b61034e806105996000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f260279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb9190610249565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a2565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020d578251610206576001600160a01b0385163b6102065760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610217565b610217838361021f565b949350505050565b81511561022f5781518083602001fd5b8060405162461bcd60e51b81526004016101fd91906102be565b60006020828403121561025b57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028d578181015183820152602001610275565b8381111561029c576000848401525b50505050565b600082516102b4818460208701610272565b9190910192915050565b60208152600082518060208401526102dd816040850160208701610272565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d51e81d3bc5ed20a26aeb05dce7e825c503b2061aa78628027300c8d65b9d89a64736f6c634300080c0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564"; @@ -84,13 +78,13 @@ contract EigenPodUser is PrintUtils { /// Note: This method also advances one epoch forward on the beacon chain, so that /// withdrawal credential proofs are generated for each validator. function startValidators() public createSnapshot virtual returns (uint40[] memory, uint) { - _logM("startValidators"); + print.method("startValidators"); return _startValidators(); } function exitValidators(uint40[] memory _validators) public createSnapshot virtual returns (uint64 exitedBalanceGwei) { - _logM("exitValidators"); + print.method("exitValidators"); return _exitValidators(_validators); } @@ -102,19 +96,19 @@ contract EigenPodUser is PrintUtils { function verifyWithdrawalCredentials( uint40[] memory _validators ) public createSnapshot virtual { - _logM("verifyWithdrawalCredentials"); + print.method("verifyWithdrawalCredentials"); _verifyWithdrawalCredentials(_validators); } function startCheckpoint() public createSnapshot virtual { - _logM("startCheckpoint"); + print.method("startCheckpoint"); _startCheckpoint(); } function completeCheckpoint() public createSnapshot virtual { - _logM("completeCheckpoint"); + print.method("completeCheckpoint"); _completeCheckpoint(); } @@ -151,8 +145,8 @@ contract EigenPodUser is PrintUtils { uint40[] memory newValidators = new uint40[](totalValidators); uint totalBeaconBalance = address(this).balance - balanceWei; - _log("- creating new validators", newValidators.length); - _log("- depositing balance to beacon chain (wei)", totalBeaconBalance); + console.log("- creating new validators", newValidators.length); + console.log("- depositing balance to beacon chain (wei)", totalBeaconBalance); // Create each of the full validators for (uint i = 0; i < numValidators; i++) { @@ -181,13 +175,13 @@ contract EigenPodUser is PrintUtils { } function _exitValidators(uint40[] memory _validators) internal returns (uint64 exitedBalanceGwei) { - _log("- exiting num validators", _validators.length); + console.log("- exiting num validators", _validators.length); for (uint i = 0; i < _validators.length; i++) { exitedBalanceGwei += beaconChain.exitValidator(_validators[i]); } - _log("- exited balance to pod (gwei)", exitedBalanceGwei); + console.log("- exited balance to pod (gwei)", exitedBalanceGwei); return exitedBalanceGwei; } @@ -197,8 +191,8 @@ contract EigenPodUser is PrintUtils { } function _completeCheckpoint() internal { - _log("- active validator count", pod.activeValidatorCount()); - _log("- proofs remaining", pod.currentCheckpoint().proofsRemaining); + console.log("- active validator count", pod.activeValidatorCount()); + console.log("- proofs remaining", pod.currentCheckpoint().proofsRemaining); uint64 checkpointTimestamp = pod.currentCheckpointTimestamp(); if (checkpointTimestamp == 0) { @@ -206,7 +200,7 @@ contract EigenPodUser is PrintUtils { } CheckpointProofs memory proofs = beaconChain.getCheckpointProofs(validators, checkpointTimestamp); - _log("- submitting num checkpoint proofs", proofs.balanceProofs.length); + console.log("- submitting num checkpoint proofs", proofs.balanceProofs.length); pod.verifyCheckpointProofs({ balanceContainerProof: proofs.balanceContainerProof, diff --git a/src/test/utils/Logger.t.sol b/src/test/utils/Logger.t.sol new file mode 100644 index 000000000..41a64fbf6 --- /dev/null +++ b/src/test/utils/Logger.t.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "forge-std/Test.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import "src/contracts/interfaces/IStrategy.sol"; +import {IAllocationManagerTypes} from "src/contracts/interfaces/IAllocationManager.sol"; + +Vm constant cheats = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + +IStrategy constant BEACONCHAIN_ETH_STRAT = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); +IERC20 constant NATIVE_ETH = IERC20(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); + +uint256 constant MIN_BALANCE = 1e6; +uint256 constant MAX_BALANCE = 5e6; +uint256 constant GWEI_TO_WEI = 1e9; + +uint256 constant FLAG = 1; + +/// @dev Types representing the different types of assets a ranomized users can hold. +uint256 constant NO_ASSETS = (FLAG << 0); // will have no assets +uint256 constant HOLDS_LST = (FLAG << 1); // will hold some random amount of LSTs +uint256 constant HOLDS_ETH = (FLAG << 2); // will hold some random amount of ETH +uint256 constant HOLDS_ALL = (FLAG << 3); // will hold every LST and ETH + +/// @dev Types representing the different types of users that can be created. +uint256 constant DEFAULT = (FLAG << 0); +uint256 constant ALT_METHODS = (FLAG << 1); + +/// @dev Types representing the different types of forks that can be simulated. +uint256 constant LOCAL = (FLAG << 0); +uint256 constant MAINNET = (FLAG << 1); +uint256 constant HOLESKY = (FLAG << 2); + +abstract contract Logger is Test { + using StdStyle for *; + + /// ----------------------------------------------------------------------- + /// Storage + /// ----------------------------------------------------------------------- + + bool on = true; + + /// ----------------------------------------------------------------------- + /// Modifiers + /// ----------------------------------------------------------------------- + + modifier noTracing() { + cheats.pauseTracing(); + _; + cheats.resumeTracing(); + } + + modifier noLogging() { + _pauseLogging(); + _; + _resumeLogging(); + } + + /// ----------------------------------------------------------------------- + /// Must Override + /// ----------------------------------------------------------------------- + + /// @dev Provide a name for the inheriting contract. + function NAME() public view virtual returns (string memory); + + /// ----------------------------------------------------------------------- + /// Colored Names + /// ----------------------------------------------------------------------- + + /// @dev Returns `NAME` colored based on the inheriting contract's role. + function NAME_COLORED() public view returns (string memory) { + return colorByRole(NAME()); + } + + /// @dev Returns `name` colored based on its role. + function colorByRole( + string memory name + ) public view noTracing returns (string memory colored) { + bool isOperator = _contains(name, "operator"); + bool isStaker = _contains(name, "staker"); + bool isAVS = _contains(name, "avs"); + + if (isOperator) { + colored = name.blue(); + } else if (isStaker) { + colored = name.cyan(); + } else if (isAVS) { + colored = name.magenta(); + } else { + colored = name.yellow(); + } + } + + /// @dev Returns `true` if `needle` is found in `haystack`. + function _contains(string memory haystack, string memory needle) internal pure returns (bool) { + return cheats.indexOf(haystack, needle) != type(uint256).max; + } + + /// ----------------------------------------------------------------------- + /// Cheats + /// ----------------------------------------------------------------------- + + function rollForward( + uint256 blocks + ) internal { + cheats.roll(block.timestamp + blocks); + console.log("%s.roll(%d)", colorByRole("cheats"), block.timestamp); + } + + /// ----------------------------------------------------------------------- + /// Logging + /// ----------------------------------------------------------------------- + + function _pauseLogging() internal { + console.log("\n%s logging paused...", NAME_COLORED()); + on = false; + } + + function _resumeLogging() internal { + console.log("\n%s logging unpaused...", NAME_COLORED()); + on = true; + } +} + +/// @dev Assumes the user is a `Logger`. +library print { + using print for *; + using StdStyle for *; + + /// ----------------------------------------------------------------------- + /// Logging + /// ----------------------------------------------------------------------- + + function method( + string memory m + ) internal view { + console.log("%s.%s()", _name(), m.italic()); + } + + function method(string memory m, string memory args) internal view { + console.log("%s.%s(%s)", _name(), m.italic(), args); + } + + function user( + string memory name, + uint256 assetType, + uint256 userType, + IStrategy[] memory strategies, + uint256[] memory tokenBalances + ) internal view { + console.log( + "\nCreated %s %s who holds %s.", userType.asUserType(), _logger().colorByRole(name), assetType.asAssetType() + ); + + console.log(" Balances:"); + for (uint256 i = 0; i < strategies.length; i++) { + IStrategy strat = strategies[i]; + if (strat == BEACONCHAIN_ETH_STRAT) { + console.log(" Native ETH: %s", print.asWad(tokenBalances[i])); + } else { + IERC20 underlyingToken = strat.underlyingToken(); + console.log( + " %s: %s", IERC20Metadata(address(underlyingToken)).name(), print.asGwei(tokenBalances[i]) + ); + } + } + } + + /// ----------------------------------------------------------------------- + /// Logging + /// ----------------------------------------------------------------------- + + function createOperatorSets( + IAllocationManagerTypes.CreateSetParams[] memory p + ) internal pure { + console.log("Creating operator sets:"); + for (uint256 i; i < p.length; ++i) { + console.log(" operatorSet%d:".yellow(), p[i].operatorSetId); + for (uint256 j; j < p[i].strategies.length; ++j) { + console.log(" strategy%s: %s", cheats.toString(j), address(p[i].strategies[j])); + } + } + } + + function deregisterFromOperatorSets( + IAllocationManagerTypes.DeregisterParams memory p + ) internal pure { + console.log("Deregistering operator: %s", address(p.operator)); + console.log(" from operator sets:"); + for (uint256 i; i < p.operatorSetIds.length; ++i) { + console.log(" operatorSet%d:".yellow(), p.operatorSetIds[i]); + } + } + + /// ----------------------------------------------------------------------- + /// Strings + /// ----------------------------------------------------------------------- + + function asAssetType( + uint256 t + ) internal pure returns (string memory s) { + if (t == HOLDS_ALL) { + s = "ALL_ASSETS"; + } else if (t == HOLDS_LST) { + s = "LST"; + } else if (t == HOLDS_ETH) { + s = "ETH"; + } else if (t == NO_ASSETS) { + s = "NO_ASSETS"; + } + } + + function asUserType( + uint256 t + ) internal pure returns (string memory s) { + if (t == DEFAULT) { + s = "DEFAULT"; + } else if (t == ALT_METHODS) { + s = "ALT_METHODS"; + } + } + + function asForkType( + uint256 t + ) internal pure returns (string memory s) { + if (t == LOCAL) { + s = "LOCAL"; + } else if (t == MAINNET) { + s = "MAINNET"; + } else if (t == HOLESKY) { + s = "HOLESKY"; + } + } + + function asGwei( + uint256 x + ) internal pure returns (string memory) { + return x.asDecimal(9, " gwei"); + } + + function asWad( + uint256 x + ) internal pure returns (string memory) { + return x.asDecimal(18, " wad"); + } + + function asDecimal(uint256 x, uint8 decimals, string memory denomination) internal pure returns (string memory s) { + if (x == 0) return string.concat("0.0", denomination); + + s = cheats.toString(x); + + while (bytes(s).length < decimals) s = string.concat("0", s); + + uint256 len = bytes(s).length; + bytes memory b = bytes(s); + bytes memory left = new bytes(len > decimals ? len - decimals : 0); + bytes memory right = new bytes(decimals); + + for (uint256 i; i < left.length; ++i) { + left[i] = b[i]; + } + + for (uint256 i; i < decimals; ++i) { + right[i] = b[len - decimals + i]; + } + + return string.concat(left.length > 0 ? string(left) : "0", ".", string(right), denomination); + } + + /// ----------------------------------------------------------------------- + /// Helpers + /// ----------------------------------------------------------------------- + + function _name() internal view returns (string memory) { + try _logger().NAME_COLORED() returns (string memory name) { + return name; + } catch { + revert("This contract is not a `Logger`."); + } + } + + function _logger() internal view returns (Logger) { + return Logger(address(this)); + } +} diff --git a/src/test/utils/Operators.sol b/src/test/utils/Operators.sol deleted file mode 100644 index 7c5faabd6..000000000 --- a/src/test/utils/Operators.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "forge-std/Test.sol"; -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -contract Operators is Test { - string internal operatorConfigJson; - - constructor() { - operatorConfigJson = vm.readFile("./src/test/test-data/operators.json"); - } - - function operatorPrefix(uint256 index) public pure returns(string memory) { - return string.concat(".operators[", string.concat(vm.toString(index), "].")); - } - - function getNumOperators() public returns(uint256) { - return stdJson.readUint(operatorConfigJson, ".numOperators"); - } - - function getOperatorAddress(uint256 index) public returns(address) { - return stdJson.readAddress(operatorConfigJson, string.concat(operatorPrefix(index), "Address")); - } - - function getOperatorSecretKey(uint256 index) public returns(uint256) { - return readUint(operatorConfigJson, index, "SecretKey"); - } - - function readUint(string memory json, uint256 index, string memory key) public returns (uint256) { - return stringToUint(stdJson.readString(json, string.concat(operatorPrefix(index), key))); - } - - function stringToUint(string memory s) public pure returns (uint256) { - bytes memory b = bytes(s); - uint256 result = 0; - for (uint256 i = 0; i < b.length; i++) { - if (uint256(uint8(b[i])) >= 48 && uint256(uint8(b[i])) <= 57) { - result = result * 10 + (uint256(uint8(b[i])) - 48); - } - } - return result; - } - function setOperatorJsonFilePath(string memory filepath) public { - operatorConfigJson = vm.readFile(filepath); - } -} diff --git a/src/test/utils/Owners.sol b/src/test/utils/Owners.sol deleted file mode 100644 index 9c32971ab..000000000 --- a/src/test/utils/Owners.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "forge-std/Test.sol"; -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -contract Owners is Test { - string internal ownersConfigJson; - address[] addresses; - - constructor() { - ownersConfigJson = vm.readFile("./src/test/test-data/owners.json"); - } - - function ownerPrefix(uint256 index) public pure returns(string memory) { - return string.concat(".owners[", string.concat(vm.toString(index), "].")); - } - - function getNumOperators() public returns(uint256) { - return stdJson.readUint(ownersConfigJson, ".numOwners"); - } - - function getOwnerAddress(uint256 index) public returns(address) { - return stdJson.readAddress(ownersConfigJson, string.concat(ownerPrefix(index), "Address")); - } - - function getOwnerAddresses() public returns(address[] memory) { - for (uint256 i = 0; i < getNumOperators(); i++) { - addresses.push(getOwnerAddress(i)); - } - return addresses; - } - - function getReputedOwnerAddresses() public returns(address[] memory) { - resetOwnersConfigJson("reputedOwners.json"); - for (uint256 i = 0; i < getNumOperators(); i++) { - addresses.push(getOwnerAddress(i)); - } - return addresses; - } - - function resetOwnersConfigJson(string memory newConfig) public { - ownersConfigJson = vm.readFile(newConfig); - } - -} diff --git a/src/test/utils/ProofParsing.sol b/src/test/utils/ProofParsing.sol index e3607e07b..a6a88545f 100644 --- a/src/test/utils/ProofParsing.sol +++ b/src/test/utils/ProofParsing.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; @@ -26,51 +26,51 @@ contract ProofParsing is Test { proofConfigJson = vm.readFile(path); } - function getSlot() public returns(uint256) { + function getSlot() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".slot"); } - function getValidatorIndex() public returns(uint256) { + function getValidatorIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".validatorIndex"); } - function getValidatorPubkeyHash() public returns(bytes32) { + function getValidatorPubkeyHash() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".ValidatorFields[0]"); } - function getWithdrawalIndex() public returns(uint256) { + function getWithdrawalIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".withdrawalIndex"); } - function getBlockRootIndex() public returns(uint256) { + function getBlockRootIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".blockHeaderRootIndex"); } - function getHistoricalSummaryIndex() public returns(uint256) { + function getHistoricalSummaryIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".historicalSummaryIndex"); } - function getBeaconStateRoot() public returns(bytes32) { + function getBeaconStateRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".beaconStateRoot"); } - function getBlockRoot() public returns(bytes32) { + function getBlockRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".blockHeaderRoot"); } - function getSlotRoot() public returns(bytes32) { + function getSlotRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".slotRoot"); } - function getTimestampRoot() public returns(bytes32) { + function getTimestampRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".timestampRoot"); } - function getExecutionPayloadRoot() public returns(bytes32) { + function getExecutionPayloadRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".executionPayloadRoot"); } - function getLatestBlockRoot() public returns(bytes32) { + function getLatestBlockRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".latestBlockHeaderRoot"); } function getExecutionPayloadProof () public returns(bytes32[7] memory) { diff --git a/src/test/utils/Random.sol b/src/test/utils/Random.sol new file mode 100644 index 000000000..62a4361ee --- /dev/null +++ b/src/test/utils/Random.sol @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/contracts/interfaces/IAllocationManager.sol"; +import "src/contracts/interfaces/IStrategy.sol"; +import "src/contracts/libraries/OperatorSetLib.sol"; + +type Randomness is uint256; + +using Random for Randomness global; + +library Random { + /// ----------------------------------------------------------------------- + /// Constants + /// ----------------------------------------------------------------------- + + /// @dev Equivalent to: `uint256(keccak256("RANDOMNESS.SEED"))`. + uint256 constant SEED = 0x93bfe7cafd9427243dc4fe8c6e706851eb6696ba8e48960dd74ecc96544938ce; + + /// @dev Equivalent to: `uint256(keccak256("RANDOMNESS.SLOT"))`. + uint256 constant SLOT = 0xd0660badbab446a974e6a19901c78a2ad88d7e4f1710b85e1cfc0878477344fd; + + /// ----------------------------------------------------------------------- + /// Helpers + /// ----------------------------------------------------------------------- + + function set( + Randomness r + ) internal returns (Randomness) { + /// @solidity memory-safe-assembly + assembly { + sstore(SLOT, r) + } + return r; + } + + function shuffle( + Randomness r + ) internal returns (Randomness) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, sload(SLOT)) + mstore(0x20, r) + r := keccak256(0x00, 0x20) + } + return r.set(); + } + + /// ----------------------------------------------------------------------- + /// Native Types + /// ----------------------------------------------------------------------- + + function Int256(Randomness r, int256 min, int256 max) internal returns (int256) { + return max <= min ? min : r.Int256() % (max - min) + min; + } + + function Int256(Randomness r) internal returns (int256) { + return r.unwrap() % 2 == 0 ? int256(r.Uint256()) : -int256(r.Uint256()); + } + + function Int128(Randomness r, int128 min, int128 max) internal returns (int128) { + return int128(Int256(r, min, max)); + } + + function Int128(Randomness r) internal returns (int128) { + return int128(Int256(r)); + } + + function Int64(Randomness r, int64 min, int64 max) internal returns (int64) { + return int64(Int256(r, min, max)); + } + + function Int64(Randomness r) internal returns (int64) { + return int64(Int256(r)); + } + + function Int32(Randomness r, int32 min, int32 max) internal returns (int32) { + return int32(Int256(r, min, max)); + } + + function Uint256(Randomness r, uint256 min, uint256 max) internal returns (uint256) { + return max <= min ? min : r.Uint256() % (max - min) + min; + } + + function Uint256( + Randomness r + ) internal returns (uint256) { + return r.shuffle().unwrap(); + } + + function Uint128(Randomness r, uint128 min, uint128 max) internal returns (uint128) { + return uint128(Uint256(r, min, max)); + } + + function Uint128( + Randomness r + ) internal returns (uint128) { + return uint128(Uint256(r)); + } + + function Uint64(Randomness r, uint64 min, uint64 max) internal returns (uint64) { + return uint64(Uint256(r, min, max)); + } + + function Uint64( + Randomness r + ) internal returns (uint64) { + return uint64(Uint256(r)); + } + + function Uint32(Randomness r, uint32 min, uint32 max) internal returns (uint32) { + return uint32(Uint256(r, min, max)); + } + + function Uint32( + Randomness r + ) internal returns (uint32) { + return uint32(Uint256(r)); + } + + function Bytes32( + Randomness r + ) internal returns (bytes32) { + return bytes32(r.Uint256()); + } + + function Address( + Randomness r + ) internal returns (address) { + return address(uint160(r.Uint256(1, type(uint160).max))); + } + + function Boolean( + Randomness r + ) internal returns (bool) { + return r.Uint256() % 2 == 0; + } + + /// ----------------------------------------------------------------------- + /// General Types + /// ----------------------------------------------------------------------- + + function StakerArray(Randomness r, uint256 len) internal returns (address[] memory stakers) { + stakers = new address[](len); + for (uint256 i; i < len; ++i) { + stakers[i] = r.Address(); + } + } + + function StrategyArray(Randomness r, uint256 len) internal returns (IStrategy[] memory strategies) { + strategies = new IStrategy[](len); + for (uint256 i; i < len; ++i) { + strategies[i] = IStrategy(r.Address()); + } + } + + function OperatorSetArray( + Randomness r, + address avs, + uint256 len + ) internal returns (OperatorSet[] memory operatorSets) { + operatorSets = new OperatorSet[](len); + for (uint256 i; i < len; ++i) { + operatorSets[i] = OperatorSet(avs, r.Uint32()); + } + } + + /// ----------------------------------------------------------------------- + /// `AllocationManager` Types + /// ----------------------------------------------------------------------- + + /// @dev Usage: `r.createSetParams(r, numOpSets, numStrats)`. + function CreateSetParams( + Randomness r, + uint256 numOpSets, + uint256 numStrats + ) internal returns (IAllocationManagerTypes.CreateSetParams[] memory params) { + params = new IAllocationManagerTypes.CreateSetParams[](numOpSets); + for (uint256 i; i < numOpSets; ++i) { + params[i].operatorSetId = r.Uint32(1, type(uint32).max); + params[i].strategies = r.StrategyArray(numStrats); + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(r.createSetParams(allocateParams)); + /// ``` + function CreateSetParams( + Randomness, + IAllocationManagerTypes.AllocateParams[] memory allocateParams + ) internal pure returns (IAllocationManagerTypes.CreateSetParams[] memory params) { + params = new IAllocationManagerTypes.CreateSetParams[](allocateParams.length); + for (uint256 i; i < allocateParams.length; ++i) { + params[i] = IAllocationManagerTypes.CreateSetParams( + allocateParams[i].operatorSet.id, allocateParams[i].strategies + ); + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + /// + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(createSetParams); + /// + /// cheats.prank(operator); + /// allocationManager.modifyAllocations(allocateParams); + /// ``` + function AllocateParams( + Randomness r, + address avs, + uint256 numAllocations, + uint256 numStrats + ) internal returns (IAllocationManagerTypes.AllocateParams[] memory allocateParams) { + allocateParams = new IAllocationManagerTypes.AllocateParams[](numAllocations); + + // TODO: Randomize magnitudes such that they sum to 1e18 (100%). + uint64 magnitudePerSet = uint64(WAD / numStrats); + + for (uint256 i; i < numAllocations; ++i) { + allocateParams[i].operatorSet = OperatorSet(avs, r.Uint32()); + allocateParams[i].strategies = r.StrategyArray(numStrats); + allocateParams[i].newMagnitudes = new uint64[](numStrats); + + for (uint256 j; j < numStrats; ++j) { + allocateParams[i].newMagnitudes[j] = magnitudePerSet; + } + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// AllocateParams[] memory deallocateParams = r.deallocateParams(allocateParams); + /// CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + /// + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(createSetParams); + /// + /// cheats.prank(operator); + /// allocationManager.modifyAllocations(allocateParams); + /// + /// cheats.prank(operator) + /// allocationManager.modifyAllocations(deallocateParams); + /// ``` + function DeallocateParams( + Randomness r, + IAllocationManagerTypes.AllocateParams[] memory allocateParams + ) internal returns (IAllocationManagerTypes.AllocateParams[] memory deallocateParams) { + uint256 numDeallocations = allocateParams.length; + + deallocateParams = new IAllocationManagerTypes.AllocateParams[](numDeallocations); + + for (uint256 i; i < numDeallocations; ++i) { + deallocateParams[i].operatorSet = allocateParams[i].operatorSet; + deallocateParams[i].strategies = allocateParams[i].strategies; + + deallocateParams[i].newMagnitudes = new uint64[](allocateParams[i].strategies.length); + for (uint256 j; j < allocateParams[i].strategies.length; ++j) { + deallocateParams[i].newMagnitudes[j] = r.Uint64(0, allocateParams[i].newMagnitudes[j] - 1); + } + } + } + + /// @dev Usage: + /// ``` + /// AllocateParams[] memory allocateParams = r.allocateParams(avs, numAllocations, numStrats); + /// CreateSetParams[] memory createSetParams = r.createSetParams(allocateParams); + /// RegisterParams memory registerParams = r.registerParams(allocateParams); + /// + /// cheats.prank(avs); + /// allocationManager.createOperatorSets(createSetParams); + /// + /// cheats.prank(operator); + /// allocationmanager.registerForOperatorSets(registerParams); + /// ``` + function RegisterParams( + Randomness r, + IAllocationManagerTypes.AllocateParams[] memory allocateParams + ) internal returns (IAllocationManagerTypes.RegisterParams memory params) { + params.avs = allocateParams[0].operatorSet.avs; + params.operatorSetIds = new uint32[](allocateParams.length); + for (uint256 i; i < allocateParams.length; ++i) { + params.operatorSetIds[i] = allocateParams[i].operatorSet.id; + } + params.data = abi.encode(r.Bytes32()); + } + + function SlashingParams( + Randomness r, + address operator, + IAllocationManagerTypes.AllocateParams memory allocateParams + ) internal returns (IAllocationManagerTypes.SlashingParams memory params) { + params.operator = operator; + params.operatorSetId = allocateParams.operatorSet.id; + params.wadToSlash = r.Uint256(0.01 ether, 1 ether); + params.description = "test"; + } + + /// ----------------------------------------------------------------------- + /// Helpers + /// ----------------------------------------------------------------------- + + function wrap( + uint256 r + ) internal pure returns (Randomness) { + return Randomness.wrap(r); + } + + function unwrap( + Randomness r + ) internal pure returns (uint256) { + return Randomness.unwrap(r); + } +} diff --git a/src/test/utils/SignatureCompaction.sol b/src/test/utils/SignatureCompaction.sol deleted file mode 100644 index c10b2db1d..000000000 --- a/src/test/utils/SignatureCompaction.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -//small library for dealing with efficiently-packed signatures, where parameters v,r,s are packed into vs and r (64 bytes instead of 65) -library SignatureCompaction { - bytes32 internal constant HALF_CURVE_ORDER = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0; - - function ecrecoverPacked(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { - (address recovered, ECDSA.RecoverError err) = ECDSA.tryRecover(hash, r, vs); - require(err == ECDSA.RecoverError.NoError, "error in ecrecoverPacked"); - return recovered; - } - - function packSignature(bytes32 r, bytes32 s, uint8 v) internal pure returns (bytes32, bytes32) { - require(s <= HALF_CURVE_ORDER, "malleable signature, s too high"); - //v parity is a single bit, encoded as either v = 27 or v = 28 -- in order to recover the bit we subtract 27 - bytes32 vs = bytes32(uint256(bytes32(uint256(v) - 27) << 255) | uint256(s)); - return (r, vs); - } - - //same as above, except doesn't take 'r' as argument since it is unneeded - function packVS(bytes32 s, uint8 v) internal pure returns (bytes32) { - require(s <= HALF_CURVE_ORDER, "malleable signature, s too high"); - //v parity is a single bit, encoded as either v = 27 or v = 28 -- in order to recover the bit we subtract 27 - return bytes32(uint256(bytes32(uint256(v) - 27) << 255) | uint256(s)); - } -} diff --git a/src/test/utils/SingleItemArrayLib.sol b/src/test/utils/SingleItemArrayLib.sol new file mode 100644 index 000000000..b0da93810 --- /dev/null +++ b/src/test/utils/SingleItemArrayLib.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/contracts/interfaces/IAllocationManager.sol"; + +/// @dev Helper library for simplifying the syntax for creating single item arrays for inputs. +library SingleItemArrayLib { + /// ----------------------------------------------------------------------- + /// Native Types + /// ----------------------------------------------------------------------- + + function toArrayU16( + uint16 x + ) internal pure returns (uint16[] memory array) { + array = new uint16[](1); + array[0] = x; + } + + function toArrayU32( + uint32 x + ) internal pure returns (uint32[] memory array) { + array = new uint32[](1); + array[0] = x; + } + + function toArrayU64( + uint64 x + ) internal pure returns (uint64[] memory array) { + array = new uint64[](1); + array[0] = x; + } + + function toArrayU256( + uint256 x + ) internal pure returns (uint256[] memory array) { + array = new uint256[](1); + array[0] = x; + } + + + function toArrayU16( + uint16 x, + uint256 len + ) internal pure returns (uint16[] memory array) { + array = new uint16[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArrayU32( + uint32 x, + uint256 len + ) internal pure returns (uint32[] memory array) { + array = new uint32[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArrayU64( + uint64 x, + uint256 len + ) internal pure returns (uint64[] memory array) { + array = new uint64[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArrayU256( + uint256 x, + uint256 len + ) internal pure returns (uint256[] memory array) { + array = new uint256[](len); + for (uint256 i; i < len; ++i) { + array[i] = x; + } + } + + function toArray( + address x + ) internal pure returns (address[] memory array) { + array = new address[](1); + array[0] = x; + } + + /// ----------------------------------------------------------------------- + /// EigenLayer Types + /// ----------------------------------------------------------------------- + + function toArray( + IERC20 token + ) internal pure returns (IERC20[] memory array) { + array = new IERC20[](1); + array[0] = token; + } + + function toArray( + IStrategy strategy + ) internal pure returns (IStrategy[] memory array) { + array = new IStrategy[](1); + array[0] = strategy; + } + + function toArray( + OperatorSet memory operatorSet + ) internal pure returns (OperatorSet[] memory array) { + array = new OperatorSet[](1); + array[0] = operatorSet; + } + + function toArray( + IAllocationManagerTypes.CreateSetParams memory createSetParams + ) internal pure returns (IAllocationManagerTypes.CreateSetParams[] memory array) { + array = new IAllocationManagerTypes.CreateSetParams[](1); + array[0] = createSetParams; + } + + function toArray( + IAllocationManagerTypes.AllocateParams memory allocateParams + ) internal pure returns (IAllocationManagerTypes.AllocateParams[] memory array) { + array = new IAllocationManagerTypes.AllocateParams[](1); + array[0] = allocateParams; + } +} \ No newline at end of file diff --git a/src/test/utils/Utils.sol b/src/test/utils/Utils.sol deleted file mode 100644 index 10c5653eb..000000000 --- a/src/test/utils/Utils.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import "src/contracts/strategies/StrategyBase.sol"; - -contract Utils { - address constant dummyAdmin = address(uint160(uint256(keccak256("DummyAdmin")))); - - function deployNewStrategy(IERC20 token, IStrategyManager strategyManager, IPauserRegistry pauserRegistry, address admin) public returns (StrategyBase) { - StrategyBase newStrategy = new StrategyBase(strategyManager); - newStrategy = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(newStrategy), - address(admin), - "" - ) - ) - ); - newStrategy.initialize(token, pauserRegistry); - return newStrategy; - } -}