diff --git a/.env.example b/.env.example index 948f166c8b..66ff10e6cc 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,37 @@ -RPC_MAINNET="https://eth.llamarpc.com" -# RPC_MAINNET="https://mainnet.infura.io/v3/API-KEY" -RPC_GOERLI="https://ethereum-goerli.publicnode.com" -RPC_HOLESKY="" +FOUNDRY_PROFILE="mainnet" # "default", "medium", "mainnet", "sepolia", "hoodi", and "holesky" are supported. + +# Needed in order to verify contracts. ETHERSCAN_API_KEY="API-KEY" + +# Make sure to update foundry.toml if additional RPCs are added. +RPC_MAINNET="https://eth.llamarpc.com" +RPC_SEPOLIA="https://ethereum-sepolia.publicnode.com" +RPC_HOODI="https://0xrpc.io/hoodi" +RPC_HOLESKY="https://holesky-rpc.publicnode.com" + +# Setting `FORK_BLOCK_` allows integration tests to automatically use the correct block number (use zero for latest block). +FORK_BLOCK_MAINNET="22296566" +FORK_BLOCK_SEPOLIA="8134026" +FORK_BLOCK_HOODI="201941" +FORK_BLOCK_HOLESKY="0" + +# Whether to upgrade the contracts before integration testing. +UPGRADE_BEFORE_TEST_MAINNET="false" +UPGRADE_BEFORE_TEST_HOODI="false" +UPGRADE_BEFORE_TEST_SEPOLIA="false" +UPGRADE_BEFORE_TEST_HOLESKY="false" + +# Whether to run eigen pod tests on the given chain. +TEST_EIGEN_PODS_MAINNET="true" +TEST_EIGEN_PODS_HOODI="false" +TEST_EIGEN_PODS_SEPOLIA="false" +TEST_EIGEN_PODS_HOLESKY="false" + +# Whether to run upgrade tests on the given chain. +TEST_UPGRADES_MAINNET="true" +TEST_UPGRADES_HOODI="true" +TEST_UPGRADES_SEPOLIA="true" +TEST_UPGRADES_HOLESKY="true" + +# If non-zero, we assume integration tests need to execute a timelocked upgrade. +TIMELOCK_PAYLOAD="" \ No newline at end of file diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index d5d8f430b5..dd04fc5db1 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -7,7 +7,6 @@ on: branches: - "dev" - env: FOUNDRY_PROFILE: medium RPC_MAINNET: ${{ secrets.RPC_MAINNET }} @@ -62,6 +61,14 @@ jobs: forge --version forge build --sizes + # Generate a fuzz seed that changes weekly to avoid burning through RPC allowance. + - name: "Generate A Fuzz Seed Weekly" + if: ${{ matrix.suite == 'Fork' }} + run: > + echo "FOUNDRY_FUZZ_SEED=$( + echo $(($EPOCHSECONDS - $EPOCHSECONDS % 604800)) + )" >> $GITHUB_ENV + # Run the test suite in parallel based on the matrix configuration. - name: Run ${{ matrix.suite }} tests run: | @@ -71,7 +78,7 @@ jobs: Fork) forge test --match-contract Integration ;; esac env: - FOUNDRY_PROFILE: ${{ matrix.suite == 'Fork' && 'forktest' || 'medium' }} + FOUNDRY_PROFILE: ${{ matrix.suite == 'Fork' && 'mainnet' || 'medium' }} # ----------------------------------------------------------------------- # Forge Test (Intense) @@ -91,7 +98,7 @@ jobs: submodules: recursive # Restore Forge cache - - name: Cache Forge Build + - name: "Cache Forge Build" uses: actions/cache@v3 with: path: | @@ -115,7 +122,7 @@ jobs: id: build # Run Forge Test (Intense) - - name: Forge Test (Intense) + - name: "Forge Test (Intense)" run: | echo -e "\033[1;33mWarning: This workflow may take several hours to complete.\033[0m" echo -e "\033[1;33mThis intense fuzzing workflow is optional but helps catch edge cases through extended testing.\033[0m" diff --git a/.gitignore b/.gitignore index cf968e92e4..ee66f2f897 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,10 @@ script/output/eigenpods.json cache_hardhat artifacts *.lock + #Foundry files out -cache +snapshots *.DS_Store @@ -53,4 +54,6 @@ deployed_strategies.json populate_src* # cerota -.certora_internal/* \ No newline at end of file +.certora_internal/* + +cache/solidity-files-cache.json \ No newline at end of file diff --git a/.zeus b/.zeus index 9290b11aee..a741ebf55e 100644 --- a/.zeus +++ b/.zeus @@ -1,4 +1,4 @@ { - "zeusHost": "https://github.com/Layr-Labs/eigenlayer-contracts-zeus-metadata", + "zeusHost": "https://github.com/layr-labs/eigenlayer-contracts-zeus-metadata", "migrationDirectory": "script/releases" } \ No newline at end of file diff --git a/Makefile b/Makefile index d7ee5a691b..6ddbdff33c 100644 --- a/Makefile +++ b/Makefile @@ -51,4 +51,11 @@ fix-typos: typos --config .github/configs/typos-cli.toml --write-changes fmt: - forge fmt; FOUNDRY_PROFILE=test forge fmt \ No newline at end of file + forge fmt; FOUNDRY_PROFILE=test forge fmt + +integration: + export FOUNDRY_PROFILE=default; forge t --mc Integration + export FOUNDRY_PROFILE=mainnet; forge t --mc Integration + export FOUNDRY_PROFILE=sepolia; forge t --mc Integration + export FOUNDRY_PROFILE=hoodi; forge t --mc Integration + export FOUNDRY_PROFILE=holesky; forge t --mc Integration \ No newline at end of file diff --git a/cache/fuzz/failures b/cache/fuzz/failures new file mode 100644 index 0000000000..9f5fe1f1ce --- /dev/null +++ b/cache/fuzz/failures @@ -0,0 +1,13 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc cb16665b6c114cb28b723311e0c985f6211532509e71ac489a36f338c9358048 # shrinks to 0x7099c6310000000000000000000000000000000000000000000000000000000000000000 +cc 2913c3b8b55a4ed0bcfa8469aa3faf11e07e5a010822aeb9a0da4cf5f4879471 # shrinks to 0x8ba58f1a0000000000000000000000000000000000000000000000000000000000003c09 +cc 5c7503dcef161f8a61c52226f0eeb2c929a4c470a2cf3f205831f7bd2dd3c523 # shrinks to 0xa732bb5c0000000000000000000000000000000000000000000000000000000000000c04 +cc f51a58bcaa5989372549d7466621b643f15acb750989fede6b36911518cc1098 # shrinks to 0x4d90ad1d000000000000000000000000000000000000000000000000000000000000004a +cc 5b4bced7d1dc835b7017680c1c9443fffda3e3a1f1e435539c5da46f5d8b0188 # shrinks to 0xeccb17a50000000000000000000000000000000000000000000000000000000000000002 +cc 0fb74b55c7122b5d3cec6b6e5496ed0096f57a53e22fff950c8ed02d59229587 # shrinks to 0x3c79ca0400000000000000000000000000000000000000000000000000000000000006f6 +cc 4d277d39cb477084e6f3e893f1e2de6f395dcea0b449565275e0fe9a1f38e23d # shrinks to 0xe0a4dc5000000000000000000000000000000000000000000000000000000000005d6104 diff --git a/cache/test-failures b/cache/test-failures new file mode 100644 index 0000000000..e69de29bb2 diff --git a/foundry.toml b/foundry.toml index 86113eb783..f8e9c1c90b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -134,4 +134,5 @@ [rpc_endpoints] mainnet = "${RPC_MAINNET}" - holesky = "${RPC_HOLESKY}" \ No newline at end of file + hoodi = "${RPC_HOODI}" + sepolia = "${RPC_SEPOLIA}" \ No newline at end of file diff --git a/lib/zeus-templates b/lib/zeus-templates index 2a69798c96..ec8aea59e6 160000 --- a/lib/zeus-templates +++ b/lib/zeus-templates @@ -1 +1 @@ -Subproject commit 2a69798c961b20fc4832207bdfbfc60ce8672a7e +Subproject commit ec8aea59e62529f98a4672c0ab423539b9df14f7 diff --git a/script/configs/devnet/deploy_from_scratch.anvil.config.json b/script/configs/devnet/deploy_from_scratch.anvil.config.json deleted file mode 100644 index 6d8b5fef76..0000000000 --- a/script/configs/devnet/deploy_from_scratch.anvil.config.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "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", - "semver": "v1.0.3" -} \ 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 deleted file mode 100644 index 054a432868..0000000000 --- a/script/configs/devnet/deploy_from_scratch.holesky.config.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "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", - "semver": "v0.0.0" -} diff --git a/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json b/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json deleted file mode 100644 index 99d3c54cbe..0000000000 --- a/script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "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", - "semver": "v0.0.0" - } \ No newline at end of file diff --git a/script/configs/holesky.json b/script/configs/holesky.json deleted file mode 100644 index b6c35dd065..0000000000 --- a/script/configs/holesky.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "config": { - "environment": { - "chainid": 17000, - "lastUpdated": "v0.4.2-mainnet-pepe", - "name": "testnet-holesky" - }, - "params": { - "ethPOS": "0x4242424242424242424242424242424242424242", - "EIGENPOD_GENESIS_TIME": 1695902400, - "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, - "GLOBAL_OPERATOR_COMMISSION_BIPS": 1000 - } - }, - "deployment": { - "admin": { - "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", - "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", - "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", - "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", - "pauserRegistry": "0x85Ef7299F8311B25642679edBF02B62FA2212F06", - "proxyAdmin": "0xDB023566064246399b4AE851197a97729C93A6cf", - "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" - }, - "core": { - "avsDirectory": { - "proxy": "0x055733000064333CaDDbC92763c58BF0192fFeBf", - "impl": "0xEF5BA995Bc7722fd1e163edF8Dc09375de3d3e3a", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "delegationManager": { - "proxy": "0xA44151489861Fe9e3055d95adC98FbD462B948e7", - "impl": "0x83f8F8f0BB125F7870F6bfCf76853f874C330D76", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "rewardsCoordinator": { - "proxy": "0xAcc1fb458a1317E886dB376Fc8141540537E68fE", - "impl": "0x1a17df4170099577b79038fd310f3ff62f79752e", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "slasher": { - "proxy": "0xcAe751b75833ef09627549868A04E32679386e7C", - "impl": "0x99715D255E34a39bE9943b82F281CA734bcF345A", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyManager": { - "proxy": "0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6", - "impl": "0x59f766A603C53f3AC8Be43bBe158c1519b193a18", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "pods": { - "delayedWithdrawalRouter": { - "proxy": "0x642c646053eaf2254f088e9019ACD73d9AE0FA32", - "impl": "0xcE8b8D99773a718423F8040a6e52c06a4ce63407", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPod": { - "beacon": "0x7261C2bd75a7ACE1762f6d7FAe8F63215581832D", - "impl": "0x10ad7e30e3F52076C8462D573530f4461377319c", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPodManager": { - "proxy": "0x30770d7E3e71112d7A6b7259542D1f680a70e315", - "impl": "0x91A6525a4a843F5a5B633905300c33F79413CCc5", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "strategies": { - "strategyFactory": { - "proxy": "0x9c01252B580efD11a05C00Aa42Dd3ac1Ec52DF6d", - "impl": "0x5E699de7bFc4DD2A5E72EB5a2Ca99651EfdD51CB", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyBeacon": { - "beacon": "0xd3c6C6BA4E40dB9288c6a2077e5635344F8aFA4F", - "impl": "0xb637caeedfCBf88e0d019E7AE4691b554c994A1e", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "preLongtailStrats": { - "impl": "0xFb83e1D133D0157775eC4F19Ff81478Df1103305", - "addrs": [ - "0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9", - "0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0", - "0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3", - "0x31B6F59e1627cEfC9fA174aD03859fC337666af7", - "0x70EB4D3c164a6B4A5f908D4FBb5a9cAfFb66bAB6", - "0x9281ff96637710Cd9A5CAcce9c6FAD8C9F54631c", - "0x05037A81BD7B4C9E0F7B430f1F2A22c31a2FD943", - "0x46281E3B7fDcACdBa44CADf069a94a588Fd4C6Ef", - "0xaccc5A86732BE85b5012e8614AF237801636F8e5", - "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac", - "0xAD76D205564f955A9c18103C4422D1Cd94016899", - "0x78dBcbEF8fF94eC7F631c23d38d197744a323868" - ] - } - }, - "token": { - "bEIGEN": { - "proxy": "0x275cCf9Be51f4a6C94aBa6114cdf2a4c45B9cb27", - "impl": "0x4500927874Ad41538c1bEF2F5278E7a86DF6bce8", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0x67482666771e82c9a73bb9e9a22b2b597f448bbf" - }, - "EIGEN": { - "proxy": "0x3B78576F7D6837500bA3De27A60c7f594934027E", - "impl": "0x083bC9e0DCF2C3e13E24686e5202232995578c5a", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0x67482666771e82c9a73bb9e9a22b2b597f448bbf" - }, - "eigenStrategy": { - "proxy": "0x43252609bff8a13dFe5e057097f2f45A24387a84", - "impl": "0x94650e09a471CEF96e7966cabf26718FBf352697", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - } - } -} \ No newline at end of file diff --git a/script/configs/holesky.toml b/script/configs/holesky.toml new file mode 100644 index 0000000000..ecec883da3 --- /dev/null +++ b/script/configs/holesky.toml @@ -0,0 +1,49 @@ +# WARNING: The layout and alphabetical order of this file must be consistent with what's in the `ConfigParser` library. +# https://book.getfoundry.sh/cheatcodes/parse-toml?highlight=toml#decoding-toml-tables-into-solidity-structs + +# NOTE: Use address(0) for any null/undeployed addresses. + +[governance] +communityMultisig = "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7" +executorMultisig = "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348" +operationsMultisig = "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d" +pauserMultisig = "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7" +pauserRegistry = "0x41Dbe7BbacA97D986FCF6f5203b98Ec02412ec1D" +protocolCouncil = "0xd140eE77d9e62901d8cEFf199d3ef4Dd1F4Eaff4" +proxyAdmin = "0xDB023566064246399b4AE851197a97729C93A6cf" +timelock = "0x5e83c7d195318A5acf46B29E5810DdC323b2F6fD" + +[tokens] +beigen = "0x275cCf9Be51f4a6C94aBa6114cdf2a4c45B9cb27" +eigen = "0x3B78576F7D6837500bA3De27A60c7f594934027E" + +[core] +allocationManager = "0x78469728304326CBc65f8f95FA756B0B73164462" +avsDirectory = "0x055733000064333CaDDbC92763c58BF0192fFeBf" +delegationManager = "0xA44151489861Fe9e3055d95adC98FbD462B948e7" +permissionController = "0x598cb226B591155F767dA17AfE7A2241a68C5C10" +rewardsCoordinator = "0xAcc1fb458a1317E886dB376Fc8141540537E68fE" +strategyManager = "0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6" + +[pods] +eigenPodBeacon = "0x7261C2bd75a7ACE1762f6d7FAe8F63215581832D" +eigenPodManager = "0x30770d7E3e71112d7A6b7259542D1f680a70e315" +eigenStrategy = "0x43252609bff8a13dFe5e057097f2f45A24387a84" + +[strategies] +strategyFactory = "0x9c01252B580efD11a05C00Aa42Dd3ac1Ec52DF6d" +strategyFactoryBeacon = "0xd3c6C6BA4E40dB9288c6a2077e5635344F8aFA4F" +strategyAddresses = [ + "0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3", + "0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0", + "0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9", + "0xAD76D205564f955A9c18103C4422D1Cd94016899", + "0x05037A81BD7B4C9E0F7B430f1F2A22c31a2FD943", + "0x9281ff96637710Cd9A5CAcce9c6FAD8C9F54631c", + "0x31B6F59e1627cEfC9fA174aD03859fC337666af7", + "0x46281E3B7fDcACdBa44CADf069a94a588Fd4C6Ef", + "0x70EB4D3c164a6B4A5f908D4FBb5a9cAfFb66bAB6", + "0xaccc5A86732BE85b5012e8614AF237801636F8e5", + "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac", + "0x78dBcbEF8fF94eC7F631c23d38d197744a323868" +] \ No newline at end of file diff --git a/script/configs/hoodi.toml b/script/configs/hoodi.toml new file mode 100644 index 0000000000..7c7877e86f --- /dev/null +++ b/script/configs/hoodi.toml @@ -0,0 +1,39 @@ +# WARNING: The layout and alphabetical order of this file must be consistent with what's in the `ConfigParser` library. +# https://book.getfoundry.sh/cheatcodes/parse-toml?highlight=toml#decoding-toml-tables-into-solidity-structs + +# NOTE: Use address(0) for any null/undeployed addresses. + +[governance] +communityMultisig = "0xB87a8A3512ACb7245a37C24Ca190Ab712BeBE24D" +executorMultisig = "0x58c468A9A50673693D0f0e1DfBf5DF280b99b36E" +operationsMultisig = "0x8eA6C3Cca1c96967F7B164FfaA5fabede10311A9" +pauserMultisig = "0xb094Ba769b4976Dc37fC689A76675f31bc4923b0" +pauserRegistry = "0x64D78399B0fa32EA72959f33edCF313159F3c13D" +protocolCouncil = "0x6f8459810197cc9fE123BBeB918451757a4fBAc6" +proxyAdmin = "0xE7f4E30D2619273468afe9EC0Acf805E55532257" +timelock = "0xE3328cb5068924119d6170496c4AB2dD12c12d15" + +[tokens] +beigen = "0x43e4940aCeb1C1F5a57e307EEB212007F0f6a1C4" +eigen = "0x45D3f8CC7e6AC1c0891DAfA90CE299Abf0aD9053" + +[core] +allocationManager = "0x95a7431400F362F3647a69535C5666cA0133CAA0" +avsDirectory = "0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926" +delegationManager = "0x867837a9722C512e0862d8c2E15b8bE220E8b87d" +permissionController = "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2" +rewardsCoordinator = "0x29e8572678e0c272350aa0b4B8f304E47EBcd5e7" +strategyManager = "0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41" + +[pods] +eigenPodBeacon = "0x5e1577f8efB21b229cD5Eb4C5Aa3d6C4b228f650" +eigenPodManager = "0xcd1442415Fc5C29Aa848A49d2e232720BE07976c" +eigenStrategy = "0xB27b10291DBFE6576d17afF3e251c954Ae14f1D3" + +[strategies] +strategyFactory = "0xfB7d94501E4d4ACC264833Ef4ede70a11517422B" +strategyFactoryBeacon = "0x6d28cEC1659BC3a9BC814c3EFc1412878B406579" +strategyAddresses = [ + "0x24579ad4fe83ac53546e5c2d3df5f85d6383420d", # wETH + "0x41525d38f59895d606e8c05c229864f2db6b64fd", # stETH +] \ 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 deleted file mode 100644 index 4ee617819a..0000000000 --- a/script/configs/local/deploy_from_scratch.slashing.anvil.config.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "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": 900, - "ALLOCATION_CONFIGURATION_DELAY": 1200 - }, - "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": 900, - "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", - "semver": "v0.0.0" -} \ No newline at end of file diff --git a/script/configs/mainnet.json b/script/configs/mainnet.json deleted file mode 100644 index 856dab36ea..0000000000 --- a/script/configs/mainnet.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "config": { - "environment": { - "chainid": 1, - "lastUpdated": "slashing-integration-testing", - "name": "mainnet" - }, - "params": { - "ethPOS": "0x00000000219ab540356cBB839Cbe05303d7705Fa", - "EIGENPOD_GENESIS_TIME": 1606824023, - "CALCULATION_INTERVAL_SECONDS": 604800, - "MAX_REWARDS_DURATION": 6048000, - "MAX_RETROACTIVE_LENGTH": 14515200, - "MAX_FUTURE_LENGTH": 2592000, - "GENESIS_REWARDS_TIMESTAMP": 1710979200, - "REWARDS_UPDATER_ADDRESS": "0x8f94F55fD8c9E090296283137C303fE97d32A9e2", - "ACTIVATION_DELAY": 604800, - "GLOBAL_OPERATOR_COMMISSION_BIPS": 1000, - "MIN_WITHDRAWAL_DELAY_BLOCKS": 100800, - "ALLOCATION_CONFIGURATION_DELAY": 126000 - } - }, - "deployment": { - "admin": { - "communityMultisig": "0xFEA47018D632A77bA579846c840d5706705Dc598", - "executorMultisig": "0x369e6F597e22EaB55fFb173C6d9cD234BD699111", - "operationsMultisig": "0xBE1685C81aA44FF9FB319dD389addd9374383e90", - "pauserMultisig": "0x5050389572f2d220ad927CcbeA0D406831012390", - "pauserRegistry": "0x0c431C66F4dE941d089625E5B423D00707977060", - "proxyAdmin": "0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444", - "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF" - }, - "core": { - "avsDirectory": { - "proxy": "0x135dda560e946695d6f155dacafc6f1f25c1f5af", - "impl": "0xdabdb3cd346b7d5f5779b0b614ede1cc9dcba5b7", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "delegationManager": { - "proxy": "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A", - "impl": "0x1784be6401339fc0fedf7e9379409f5c1bfe9dda", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "rewardsCoordinator": { - "proxy": "0x7750d328b314EfFa365A0402CcfD489B80B0adda", - "impl": "0x5bf7c13D5FAdba224ECB3D5C0a67A231D1628785", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "slasher": { - "proxy": "0xD92145c07f8Ed1D392c1B88017934E301CC1c3Cd", - "impl": "0xf3234220163a757edf1e11a8a085638d9b236614", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyManager": { - "proxy": "0x858646372CC42E1A627fcE94aa7A7033e7CF075A", - "impl": "0x70f44c13944d49a236e3cd7a94f48f5dab6c619b", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "pods": { - "delayedWithdrawalRouter": { - "proxy": "0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8", - "impl": "0x4bb6731b02314d40abbffbc4540f508874014226", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPod": { - "beacon": "0x5a2a4F2F3C18f09179B6703e63D9eDD165909073", - "impl": "0x6D225e974Fa404D25Ffb84eD6E242Ffa18eF6430", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPodManager": { - "proxy": "0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338", - "impl": "0x731A0aD160e407393Ff662231Add6Dd145AD3FEa", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "strategies": { - "strategyFactory": { - "proxy": "0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647", - "impl": "0x3e07cc2D34C8E0965f5BA45Ac1E960e535155c74", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyBeacon": { - "beacon": "0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9", - "impl": "0xe9FA8F904d97854C7389b68923262ADCC6C27827", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "preLongtailStrats": { - "impl": "0xdfdA04f980bE6A64E3607c95Ca26012Ab9aA46d3", - "addrs": [ - "0x93c4b944D05dfe6df7645A86cd2206016c51564D", - "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", - "0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc", - "0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d", - "0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff", - "0xa4C637e0F704745D182e4D38cAb7E7485321d059", - "0x57ba429517c3473B6d34CA9aCd56c0e735b94c02", - "0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6", - "0x7CA911E83dabf90C90dD3De5411a10F1A6112184", - "0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6", - "0xAe60d8180437b5C34bB956822ac2710972584473", - "0x298aFB19A105D59E74658C4C334Ff360BadE6dd2" - ] - } - }, - "token": { - "bEIGEN": { - "proxy": "0x83E9115d334D248Ce39a6f36144aEaB5b3456e75", - "impl": "0xB91c69Af3eE022bd0a59Da082945914BFDcEFFE3", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9" - }, - "EIGEN": { - "proxy": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", - "impl": "0x7ec354c84680112d3cff1544ec1eb19ca583700b", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0xB8915E195121f2B5D989Ec5727fd47a5259F1CEC" - }, - "eigenStrategy": { - "proxy": "0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7", - "impl": "0x27e7a3a81741b9fcc5ad7edcbf9f8a72a5c00428", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - } - } -} \ No newline at end of file diff --git a/script/configs/mainnet.toml b/script/configs/mainnet.toml new file mode 100644 index 0000000000..7d7d833043 --- /dev/null +++ b/script/configs/mainnet.toml @@ -0,0 +1,49 @@ +# WARNING: The layout and alphabetical order of this file must be consistent with what's in the `ConfigParser` library. +# https://book.getfoundry.sh/cheatcodes/parse-toml?highlight=toml#decoding-toml-tables-into-solidity-structs + +# NOTE: Use address(0) for any null/undeployed addresses. + +[governance] +communityMultisig = "0xFEA47018D632A77bA579846c840d5706705Dc598" +executorMultisig = "0x369e6F597e22EaB55fFb173C6d9cD234BD699111" +operationsMultisig = "0xBE1685C81aA44FF9FB319dD389addd9374383e90" +pauserMultisig = "0x5050389572f2d220ad927CcbeA0D406831012390" +pauserRegistry = "0x0c431C66F4dE941d089625E5B423D00707977060" +protocolCouncil = "0x461854d84Ee845F905e0eCf6C288DDEEb4A9533F" +proxyAdmin = "0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444" +timelock = "0xC06Fd4F821eaC1fF1ae8067b36342899b57BAa2d" + +[tokens] +beigen = "0x83E9115d334D248Ce39a6f36144aEaB5b3456e75" +eigen = "0xec53bf9167f50cdeb3ae105f56099aaab9061f83" + +[core] +allocationManager = "0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39" # Currently queued in timelock +avsDirectory = "0x135dda560e946695d6f155dacafc6f1f25c1f5af" +delegationManager = "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A" +permissionController = "0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5" # Currently queued in timelock +rewardsCoordinator = "0x7750d328b314EfFa365A0402CcfD489B80B0adda" +strategyManager = "0x858646372CC42E1A627fcE94aa7A7033e7CF075A" + +[pods] +eigenPodBeacon = "0x5a2a4F2F3C18f09179B6703e63D9eDD165909073" +eigenPodManager = "0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338" +eigenStrategy = "0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7" + +[strategies] +strategyFactory = "0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647" +strategyFactoryBeacon = "0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9" +strategyAddresses = [ + "0x93c4b944D05dfe6df7645A86cd2206016c51564D", # stETH + "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", # rETH + "0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc", # cbETH + "0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d", # ETHx + "0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff", # ankrETH + "0xa4C637e0F704745D182e4D38cAb7E7485321d059", # oETH + "0x57ba429517c3473B6d34CA9aCd56c0e735b94c02", # osETH + "0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6", # swETH + "0x7CA911E83dabf90C90dD3De5411a10F1A6112184", # wBETH + "0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6", # sfrxETH + "0xAe60d8180437b5C34bB956822ac2710972584473", # lsETH + "0x298aFB19A105D59E74658C4C334Ff360BadE6dd2" # mETH +] \ No newline at end of file diff --git a/script/configs/mainnet/mainnet-addresses.config.json b/script/configs/mainnet/mainnet-addresses.config.json deleted file mode 100644 index c33d7e8380..0000000000 --- a/script/configs/mainnet/mainnet-addresses.config.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "lastUpdated": "v0.4.3-mainnet-foundation-incentives", - "addresses": { - "avsDirectory": "0x135dda560e946695d6f155dacafc6f1f25c1f5af", - "avsDirectoryImplementation": "0xdabdb3cd346b7d5f5779b0b614ede1cc9dcba5b7", - "beaconOracle": "0x343907185b71aDF0eBa9567538314396aa985442", - "baseStrategyImplementation": "0xdfdA04f980bE6A64E3607c95Ca26012Ab9aA46d3", - "delayedWithdrawalRouter": "0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8", - "delayedWithdrawalRouterImplementation": "0x4bb6731b02314d40abbffbc4540f508874014226", - "delegationManager": "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A", - "delegationManagerImplementation": "0x1784be6401339fc0fedf7e9379409f5c1bfe9dda", - "eigenLayerPauserReg": "0x0c431C66F4dE941d089625E5B423D00707977060", - "eigenLayerProxyAdmin": "0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444", - "eigenPodBeacon": "0x5a2a4F2F3C18f09179B6703e63D9eDD165909073", - "eigenPodImplementation": "0x6D225e974Fa404D25Ffb84eD6E242Ffa18eF6430", - "eigenPodManager": "0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338", - "eigenPodManagerImplementation": "0x731A0aD160e407393Ff662231Add6Dd145AD3FEa", - "emptyContract": "0x1f96861fEFa1065a5A96F20Deb6D8DC3ff48F7f9", - "rewardsCoordinator": "0x7750d328b314EfFa365A0402CcfD489B80B0adda", - "rewardsCoordinatorImplementation": "0xb6738A8E7793D44c5895B6A6F2a62F6bF86Ba8d2", - "slasher": "0xD92145c07f8Ed1D392c1B88017934E301CC1c3Cd", - "slasherImplementation": "0xf3234220163a757edf1e11a8a085638d9b236614", - "strategyManager": "0x858646372CC42E1A627fcE94aa7A7033e7CF075A", - "strategyManagerImplementation": "0x70f44c13944d49a236e3cd7a94f48f5dab6c619b", - "strategyFactory": "0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647", - "strategyFactoryImplementation": "0x3e07cc2D34C8E0965f5BA45Ac1E960e535155c74", - "strategyFactoryBeacon": "0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9", - "strategyFactoryBeaconImplementation": "0xe9FA8F904d97854C7389b68923262ADCC6C27827", - "numStrategiesDeployed": 12, - "strategies": { - "stETH": "0x93c4b944D05dfe6df7645A86cd2206016c51564D", - "rETH": "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", - "cbETH": "0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc", - "ETHx": "0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d", - "ankrETH": "0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff", - "oETH": "0xa4C637e0F704745D182e4D38cAb7E7485321d059", - "osETH": "0x57ba429517c3473B6d34CA9aCd56c0e735b94c02", - "swETH": "0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6", - "wBETH": "0x7CA911E83dabf90C90dD3De5411a10F1A6112184", - "sfrxETH": "0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6", - "lsETH": "0xAe60d8180437b5C34bB956822ac2710972584473", - "mETH": "0x298aFB19A105D59E74658C4C334Ff360BadE6dd2" - }, - "strategyAddresses": [ - "0x93c4b944D05dfe6df7645A86cd2206016c51564D", - "0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2", - "0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc", - "0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d", - "0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff", - "0xa4C637e0F704745D182e4D38cAb7E7485321d059", - "0x57ba429517c3473B6d34CA9aCd56c0e735b94c02", - "0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6", - "0x7CA911E83dabf90C90dD3De5411a10F1A6112184", - "0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6", - "0xAe60d8180437b5C34bB956822ac2710972584473", - "0x298aFB19A105D59E74658C4C334Ff360BadE6dd2" - ], - "token": { - "tokenProxyAdmin": "0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9", - "EIGEN": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", - "bEIGEN": "0x83E9115d334D248Ce39a6f36144aEaB5b3456e75", - "EIGENImpl": "0x17f56E911C279bad67eDC08acbC9cf3DC4eF26A0", - "bEIGENImpl": "0xF2b225815F70c9b327DC9db758A36c92A4279b17", - "eigenStrategy": "0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7", - "eigenStrategyImpl": "0x27e7a3a81741b9fcc5ad7edcbf9f8a72a5c00428" - } - }, - "numStrategies": 12, - "chainInfo": { - "chainId": 1, - "deploymentBlock": 20571838 - }, - "parameters": { - "communityMultisig": "0xFEA47018D632A77bA579846c840d5706705Dc598", - "executorMultisig": "0x369e6F597e22EaB55fFb173C6d9cD234BD699111", - "operationsMultisig": "0xBE1685C81aA44FF9FB319dD389addd9374383e90", - "pauserMultisig": "0x5050389572f2d220ad927CcbeA0D406831012390", - "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF", - "semver": "v0.5.4" - } -} \ No newline at end of file diff --git a/script/configs/preprod.json b/script/configs/preprod.json deleted file mode 100644 index 877caa40ad..0000000000 --- a/script/configs/preprod.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "config": { - "environment": { - "chainid": 17000, - "lastUpdated": "v0.4.2-mainnet-pepe", - "name": "preprod-holesky" - }, - "params": { - "ACTIVATION_DELAY": 7200, - "CALCULATION_INTERVAL_SECONDS": 604800, - "EIGENPOD_GENESIS_TIME": 1695902400, - "GENESIS_REWARDS_TIMESTAMP": 1710979200, - "GLOBAL_OPERATOR_COMMISSION_BIPS": 1000, - "MAX_FUTURE_LENGTH": 2592000, - "MAX_RETROACTIVE_LENGTH": 7776000, - "MAX_REWARDS_DURATION": 6048000, - "REWARDS_UPDATER_ADDRESS": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", - "ethPOS": "0x4242424242424242424242424242424242424242", - "multiSendCallOnly": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D" - } - }, - "deployment": { - "admin": { - "communityMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "executorMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "operationsMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "pauserMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "pauserRegistry": "0x9Ab2FEAf0465f0eD51Fc2b663eF228B418c9Dad1", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B", - "timelock": "0x0000000000000000000000000000000000000000" - }, - "core": { - "avsDirectory": { - "proxy": "0x141d6995556135D4997b2ff72EB443Be300353bC", - "impl": "0x357978adC03375BD6a3605DE055fABb84695d79A", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "delegationManager": { - "proxy": "0x75dfE5B44C2E530568001400D3f704bC8AE350CC", - "impl": "0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "rewardsCoordinator": { - "proxy": "0xb22Ef643e1E067c994019A4C19e403253C05c2B0", - "impl": "0x7523b42b081C30fA245AA4039c645e36746fC400", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "slasher": { - "proxy": "0x12699471dF8dca329C76D72823B1b79d55709384", - "impl": "0x9460fCe11E1e0365419fa860599903B4E5097cf0", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyManager": { - "proxy": "0xF9fbF2e35D8803273E214c99BF15174139f4E67a", - "impl": "0x1a26B23a004C512350d7Dd89056655A80b850199", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "pods": { - "delayedWithdrawalRouter": { - "proxy": "0xC4BC46a87A67a531eCF7f74338E1FA79533334Fa", - "impl": "0x0011FA2c512063C495f77296Af8d195F33A8Dd38", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPod": { - "beacon": "0x92Cc4a800A1513E85C481dDDf3A06C6921211eaC", - "impl": "0x8Da4b953cbFb715624D98C0D2b4a7978462eFd38", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPodManager": { - "proxy": "0xB8d8952f572e67B11e43bC21250967772fa883Ff", - "impl": "0x10EBa780CCd9E5e9FFBe529C25046c076Be91048", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - }, - "strategies": { - "strategyFactory": { - "proxy": "0xad4A89E3cA9b3dc25AABe0aa7d72E61D2Ec66052", - "impl": "0x7a9478c0AcB819d7c235FbE2a6E13ee1D2fCD862", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyBeacon": { - "beacon": "0xf2c2AcA859C685895E60ca7A14274365b64c0c2a", - "impl": "0xd648792F932FbabcCC80Cd376812074434412685", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "preLongtailStrats": { - "impl": "0x62450517EfA1CE60d79801daf8f95973865e8D40", - "addrs": [ - "0x6e5d5060b33ca2090a78e9cb74fe207453b30e49", - "0xf6a09ae03d7760aecf1626ce7df0f113bec2d9bd", - "0x7fa77c321bf66e42eabc9b10129304f7f90c5585", - "0x24da526f9e465c4fb6bae41e226df8aa5b34eac7", - "0x6dc6ce589f852f96ac86cb160ab0b15b9f56dedd", - "0x3c28437e610fb099cc3d6de4d9c707dfacd308ae", - "0x7b6257f5caf7311b36f7416133a8499c68a83c3a", - "0xc86382179500e8ed3e686fc4a99ed9ec72df3f56", - "0x3cb1fd19cfb178c1098f2fc1e11090a0642b2314", - "0x87f6c7d24b109919eb38295e3f8298425e6331d9", - "0x5c8b55722f421556a2aafb7a3ea63d4c3e514312", - "0xd523267698c81a372191136e477fdebfa33d9fb4", - "0xdccf401fd121d8c542e96bc1d0078884422afad2" - ] - } - }, - "token": { - "bEIGEN": { - "proxy": "0xA72942289a043874249E60469F68f08B8c6ECCe8", - "impl": "0xd5FdabDac3d8ACeAB7BFfDDFA18877A4c5D5Aa82", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" - }, - "EIGEN": { - "proxy": "0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926", - "impl": "0x95a7431400F362F3647a69535C5666cA0133CAA0", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" - }, - "eigenStrategy": { - "proxy": "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2", - "impl": "0x59D13E7Fb0bC0e57c1fc6594ff701592A6e4dD2B", - "pendingImpl": "0x0000000000000000000000000000000000000000" - } - } - } -} \ No newline at end of file diff --git a/script/configs/sepolia.toml b/script/configs/sepolia.toml new file mode 100644 index 0000000000..e5266345f9 --- /dev/null +++ b/script/configs/sepolia.toml @@ -0,0 +1,39 @@ +# WARNING: The layout and alphabetical order of this file must be consistent with what's in the `ConfigParser` library. +# https://book.getfoundry.sh/cheatcodes/parse-toml?highlight=toml#decoding-toml-tables-into-solidity-structs + +# NOTE: Use address(0) for any null/undeployed addresses. + +[governance] +communityMultisig = "0x6f8459810197cc9fE123BBeB918451757a4fBAc6" +executorMultisig = "0x4FDA8998EC3b7d4b4A612d45FeB8fB36734470f2" +operationsMultisig = "0xb094Ba769b4976Dc37fC689A76675f31bc4923b0" +pauserMultisig = "0x0B415f75980D863872C3eb8caa76E6eC8Bc81536" +pauserRegistry = "0x63AAe451780090f50Ad323aAEF155F63a29D20f3" +protocolCouncil = "0x8eA6C3Cca1c96967F7B164FfaA5fabede10311A9" +proxyAdmin = "0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1" +timelock = "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" + +[tokens] +beigen = "0xc5B857A92245f64e9D90cCc5b096Db82eB77eB5c" +eigen = "0x0011FA2c512063C495f77296Af8d195F33A8Dd38" + +[core] +allocationManager = "0x42583067658071247ec8CE0A516A58f682002d07" +avsDirectory = "0xa789c91ECDdae96865913130B786140Ee17aF545" +delegationManager = "0xD4A7E1Bd8015057293f0D0A557088c286942e84b" +permissionController = "0x44632dfBdCb6D3E21EF613B0ca8A6A0c618F5a37" +rewardsCoordinator = "0x5ae8152fb88c26ff9ca5C014c94fca3c68029349" +strategyManager = "0x2E3D6c0744b10eb0A4e6F679F71554a39Ec47a5D" + +[pods] +eigenPodBeacon = "0x0e19E56E41D42137d00dD4f51EC2F613E50cAcf4" +eigenPodManager = "0x56BfEb94879F4543E756d26103976c567256034a" +eigenStrategy = "0x8E93249a6C37a32024756aaBd813E6139b17D1d5" + +[strategies] +strategyFactory = "0x066cF95c1bf0927124DFB8B02B401bc23A79730D" +strategyFactoryBeacon = "0x427e627Bc7E83cac0f84337d3Ad94230C32697D3" +strategyAddresses = [ + "0x424246ef71b01ee33aa33ac590fd9a0855f5efbc", # wETH + "0x8b29d91e67b013e855eafe0ad704ac4ab086a574", # stETH +] \ No newline at end of file diff --git a/script/configs/zipzoop.json b/script/configs/zipzoop.json deleted file mode 100644 index cb1a019d1e..0000000000 --- a/script/configs/zipzoop.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "config": { - "environment": { - "chainid": 31337, - "lastUpdated": "v0.4.2-mainnet-pepe", - "name": "zipzoop-tester" - }, - "params": { - "ACTIVATION_DELAY": 7200, - "CALCULATION_INTERVAL_SECONDS": 604800, - "EIGENPOD_GENESIS_TIME": 1695902400, - "GENESIS_REWARDS_TIMESTAMP": 1710979200, - "GLOBAL_OPERATOR_COMMISSION_BIPS": 1000, - "MAX_FUTURE_LENGTH": 2592000, - "MAX_RETROACTIVE_LENGTH": 7776000, - "MAX_REWARDS_DURATION": 6048000, - "REWARDS_UPDATER_ADDRESS": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", - "ethPOS": "0x4242424242424242424242424242424242424242", - "multiSendCallOnly": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D" - } - }, - "deployment": { - "admin": { - "communityMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "executorMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "operationsMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "pauserMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", - "pauserRegistry": "0x9Ab2FEAf0465f0eD51Fc2b663eF228B418c9Dad1", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B", - "timelock": "0x0000000000000000000000000000000000000000" - }, - "core": { - "avsDirectory": { - "impl": "0x357978adC03375BD6a3605DE055fABb84695d79A", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0x141d6995556135D4997b2ff72EB443Be300353bC" - }, - "delegationManager": { - "impl": "0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0x75dfE5B44C2E530568001400D3f704bC8AE350CC" - }, - "rewardsCoordinator": { - "impl": "0x7523b42b081C30fA245AA4039c645e36746fC400", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xb22Ef643e1E067c994019A4C19e403253C05c2B0" - }, - "slasher": { - "impl": "0x9460fCe11E1e0365419fa860599903B4E5097cf0", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0x12699471dF8dca329C76D72823B1b79d55709384" - }, - "strategyManager": { - "impl": "0x1a26B23a004C512350d7Dd89056655A80b850199", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xF9fbF2e35D8803273E214c99BF15174139f4E67a" - } - }, - "pods": { - "delayedWithdrawalRouter": { - "impl": "0x0011FA2c512063C495f77296Af8d195F33A8Dd38", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xC4BC46a87A67a531eCF7f74338E1FA79533334Fa" - }, - "eigenPod": { - "beacon": "0x92Cc4a800A1513E85C481dDDf3A06C6921211eaC", - "impl": "0x8Da4b953cbFb715624D98C0D2b4a7978462eFd38", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "eigenPodManager": { - "impl": "0x10EBa780CCd9E5e9FFBe529C25046c076Be91048", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xB8d8952f572e67B11e43bC21250967772fa883Ff" - } - }, - "strategies": { - "preLongtailStrats": { - "addrs": [ - "0x6E5D5060B33ca2090A78E9cb74Fe207453b30E49", - "0xf6a09ae03D7760aEcf1626Ce7Df0F113BEC2d9bD", - "0x7fA77c321bf66e42eaBC9b10129304F7f90c5585", - "0x24DA526F9e465c4fb6BAe41E226Df8aA5b34eAc7", - "0x6dC6cE589F852F96ac86cB160AB0B15b9f56DeDd", - "0x3c28437E610fB099Cc3d6De4D9c707DFACD308AE", - "0x7b6257F5caf7311b36F7416133A8499c68a83c3a", - "0xC86382179500e8Ed3e686fC4A99eD9EC72df3f56", - "0x3cb1fD19CFb178C1098f2fc1e11090A0642B2314", - "0x87f6C7d24b109919eB38295e3F8298425e6331D9", - "0x5C8b55722f421556a2AAfb7A3EA63d4c3e514312", - "0xD523267698C81a372191136e477fdebFa33D9FB4", - "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2" - ], - "impl": "0x62450517EfA1CE60d79801daf8f95973865e8D40" - }, - "strategyBeacon": { - "beacon": "0xf2c2AcA859C685895E60ca7A14274365b64c0c2a", - "impl": "0xd648792F932FbabcCC80Cd376812074434412685", - "pendingImpl": "0x0000000000000000000000000000000000000000" - }, - "strategyFactory": { - "impl": "0x7a9478c0AcB819d7c235FbE2a6E13ee1D2fCD862", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xad4A89E3cA9b3dc25AABe0aa7d72E61D2Ec66052" - } - }, - "token": { - "EIGEN": { - "impl": "0x95a7431400F362F3647a69535C5666cA0133CAA0", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" - }, - "bEIGEN": { - "impl": "0xd5FdabDac3d8ACeAB7BFfDDFA18877A4c5D5Aa82", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xA72942289a043874249E60469F68f08B8c6ECCe8", - "proxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" - }, - "eigenStrategy": { - "impl": "0x59D13E7Fb0bC0e57c1fc6594ff701592A6e4dD2B", - "pendingImpl": "0x0000000000000000000000000000000000000000", - "proxy": "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2" - } - } - } -} \ 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 deleted file mode 100644 index ae5027520e..0000000000 --- a/script/deploy/devnet/deploy_from_scratch.s.sol +++ /dev/null @@ -1,620 +0,0 @@ -// 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; - - string SEMVER; - - // IMMUTABLES TO SET - uint64 HOLESKY_GENESIS_TIME = 1_616_508_000; - - // 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 = 86_400; - - // 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); - - SEMVER = stdJson.readString(config_data, ".semver"); - - 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, HOLESKY_GENESIS_TIME, SEMVER); - - eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); - - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - - delegationImplementation = new DelegationManager( - strategyManager, - eigenPodManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - MIN_WITHDRAWAL_DELAY, - SEMVER - ); - - strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg, SEMVER); - avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg, SEMVER); - eigenPodManagerImplementation = - new EigenPodManager(ethPOSDeposit, eigenPodBeacon, delegation, eigenLayerPauserReg, SEMVER); - rewardsCoordinatorImplementation = new RewardsCoordinator( - IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( - 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, - SEMVER - ) - ); - allocationManagerImplementation = new AllocationManager( - delegation, - eigenLayerPauserReg, - permissionController, - DEALLOCATION_DELAY, - ALLOCATION_CONFIGURATION_DELAY, - SEMVER - ); - permissionControllerImplementation = new PermissionController(SEMVER); - strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg, SEMVER); - - // 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.upgrade( - ITransparentUpgradeableProxy(payable(address(permissionController))), - address(permissionControllerImplementation) - ); - - // Deploy strategyFactory & base - // Create base strategy implementation - baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg, SEMVER); - - // Create a proxy beacon for base strategy implementation - strategyBeacon = new UpgradeableBeacon(address(baseStrategyImplementation)); - - // Strategy Factory, upgrade and initialized - 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.minWithdrawalDelayBlocks() == 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, "permissionController", address(permissionController)); - vm.serializeAddress( - deployed_addresses, "permissionControllerImplementation", address(permissionControllerImplementation) - ); - 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( - 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/local/deploy_from_scratch.slashing.s.sol b/script/deploy/local/deploy_from_scratch.slashing.s.sol deleted file mode 100644 index 86caedacc1..0000000000 --- a/script/deploy/local/deploy_from_scratch.slashing.s.sol +++ /dev/null @@ -1,626 +0,0 @@ -// 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 -vvvv --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; - - string SEMVER; - - // 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 HOLESKY_GENESIS_TIME = 1_616_508_000; - - // 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_DEFAULT_OPERATOR_SPLIT_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); - - SEMVER = stdJson.readString(config_data, ".semver"); - - 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_DEFAULT_OPERATOR_SPLIT_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, HOLESKY_GENESIS_TIME, SEMVER); - - eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); - - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - - delegationImplementation = new DelegationManager( - strategyManager, - eigenPodManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - MIN_WITHDRAWAL_DELAY, - SEMVER - ); - strategyManagerImplementation = new StrategyManager(delegation, eigenLayerPauserReg, SEMVER); - avsDirectoryImplementation = new AVSDirectory(delegation, eigenLayerPauserReg, SEMVER); - eigenPodManagerImplementation = - new EigenPodManager(ethPOSDeposit, eigenPodBeacon, delegation, eigenLayerPauserReg, SEMVER); - rewardsCoordinatorImplementation = new RewardsCoordinator( - IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( - 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, - SEMVER - ) - ); - allocationManagerImplementation = new AllocationManager( - delegation, - eigenLayerPauserReg, - permissionController, - DEALLOCATION_DELAY, - ALLOCATION_CONFIGURATION_DELAY, - SEMVER - ); - permissionControllerImplementation = new PermissionController(SEMVER); - - // 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_DEFAULT_OPERATOR_SPLIT_BIPS - ) - ); - - eigenLayerProxyAdmin.upgradeAndCall( - ITransparentUpgradeableProxy(payable(address(allocationManager))), - address(allocationManagerImplementation), - abi.encodeWithSelector( - AllocationManager.initialize.selector, executorMultisig, ALLOCATION_MANAGER_INIT_PAUSED_STATUS - ) - ); - - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(permissionController))), - address(permissionControllerImplementation) - ); - - // deploy StrategyBaseTVLLimits contract implementation - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager, eigenLayerPauserReg, SEMVER); - // 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) - ) - ) - ) - ) - ); - } - - // Transfer ownership - eigenLayerProxyAdmin.transferOwnership(executorMultisig); - eigenPodBeacon.transferOwnership(executorMultisig); - - // 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, "permissionController", address(permissionController)); - vm.serializeAddress( - deployed_addresses, "permissionControllerImplementation", address(permissionControllerImplementation) - ); - 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); - vm.writeJson(finalJson, "script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.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( - 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 (uint256 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/interfaces/IUpgradeableBeacon.sol b/script/interfaces/IUpgradeableBeacon.sol deleted file mode 100644 index ad35ce2384..0000000000 --- a/script/interfaces/IUpgradeableBeacon.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -interface IUpgradeableBeacon { - function upgradeTo( - address newImplementation - ) external; - function implementation() external returns (address); -} diff --git a/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json b/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json index b83fcb7d80..044ffe5322 100644 --- a/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json +++ b/script/output/devnet/SLASHING_deploy_from_scratch_deployment_data.json @@ -1,33 +1,31 @@ { "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", + "TestToken": "0xcae746B46013Bf4D43B8E2B9e98F9DBE2461532A", + "allocationManager": "0xD718d5A27a29FF1cD22403426084bA0d479869a0", + "allocationManagerImplementation": "0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D", + "avsDirectory": "0x50EEf481cae4250d252Ae577A09bF514f224C6C4", + "avsDirectoryImplementation": "0x8B71b41D4dBEb2b6821d44692d3fACAAf77480Bb", + "baseStrategyImplementation": "0x29C66C9208f106f34754814f488FA80b6d566790", + "delegationManager": "0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3", + "delegationManagerImplementation": "0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1", + "eigenLayerPauserReg": "0x90193C961A926261B756D1E5bb255e67ff9498A1", + "eigenLayerProxyAdmin": "0x34A1D3fff3958843C43aD80F30b94c510645C316", + "eigenPodBeacon": "0xd21060559c9beb54fC07aFd6151aDf6cFCDDCAeB", + "eigenPodImplementation": "0x416C42991d05b31E9A6dC209e91AD22b79D87Ae6", + "eigenPodManager": "0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1", + "eigenPodManagerImplementation": "0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4", + "emptyContract": "0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496", + "numStrategiesDeployed": 0, + "permissionController": "0x4f559F30f5eB88D635FDe1548C4267DB8FaB0351", + "permissionControllerImplementation": "0xDeF3bca8c80064589E6787477FFa7Dd616B5574F", + "rewardsCoordinator": "0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809", + "rewardsCoordinatorImplementation": "0x0c8b5822b6e02CDa722174F19A1439A7495a3fA6", + "strategies": { + "WETH": "0xC92B57772d68b7445F19ef9f08226f4C8C74E499" + }, + "strategy": "0xC92B57772d68b7445F19ef9f08226f4C8C74E499", + "strategyManager": "0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76", + "strategyManagerImplementation": "0x978e3286EB805934215a88694d80b09aDed68D90", "token": { "tokenProxyAdmin": "0x0000000000000000000000000000000000000000", "EIGEN": "0x0000000000000000000000000000000000000000", @@ -39,14 +37,14 @@ } }, "chainInfo": { - "chainId": 17000, - "deploymentBlock": 2548240 + "chainId": 31337, + "deploymentBlock": 1 }, "parameters": { - "communityMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", - "executorMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", - "operationsMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", - "pauserMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", + "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "timelock": "0x0000000000000000000000000000000000000000" } } \ No newline at end of file diff --git a/script/releases/Env.sol b/script/releases/Env.sol index 34e62072b9..2bc6c84ff9 100644 --- a/script/releases/Env.sol +++ b/script/releases/Env.sol @@ -5,6 +5,7 @@ import "forge-std/Vm.sol"; import "zeus-templates/utils/ZEnvHelpers.sol"; import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; /// core/ @@ -12,8 +13,9 @@ import "src/contracts/core/AllocationManager.sol"; import "src/contracts/core/AVSDirectory.sol"; import "src/contracts/core/DelegationManager.sol"; import "src/contracts/core/RewardsCoordinator.sol"; -import "src/contracts/interfaces/IRewardsCoordinator.sol"; + import "src/contracts/core/StrategyManager.sol"; +import "src/contracts/interfaces/IRewardsCoordinator.sol"; /// permissions/ import "src/contracts/permissions/PauserRegistry.sol"; diff --git a/script/releases/v1.4.1-slashing/2-queueUpgrade.s.sol b/script/releases/v1.4.1-slashing/2-queueUpgrade.s.sol index 0c9082392e..e6e7f1782b 100644 --- a/script/releases/v1.4.1-slashing/2-queueUpgrade.s.sol +++ b/script/releases/v1.4.1-slashing/2-queueUpgrade.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {Deploy} from "./1-deployContracts.s.sol"; import "../Env.sol"; +import {Deploy} from "./1-deployContracts.s.sol"; import {MultisigBuilder} from "zeus-templates/templates/MultisigBuilder.sol"; import "zeus-templates/utils/Encode.sol"; diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol deleted file mode 100644 index 575f632c0c..0000000000 --- a/script/utils/ExistingDeploymentParser.sol +++ /dev/null @@ -1,808 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -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/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"; -import "../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; -import "../../src/contracts/strategies/EigenStrategy.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/contracts/interfaces/IBackingEigen.sol"; -import "../../src/contracts/interfaces/IEigen.sol"; - -import "forge-std/Script.sol"; - -import "src/test/utils/Logger.t.sol"; - -struct StrategyUnderlyingTokenConfig { - address tokenAddress; - string tokenName; - string tokenSymbol; -} - -struct DeployedEigenPods { - address[] multiValidatorPods; - address[] singleValidatorPods; - address[] inActivePods; -} - -contract ExistingDeploymentParser is Script, Logger { - using stdJson for string; - - /// ----------------------------------------------------------------------- - /// EigenLayer Contract Parameters - /// ----------------------------------------------------------------------- - - string public SEMVER; - /// @dev AllocationManager - uint256 ALLOCATION_MANAGER_INIT_PAUSED_STATUS; - uint32 DEALLOCATION_DELAY; - uint32 ALLOCATION_CONFIGURATION_DELAY; - - /// @dev AVSDirectory - uint256 AVS_DIRECTORY_INIT_PAUSED_STATUS; - - /// @dev DelegationManager - uint256 DELEGATION_MANAGER_INIT_PAUSED_STATUS; - uint32 DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS; - - /// @dev EigenPodManager - uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; - - /// @dev EigenPod - uint64 EIGENPOD_GENESIS_TIME; - uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; - address ETHPOSDepositAddress; - - /// @dev RewardsCoordinator - uint256 REWARDS_COORDINATOR_INIT_PAUSED_STATUS; - 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_DEFAULT_OPERATOR_SPLIT_BIPS; - uint32 REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP; - uint32 REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH; - - /// @dev StrategyManager - uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; - address STRATEGY_MANAGER_WHITELISTER; - - /// @dev Strategy Deployment - uint256 STRATEGY_MAX_PER_DEPOSIT; - uint256 STRATEGY_MAX_TOTAL_DEPOSITS; - - /// ----------------------------------------------------------------------- - /// EigenLayer Contracts - /// ----------------------------------------------------------------------- - - ProxyAdmin public eigenLayerProxyAdmin; - PauserRegistry public eigenLayerPauserReg; - UpgradeableBeacon public eigenPodBeacon; - UpgradeableBeacon public strategyBeacon; - - /// @dev AllocationManager - AllocationManager public allocationManager; - AllocationManager public allocationManagerImplementation; - - /// @dev AVSDirectory - AVSDirectory public avsDirectory; - AVSDirectory public avsDirectoryImplementation; - - /// @dev DelegationManager - DelegationManager public delegationManager; - DelegationManager public delegationManagerImplementation; - - /// @dev EigenPods - EigenPodManager public eigenPodManager; - EigenPodManager public eigenPodManagerImplementation; - EigenPod public eigenPodImplementation; - - /// @dev PermissionController - PermissionController public permissionController; - PermissionController public permissionControllerImplementation; - - /// @dev RewardsCoordinator - RewardsCoordinator public rewardsCoordinator; - RewardsCoordinator public rewardsCoordinatorImplementation; - - /// @dev StrategyManager - StrategyManager public strategyManager; - StrategyManager public strategyManagerImplementation; - - /// @dev StrategyFactory - StrategyFactory public strategyFactory; - StrategyFactory public strategyFactoryImplementation; - StrategyBase public baseStrategyImplementation; - StrategyBase public strategyFactoryBeaconImplementation; - - // Token - ProxyAdmin public tokenProxyAdmin; - IEigen public EIGEN; - IEigen public EIGENImpl; - IBackingEigen public bEIGEN; - IBackingEigen public bEIGENImpl; - EigenStrategy public eigenStrategy; - EigenStrategy public eigenStrategyImpl; - - /// ----------------------------------------------------------------------- - /// Storage - /// ----------------------------------------------------------------------- - - // EigenPods deployed - address[] public multiValidatorPods; - address[] public singleValidatorPods; - address[] public inActivePods; - // All eigenpods is just single array list of above eigenPods - address[] public allEigenPods; - - EmptyContract public emptyContract; - - address executorMultisig; - address operationsMultisig; - address communityMultisig; - address pauserMultisig; - address timelock; - - // strategies deployed - uint256 numStrategiesDeployed; - StrategyBase[] public deployedStrategyArray; - // Strategies to Deploy - uint256 numStrategiesToDeploy; - StrategyUnderlyingTokenConfig[] public strategiesToDeploy; - - /// ----------------------------------------------------------------------- - /// - /// ----------------------------------------------------------------------- - - function NAME() public view virtual override returns (string memory) { - return "ExistingDeploymentParser"; - } - - /// ----------------------------------------------------------------------- - /// - /// ----------------------------------------------------------------------- - - /// @notice use for parsing already deployed EigenLayer contracts - function _parseDeployedContracts( - string memory existingDeploymentInfoPath - ) internal virtual noTracing { - // read and log the chainID - uint256 currentChainId = block.chainid; - console.log("You are parsing on ChainID", currentChainId); - - // READ JSON CONFIG DATA - string memory json = cheats.readFile(existingDeploymentInfoPath); - - SEMVER = stdJson.readString(json, ".parameters.semver"); - - // check that the chainID matches the one in the config - uint256 configChainId = json.readUint(".chainInfo.chainId"); - assertEq(configChainId, currentChainId, "You are on the wrong chain for this config"); - - console.log("Using addresses file", existingDeploymentInfoPath); - console.log("- Last Updated", stdJson.readString(json, ".lastUpdated")); - - // read all of the deployed addresses - executorMultisig = json.readAddress(".parameters.executorMultisig"); - operationsMultisig = json.readAddress(".parameters.operationsMultisig"); - communityMultisig = json.readAddress(".parameters.communityMultisig"); - pauserMultisig = json.readAddress(".parameters.pauserMultisig"); - timelock = json.readAddress(".parameters.timelock"); - - eigenLayerProxyAdmin = ProxyAdmin(json.readAddress(".addresses.eigenLayerProxyAdmin")); - eigenLayerPauserReg = PauserRegistry(json.readAddress(".addresses.eigenLayerPauserReg")); - - // FIXME: hotfix - remove later... - permissionControllerImplementation = new PermissionController(SEMVER); - permissionController = PermissionController( - address( - new TransparentUpgradeableProxy( - address(permissionControllerImplementation), address(eigenLayerProxyAdmin), "" - ) - ) - ); - - allocationManagerImplementation = new AllocationManager( - delegationManager, - eigenLayerPauserReg, - permissionController, - DEALLOCATION_DELAY, - ALLOCATION_CONFIGURATION_DELAY, - SEMVER - ); - allocationManager = AllocationManager( - address( - new TransparentUpgradeableProxy( - address(allocationManagerImplementation), address(eigenLayerProxyAdmin), "" - ) - ) - ); - - // // AllocationManager - // allocationManager = AllocationManager(json.readAddress(".addresses.allocationManager")); - // allocationManagerImplementation = json.readAddress(".addresses.allocationManagerImplementation"); - - // AVSDirectory - avsDirectory = AVSDirectory(json.readAddress(".addresses.avsDirectory")); - avsDirectoryImplementation = AVSDirectory(json.readAddress(".addresses.avsDirectoryImplementation")); - - // DelegationManager - delegationManager = DelegationManager(json.readAddress(".addresses.delegationManager")); - delegationManagerImplementation = - DelegationManager(json.readAddress(".addresses.delegationManagerImplementation")); - - // // PermissionController - // permissionController = PermissionController(json.readAddress(".addresses.permissionController")); - // permissionControllerImplementation = json.readAddress(".addresses.permissionControllerImplementation"); - - // RewardsCoordinator - rewardsCoordinator = RewardsCoordinator(json.readAddress(".addresses.rewardsCoordinator")); - rewardsCoordinatorImplementation = - RewardsCoordinator(json.readAddress(".addresses.rewardsCoordinatorImplementation")); - - // StrategyManager - strategyManager = StrategyManager(json.readAddress(".addresses.strategyManager")); - strategyManagerImplementation = StrategyManager(json.readAddress(".addresses.strategyManagerImplementation")); - - // StrategyFactory - strategyFactory = StrategyFactory(json.readAddress(".addresses.strategyFactory")); - strategyFactoryImplementation = StrategyFactory(json.readAddress(".addresses.strategyFactoryImplementation")); - - // StrategyBeacon - strategyBeacon = UpgradeableBeacon(json.readAddress(".addresses.strategyFactoryBeacon")); - strategyFactoryBeaconImplementation = - StrategyBase(json.readAddress(".addresses.strategyFactoryBeaconImplementation")); - baseStrategyImplementation = StrategyBase(json.readAddress(".addresses.baseStrategyImplementation")); - - // EigenPodManager - eigenPodManager = EigenPodManager(json.readAddress(".addresses.eigenPodManager")); - eigenPodManagerImplementation = EigenPodManager(json.readAddress(".addresses.eigenPodManagerImplementation")); - - // EigenPod - eigenPodBeacon = UpgradeableBeacon(json.readAddress(".addresses.eigenPodBeacon")); - eigenPodImplementation = EigenPod(payable(json.readAddress(".addresses.eigenPodImplementation"))); - - emptyContract = EmptyContract(json.readAddress(".addresses.emptyContract")); - - // Strategies Deployed, load strategy list - numStrategiesDeployed = json.readUint(".addresses.numStrategiesDeployed"); - for (uint256 i = 0; i < numStrategiesDeployed; ++i) { - // Form the key for the current element - string memory key = string.concat(".addresses.strategyAddresses[", cheats.toString(i), "]"); - // Use the key and parse the strategy address - address strategyAddress = abi.decode(json.parseRaw(key), (address)); - deployedStrategyArray.push(StrategyBase(strategyAddress)); - } - - // token - tokenProxyAdmin = ProxyAdmin(json.readAddress(".addresses.token.tokenProxyAdmin")); - EIGEN = IEigen(json.readAddress(".addresses.token.EIGEN")); - EIGENImpl = IEigen(json.readAddress(".addresses.token.EIGENImpl")); - bEIGEN = IBackingEigen(json.readAddress(".addresses.token.bEIGEN")); - bEIGENImpl = IBackingEigen(json.readAddress(".addresses.token.bEIGENImpl")); - eigenStrategy = EigenStrategy(json.readAddress(".addresses.token.eigenStrategy")); - eigenStrategyImpl = EigenStrategy(json.readAddress(".addresses.token.eigenStrategyImpl")); - } - - function _parseDeployedEigenPods( - string memory existingDeploymentInfoPath - ) internal returns (DeployedEigenPods memory) { - uint256 currentChainId = block.chainid; - - // READ JSON CONFIG DATA - string memory json = cheats.readFile(existingDeploymentInfoPath); - - // check that the chainID matches the one in the config - uint256 configChainId = json.readUint(".chainInfo.chainId"); - assertEq(configChainId, currentChainId, "You are on the wrong chain for this config"); - - multiValidatorPods = json.readAddressArray(".eigenPods.multiValidatorPods"); - singleValidatorPods = json.readAddressArray(".eigenPods.singleValidatorPods"); - inActivePods = json.readAddressArray(".eigenPods.inActivePods"); - allEigenPods = json.readAddressArray(".eigenPods.allEigenPods"); - return DeployedEigenPods({ - multiValidatorPods: multiValidatorPods, - singleValidatorPods: singleValidatorPods, - inActivePods: inActivePods - }); - } - - /// @notice use for deploying a new set of EigenLayer contracts - /// Note that this does assertEq multisigs to already be deployed - function _parseInitialDeploymentParams( - string memory initialDeploymentParamsPath - ) internal virtual { - // read and log the chainID - uint256 currentChainId = block.chainid; - console.log("You are parsing on ChainID", currentChainId); - - // READ JSON CONFIG DATA - string memory json = cheats.readFile(initialDeploymentParamsPath); - - // check that the chainID matches the one in the config - uint256 configChainId = json.readUint(".chainInfo.chainId"); - assertEq(configChainId, currentChainId, "You are on the wrong chain for this config"); - - console.log("Using config file", initialDeploymentParamsPath); - console.log("- Last Updated", stdJson.readString(json, ".lastUpdated")); - - // read all of the deployed addresses - executorMultisig = json.readAddress(".multisig_addresses.executorMultisig"); - operationsMultisig = json.readAddress(".multisig_addresses.operationsMultisig"); - communityMultisig = json.readAddress(".multisig_addresses.communityMultisig"); - pauserMultisig = json.readAddress(".multisig_addresses.pauserMultisig"); - - // Strategies to Deploy, load strategy list - numStrategiesToDeploy = json.readUint(".strategies.numStrategies"); - STRATEGY_MAX_PER_DEPOSIT = json.readUint(".strategies.MAX_PER_DEPOSIT"); - STRATEGY_MAX_TOTAL_DEPOSITS = json.readUint(".strategies.MAX_TOTAL_DEPOSITS"); - for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { - // Form the key for the current element - string memory key = string.concat(".strategies.strategiesToDeploy[", cheats.toString(i), "]"); - - // Use parseJson with the key to get the value for the current element - bytes memory tokenInfoBytes = stdJson.parseRaw(json, key); - - // Decode the token information into the Token struct - StrategyUnderlyingTokenConfig memory tokenInfo = abi.decode(tokenInfoBytes, (StrategyUnderlyingTokenConfig)); - - strategiesToDeploy.push(tokenInfo); - } - - // Read initialize params for upgradeable contracts - STRATEGY_MANAGER_INIT_PAUSED_STATUS = json.readUint(".strategyManager.init_paused_status"); - STRATEGY_MANAGER_WHITELISTER = json.readAddress(".strategyManager.init_strategy_whitelister"); - // DelegationManager - DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = - uint32(json.readUint(".delegationManager.init_minWithdrawalDelayBlocks")); - DELEGATION_MANAGER_INIT_PAUSED_STATUS = json.readUint(".delegationManager.init_paused_status"); - // RewardsCoordinator - - REWARDS_COORDINATOR_INIT_PAUSED_STATUS = json.readUint(".rewardsCoordinator.init_paused_status"); - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = - uint32(json.readUint(".rewardsCoordinator.CALCULATION_INTERVAL_SECONDS")); - REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32(json.readUint(".rewardsCoordinator.MAX_REWARDS_DURATION")); - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32(json.readUint(".rewardsCoordinator.MAX_RETROACTIVE_LENGTH")); - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32(json.readUint(".rewardsCoordinator.MAX_FUTURE_LENGTH")); - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = - uint32(json.readUint(".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP")); - REWARDS_COORDINATOR_UPDATER = json.readAddress(".rewardsCoordinator.rewards_updater_address"); - REWARDS_COORDINATOR_ACTIVATION_DELAY = uint32(json.readUint(".rewardsCoordinator.activation_delay")); - REWARDS_COORDINATOR_DEFAULT_OPERATOR_SPLIT_BIPS = - uint32(json.readUint(".rewardsCoordinator.default_operator_split_bips")); - REWARDS_COORDINATOR_OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = - uint32(json.readUint(".rewardsCoordinator.OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP")); - REWARDS_COORDINATOR_OPERATOR_SET_MAX_RETROACTIVE_LENGTH = - uint32(json.readUint(".rewardsCoordinator.OPERATOR_SET_MAX_RETROACTIVE_LENGTH")); - // AVSDirectory - AVS_DIRECTORY_INIT_PAUSED_STATUS = json.readUint(".avsDirectory.init_paused_status"); - // EigenPodManager - EIGENPOD_MANAGER_INIT_PAUSED_STATUS = json.readUint(".eigenPodManager.init_paused_status"); - // AllocationManager - ALLOCATION_MANAGER_INIT_PAUSED_STATUS = json.readUint(".allocationManager.init_paused_status"); - // EigenPod - EIGENPOD_GENESIS_TIME = uint64(json.readUint(".eigenPod.GENESIS_TIME")); - ETHPOSDepositAddress = json.readAddress(".ethPOSDepositAddress"); - - // check that all values are non-zero - logInitialDeploymentParams(); - } - - /// @notice Ensure contracts point at each other correctly via constructors - function _verifyContractPointers() internal view virtual { - // AVSDirectory - assertTrue( - avsDirectory.delegation() == delegationManager, "avsDirectory: delegationManager address not set correctly" - ); - // RewardsCoordinator - assertTrue( - rewardsCoordinator.delegationManager() == delegationManager, - "rewardsCoordinator: delegationManager address not set correctly" - ); - assertTrue( - rewardsCoordinator.strategyManager() == strategyManager, - "rewardsCoordinator: strategyManager address not set correctly" - ); - // DelegationManager - assertTrue( - delegationManager.strategyManager() == strategyManager, - "delegationManager: strategyManager address not set correctly" - ); - assertTrue( - delegationManager.eigenPodManager() == eigenPodManager, - "delegationManager: eigenPodManager address not set correctly" - ); - // StrategyManager - assertTrue( - strategyManager.delegation() == delegationManager, - "strategyManager: delegationManager address not set correctly" - ); - // EPM - assertTrue( - address(eigenPodManager.ethPOS()) == ETHPOSDepositAddress, - "eigenPodManager: ethPOSDeposit contract address not set correctly" - ); - assertTrue( - eigenPodManager.eigenPodBeacon() == eigenPodBeacon, - "eigenPodManager: eigenPodBeacon contract address not set correctly" - ); - assertTrue( - eigenPodManager.delegationManager() == delegationManager, - "eigenPodManager: delegationManager contract address not set correctly" - ); - } - - /// @notice verify implementations for Transparent Upgradeable Proxies - function _verifyImplementations() internal view virtual { - assertEq( - eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(avsDirectory)))), - address(avsDirectoryImplementation), - "avsDirectory: implementation set incorrectly" - ); - assertEq( - eigenLayerProxyAdmin.getProxyImplementation( - ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))) - ), - address(rewardsCoordinatorImplementation), - "rewardsCoordinator: implementation set incorrectly" - ); - assertEq( - eigenLayerProxyAdmin.getProxyImplementation( - ITransparentUpgradeableProxy(payable(address(delegationManager))) - ), - address(delegationManagerImplementation), - "delegationManager: implementation set incorrectly" - ); - assertEq( - eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(strategyManager)))), - address(strategyManagerImplementation), - "strategyManager: implementation set incorrectly" - ); - assertEq( - eigenLayerProxyAdmin.getProxyImplementation(ITransparentUpgradeableProxy(payable(address(eigenPodManager)))), - address(eigenPodManagerImplementation), - "eigenPodManager: implementation set incorrectly" - ); - - for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { - assertEq( - eigenLayerProxyAdmin.getProxyImplementation( - ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) - ), - address(baseStrategyImplementation), - "strategy: implementation set incorrectly" - ); - } - - assertEq( - eigenPodBeacon.implementation(), - address(eigenPodImplementation), - "eigenPodBeacon: implementation set incorrectly" - ); - } - - /** - * @notice Verify initialization of Transparent Upgradeable Proxies. Also check - * initialization params if this is the first deployment. - * @dev isInitialDeployment True if this is the first deployment of contracts from scratch - */ - function _verifyContractsInitialized( - bool /* isInitialDeployment */ - ) internal virtual { - // AVSDirectory - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - avsDirectory.initialize(address(0), AVS_DIRECTORY_INIT_PAUSED_STATUS); - // RewardsCoordinator - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - rewardsCoordinator.initialize( - address(0), - 0, // initialPausedStatus - address(0), // rewardsUpdater - 0, // activationDelay - 0 // defaultSplitBips - ); - // DelegationManager - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - delegationManager.initialize(address(0), 0); - // StrategyManager - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - strategyManager.initialize(address(0), address(0), STRATEGY_MANAGER_INIT_PAUSED_STATUS); - // EigenPodManager - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - eigenPodManager.initialize(address(0), EIGENPOD_MANAGER_INIT_PAUSED_STATUS); - // Strategies - for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { - cheats.expectRevert(bytes("Initializable: contract is already initialized")); - StrategyBaseTVLLimits(address(deployedStrategyArray[i])).initialize(0, 0, IERC20(address(0))); - } - } - - /// @notice Verify params based on config constants that are updated from calling `_parseInitialDeploymentParams` - function _verifyInitializationParams() internal view virtual { - // AVSDirectory - assertTrue( - avsDirectory.pauserRegistry() == eigenLayerPauserReg, "avsdirectory: pauser registry not set correctly" - ); - assertEq(avsDirectory.owner(), executorMultisig, "avsdirectory: owner not set correctly"); - assertEq( - avsDirectory.paused(), AVS_DIRECTORY_INIT_PAUSED_STATUS, "avsdirectory: init paused status set incorrectly" - ); - // RewardsCoordinator - assertTrue( - rewardsCoordinator.pauserRegistry() == eigenLayerPauserReg, - "rewardsCoordinator: pauser registry not set correctly" - ); - // assertEq( - // rewardsCoordinator.owner(), executorMultisig, - // "rewardsCoordinator: owner not set correctly" - // ); - // assertEq( - // rewardsCoordinator.paused(), REWARDS_COORDINATOR_INIT_PAUSED_STATUS, - // "rewardsCoordinator: init paused status set incorrectly" - // ); - assertEq( - rewardsCoordinator.MAX_REWARDS_DURATION(), - REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - "rewardsCoordinator: maxRewardsDuration not set correctly" - ); - assertEq( - rewardsCoordinator.MAX_RETROACTIVE_LENGTH(), - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - "rewardsCoordinator: maxRetroactiveLength not set correctly" - ); - assertEq( - rewardsCoordinator.MAX_FUTURE_LENGTH(), - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - "rewardsCoordinator: maxFutureLength not set correctly" - ); - assertEq( - rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP(), - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, - "rewardsCoordinator: genesisRewardsTimestamp not set correctly" - ); - // assertEq( - // rewardsCoordinator.rewardsUpdater(), REWARDS_COORDINATOR_UPDATER, - // "rewardsCoordinator: rewardsUpdater not set correctly" - // ); - assertEq( - rewardsCoordinator.activationDelay(), - REWARDS_COORDINATOR_ACTIVATION_DELAY, - "rewardsCoordinator: activationDelay not set correctly" - ); - assertEq( - rewardsCoordinator.CALCULATION_INTERVAL_SECONDS(), - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - "rewardsCoordinator: CALCULATION_INTERVAL_SECONDS not set correctly" - ); - assertEq( - rewardsCoordinator.defaultOperatorSplitBips(), - REWARDS_COORDINATOR_DEFAULT_OPERATOR_SPLIT_BIPS, - "rewardsCoordinator: defaultSplitBips not set correctly" - ); - // DelegationManager - assertTrue( - delegationManager.pauserRegistry() == eigenLayerPauserReg, - "delegationManager: pauser registry not set correctly" - ); - assertEq(delegationManager.owner(), executorMultisig, "delegationManager: owner not set correctly"); - assertEq( - delegationManager.paused(), - DELEGATION_MANAGER_INIT_PAUSED_STATUS, - "delegationManager: init paused status set incorrectly" - ); - // StrategyManager - assertTrue( - strategyManager.pauserRegistry() == eigenLayerPauserReg, - "strategyManager: pauser registry not set correctly" - ); - assertEq(strategyManager.owner(), executorMultisig, "strategyManager: owner not set correctly"); - assertEq( - strategyManager.paused(), - STRATEGY_MANAGER_INIT_PAUSED_STATUS, - "strategyManager: init paused status set incorrectly" - ); - if (block.chainid == 1) { - assertEq( - strategyManager.strategyWhitelister(), - address(strategyFactory), - "strategyManager: strategyWhitelister not set correctly" - ); - } else if (block.chainid == 17_000) { - // On holesky, for ease of whitelisting we set to executorMultisig - // assertEq( - // strategyManager.strategyWhitelister(), executorMultisig, - // "strategyManager: strategyWhitelister not set correctly" - // ); - } - // EigenPodManager - assertTrue( - eigenPodManager.pauserRegistry() == eigenLayerPauserReg, - "eigenPodManager: pauser registry not set correctly" - ); - assertEq(eigenPodManager.owner(), executorMultisig, "eigenPodManager: owner not set correctly"); - assertEq( - eigenPodManager.paused(), - EIGENPOD_MANAGER_INIT_PAUSED_STATUS, - "eigenPodManager: init paused status set incorrectly" - ); - assertEq( - address(eigenPodManager.ethPOS()), - address(ETHPOSDepositAddress), - "eigenPodManager: ethPOS not set correctly" - ); - // EigenPodBeacon - assertEq(eigenPodBeacon.owner(), executorMultisig, "eigenPodBeacon: owner not set correctly"); - // EigenPodImplementation - assertEq( - eigenPodImplementation.GENESIS_TIME(), - EIGENPOD_GENESIS_TIME, - "eigenPodImplementation: GENESIS TIME not set correctly" - ); - assertEq( - address(eigenPodImplementation.ethPOS()), - ETHPOSDepositAddress, - "eigenPodImplementation: ethPOS not set correctly" - ); - // Strategies - for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { - assertTrue( - deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, - "StrategyBaseTVLLimits: pauser registry not set correctly" - ); - assertEq(deployedStrategyArray[i].paused(), 0, "StrategyBaseTVLLimits: init paused status set incorrectly"); - assertTrue( - strategyManager.strategyIsWhitelistedForDeposit(deployedStrategyArray[i]), - "StrategyBaseTVLLimits: strategy should be whitelisted" - ); - } - - // Pausing Permissions - assertTrue(eigenLayerPauserReg.isPauser(operationsMultisig), "pauserRegistry: operationsMultisig is not pauser"); - assertTrue(eigenLayerPauserReg.isPauser(executorMultisig), "pauserRegistry: executorMultisig is not pauser"); - assertTrue(eigenLayerPauserReg.isPauser(pauserMultisig), "pauserRegistry: pauserMultisig is not pauser"); - assertEq(eigenLayerPauserReg.unpauser(), executorMultisig, "pauserRegistry: unpauser not set correctly"); - } - - function logInitialDeploymentParams() public { - console.log("==== Parsed Initialize Params for Initial Deployment,=="); - - console.log("executorMultisig", executorMultisig); - console.log("operationsMultisig", operationsMultisig); - console.log("communityMultisig", communityMultisig); - console.log("pauserMultisig", pauserMultisig); - - console.log("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); - console.log("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); - console.log("DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS); - console.log("DELEGATION_MANAGER_INIT_PAUSED_STATUS", DELEGATION_MANAGER_INIT_PAUSED_STATUS); - console.log("AVS_DIRECTORY_INIT_PAUSED_STATUS", AVS_DIRECTORY_INIT_PAUSED_STATUS); - console.log("REWARDS_COORDINATOR_INIT_PAUSED_STATUS", REWARDS_COORDINATOR_INIT_PAUSED_STATUS); - // todo log all rewards coordinator params - console.log("EIGENPOD_MANAGER_INIT_PAUSED_STATUS", EIGENPOD_MANAGER_INIT_PAUSED_STATUS); - console.log("EIGENPOD_GENESIS_TIME", EIGENPOD_GENESIS_TIME); - console.log("ETHPOSDepositAddress", ETHPOSDepositAddress); - - console.log("==== Strategies to Deploy,=="); - for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { - // Decode the token information into the Token struct - StrategyUnderlyingTokenConfig memory tokenInfo = strategiesToDeploy[i]; - - strategiesToDeploy.push(tokenInfo); - console.log("TOKEN ADDRESS", tokenInfo.tokenAddress); - console.log("TOKEN NAME", tokenInfo.tokenName); - console.log("TOKEN SYMBOL", tokenInfo.tokenSymbol); - } - } - - /** - * @notice Log contract addresses and write to output json file - */ - function logAndOutputContractAddresses( - string memory outputPath - ) public { - // WRITE JSON DATA - string memory parent_object = "parent object"; - - string memory deployed_strategies = "strategies"; - for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { - deployed_strategies.serialize(strategiesToDeploy[i].tokenSymbol, address(deployedStrategyArray[i])); - } - string memory deployed_strategies_output = numStrategiesToDeploy == 0 - ? "" - : deployed_strategies.serialize( - strategiesToDeploy[numStrategiesToDeploy - 1].tokenSymbol, - address(deployedStrategyArray[numStrategiesToDeploy - 1]) - ); - - string memory deployed_addresses = "addresses"; - deployed_addresses.serialize("eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); - deployed_addresses.serialize("eigenLayerPauserReg", address(eigenLayerPauserReg)); - deployed_addresses.serialize("avsDirectory", address(avsDirectory)); - deployed_addresses.serialize("avsDirectoryImplementation", address(avsDirectoryImplementation)); - deployed_addresses.serialize("delegationManager", address(delegationManager)); - deployed_addresses.serialize("delegationManagerImplementation", address(delegationManagerImplementation)); - deployed_addresses.serialize("strategyManager", address(strategyManager)); - deployed_addresses.serialize("strategyManagerImplementation", address(strategyManagerImplementation)); - deployed_addresses.serialize("rewardsCoordinator", address(rewardsCoordinator)); - deployed_addresses.serialize("rewardsCoordinatorImplementation", address(rewardsCoordinatorImplementation)); - deployed_addresses.serialize("eigenPodManager", address(eigenPodManager)); - deployed_addresses.serialize("eigenPodManagerImplementation", address(eigenPodManagerImplementation)); - deployed_addresses.serialize("eigenPodBeacon", address(eigenPodBeacon)); - deployed_addresses.serialize("eigenPodImplementation", address(eigenPodImplementation)); - deployed_addresses.serialize("baseStrategyImplementation", address(baseStrategyImplementation)); - deployed_addresses.serialize("emptyContract", address(emptyContract)); - string memory deployed_addresses_output = deployed_addresses.serialize("strategies", deployed_strategies_output); - - string memory parameters = "parameters"; - parameters.serialize("executorMultisig", executorMultisig); - parameters.serialize("operationsMultisig", operationsMultisig); - parameters.serialize("communityMultisig", communityMultisig); - parameters.serialize("pauserMultisig", pauserMultisig); - parameters.serialize("timelock", timelock); - string memory parameters_output = parameters.serialize("operationsMultisig", operationsMultisig); - - string memory chain_info = "chainInfo"; - chain_info.serialize("deploymentBlock", block.number); - string memory chain_info_output = chain_info.serialize("chainId", block.chainid); - - // serialize all the data - parent_object.serialize(deployed_addresses, deployed_addresses_output); - parent_object.serialize(chain_info, chain_info_output); - string memory finalJson = parent_object.serialize(parameters, parameters_output); - - cheats.writeJson(finalJson, outputPath); - } - - /// @notice used for parsing parameters used in the integration test upgrade - function _parseParamsForIntegrationUpgrade( - string memory initialDeploymentParamsPath - ) internal virtual noTracing { - // read and log the chainID - uint256 currentChainId = block.chainid; - console.log("You are parsing on ChainID", currentChainId); - - // READ JSON CONFIG DATA - string memory json = cheats.readFile(initialDeploymentParamsPath); - - // check that the chainID matches the one in the config - uint256 configChainId = json.readUint(".config.environment.chainid"); - assertEq(configChainId, currentChainId, "You are on the wrong chain for this config"); - - console.log("Using config file", initialDeploymentParamsPath); - console.log("- Last Updated", stdJson.readString(json, ".config.environment.lastUpdated")); - - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = - uint32(json.readUint(".config.params.CALCULATION_INTERVAL_SECONDS")); - REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32(json.readUint(".config.params.MAX_REWARDS_DURATION")); - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32(json.readUint(".config.params.MAX_RETROACTIVE_LENGTH")); - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32(json.readUint(".config.params.MAX_FUTURE_LENGTH")); - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = - uint32(json.readUint(".config.params.GENESIS_REWARDS_TIMESTAMP")); - - DEALLOCATION_DELAY = uint32(json.readUint(".config.params.MIN_WITHDRAWAL_DELAY_BLOCKS")); - ALLOCATION_CONFIGURATION_DELAY = uint32(json.readUint(".config.params.ALLOCATION_CONFIGURATION_DELAY")); - DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = - uint32(json.readUint(".config.params.MIN_WITHDRAWAL_DELAY_BLOCKS")); - } -} diff --git a/snapshots/Integration_ALM_Multi.json b/snapshots/Integration_ALM_Multi.json index a2c3359a1a..ce5ec90dda 100644 --- a/snapshots/Integration_ALM_Multi.json +++ b/snapshots/Integration_ALM_Multi.json @@ -1,3 +1,3 @@ { - "gasUsed": "47579" + "gasUsed": "137087" } \ No newline at end of file diff --git a/src/test/integration/TypeImporter.t.sol b/src/contracts/interfaces/ICore.sol similarity index 81% rename from src/test/integration/TypeImporter.t.sol rename to src/contracts/interfaces/ICore.sol index 91600d6796..f33291f7aa 100644 --- a/src/test/integration/TypeImporter.t.sol +++ b/src/contracts/interfaces/ICore.sol @@ -15,4 +15,10 @@ import "src/contracts/interfaces/IStrategyManager.sol"; /// `AllocateParams memory params;` /// vs /// `IAllocationManagerTypes.AllocateParams memory params;` -interface TypeImporter is IAllocationManagerTypes, IAVSDirectoryTypes, IDelegationManagerTypes, IEigenPodManagerTypes, IEigenPodTypes {} +interface ICoreTypes is + IAllocationManagerTypes, + IAVSDirectoryTypes, + IDelegationManagerTypes, + IEigenPodManagerTypes, + IEigenPodTypes +{} diff --git a/src/test/Config.t.sol b/src/test/Config.t.sol new file mode 100644 index 0000000000..746a44b22a --- /dev/null +++ b/src/test/Config.t.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.19; + +import "src/test/ConfigParser.t.sol"; + +abstract contract ConfigGetters { + using ConfigParser for *; + + Config public config; + + /// ----------------------------------------------------------------------- + /// Governance + /// ----------------------------------------------------------------------- + + function communityMultisig() public view virtual returns (address) { + return config.governance.communityMultisig; + } + + function executorMultisig() public view virtual returns (address) { + return config.governance.executorMultisig; + } + + function operationsMultisig() public view virtual returns (address) { + return config.governance.operationsMultisig; + } + + function pauserMultisig() public view virtual returns (address) { + return config.governance.pauserMultisig; + } + + function pauserRegistry() public view virtual returns (PauserRegistry) { + return config.governance.pauserRegistry; + } + + function protocolCouncil() public view virtual returns (address) { + return config.governance.protocolCouncil; + } + + function proxyAdmin() public view virtual returns (ProxyAdmin) { + return config.governance.proxyAdmin; + } + + function timelock() public view virtual returns (TimelockController) { + return config.governance.timelock; + } + + /// ----------------------------------------------------------------------- + /// Tokens + /// ----------------------------------------------------------------------- + + function bEIGEN() public view virtual returns (IERC20) { + return config.tokens.bEIGEN; + } + + function EIGEN() public view virtual returns (IERC20) { + return config.tokens.EIGEN; + } + + /// ----------------------------------------------------------------------- + /// Core + /// ----------------------------------------------------------------------- + + function allocationManager() public view virtual returns (AllocationManager) { + return config.core.allocationManager; + } + + function allocationManagerImpl() public view virtual returns (address) { + return address(config.core.allocationManager).impl(); + } + + function avsDirectory() public view virtual returns (AVSDirectory) { + return config.core.avsDirectory; + } + + function avsDirectoryImpl() public view virtual returns (address) { + return address(config.core.avsDirectory).impl(); + } + + function delegationManager() public view virtual returns (DelegationManager) { + return config.core.delegationManager; + } + + function delegationManagerImpl() public view virtual returns (address) { + return address(config.core.delegationManager).impl(); + } + + function permissionController() public view virtual returns (PermissionController) { + return config.core.permissionController; + } + + function permissionControllerImpl() public view virtual returns (address) { + return address(config.core.permissionController).impl(); + } + + function rewardsCoordinator() public view virtual returns (RewardsCoordinator) { + return config.core.rewardsCoordinator; + } + + function rewardsCoordinatorImpl() public view virtual returns (address) { + return address(config.core.rewardsCoordinator).impl(); + } + + function strategyManager() public view virtual returns (StrategyManager) { + return config.core.strategyManager; + } + + function strategyManagerImpl() public view virtual returns (address) { + return address(config.core.strategyManager).impl(); + } + + /// ----------------------------------------------------------------------- + /// Pods + /// ----------------------------------------------------------------------- + + function eigenPodBeacon() public view virtual returns (UpgradeableBeacon) { + return config.pods.eigenPodBeacon; + } + + function eigenPodManager() public view virtual returns (EigenPodManager) { + return config.pods.eigenPodManager; + } + + function eigenPodManagerImpl() public view virtual returns (address) { + return address(config.pods.eigenPodManager).impl(); + } + + function eigenStrategy() public view virtual returns (EigenStrategy) { + return config.pods.eigenStrategy; + } + + function eigenStrategyImpl() public view virtual returns (address) { + return address(config.pods.eigenStrategy).impl(); + } + + /// ----------------------------------------------------------------------- + /// Strategies + /// ----------------------------------------------------------------------- + + function strategyFactory() public view virtual returns (StrategyFactory) { + return config.strategies.strategyFactory; + } + + function strategyFactoryBeacon() public view virtual returns (UpgradeableBeacon) { + return config.strategies.strategyFactoryBeacon; + } + + function strategyAddresses() public view virtual returns (IStrategy[] memory) { + return config.strategies.strategyAddresses; + } + + function strategyAddresses(uint index) public view virtual returns (IStrategy) { + return config.strategies.strategyAddresses[index]; + } + + function totalStrategies() public view virtual returns (uint) { + return config.strategies.strategyAddresses.length; + } +} + +contract ConfigGettersTest is ConfigGetters, Test { + function setUp() public { + vm.createSelectFork(vm.rpcUrl("mainnet"), 22_181_590); + config = ConfigParser.parse("./script/configs/mainnet.toml"); + } + + function test_parseTOML() public { + // Governance addresses + assertEq(communityMultisig(), 0xFEA47018D632A77bA579846c840d5706705Dc598); + assertEq(executorMultisig(), 0x369e6F597e22EaB55fFb173C6d9cD234BD699111); + assertEq(operationsMultisig(), 0xBE1685C81aA44FF9FB319dD389addd9374383e90); + assertEq(pauserMultisig(), 0x5050389572f2d220ad927CcbeA0D406831012390); + assertEq(address(pauserRegistry()), 0x0c431C66F4dE941d089625E5B423D00707977060); + assertEq(address(protocolCouncil()), 0x461854d84Ee845F905e0eCf6C288DDEEb4A9533F); + assertEq(address(proxyAdmin()), 0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444); + assertEq(address(timelock()), 0xC06Fd4F821eaC1fF1ae8067b36342899b57BAa2d); + + // Token addresses + assertEq(address(bEIGEN()), 0x83E9115d334D248Ce39a6f36144aEaB5b3456e75); + assertEq(address(EIGEN()), 0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83); + + // Core addresses + assertEq(address(allocationManager()), 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39); + assertEq(address(avsDirectory()), 0x135DDa560e946695d6f155dACaFC6f1F25C1F5AF); + assertEq(address(delegationManager()), 0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A); + assertEq(address(permissionController()), 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5); + assertEq(address(rewardsCoordinator()), 0x7750d328b314EfFa365A0402CcfD489B80B0adda); + assertEq(address(strategyManager()), 0x858646372CC42E1A627fcE94aa7A7033e7CF075A); + + // Pod addresses + assertEq(address(eigenPodBeacon()), 0x5a2a4F2F3C18f09179B6703e63D9eDD165909073); + assertEq(address(eigenPodManager()), 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338); + assertEq(address(eigenStrategy()), 0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7); + + // Strategy addresses + assertEq(address(strategyFactory()), 0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647); + assertEq(address(strategyFactoryBeacon()), 0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9); + assertEq(totalStrategies(), 12); + assertEq(address(strategyAddresses(0)), 0x93c4b944D05dfe6df7645A86cd2206016c51564D); // stETH + assertEq(address(strategyAddresses(1)), 0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2); // rETH + assertEq(address(strategyAddresses(2)), 0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc); // cbETH + assertEq(address(strategyAddresses(3)), 0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d); // ETHx + assertEq(address(strategyAddresses(4)), 0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff); // ankrETH + assertEq(address(strategyAddresses(5)), 0xa4C637e0F704745D182e4D38cAb7E7485321d059); // oETH + assertEq(address(strategyAddresses(6)), 0x57ba429517c3473B6d34CA9aCd56c0e735b94c02); // osETH + assertEq(address(strategyAddresses(7)), 0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6); // swETH + assertEq(address(strategyAddresses(8)), 0x7CA911E83dabf90C90dD3De5411a10F1A6112184); // wBETH + assertEq(address(strategyAddresses(9)), 0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6); // sfrxETH + assertEq(address(strategyAddresses(10)), 0xAe60d8180437b5C34bB956822ac2710972584473); // lsETH + assertEq(address(strategyAddresses(11)), 0x298aFB19A105D59E74658C4C334Ff360BadE6dd2); // mETH + } +} diff --git a/src/test/ConfigParser.t.sol b/src/test/ConfigParser.t.sol new file mode 100644 index 0000000000..a511e3a382 --- /dev/null +++ b/src/test/ConfigParser.t.sol @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.19; + +import "forge-std/Test.sol"; +import "script/releases/Env.sol"; +import "src/test/mocks/EmptyContract.sol"; + +// WARNING: We expect the layout to follow the order of the toml config file. Please see: +// - script/configs/mainnet/mainnet-addresses.toml +// - https://book.getfoundry.sh/cheatcodes/parse-toml?highlight=toml#decoding-toml-tables-into-solidity-structs + +struct Tokens { + IERC20 bEIGEN; + IERC20 EIGEN; +} + +struct Core { + AllocationManager allocationManager; + AVSDirectory avsDirectory; + DelegationManager delegationManager; + PermissionController permissionController; + RewardsCoordinator rewardsCoordinator; + StrategyManager strategyManager; +} + +struct Governance { + address communityMultisig; + address executorMultisig; + address operationsMultisig; + address pauserMultisig; + PauserRegistry pauserRegistry; + address protocolCouncil; + ProxyAdmin proxyAdmin; + TimelockController timelock; +} + +struct Pods { + UpgradeableBeacon eigenPodBeacon; + EigenPodManager eigenPodManager; + EigenStrategy eigenStrategy; +} + +struct Strategies { + IStrategy[] strategyAddresses; + StrategyFactory strategyFactory; + UpgradeableBeacon strategyFactoryBeacon; +} + +struct Config { + Core core; + Governance governance; + Pods pods; + Strategies strategies; + Tokens tokens; +} + +struct ForkConfig { + uint forkBlock; + bool upgradeBeforeTesting; + bool supportEigenPodTests; + bool supportUpgradeTests; + bytes timelockPayload; +} + +library ConfigParser { + using ConfigParser for *; + using stdToml for string; + + Vm constant vm = Vm(address(uint160(uint(keccak256("hevm cheat code"))))); + + /// ----------------------------------------------------------------------- + /// Config Parsing + /// ----------------------------------------------------------------------- + + /// @dev Returns the config from a given TOML file. + function parse(string memory path) internal returns (Config memory) { + return abi.decode(vm.readFile(path).parseRaw("."), (Config)); + } + + /// @dev Returns the config from a given Zeus environment. + function parseZeus() internal returns (Config memory c) { + // Governance addresses + c.governance.communityMultisig = Env.protocolCouncilMultisig(); + c.governance.executorMultisig = Env.executorMultisig(); + c.governance.operationsMultisig = Env.opsMultisig(); + c.governance.pauserMultisig = Env.pauserMultisig(); + c.governance.pauserRegistry = Env.pauserRegistry(Env.impl); + c.governance.protocolCouncil = Env.protocolCouncilMultisig(); + c.governance.proxyAdmin = ProxyAdmin(Env.proxyAdmin()); + c.governance.timelock = Env.timelockController(); + // Token addresses + c.tokens.bEIGEN = Env.beigen(Env.proxy); + c.tokens.EIGEN = Env.eigen(Env.proxy); + // Core addresses + c.core.allocationManager = Env.allocationManager(Env.proxy); + c.core.avsDirectory = Env.avsDirectory(Env.proxy); + c.core.delegationManager = Env.delegationManager(Env.proxy); + c.core.permissionController = Env.permissionController(Env.proxy); + c.core.rewardsCoordinator = Env.rewardsCoordinator(Env.proxy); + c.core.strategyManager = Env.strategyManager(Env.proxy); + // Pod addresses + c.pods.eigenPodBeacon = Env.eigenPod(Env.beacon); + c.pods.eigenPodManager = Env.eigenPodManager(Env.proxy); + c.pods.eigenStrategy = Env.eigenStrategy(Env.proxy); + // Strategy addresses + c.strategies.strategyFactory = Env.strategyFactory(Env.proxy); + c.strategies.strategyFactoryBeacon = Env.strategyBase(Env.beacon); + // Get all strategy instances + c.strategies.strategyAddresses = new IStrategy[](Env.strategyBaseTVLLimits_Count(Env.instance)); + for (uint i; i < c.strategies.strategyAddresses.length; ++i) { + c.strategies.strategyAddresses[i] = Env.strategyBaseTVLLimits(Env.instance, i); + } + } + + function label(Config memory c) internal { + // Governance + vm.label(address(c.governance.communityMultisig), "CommunityMultisig"); + vm.label(address(c.governance.executorMultisig), "ExecutorMultisig"); + vm.label(address(c.governance.operationsMultisig), "OperationsMultisig"); + vm.label(address(c.governance.pauserMultisig), "PauserMultisig"); + vm.label(address(c.governance.pauserRegistry), "PauserRegistry"); + vm.label(address(c.governance.protocolCouncil), "ProtocolCouncil"); + vm.label(address(c.governance.proxyAdmin), "ProxyAdmin"); + vm.label(address(c.governance.timelock), "Timelock"); + // Tokens + vm.label(address(c.tokens.bEIGEN), "bEIGEN"); + vm.label(address(c.tokens.EIGEN), "EIGEN"); + // Core + vm.label(address(c.core.allocationManager), "AllocationManager"); + vm.label(address(c.core.avsDirectory), "AVSDirectory"); + vm.label(address(c.core.delegationManager), "DelegationManager"); + vm.label(address(c.core.permissionController), "PermissionController"); + vm.label(address(c.core.rewardsCoordinator), "RewardsCoordinator"); + vm.label(address(c.core.strategyManager), "StrategyManager"); + // Pods + vm.label(address(c.pods.eigenPodBeacon), "EigenPodBeacon"); + vm.label(address(c.pods.eigenPodManager), "EigenPodManager"); + vm.label(address(c.pods.eigenStrategy), "EigenStrategy"); + // Strategies + vm.label(address(c.strategies.strategyFactory), "StrategyFactory"); + vm.label(address(c.strategies.strategyFactoryBeacon), "StrategyFactoryBeacon"); + // Label all the strategy addresses + for (uint i; i < c.strategies.strategyAddresses.length; ++i) { + vm.label(address(c.strategies.strategyAddresses[i]), string.concat("Strategy", vm.toString(i))); + } + } + + /// @dev Returns the fork config from a given profile. + function parseForkConfig(string memory profile) internal view returns (ForkConfig memory) { + return ForkConfig({ + forkBlock: vm.envOr(string.concat("FORK_BLOCK_", vm.toUppercase(profile)), uint(0)), + upgradeBeforeTesting: vm.envOr(string.concat("UPGRADE_BEFORE_TEST_", vm.toUppercase(profile)), true), + supportEigenPodTests: vm.envOr(string.concat("TEST_EIGEN_PODS_", vm.toUppercase(profile)), true), + supportUpgradeTests: vm.envOr(string.concat("TEST_UPGRADES_", vm.toUppercase(profile)), false), + timelockPayload: vm.envOr("TIMELOCK_PAYLOAD", bytes("")) + }); + } + + /// ----------------------------------------------------------------------- + /// Proxy Storage + /// ----------------------------------------------------------------------- + + bytes32 constant ERC1967_IMPL_SLOT = bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1); + bytes32 constant ERC1967_BEACON_SLOT = bytes32(uint(keccak256("eip1967.proxy.beacon")) - 1); + bytes32 constant ERC1967_ADMIN_SLOT = bytes32(uint(keccak256("eip1967.proxy.admin")) - 1); + + /// @dev Returns the implementation address of a ERC1967 proxy. + function impl(address proxy) internal view returns (address) { + return address(uint160(uint(vm.load(proxy, ERC1967_IMPL_SLOT)))); + } + + /// @dev Returns the beacon address of a ERC1967 proxy. + function beacon(address proxy) internal view returns (address) { + return address(uint160(uint(vm.load(proxy, ERC1967_BEACON_SLOT)))); + } + + /// @dev Returns the admin address of a ERC1967 proxy. + function admin(address proxy) internal view returns (address) { + return address(uint160(uint(vm.load(proxy, ERC1967_ADMIN_SLOT)))); + } + + function setImpl(address proxy, address impl) internal returns (address) { + vm.store(proxy, ERC1967_IMPL_SLOT, bytes32(uint(uint160(impl)))); + return proxy; + } + + function setBeacon(address proxy, address beacon) internal returns (address) { + vm.store(proxy, ERC1967_BEACON_SLOT, bytes32(uint(uint160(beacon)))); + return proxy; + } + + function setAdmin(address proxy, address admin) internal returns (address) { + vm.store(proxy, ERC1967_ADMIN_SLOT, bytes32(uint(uint160(admin)))); + return proxy; + } + + function emptyContract() external returns (address deployed) { + assembly { + // Deploy a contract with a 1 opcode (STOP). + deployed := create(0x00, 0x00, 1) + } + require(deployed != address(0), "Deployment failed"); + } +} + +contract ConfigParserTest is Test { + using ConfigParser for *; + + function test_ParseTOML() public { + vm.createSelectFork(vm.rpcUrl("mainnet"), 22_181_590); + Config memory c = ConfigParser.parse("./script/configs/mainnet.toml"); + + assertEq(c.governance.communityMultisig, 0xFEA47018D632A77bA579846c840d5706705Dc598); + assertEq(c.governance.executorMultisig, 0x369e6F597e22EaB55fFb173C6d9cD234BD699111); + assertEq(c.governance.operationsMultisig, 0xBE1685C81aA44FF9FB319dD389addd9374383e90); + assertEq(c.governance.pauserMultisig, 0x5050389572f2d220ad927CcbeA0D406831012390); + assertEq(address(c.governance.pauserRegistry), 0x0c431C66F4dE941d089625E5B423D00707977060); + assertEq(address(c.governance.protocolCouncil), 0x461854d84Ee845F905e0eCf6C288DDEEb4A9533F); + assertEq(address(c.governance.proxyAdmin), 0x8b9566AdA63B64d1E1dcF1418b43fd1433b72444); + assertEq(address(c.governance.timelock), 0xC06Fd4F821eaC1fF1ae8067b36342899b57BAa2d); + + assertEq(address(c.tokens.bEIGEN), 0x83E9115d334D248Ce39a6f36144aEaB5b3456e75); + assertEq(address(c.tokens.EIGEN), 0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83); + + assertEq(address(c.core.allocationManager), 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39); + assertEq(address(c.core.avsDirectory), 0x135DDa560e946695d6f155dACaFC6f1F25C1F5AF); + assertEq(address(c.core.delegationManager), 0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A); + assertEq(address(c.core.permissionController), 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5); + assertEq(address(c.core.rewardsCoordinator), 0x7750d328b314EfFa365A0402CcfD489B80B0adda); + assertEq(address(c.core.strategyManager), 0x858646372CC42E1A627fcE94aa7A7033e7CF075A); + + assertEq(address(c.pods.eigenPodBeacon), 0x5a2a4F2F3C18f09179B6703e63D9eDD165909073); + assertEq(address(c.pods.eigenPodManager), 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338); + assertEq(address(c.pods.eigenStrategy), 0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7); + + assertEq(address(c.strategies.strategyFactory), 0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647); + assertEq(address(c.strategies.strategyFactoryBeacon), 0x0ed6703C298d28aE0878d1b28e88cA87F9662fE9); + assertEq(c.strategies.strategyAddresses.length, 12); + assertEq(address(c.strategies.strategyAddresses[0]), 0x93c4b944D05dfe6df7645A86cd2206016c51564D); // stETH + assertEq(address(c.strategies.strategyAddresses[1]), 0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2); // rETH + assertEq(address(c.strategies.strategyAddresses[2]), 0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc); // cbETH + assertEq(address(c.strategies.strategyAddresses[3]), 0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d); // ETHx + assertEq(address(c.strategies.strategyAddresses[4]), 0x13760F50a9d7377e4F20CB8CF9e4c26586c658ff); // ankrETH + assertEq(address(c.strategies.strategyAddresses[5]), 0xa4C637e0F704745D182e4D38cAb7E7485321d059); // oETH + assertEq(address(c.strategies.strategyAddresses[6]), 0x57ba429517c3473B6d34CA9aCd56c0e735b94c02); // osETH + assertEq(address(c.strategies.strategyAddresses[7]), 0x0Fe4F44beE93503346A3Ac9EE5A26b130a5796d6); // swETH + assertEq(address(c.strategies.strategyAddresses[8]), 0x7CA911E83dabf90C90dD3De5411a10F1A6112184); // wBETH + assertEq(address(c.strategies.strategyAddresses[9]), 0x8CA7A5d6f3acd3A7A8bC468a8CD0FB14B6BD28b6); // sfrxETH + assertEq(address(c.strategies.strategyAddresses[10]), 0xAe60d8180437b5C34bB956822ac2710972584473); // lsETH + assertEq(address(c.strategies.strategyAddresses[11]), 0x298aFB19A105D59E74658C4C334Ff360BadE6dd2); // mETH + } +} diff --git a/src/test/integration/IntegrationBase.t.sol b/src/test/integration/IntegrationBase.t.sol index 5b768f7ae4..56ce7a8877 100644 --- a/src/test/integration/IntegrationBase.t.sol +++ b/src/test/integration/IntegrationBase.t.sol @@ -4,195 +4,27 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; 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/TypeImporter.t.sol"; -import "src/test/integration/IntegrationDeployer.t.sol"; -import "src/test/integration/TimeMachine.t.sol"; +import "src/test/integration/IntegrationGetters.t.sol"; import "src/test/integration/users/User.t.sol"; import "src/test/integration/users/User_M1.t.sol"; -abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { - using StdStyle for *; - using SlashingLib for *; - using Math for uint; - using Strings for *; - using print for *; - +abstract contract IntegrationBase is IntegrationGetters { using ArrayLib for *; + using Math for *; + using SlashingLib for *; + using StdStyle for *; - uint numStakers = 0; - uint numOperators = 0; - uint numAVSs = 0; - - // Lists of operators created before the m2 (not slashing) upgrade - // - // When we call _upgradeEigenLayerContracts, we iterate over - // these lists and migrate perform the standard migration actions - // for each user - User[] operatorsToMigrate; - User[] stakersToMigrate; - - /** - * Gen/Init methods: - */ - - /** - * @dev Create a new user according to configured random variants. - * This user is ready to deposit into some strategies and has some underlying token balances - */ - function _newRandomStaker() internal returns (User, IStrategy[] memory, uint[] memory) { - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _randUser(_getStakerName()); - - if (!isUpgraded) stakersToMigrate.push(staker); - - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "_newRandomStaker: failed to award token balances"); - return (staker, strategies, tokenBalances); - } - - /// Given a list of strategies, creates a new user with random token balances in each underlying token - function _newStaker(IStrategy[] memory strategies) internal returns (User, uint[] memory) { - (User staker, uint[] memory tokenBalances) = _randUser(_getStakerName(), strategies); - - if (!isUpgraded) stakersToMigrate.push(staker); - - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "_newStaker: failed to award token balances"); - return (staker, tokenBalances); - } - - /** - * @dev Create a new operator according to configured random variants. - * This user will immediately deposit their randomized assets into eigenlayer. - */ - function _newRandomOperator() internal returns (User, IStrategy[] memory, uint[] memory) { - /// TODO: Allow operators to have ETH - (User operator, IStrategy[] memory strategies, uint[] memory tokenBalances) = _randUser_NoETH(_getOperatorName()); - - /// Operators are created with all assets already deposited - uint[] memory addedShares = _calculateExpectedShares(strategies, tokenBalances); - operator.depositIntoEigenlayer(strategies, tokenBalances); - - /// Registration flow differs for M2 vs Slashing release - if (!isUpgraded) { - User_M2(payable(operator)).registerAsOperator_M2(); - - operatorsToMigrate.push(operator); - } else { - operator.registerAsOperator(); - - rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); - } - - assert_Snap_Added_OperatorShares(operator, strategies, addedShares, "_newRandomOperator: failed to award shares to operator"); - assertTrue(delegationManager.isOperator(address(operator)), "_newRandomOperator: operator should be registered"); - assertEq(delegationManager.delegatedTo(address(operator)), address(operator), "_newRandomOperator: should be self-delegated"); - return (operator, strategies, tokenBalances); - } - - /// @dev Creates a new operator with no assets - function _newRandomOperator_NoAssets() internal returns (User) { - User operator = _randUser_NoAssets(_getOperatorName()); - - /// Registration flow differs for M2 vs Slashing release - if (!isUpgraded) { - User_M2(payable(operator)).registerAsOperator_M2(); - - operatorsToMigrate.push(operator); - } else { - operator.registerAsOperator(); - - rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); - } - - assertTrue(delegationManager.isOperator(address(operator)), "_newRandomOperator: operator should be registered"); - assertEq(delegationManager.delegatedTo(address(operator)), address(operator), "_newRandomOperator: should be self-delegated"); - return operator; - } - - /// @dev Name a newly-created staker ("staker1", "staker2", ...) - function _getStakerName() private returns (string memory) { - numStakers++; - - string memory stakerNum = cheats.toString(numStakers); - string memory namePrefix = isUpgraded ? "staker" : "m2-staker"; - - return string.concat(namePrefix, stakerNum); - } - - /// @dev Name a newly-created operator ("operator1", "operator2", ...) - function _getOperatorName() private returns (string memory) { - numOperators++; - - string memory operatorNum = cheats.toString(numOperators); - string memory namePrefix = isUpgraded ? "operator" : "m2-operator"; - - return string.concat(namePrefix, operatorNum); - } - - function _newRandomAVS() internal returns (AVS avs, OperatorSet[] memory operatorSets) { - string memory avsName = string.concat("avs", numAVSs.toString()); - avs = _genRandAVS(avsName); - avs.updateAVSMetadataURI("https://example.com"); - 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. - /// - /// Total sent == `gweiSent + remainderSent` - function _sendRandomETH(address destination) internal returns (uint64 gweiSent, uint remainderSent) { - gweiSent = uint64(_randUint({min: 1, max: 10})); - remainderSent = _randUint({min: 1, max: 100}); - uint totalSent = (gweiSent * GWEI_TO_WEI) + remainderSent; - - cheats.deal(address(this), address(this).balance + totalSent); - bool r; - bytes memory d; - (r, d) = destination.call{value: totalSent}(""); - - return (gweiSent, remainderSent); - } - - /// @dev Choose a random subset of validators (selects AT LEAST ONE) - function _choose(uint40[] memory validators) internal returns (uint40[] memory) { - uint _rand = _randUint({min: 1, max: (2 ** validators.length) - 1}); - - uint40[] memory result = new uint40[](validators.length); - uint newLen; - for (uint i = 0; i < validators.length; i++) { - // if bit set, add validator - if (_rand >> i & 1 == 1) { - result[newLen] = validators[i]; - newLen++; - } - } - - // Manually update length of result - assembly { - mstore(result, newLen) - } - - 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 view { - (IStrategy[] memory strategies, uint[] memory shares) = delegationManager.getDepositedShares(address(user)); - + (IStrategy[] memory strategies, uint[] memory shares) = delegationManager().getDepositedShares(address(user)); assertEq(strategies.length, 0, err); assertEq(strategies.length, shares.length, "assert_HasNoDelegatableShares: return length mismatch"); } @@ -203,12 +35,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - uint expectedBalance = expectedBalances[i]; - uint tokenBalance; - if (strat == BEACONCHAIN_ETH_STRAT) tokenBalance = address(user).balance; - else tokenBalance = strat.underlyingToken().balanceOf(address(user)); - + uint tokenBalance = strat == BEACONCHAIN_ETH_STRAT ? address(user).balance : strat.underlyingToken().balanceOf(address(user)); assertApproxEqAbs(expectedBalance, tokenBalance, 1, err); } } @@ -244,24 +72,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } } - function assert_HasOperatorShares(User user, IStrategy[] memory strategies, uint[] memory expectedShares, string memory err) - internal - view - { - for (uint i = 0; i < strategies.length; i++) { - uint actualShares = delegationManager.operatorShares(address(user), strategies[i]); - assertEq(expectedShares[i], actualShares, err); - } - } - - /// @dev Asserts that ALL of the `withdrawalRoots` is in `delegationManager.pendingWithdrawals` + /// @dev Asserts that ALL of the `withdrawalRoots` is in `delegationManager().pendingWithdrawals` 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` + /// @dev Asserts that NONE of the `withdrawalRoots` is in `delegationManager().pendingWithdrawals` function assert_NoWithdrawalsPending(bytes32[] memory withdrawalRoots, string memory err) internal view { for (uint i = 0; i < withdrawalRoots.length; i++) { assert_WithdrawalNotPending(withdrawalRoots[i], err); @@ -270,11 +88,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { /// @dev Asserts that the hash of each withdrawal corresponds to the provided withdrawal root function assert_WithdrawalPending(bytes32 withdrawalRoot, string memory err) internal view { - assertTrue(delegationManager.pendingWithdrawals(withdrawalRoot), err); + assertTrue(delegationManager().pendingWithdrawals(withdrawalRoot), err); } function assert_WithdrawalNotPending(bytes32 withdrawalRoot, string memory err) internal view { - assertFalse(delegationManager.pendingWithdrawals(withdrawalRoot), err); + assertFalse(delegationManager().pendingWithdrawals(withdrawalRoot), err); } function assert_ValidWithdrawalHashes(Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots, string memory err) @@ -287,7 +105,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } function assert_ValidWithdrawalHash(Withdrawal memory withdrawal, bytes32 withdrawalRoot, string memory err) internal view { - assertEq(withdrawalRoot, delegationManager.calculateWithdrawalRoot(withdrawal), err); + assertEq(withdrawalRoot, delegationManager().calculateWithdrawalRoot(withdrawal), err); } function assert_StakerStrategyListEmpty(User staker, string memory err) internal view { @@ -298,7 +116,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_StrategyNotInStakerStrategyList(User staker, IStrategy strategy, string memory err) internal view { // BEACONCHAIN_ETH_STRAT is not in the staker's strategy list if (strategy == BEACONCHAIN_ETH_STRAT) return; - IStrategy[] memory strategies = _getStakerStrategyList(staker); assertFalse(strategies.contains(strategy), err); } @@ -312,7 +129,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_StrategyInStakerStrategyList(User staker, IStrategy strategy, string memory err) internal view { // BEACONCHAIN_ETH_STRAT is not in the staker's strategy list if (strategy == BEACONCHAIN_ETH_STRAT) return; - IStrategy[] memory strategies = _getStakerStrategyList(staker); assertTrue(strategies.contains(strategy), err); } @@ -336,7 +152,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_MaxEqualsAllocatablePlusEncumbered(User operator, string memory err) internal view { Magnitudes[] memory mags = _getMagnitudes(operator, allStrats); - for (uint i = 0; i < allStrats.length; i++) { Magnitudes memory m = mags[i]; assertEq(m.max, m.encumbered + m.allocatable, err); @@ -349,26 +164,19 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { IStrategy[] memory strategies, string memory err ) internal view { - uint[] memory minSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - uint[] memory minAllocatedStake = _getAllocatedStake(operator, operatorSet, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(minSlashableStake[i], minAllocatedStake[i], err); - } + assertEq(_getMinSlashableStake(operator, operatorSet, strategies), _getAllocatedStake(operator, operatorSet, strategies), err); } function assert_MaxMagsEqualMaxMagsAtCurrentBlock(User operator, IStrategy[] memory strategies, string memory err) internal view { - uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, strategies); - uint64[] memory maxAtCurrentBlock = _getMaxMagnitudes(operator, strategies, uint32(block.number)); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(maxMagnitudes[i], maxAtCurrentBlock[i], err); - } + assertEq( + _getMaxMagnitudes(operator, strategies).toUintArray(), + _getMaxMagnitudes(operator, strategies, uint32(block.number)).toUintArray(), + err + ); } function assert_CurrentMagnitude(User operator, AllocateParams memory params, string memory err) internal view { Allocation[] memory allocations = _getAllocations(operator, params.operatorSet, params.strategies); - for (uint i = 0; i < allocations.length; i++) { assertEq(allocations[i].currentMagnitude, params.newMagnitudes[i], err); } @@ -379,7 +187,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { view { Allocation[] memory allocations = _getAllocations(operator, operatorSet, strategies); - for (uint i = 0; i < allocations.length; i++) { assertEq(0, allocations[i].effectBlock, err); } @@ -388,7 +195,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_HasPendingIncrease(User operator, AllocateParams memory params, string memory err) internal view { uint32 delay = _getExistingAllocationDelay(operator); Allocation[] memory allocations = _getAllocations(operator, params.operatorSet, params.strategies); - for (uint i = 0; i < allocations.length; i++) { assertEq(allocations[i].effectBlock, uint32(block.number) + delay, err); assertTrue(allocations[i].currentMagnitude != params.newMagnitudes[i], err); @@ -397,9 +203,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } function assert_HasPendingDecrease(User operator, AllocateParams memory params, string memory err) internal view { - uint32 deallocationDelay = allocationManager.DEALLOCATION_DELAY(); + uint32 deallocationDelay = allocationManager().DEALLOCATION_DELAY(); Allocation[] memory allocations = _getAllocations(operator, params.operatorSet, params.strategies); - for (uint i = 0; i < allocations.length; i++) { assertEq(allocations[i].effectBlock, uint32(block.number) + deallocationDelay + 1, err); assertTrue(allocations[i].currentMagnitude != params.newMagnitudes[i], err); @@ -407,32 +212,23 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } } - function assert_IsRegistered(User operator, OperatorSet memory operatorSet, string memory err) internal view { - assertTrue(allocationManager.isMemberOfOperatorSet(address(operator), operatorSet), err); - } - function assert_IsSlashable(User operator, OperatorSet memory operatorSet, string memory err) internal view { - assertTrue(allocationManager.isOperatorSlashable(address(operator), operatorSet), err); + assertTrue(allocationManager().isOperatorSlashable(address(operator), operatorSet), err); } function assert_NotSlashable(User operator, OperatorSet memory operatorSet, string memory err) internal view { - assertFalse(allocationManager.isOperatorSlashable(address(operator), operatorSet), err); + assertFalse(allocationManager().isOperatorSlashable(address(operator), operatorSet), err); } function assert_IsAllocatedToSet(User operator, OperatorSet memory operatorSet, string memory err) internal view { - assertTrue(allocationManager.getAllocatedSets(address(operator)).contains(operatorSet), err); - } - - function assert_IsNotAllocated(User operator, OperatorSet memory operatorSet, string memory err) internal view { - assertEq(allocationManager.getAllocatedStrategies(address(operator), operatorSet).length, 0, err); + assertTrue(allocationManager().getAllocatedSets(address(operator)).contains(operatorSet), err); } function assert_IsAllocatedToSetStrats(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies, string memory err) internal view { - IStrategy[] memory allocatedStrategies = allocationManager.getAllocatedStrategies(address(operator), operatorSet); - + IStrategy[] memory allocatedStrategies = allocationManager().getAllocatedStrategies(address(operator), operatorSet); for (uint i = 0; i < strategies.length; i++) { assertTrue(allocatedStrategies.contains(strategies[i]), err); } @@ -442,11 +238,9 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { OperatorSet memory operatorSet = params.operatorSet; IStrategy[] memory strategies = params.strategies; uint64[] memory curMagnitudes = params.newMagnitudes; - uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, params.strategies); uint[] memory operatorShares = _getOperatorShares(operator, params.strategies); uint[] memory allocatedStake = _getAllocatedStake(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { uint expectedAllocated; if (maxMagnitudes[i] == 0) { @@ -455,7 +249,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint slashableProportion = uint(curMagnitudes[i]).divWad(maxMagnitudes[i]); expectedAllocated = operatorShares[i].mulWad(slashableProportion); } - assertEq(expectedAllocated, allocatedStake[i], err); } } @@ -464,11 +257,9 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { OperatorSet memory operatorSet = params.operatorSet; IStrategy[] memory strategies = params.strategies; uint64[] memory curMagnitudes = params.newMagnitudes; - uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, params.strategies); uint[] memory operatorShares = _getOperatorShares(operator, params.strategies); uint[] memory slashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { uint expectedSlashable; if (maxMagnitudes[i] == 0) { @@ -477,15 +268,13 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint slashableProportion = uint(curMagnitudes[i]).divWad(maxMagnitudes[i]); expectedSlashable = operatorShares[i].mulWad(slashableProportion); } - assertEq(expectedSlashable, slashableStake[i], err); } } function assert_NoSlashableStake(User operator, OperatorSet memory operatorSet, string memory err) internal view { - IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); + IStrategy[] memory strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); uint[] memory slashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - for (uint i = 0; i < slashableStake.length; i++) { assertEq(slashableStake[i], 0, err); } @@ -563,7 +352,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Became_Registered(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsMemberOfSet = _getIsMemberOfSet(operator, operatorSet); bool prevIsMemberOfSet = _getPrevIsMemberOfSet(operator, operatorSet); - assertFalse(prevIsMemberOfSet, err); assertTrue(curIsMemberOfSet, err); } @@ -571,7 +359,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Became_Deregistered(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsMemberOfSet = _getIsMemberOfSet(operator, operatorSet); bool prevIsMemberOfSet = _getPrevIsMemberOfSet(operator, operatorSet); - assertTrue(prevIsMemberOfSet, err); assertFalse(curIsMemberOfSet, err); } @@ -579,14 +366,12 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Unchanged_Registration(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsMemberOfSet = _getIsMemberOfSet(operator, operatorSet); bool prevIsMemberOfSet = _getPrevIsMemberOfSet(operator, operatorSet); - assertEq(prevIsMemberOfSet, curIsMemberOfSet, err); } function assert_Snap_Became_Slashable(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsSlashable = _getIsSlashable(operator, operatorSet); bool prevIsSlashable = _getPrevIsSlashable(operator, operatorSet); - assertFalse(prevIsSlashable, err); assertTrue(curIsSlashable, err); } @@ -594,7 +379,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Remains_Slashable(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsSlashable = _getIsSlashable(operator, operatorSet); bool prevIsSlashable = _getPrevIsSlashable(operator, operatorSet); - assertTrue(prevIsSlashable, err); assertTrue(curIsSlashable, err); } @@ -602,19 +386,15 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Unchanged_Slashability(User operator, OperatorSet memory operatorSet, string memory err) internal { bool curIsSlashable = _getIsSlashable(operator, operatorSet); bool prevIsSlashable = _getPrevIsSlashable(operator, operatorSet); - assertEq(prevIsSlashable, curIsSlashable, err); } function assert_Snap_Unchanged_AllocatedStrats(User operator, OperatorSet memory operatorSet, string memory err) internal { - IStrategy[] memory curAllocatedStrats = _getAllocatedStrats(operator, operatorSet); - IStrategy[] memory prevAllocatedStrats = _getPrevAllocatedStrats(operator, operatorSet); - - assertEq(curAllocatedStrats.length, prevAllocatedStrats.length, err); - - for (uint i = 0; i < curAllocatedStrats.length; i++) { - assertEq(address(curAllocatedStrats[i]), address(prevAllocatedStrats[i]), err); - } + assertEq( + _getAllocatedStrats(operator, operatorSet).toAddressArray(), + _getPrevAllocatedStrats(operator, operatorSet).toAddressArray(), + err + ); } function assert_Snap_Removed_AllocatedStrats( @@ -625,9 +405,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { IStrategy[] memory curAllocatedStrats = _getAllocatedStrats(operator, operatorSet); IStrategy[] memory prevAllocatedStrats = _getPrevAllocatedStrats(operator, operatorSet); - assertEq(curAllocatedStrats.length + removedStrats.length, prevAllocatedStrats.length, err); - for (uint i = 0; i < removedStrats.length; i++) { assertFalse(curAllocatedStrats.contains(removedStrats[i]), err); } @@ -641,37 +419,24 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { Allocation[] memory curAllocations = _getAllocations(operator, operatorSet, strategies); Allocation[] memory prevAllocations = _getPrevAllocations(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { Allocation memory curAllocation = curAllocations[i]; Allocation memory prevAllocation = prevAllocations[i]; - assertEq(curAllocation.currentMagnitude, prevAllocation.currentMagnitude, err); assertEq(curAllocation.pendingDiff, prevAllocation.pendingDiff, err); assertEq(curAllocation.effectBlock, prevAllocation.effectBlock, err); } } - function assert_Snap_Added_AllocatedSet(User operator, OperatorSet memory operatorSet, string memory err) internal { - OperatorSet[] memory curAllocatedSets = _getAllocatedSets(operator); - OperatorSet[] memory prevAllocatedSets = _getPrevAllocatedSets(operator); - - assertEq(curAllocatedSets.length, prevAllocatedSets.length + 1, err); - assertFalse(prevAllocatedSets.contains(operatorSet), err); - assertTrue(curAllocatedSets.contains(operatorSet), err); - } - function assert_Snap_Unchanged_AllocatedSets(User operator, string memory err) internal { OperatorSet[] memory curAllocatedSets = _getAllocatedSets(operator); OperatorSet[] memory prevAllocatedSets = _getPrevAllocatedSets(operator); - assertEq(curAllocatedSets.length, prevAllocatedSets.length, err); } function assert_Snap_Removed_AllocatedSet(User operator, OperatorSet memory operatorSet, string memory err) internal { OperatorSet[] memory curAllocatedSets = _getAllocatedSets(operator); OperatorSet[] memory prevAllocatedSets = _getPrevAllocatedSets(operator); - assertEq(curAllocatedSets.length + 1, prevAllocatedSets.length, err); assertTrue(prevAllocatedSets.contains(operatorSet), err); assertFalse(curAllocatedSets.contains(operatorSet), err); @@ -680,7 +445,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Added_RegisteredSet(User operator, OperatorSet memory operatorSet, string memory err) internal { OperatorSet[] memory curRegisteredSets = _getRegisteredSets(operator); OperatorSet[] memory prevRegisteredSets = _getPrevRegisteredSets(operator); - assertEq(curRegisteredSets.length, prevRegisteredSets.length + 1, err); assertFalse(prevRegisteredSets.contains(operatorSet), err); assertTrue(curRegisteredSets.contains(operatorSet), err); @@ -689,7 +453,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Removed_RegisteredSet(User operator, OperatorSet memory operatorSet, string memory err) internal { OperatorSet[] memory curRegisteredSets = _getRegisteredSets(operator); OperatorSet[] memory prevRegisteredSets = _getPrevRegisteredSets(operator); - assertEq(curRegisteredSets.length + 1, prevRegisteredSets.length, err); assertTrue(prevRegisteredSets.contains(operatorSet), err); assertFalse(curRegisteredSets.contains(operatorSet), err); @@ -698,7 +461,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Unchanged_RegisteredSet(User operator, string memory err) internal { OperatorSet[] memory curRegisteredSets = _getRegisteredSets(operator); OperatorSet[] memory prevRegisteredSets = _getPrevRegisteredSets(operator); - assertEq(curRegisteredSets.length, prevRegisteredSets.length, err); for (uint i = 0; i < curRegisteredSets.length; i++) { assertEq(curRegisteredSets[i].avs, prevRegisteredSets[i].avs, err); @@ -709,7 +471,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Added_MemberOfSet(User operator, OperatorSet memory operatorSet, string memory err) internal { address[] memory curOperators = _getMembers(operatorSet); address[] memory prevOperators = _getPrevMembers(operatorSet); - assertEq(curOperators.length, prevOperators.length + 1, err); assertFalse(prevOperators.contains(address(operator)), err); assertTrue(curOperators.contains(address(operator)), err); @@ -718,20 +479,13 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Removed_MemberOfSet(User operator, OperatorSet memory operatorSet, string memory err) internal { address[] memory curOperators = _getMembers(operatorSet); address[] memory prevOperators = _getPrevMembers(operatorSet); - assertEq(curOperators.length + 1, prevOperators.length, err); assertTrue(prevOperators.contains(address(operator)), err); assertFalse(curOperators.contains(address(operator)), err); } function assert_Snap_Unchanged_MemberOfSet(OperatorSet memory operatorSet, string memory err) internal { - address[] memory curOperators = _getMembers(operatorSet); - address[] memory prevOperators = _getPrevMembers(operatorSet); - - assertEq(curOperators.length, prevOperators.length, err); - for (uint i = 0; i < curOperators.length; i++) { - assertEq(curOperators[i], prevOperators[i], err); - } + assertEq(_getMembers(operatorSet), _getPrevMembers(operatorSet), err); } function assert_Snap_StakeBecameSlashable( @@ -742,7 +496,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { assertTrue(prevSlashableStake[i] < curSlashableStake[i], err); } @@ -756,55 +509,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curSlashableStake = _getMinSlashableStake(address(operator), operatorSet, strategies); uint[] memory prevSlashableStake = _getPrevMinSlashableStake(address(operator), operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { assertTrue(prevSlashableStake[i] > curSlashableStake[i], err); assertTrue(prevSlashableStake[i] > curSlashableStake[i], err); } } - function assert_Snap_Added_SlashableStake( - User operator, - OperatorSet memory operatorSet, - IStrategy[] memory strategies, - uint[] memory slashableShares, - string memory err - ) internal { - uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(curSlashableStake[i], prevSlashableStake[i] + slashableShares[i], err); - } - } - function assert_Snap_Unchanged_SlashableStake( User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies, string memory err ) internal { - uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(curSlashableStake[i], prevSlashableStake[i], err); - } - } - - function assert_Snap_Removed_SlashableStake( - User operator, - OperatorSet memory operatorSet, - IStrategy[] memory strategies, - uint[] memory removedSlashableShares, - string memory err - ) internal { - uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); - uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(curSlashableStake[i] + removedSlashableShares[i], prevSlashableStake[i], err); - } + assertEq( + _getMinSlashableStake(operator, operatorSet, strategies), _getPrevMinSlashableStake(operator, operatorSet, strategies), err + ); } function assert_Snap_Slashed_SlashableStake( @@ -815,10 +534,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, params.strategies); uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, params.strategies); - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { // Slashing doesn't occur if the operator has no slashable magnitude // This prevents a div by 0 when calculating expected slashed @@ -829,13 +546,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { prevMaxMagnitude: prevMagnitudes[i].max, newMaxMagnitude: curMagnitudes[i].max }); - assertEq(curSlashableStake[i], prevSlashableStake[i] - expectedSlashed, err); } } - //@dev requires slashparams strategies to be same as withdrawal strategies - // meant to be used in check_base_slashing_state + /// @dev requires slashparams strategies to be same as withdrawal strategies meant to be used in check_base_slashing_state function assert_Snap_Decreased_SlashableSharesInQueue( User operator, SlashingParams memory slashParams, @@ -845,14 +560,12 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { IStrategy[] memory strategies = slashParams.strategies; uint[] memory curSlashableSharesInQueue = _getSlashableSharesInQueue(operator, strategies); uint[] memory prevSlashableSharesInQueue = _getPrevSlashableSharesInQueue(operator, strategies); - uint[] memory totalScaledShares = new uint[](strategies.length); for (uint i = 0; i < withdrawals.length; i++) { for (uint j = 0; j < withdrawals[i].strategies.length; j++) { totalScaledShares[j] = totalScaledShares[j] + withdrawals[i].scaledShares[j]; } } - for (uint i = 0; i < strategies.length; i++) { assertEq( curSlashableSharesInQueue[i], prevSlashableSharesInQueue[i] - totalScaledShares[i].mulWad(slashParams.wadsToSlash[i]), err @@ -868,7 +581,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { curSlashableSharesInQueue = _getSlashableSharesInQueue(operator, withdrawals[i].strategies); prevSlashableSharesInQueue = _getPrevSlashableSharesInQueue(operator, withdrawals[i].strategies); maxMagnitudes = _getMaxMagnitudes(operator, withdrawals[i].strategies); - for (uint j = 0; j < withdrawals[i].strategies.length; j++) { assertEq( curSlashableSharesInQueue[j], @@ -887,7 +599,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curMinAllocatedStake = _getAllocatedStake(operator, operatorSet, strategies); uint[] memory prevMinAllocatedStake = _getPrevAllocatedStake(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { assertGt(curMinAllocatedStake[i], prevMinAllocatedStake[i], err); } @@ -901,7 +612,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curMinAllocatedStake = _getAllocatedStake(operator, operatorSet, strategies); uint[] memory prevMinAllocatedStake = _getPrevAllocatedStake(operator, operatorSet, strategies); - for (uint i = 0; i < strategies.length; i++) { assertLt(curMinAllocatedStake[i], prevMinAllocatedStake[i], err); } @@ -913,12 +623,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { IStrategy[] memory strategies, string memory err ) internal { - uint[] memory curAllocatedStake = _getAllocatedStake(operator, operatorSet, strategies); - uint[] memory prevAllocatedStake = _getPrevAllocatedStake(operator, operatorSet, strategies); - - for (uint i = 0; i < curAllocatedStake.length; i++) { - assertEq(curAllocatedStake[i], prevAllocatedStake[i], err); - } + assertEq(_getAllocatedStake(operator, operatorSet, strategies), _getPrevAllocatedStake(operator, operatorSet, strategies), err); } function assert_Snap_Slashed_AllocatedStake( @@ -929,10 +634,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curAllocatedStake = _getAllocatedStake(operator, operatorSet, params.strategies); uint[] memory prevAllocatedStake = _getPrevAllocatedStake(operator, operatorSet, params.strategies); - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies); - for (uint i = 0; i < curAllocatedStake.length; i++) { // Slashing doesn't occur if the operator has no slashable magnitude // This prevents a div by 0 when calculating expected slashed @@ -943,29 +646,13 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { prevMaxMagnitude: prevMagnitudes[i].max, newMaxMagnitude: curMagnitudes[i].max }); - assertEq(curAllocatedStake[i], prevAllocatedStake[i] - expectedSlashed, err); } } - function assert_Snap_Added_EncumberedMagnitude( - User operator, - IStrategy[] memory strategies, - uint64[] memory magnitudeAdded, - string memory err - ) internal { - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); - Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(curMagnitudes[i].encumbered, prevMagnitudes[i].encumbered + magnitudeAdded[i], err); - } - } - function assert_Snap_Unchanged_EncumberedMagnitude(User operator, IStrategy[] memory strategies, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { assertEq(curMagnitudes[i].encumbered, prevMagnitudes[i].encumbered, err); } @@ -979,7 +666,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { assertEq(curMagnitudes[i].encumbered + magnitudeRemoved[i], prevMagnitudes[i].encumbered, err); } @@ -988,7 +674,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Slashed_EncumberedMagnitude(User operator, SlashingParams memory params, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { uint expectedSlashed = prevMagnitudes[i].encumbered.mulWadRoundUp(params.wadsToSlash[i]); assertEq(curMagnitudes[i].encumbered, prevMagnitudes[i].encumbered - expectedSlashed, err); @@ -1003,7 +688,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { assertEq(curMagnitudes[i].allocatable, prevMagnitudes[i].allocatable + magnitudeFreed[i], err); } @@ -1012,30 +696,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Unchanged_AllocatableMagnitude(User operator, IStrategy[] memory strategies, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { assertEq(curMagnitudes[i].allocatable, prevMagnitudes[i].allocatable, err); } } - function assert_Snap_Removed_AllocatableMagnitude( - User operator, - IStrategy[] memory strategies, - uint64[] memory magnitudeRemoved, - string memory err - ) internal { - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); - Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(curMagnitudes[i].allocatable, prevMagnitudes[i].allocatable - magnitudeRemoved[i], err); - } - } - function assert_Snap_Allocated_Magnitude(User operator, IStrategy[] memory strategies, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - /// Check: /// allocatable increased /// encumbered decreased @@ -1048,7 +716,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Deallocated_Magnitude(User operator, IStrategy[] memory strategies, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - /// Check: /// allocatable increased /// encumbered decreased @@ -1061,7 +728,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Set_CurrentMagnitude(User operator, AllocateParams memory params, string memory err) internal { Allocation[] memory curAllocations = _getAllocations(operator, params.operatorSet, params.strategies); Allocation[] memory prevAllocations = _getPrevAllocations(operator, params.operatorSet, params.strategies); - /// Prev allocation.currentMagnitude should NOT equal newly-set magnitude /// Cur allocation.currentMagnitude SHOULD for (uint i = 0; i < params.strategies.length; i++) { @@ -1075,7 +741,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { { Allocation[] memory curAllocations = _getAllocations(operator, operatorSet, params.strategies); Allocation[] memory prevAllocations = _getPrevAllocations(operator, operatorSet, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { uint expectedSlashed = prevAllocations[i].currentMagnitude.mulWadRoundUp(params.wadsToSlash[i]); assertEq(curAllocations[i].currentMagnitude, prevAllocations[i].currentMagnitude - expectedSlashed, err); @@ -1085,7 +750,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Unchanged_MaxMagnitude(User operator, IStrategy[] memory strategies, string memory err) internal { Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { assertEq(curMagnitudes[i].max, prevMagnitudes[i].max, err); } @@ -1098,10 +762,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { string memory err ) internal { Allocation[] memory prevAllocations = _getPrevAllocations(operator, operatorSet, params.strategies); - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { uint expectedSlashed = prevAllocations[i].currentMagnitude.mulWadRoundUp(params.wadsToSlash[i]); assertEq(curMagnitudes[i].max, prevMagnitudes[i].max - expectedSlashed, err); @@ -1115,23 +777,17 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { string memory err ) internal { User op = User(payable(slashingParams.operator)); - Allocation[] memory curAllocs = _getAllocations(op, operatorSet, slashingParams.strategies); Allocation[] memory prevAllocs = _getPrevAllocations(op, operatorSet, slashingParams.strategies); Magnitudes[] memory curMagnitudes = _getMagnitudes(op, slashingParams.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(op, slashingParams.strategies); - uint32 delay = _getExistingAllocationDelay(User(payable(slashingParams.operator))); - for (uint i = 0; i < slashingParams.strategies.length; i++) { Allocation memory curAlloc = curAllocs[i]; Allocation memory prevAlloc = prevAllocs[i]; - uint64 slashedMagnitude = uint64(uint(prevAlloc.currentMagnitude).mulWadRoundUp(slashingParams.wadsToSlash[i])); - // Check Allocations assertEq(curAlloc.currentMagnitude, prevAlloc.currentMagnitude - slashedMagnitude, string.concat(err, " (currentMagnitude)")); - if (completed) { assertEq(curAlloc.pendingDiff, 0, string.concat(err, " (pendingDiff)")); assertEq(curAlloc.effectBlock, 0, string.concat(err, " (effectBlock)")); @@ -1139,29 +795,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { assertEq( curAlloc.currentMagnitude, prevAlloc.currentMagnitude - slashedMagnitude, string.concat(err, " (currentMagnitude)") ); - // If (isDeallocation) ... if (prevAlloc.pendingDiff < 0) { uint64 slashedPending = uint64(uint(uint128(-prevAlloc.pendingDiff)).mulWadRoundUp(slashingParams.wadsToSlash[i])); - assertEq( curAlloc.pendingDiff, prevAlloc.pendingDiff + int128(uint128(slashedPending)), string.concat(err, " (pendingDiff)") ); - delay = DEALLOCATION_DELAY + 1; } - assertEq(curAlloc.effectBlock, block.number + delay, string.concat(err, " (effectBlock)")); } - // Check Magnitudes Magnitudes memory curMagnitude = curMagnitudes[i]; Magnitudes memory prevMagnitude = prevMagnitudes[i]; - assertEq(curMagnitude.encumbered, prevMagnitude.encumbered - slashedMagnitude, string.concat(err, " (encumbered magnitude)")); - assertEq(curMagnitude.allocatable, prevMagnitude.allocatable, string.concat(err, " (allocatable magnitude)")); - assertEq(curMagnitude.max, prevMagnitude.max - slashedMagnitude, string.concat(err, " (max magnitude)")); } } @@ -1174,17 +822,13 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { uint[] memory curShares = _getWithdrawableShares(staker, allocateParams.strategies); uint[] memory prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies); - for (uint i = 0; i < allocateParams.strategies.length; i++) { IStrategy strat = allocateParams.strategies[i]; - uint slashedShares = 0; - if (slashingParams.strategies.contains(strat)) { uint wadToSlash = slashingParams.wadsToSlash[slashingParams.strategies.indexOf(strat)]; slashedShares = prevShares[i].mulWadRoundUp(allocateParams.newMagnitudes[i].mulWadRoundUp(wadToSlash)); } - assertApproxEqAbs(prevShares[i] - slashedShares, curShares[i], 1, err); } } @@ -1206,16 +850,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { require(allocateParams.strategies.length == 1 && slashingParams.strategies.length == 1, "only beacon strategy supported"); require(allocateParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - require(slashingParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - uint curShares = _getWithdrawableShares(staker, allocateParams.strategies)[0]; uint prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies)[0]; - uint slashedShares = 0; - uint wadToSlash = slashingParams.wadsToSlash[0]; slashedShares = prevShares.mulWadRoundUp(allocateParams.newMagnitudes[0].mulWadRoundUp(wadToSlash)); - assertApproxEqAbs(prevShares - slashedShares, curShares, 1e2, err); } @@ -1228,19 +867,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { require(allocateParams.strategies.length == 1 && slashingParams.strategies.length == 1, "only beacon strategy supported"); require(allocateParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - require(slashingParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - uint curShares = _getWithdrawableShares(staker, allocateParams.strategies)[0]; uint prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies)[0]; uint depositShares = _getStakerDepositShares(staker, allocateParams.strategies)[0]; - - // 1. The slashing factor and withdrawable shares should decrease by a factor of the BCSF - // We use assertApproxEq on shares since intermediate division on calculation of slashing factor introduces some additional rounding error - uint slashingFactor = _getSlashingFactor(staker, allocateParams.strategies[0]); - uint prevSlashingFactor = _getPrevSlashingFactor(staker, allocateParams.strategies[0]); - assertEq(prevSlashingFactor.mulWad(_getBeaconChainSlashingFactor(staker)), slashingFactor, err); + // 1. The withdrawable shares should decrease by a factor of the BCSF assertApproxEqAbs(prevShares.mulWad(_getBeaconChainSlashingFactor(staker)), curShares, 1e2, err); - /** * 2. The delta in shares is given by: * (depositShares * operatorMag) - (depositShares * operatorMag * BCSF) @@ -1249,11 +880,9 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint beaconChainSlashingFactor = _getBeaconChainSlashingFactor(staker); uint wadToSlash = slashingParams.wadsToSlash[0]; uint originalAVSSlashedShares = depositShares.mulWadRoundUp(allocateParams.newMagnitudes[0].mulWadRoundUp(wadToSlash)); - { - uint withdrawableSharesAfterAVSSlash = depositShares - originalAVSSlashedShares; - uint expectedDelta = withdrawableSharesAfterAVSSlash.mulWad(WAD - beaconChainSlashingFactor); - assertApproxEqAbs(prevShares - expectedDelta, curShares, 1e2, err); - } + uint withdrawableSharesAfterAVSSlash = depositShares - originalAVSSlashedShares; + uint expectedDelta = withdrawableSharesAfterAVSSlash.mulWad(WAD - beaconChainSlashingFactor); + assertApproxEqAbs(prevShares - expectedDelta, curShares, 1e2, err); /** * 3. The attributable avs slashed shares should decrease by a factor of the BCSF @@ -1280,14 +909,10 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { ) internal { require(allocateParams.strategies.length == 1 && slashingParams.strategies.length == 1, "only beacon strategy supported"); require(allocateParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - require(slashingParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported"); - uint curShares = _getWithdrawableShares(staker, allocateParams.strategies)[0]; uint prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies)[0]; - // 1. The withdrawable shares should decrease by a factor of the BCSF assertApproxEqAbs(prevShares.mulWad(_getBeaconChainSlashingFactor(staker)), curShares, 1e5, err); - /** * 2. The delta in shares is given by: * (originalWithdrawableShares * operatorMag) + extraValidatorShares - (depositShares * operatorMag * BCSF * dsf) @@ -1298,7 +923,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint withdrawableSharesAfterValidatorProven = originalWithdrawableShares - originalAVSSlashedShares + extraValidatorShares; uint expectedDelta = withdrawableSharesAfterValidatorProven.mulWad(WAD - beaconChainSlashingFactor); assertApproxEqAbs(prevShares - expectedDelta, curShares, 1e5, err); - /** * 3. The attributable avs slashed shares should decrease by a factor of the BCSF * Attributable avs slashed shares = depositShares - bcSlashedShares - curShars @@ -1309,7 +933,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint attributableAVSSlashedShares = depositShares - bcSlashedShares - curShares; assertApproxEqAbs(originalAVSSlashedShares.mulWad(beaconChainSlashingFactor), attributableAVSSlashedShares, 1e5, err); } - // TODO: slashable stake /** @@ -1326,7 +949,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getOperatorShares(operator, strategies); // Use timewarp to get previous operator shares uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); - // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { assertEq(prevShares[i] + addedShares[i], curShares[i], err); @@ -1344,26 +966,16 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getOperatorShares(operator, strategies); // Use timewarp to get previous operator shares uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); - // For each strategy, check (prev - removed == cur) for (uint i = 0; i < strategies.length; i++) { assertEq(prevShares[i], curShares[i] + removedShares[i], err); } } - /// @dev Check that the operator's shares in ALL strategies have not changed - /// since the last snapshot + /// @dev Check that the operator's shares in ALL strategies have not changed since the last snapshot function assert_Snap_Unchanged_OperatorShares(User operator, string memory err) internal { IStrategy[] memory strategies = allStrats; - - uint[] memory curShares = _getOperatorShares(operator, strategies); - // Use timewarp to get previous operator shares - uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); - - // For each strategy, check (prev == cur) - for (uint i = 0; i < strategies.length; i++) { - assertEq(prevShares[i], curShares[i], err); - } + assertEq(_getOperatorShares(operator, strategies), _getPrevOperatorShares(operator, strategies), err); } function assert_Snap_Delta_OperatorShares(User operator, IStrategy[] memory strategies, int[] memory shareDeltas, string memory err) @@ -1372,7 +984,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getOperatorShares(operator, strategies); // Use timewarp to get previous operator shares uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); - // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { uint expectedShares; @@ -1385,10 +996,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Slashed_OperatorShares(User operator, SlashingParams memory params, string memory err) internal { uint[] memory curShares = _getOperatorShares(operator, params.strategies); uint[] memory prevShares = _getPrevOperatorShares(operator, params.strategies); - Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies); Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { // Slashing doesn't occur if the operator has no slashable magnitude // This prevents a div by 0 when calculating expected slashed @@ -1399,7 +1008,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { prevMaxMagnitude: prevMagnitudes[i].max, newMaxMagnitude: curMagnitudes[i].max }); - assertEq(curShares[i], prevShares[i] - expectedSlashed, err); } } @@ -1407,13 +1015,10 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Increased_BurnableShares(User operator, SlashingParams memory params, string memory err) internal { uint[] memory curBurnable = _getBurnableShares(params.strategies); uint[] memory prevBurnable = _getPrevBurnableShares(params.strategies); - uint[] memory curShares = _getOperatorShares(operator, params.strategies); uint[] memory prevShares = _getPrevOperatorShares(operator, params.strategies); - for (uint i = 0; i < params.strategies.length; i++) { uint slashedAtLeast = prevShares[i] - curShares[i]; - // Not factoring in slashable shares in queue here, because that gets more complex (TODO) assertTrue(curBurnable[i] >= (prevBurnable[i] + slashedAtLeast), err); } @@ -1436,7 +1041,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getStakerDepositShares(staker, strategies); // Use timewarp to get previous staker shares uint[] memory prevShares = _getPrevStakerDepositShares(staker, strategies); - // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { assertApproxEqAbs(prevShares[i] + addedShares[i], curShares[i], 1, err); @@ -1458,7 +1062,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { 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); @@ -1473,15 +1076,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { /// since the last snapshot function assert_Snap_Unchanged_Staker_DepositShares(User staker, string memory err) internal { IStrategy[] memory strategies = allStrats; - - uint[] memory curShares = _getStakerDepositShares(staker, strategies); - // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerDepositShares(staker, strategies); - - // For each strategy, check (prev == cur) - for (uint i = 0; i < strategies.length; i++) { - assertEq(prevShares[i], curShares[i], err); - } + assertEq(_getStakerDepositShares(staker, strategies), _getPrevStakerDepositShares(staker, strategies), err); } /// @dev Check that the staker's withdrawable shares have increased by `addedShares` @@ -1494,7 +1089,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); // Use timewarp to get previous staker shares uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); - // For each strategy, check (prev - removed == cur) for (uint i = 0; i < strategies.length; i++) { assertEq(prevShares[i] + addedShares[i], curShares[i], err); @@ -1512,7 +1106,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); // Use timewarp to get previous staker shares uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); - // For each strategy, check (prev - removed == cur) for (uint i = 0; i < strategies.length; i++) { assertApproxEqAbs(prevShares[i] + addedShares[i], curShares[i], 1e3, err); @@ -1529,7 +1122,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); // Use timewarp to get previous staker shares uint[] memory prevShares = _getPrevStakerWithdrawableShares(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); @@ -1541,12 +1133,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } function assert_Snap_Unchanged_Staker_WithdrawableShares(User staker, IStrategy[] memory strategies, string memory err) internal { - uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); - uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); - // For each strategy, check all shares have been withdrawn - for (uint i = 0; i < strategies.length; i++) { - assertEq(prevShares[i], curShares[i], err); - } + assertEq(_getStakerWithdrawableShares(staker, strategies), _getPrevStakerWithdrawableShares(staker, strategies), err); } /// @dev Check that the staker's withdrawable shares have changed by the expected amount @@ -1557,14 +1144,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory depositShares, string memory err ) internal { - uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); - // Use timewarp to get previous staker shares - uint[] memory expectedShares = _getExpectedWithdrawableSharesDelegate(staker, operator, strategies, depositShares); - - // For each strategy, check expected == current - for (uint i = 0; i < strategies.length; i++) { - assertEq(expectedShares[i], curShares[i], err); - } + assertEq( + _getStakerWithdrawableShares(staker, strategies), + _getExpectedWithdrawableSharesDelegate(staker, operator, strategies, depositShares), + err + ); } function assert_Snap_Expected_Staker_WithdrawableShares_Deposit( @@ -1607,7 +1191,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory curShares = _getStakerWithdrawableShares(staker, strategies); // Use timewarp to get previous staker shares uint[] memory prevShares = _getPrevStakerWithdrawableShares(staker, strategies); - // Assert that the decrease in withdrawable shares is at least as much as the removed shares // Checking for expected rounding down behavior for (uint i = 0; i < strategies.length; i++) { @@ -1627,7 +1210,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { 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], errBound, err); @@ -1646,7 +1228,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { int[] memory curShares = _getStakerDepositSharesInt(staker, strategies); // Use timewarp to get previous staker shares int[] memory prevShares = _getPrevStakerDepositSharesInt(staker, strategies); - // For each strategy, check (prev + added == cur) for (uint i = 0; i < strategies.length; i++) { assertEq(prevShares[i] + shareDeltas[i], curShares[i], err); @@ -1654,32 +1235,17 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } function assert_Snap_Unchanged_DSF(User staker, IStrategy[] memory strategies, string memory err) internal { - uint[] memory curDSFs = _getDepositScalingFactors(staker, strategies); - uint[] memory prevDSFs = _getPrevDepositScalingFactors(staker, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertEq(prevDSFs[i], curDSFs[i], err); - } + assertEq(_getDepositScalingFactors(staker, strategies), _getPrevDepositScalingFactors(staker, strategies), err); } function assert_Snap_Increased_DSF(User staker, IStrategy[] memory strategies, string memory err) internal { uint[] memory curDSFs = _getDepositScalingFactors(staker, strategies); uint[] memory prevDSFs = _getPrevDepositScalingFactors(staker, strategies); - for (uint i = 0; i < strategies.length; i++) { assertGt(curDSFs[i], prevDSFs[i], err); } } - function assert_Snap_WithinErrorBounds_DSF(User staker, IStrategy[] memory strategies, string memory err) internal { - uint[] memory curDSFs = _getDepositScalingFactors(staker, strategies); - uint[] memory prevDSFs = _getPrevDepositScalingFactors(staker, strategies); - - for (uint i = 0; i < strategies.length; i++) { - assertApproxEqAbs(curDSFs[i], prevDSFs[i], 1e2, err); - } - } - /// @dev Used to assert that the DSF is either increased or unchanged, depending on the slashing factor, on a deposit function assert_Snap_DSF_State_Deposit(User staker, IStrategy[] memory strategies, string memory err) internal { uint[] memory curDepositShares = _getStakerDepositShares(staker, strategies); @@ -1718,7 +1284,6 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory prevDSFs = _getPrevDepositScalingFactors(staker, strategies); uint[] memory curSlashingFactors = _getSlashingFactors(staker, strategies); uint[] memory prevSlashingFactors = _getPrevSlashingFactors(staker, strategies); - for (uint i = 0; i < strategies.length; i++) { // If there was never a slashing, no need to normalize // If there was a slashing, but we complete a withdrawal for 0 shares, no need to normalize @@ -1753,17 +1318,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { uint[] memory delegatableShares, string memory err ) internal { - address operator = delegationManager.delegatedTo(address(staker)); + address operator = delegationManager().delegatedTo(address(staker)); uint64[] memory maxMags = _getMaxMagnitudes(User(payable(operator)), strategies); - for (uint i = 0; i < strategies.length; i++) { IStrategy[] memory stratArray = strategies[i].toArray(); - // If you are delegating with 0 shares, no need to normalize // If there was never an operator slashing, no need to normalize if (delegatableShares[i] == 0 || maxMags[i] == WAD) { assert_Snap_Unchanged_DSF(staker, stratArray, err); - // If we are not a beaconChainStrategy, we should also have a DSF of WAD // We exclude BEACONCHAIN_ETH_STRAT because it could have had a non-WAD DSF from BC slashings if (strategies[i] != BEACONCHAIN_ETH_STRAT) assert_DSF_WAD(staker, stratArray, err); @@ -1782,37 +1344,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { */ function assert_Snap_Removed_StrategyShares(IStrategy[] memory strategies, uint[] memory removedShares, string memory err) internal { uint[] memory curShares = _getTotalStrategyShares(strategies); - - // Use timewarp to get previous strategy shares uint[] memory prevShares = _getPrevTotalStrategyShares(strategies); - for (uint i = 0; i < strategies.length; i++) { // Ignore BeaconChainETH strategy since it doesn't keep track of global strategy shares if (strategies[i] == BEACONCHAIN_ETH_STRAT) continue; - uint prevShare = prevShares[i]; - uint curShare = curShares[i]; - - assertApproxEqAbs(prevShare - removedShares[i], curShare, 1, err); + assertApproxEqAbs(prevShares[i] - removedShares[i], curShares[i], 1, err); } } function assert_Snap_Unchanged_StrategyShares(IStrategy[] memory strategies, string memory err) internal { - uint[] memory curShares = _getTotalStrategyShares(strategies); - - // Use timewarp to get previous strategy shares - uint[] memory prevShares = _getPrevTotalStrategyShares(strategies); - - for (uint i = 0; i < strategies.length; i++) { - uint prevShare = prevShares[i]; - uint curShare = curShares[i]; - - assertEq(prevShare, curShare, err); - } + assertEq(_getTotalStrategyShares(strategies), _getPrevTotalStrategyShares(strategies), err); } function assert_SlashableStake_Decrease_BCSlash(User staker) internal { - if (delegationManager.isDelegated(address(staker))) { - address operator = delegationManager.delegatedTo(address(staker)); + if (delegationManager().isDelegated(address(staker))) { + address operator = delegationManager().delegatedTo(address(staker)); (OperatorSet[] memory operatorSets, Allocation[] memory allocations) = _getStrategyAllocations(operator, BEACONCHAIN_ETH_STRAT); for (uint i = 0; i < operatorSets.length; i++) { if (allocations[i].currentMagnitude > 0) { @@ -1833,52 +1379,30 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { * */ - /// @dev Check that the staker has `addedTokens` additional underlying tokens - // since the last snapshot + /// @dev Check that the staker has `addedTokens` additional underlying tokens since the last snapshot function assert_Snap_Added_TokenBalances(User staker, IERC20[] memory tokens, uint[] memory addedTokens, string memory err) internal { uint[] memory curTokenBalances = _getTokenBalances(staker, tokens); - // Use timewarp to get previous token balances uint[] memory prevTokenBalances = _getPrevTokenBalances(staker, tokens); - for (uint i = 0; i < tokens.length; i++) { - uint prevBalance = prevTokenBalances[i]; - uint curBalance = curTokenBalances[i]; - - assertApproxEqAbs(prevBalance + addedTokens[i], curBalance, 1, err); + assertApproxEqAbs(prevTokenBalances[i] + addedTokens[i], curTokenBalances[i], 1, err); } } - /// @dev Check that the staker has `removedTokens` fewer underlying tokens - // since the last snapshot - function assert_Snap_Removed_TokenBalances(User staker, IStrategy[] memory strategies, uint[] memory removedTokens, string memory err) + function assert_Snap_Added_TokenBalances(User staker, IStrategy[] memory strategies, uint[] memory addedTokens, string memory err) internal { IERC20[] memory tokens = _getUnderlyingTokens(strategies); - uint[] memory curTokenBalances = _getTokenBalances(staker, tokens); - // Use timewarp to get previous token balances uint[] memory prevTokenBalances = _getPrevTokenBalances(staker, tokens); - for (uint i = 0; i < tokens.length; i++) { - uint prevBalance = prevTokenBalances[i]; - uint curBalance = curTokenBalances[i]; - - assertEq(prevBalance - removedTokens[i], curBalance, err); + assertApproxEqAbs(prevTokenBalances[i] + addedTokens[i], curTokenBalances[i], 1, err); } } - /// @dev Check that the staker's underlying token balance for ALL tokens have - /// not changed since the last snapshot + /// @dev Check that the staker's underlying token balance for ALL tokens have not changed since the last snapshot function assert_Snap_Unchanged_TokenBalances(User staker, string memory err) internal { IERC20[] memory tokens = allTokens; - - uint[] memory curTokenBalances = _getTokenBalances(staker, tokens); - // Use timewarp to get previous token balances - uint[] memory prevTokenBalances = _getPrevTokenBalances(staker, tokens); - - for (uint i = 0; i < tokens.length; i++) { - assertEq(prevTokenBalances[i], curTokenBalances[i], err); - } + assertEq(_getTokenBalances(staker, tokens), _getPrevTokenBalances(staker, tokens), err); } /** @@ -1887,53 +1411,34 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { * */ function assert_Snap_Added_QueuedWithdrawals(User staker, Withdrawal[] memory withdrawals, string memory err) internal { - uint curQueuedWithdrawals = _getCumulativeWithdrawals(staker); - // Use timewarp to get previous cumulative withdrawals - uint prevQueuedWithdrawals = _getPrevCumulativeWithdrawals(staker); - - assertEq(prevQueuedWithdrawals + withdrawals.length, curQueuedWithdrawals, err); + assertEq(_getPrevCumulativeWithdrawals(staker) + withdrawals.length, _getCumulativeWithdrawals(staker), err); } function assert_Snap_Added_QueuedWithdrawal(User staker, Withdrawal memory, /*withdrawal*/ string memory err) internal { - uint curQueuedWithdrawal = _getCumulativeWithdrawals(staker); - // Use timewarp to get previous cumulative withdrawals - uint prevQueuedWithdrawal = _getPrevCumulativeWithdrawals(staker); - - assertEq(prevQueuedWithdrawal + 1, curQueuedWithdrawal, err); + assertEq(_getPrevCumulativeWithdrawals(staker) + 1, _getCumulativeWithdrawals(staker), err); } - /** * * SNAPSHOT ASSERTIONS: EIGENPODS * */ - function assert_Snap_Added_ActiveValidatorCount(User staker, uint addedValidators, string memory err) internal { - uint curActiveValidatorCount = _getActiveValidatorCount(staker); - uint prevActiveValidatorCount = _getPrevActiveValidatorCount(staker); - assertEq(prevActiveValidatorCount + addedValidators, curActiveValidatorCount, err); + function assert_Snap_Added_ActiveValidatorCount(User staker, uint addedValidators, string memory err) internal { + assertEq(_getPrevActiveValidatorCount(staker) + addedValidators, _getActiveValidatorCount(staker), err); } function assert_Snap_Removed_ActiveValidatorCount(User staker, uint exitedValidators, string memory err) internal { - uint curActiveValidatorCount = _getActiveValidatorCount(staker); - uint prevActiveValidatorCount = _getPrevActiveValidatorCount(staker); - - assertEq(curActiveValidatorCount + exitedValidators, prevActiveValidatorCount, err); + assertEq(_getActiveValidatorCount(staker) + exitedValidators, _getPrevActiveValidatorCount(staker), err); } function assert_Snap_Unchanged_ActiveValidatorCount(User staker, string memory err) internal { - uint curActiveValidatorCount = _getActiveValidatorCount(staker); - uint prevActiveValidatorCount = _getPrevActiveValidatorCount(staker); - - assertEq(curActiveValidatorCount, prevActiveValidatorCount, err); + assertEq(_getActiveValidatorCount(staker), _getPrevActiveValidatorCount(staker), err); } function assert_Snap_Added_ActiveValidators(User staker, uint40[] memory addedValidators, string memory err) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(addedValidators); - VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); - for (uint i = 0; i < curStatuses.length; i++) { assertTrue(prevStatuses[i] == VALIDATOR_STATUS.INACTIVE, err); assertTrue(curStatuses[i] == VALIDATOR_STATUS.ACTIVE, err); @@ -1942,10 +1447,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { function assert_Snap_Removed_ActiveValidators(User staker, uint40[] memory exitedValidators, string memory err) internal { bytes32[] memory pubkeyHashes = beaconChain.getPubkeyHashes(exitedValidators); - VALIDATOR_STATUS[] memory curStatuses = _getValidatorStatuses(staker, pubkeyHashes); VALIDATOR_STATUS[] memory prevStatuses = _getPrevValidatorStatuses(staker, pubkeyHashes); - for (uint i = 0; i < curStatuses.length; i++) { assertTrue(prevStatuses[i] == VALIDATOR_STATUS.ACTIVE, err); assertTrue(curStatuses[i] == VALIDATOR_STATUS.WITHDRAWN, err); @@ -1953,1133 +1456,49 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } function assert_Snap_Created_Checkpoint(User staker, string memory err) internal { - uint64 curCheckpointTimestamp = _getCheckpointTimestamp(staker); - uint64 prevCheckpointTimestamp = _getPrevCheckpointTimestamp(staker); - - assertEq(prevCheckpointTimestamp, 0, err); - assertTrue(curCheckpointTimestamp != 0, err); + assertEq(_getPrevCheckpointTimestamp(staker), 0, err); + assertTrue(_getCheckpointTimestamp(staker) != 0, err); } function assert_Snap_Removed_Checkpoint(User staker, string memory err) internal { - uint64 curCheckpointTimestamp = _getCheckpointTimestamp(staker); - uint64 prevCheckpointTimestamp = _getPrevCheckpointTimestamp(staker); - - assertEq(curCheckpointTimestamp, 0, err); - assertTrue(prevCheckpointTimestamp != 0, err); + assertEq(_getCheckpointTimestamp(staker), 0, err); + assertTrue(_getPrevCheckpointTimestamp(staker) != 0, err); } function assert_Snap_Unchanged_Checkpoint(User staker, string memory err) internal { - uint64 curCheckpointTimestamp = _getCheckpointTimestamp(staker); - uint64 prevCheckpointTimestamp = _getPrevCheckpointTimestamp(staker); - - assertEq(curCheckpointTimestamp, prevCheckpointTimestamp, err); + assertEq(_getCheckpointTimestamp(staker), _getPrevCheckpointTimestamp(staker), err); } function assert_Snap_Updated_LastCheckpoint(User staker, string memory err) internal { - // Sorry for the confusing naming... the pod variable is called `lastCheckpointTimestamp` - uint64 curLastCheckpointTimestamp = _getLastCheckpointTimestamp(staker); - uint64 prevLastCheckpointTimestamp = _getPrevLastCheckpointTimestamp(staker); - - assertTrue(curLastCheckpointTimestamp > prevLastCheckpointTimestamp, err); + assertTrue(_getLastCheckpointTimestamp(staker) > _getPrevLastCheckpointTimestamp(staker), err); } function assert_Snap_Added_PodBalanceToWithdrawable(User staker, string memory err) internal { - uint64 curWithdrawableRestakedGwei = _getWithdrawableRestakedGwei(staker); - uint64 prevWithdrawableRestakedGwei = _getPrevWithdrawableRestakedGwei(staker); - - uint64 prevCheckpointPodBalanceGwei = _getPrevCheckpointPodBalanceGwei(staker); - - assertEq(prevWithdrawableRestakedGwei + prevCheckpointPodBalanceGwei, curWithdrawableRestakedGwei, err); + assertEq( + _getPrevWithdrawableRestakedGwei(staker) + _getPrevCheckpointPodBalanceGwei(staker), _getWithdrawableRestakedGwei(staker), err + ); } function assert_Snap_Added_WithdrawableGwei(User staker, uint64 addedGwei, string memory err) internal { - uint64 curWithdrawableRestakedGwei = _getWithdrawableRestakedGwei(staker); - uint64 prevWithdrawableRestakedGwei = _getPrevWithdrawableRestakedGwei(staker); - - assertEq(prevWithdrawableRestakedGwei + addedGwei, curWithdrawableRestakedGwei, err); + assertEq(_getPrevWithdrawableRestakedGwei(staker) + addedGwei, _getWithdrawableRestakedGwei(staker), err); } function assert_Snap_Added_BalanceExitedGwei(User staker, uint64 addedGwei, string memory err) internal { uint64 curCheckpointTimestamp = _getCheckpointTimestamp(staker); uint64 prevCheckpointTimestamp = _getPrevCheckpointTimestamp(staker); - - // If we just finalized a checkpoint, that's the timestamp we want to use - // to look up checkpoint balances exited + // If we just finalized a checkpoint, that's the timestamp we want to use to look up checkpoint balances exited uint64 targetTimestamp = curCheckpointTimestamp; if (curCheckpointTimestamp != prevCheckpointTimestamp) targetTimestamp = prevCheckpointTimestamp; - - uint64 curExitedBalanceGwei = _getCheckpointBalanceExited(staker, targetTimestamp); - uint64 prevExitedBalanceGwei = _getPrevCheckpointBalanceExited(staker, targetTimestamp); - - assertEq(prevExitedBalanceGwei + addedGwei, curExitedBalanceGwei, err); + assertEq( + _getPrevCheckpointBalanceExited(staker, targetTimestamp) + addedGwei, _getCheckpointBalanceExited(staker, targetTimestamp), err + ); } function assert_Snap_Decreased_BCSF(User staker, string memory err) internal { - uint64 curBCSF = _getBeaconChainSlashingFactor(staker); - uint64 prevBCSF = _getPrevBeaconChainSlashingFactor(staker); - - assertLt(curBCSF, prevBCSF, err); + assertLt(_getBeaconChainSlashingFactor(staker), _getPrevBeaconChainSlashingFactor(staker), err); } function assert_Snap_Unchanged_BCSF(User staker, string memory err) internal { - uint64 curBCSF = _getBeaconChainSlashingFactor(staker); - uint64 prevBCSF = _getPrevBeaconChainSlashingFactor(staker); - - assertEq(curBCSF, prevBCSF, err); - } - - /** - * - * UTILITY METHODS - * - */ - - /// @dev Fetches the opreator's allocation delay; asserts that it is set - function _getExistingAllocationDelay(User operator) internal view returns (uint32) { - (bool isSet, uint32 delay) = allocationManager.getAllocationDelay(address(operator)); - assertTrue(isSet, "_getExistingAllocationDelay: expected allocation delay to be set"); - - return delay; - } - - /// @dev Generate params to allocate all available magnitude to each strategy in the operator set - function _genAllocation_AllAvailable(User operator, OperatorSet memory operatorSet) - internal - view - returns (AllocateParams memory params) - { - return _genAllocation_AllAvailable({ - operator: operator, - operatorSet: operatorSet, - strategies: allocationManager.getStrategiesInOperatorSet(operatorSet) - }); - } - - /// @dev Generate params to allocate all available magnitude to each strategy in the operator set - function _genAllocation_AllAvailable(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (AllocateParams memory params) - { - params.operatorSet = operatorSet; - params.strategies = strategies; - params.newMagnitudes = new uint64[](params.strategies.length); - - for (uint i = 0; i < params.strategies.length; i++) { - IStrategy strategy = params.strategies[i]; - params.newMagnitudes[i] = allocationManager.getMaxMagnitude(address(operator), strategy); - } - } - - /// @dev Gen params to allocate half of available magnitude to each strategy in the operator set - /// returns the params to complete this allocation - function _genAllocation_HalfAvailable(User operator, OperatorSet memory operatorSet) - internal - view - returns (AllocateParams memory params) - { - return _genAllocation_HalfAvailable({ - operator: operator, - operatorSet: operatorSet, - strategies: allocationManager.getStrategiesInOperatorSet(operatorSet) - }); - } - - /// @dev Gen params to allocate half of available magnitude to each strategy in the operator set - /// returns the params to complete this allocation - function _genAllocation_HalfAvailable(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (AllocateParams memory params) - { - params.operatorSet = operatorSet; - params.strategies = strategies; - params.newMagnitudes = new uint64[](params.strategies.length); - - Allocation[] memory allocations = _getAllocations(operator, operatorSet, strategies); - Magnitudes[] memory magnitudes = _getMagnitudes(operator, strategies); - - for (uint i = 0; i < params.strategies.length; i++) { - uint64 halfAvailable = uint64(magnitudes[i].allocatable) / 2; - params.newMagnitudes[i] = allocations[i].currentMagnitude + halfAvailable; - } - } - - /// @dev Generate params to allocate a random portion of available magnitude to each strategy - /// in the operator set. All strategies will have a nonzero allocation, and the minimum allocation - /// will be 10% of available magnitude - function _genAllocation_Rand(User operator, OperatorSet memory operatorSet) internal returns (AllocateParams memory params) { - params.operatorSet = operatorSet; - params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); - params.newMagnitudes = new uint64[](params.strategies.length); - - Allocation[] memory allocations = _getAllocations(operator, operatorSet, params.strategies); - Magnitudes[] memory magnitudes = _getMagnitudes(operator, params.strategies); - - for (uint i = 0; i < params.strategies.length; i++) { - // minimum of 10%, maximum of 100%. increments of 10%. - uint r = _randUint({min: 1, max: 10}); - uint64 allocation = uint64(magnitudes[i].allocatable) / uint64(r); - - params.newMagnitudes[i] = allocations[i].currentMagnitude + allocation; - } - } - - /// @dev Generates params for a half deallocation from all strategies the operator is allocated to in the operator set - function _genDeallocation_HalfRemaining(User operator, OperatorSet memory operatorSet) - internal - view - returns (AllocateParams memory params) - { - return _genDeallocation_HalfRemaining({ - operator: operator, - operatorSet: operatorSet, - strategies: allocationManager.getStrategiesInOperatorSet(operatorSet) - }); - } - - /// @dev Generates params for a half deallocation from all strategies the operator is allocated to in the operator set - function _genDeallocation_HalfRemaining(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (AllocateParams memory params) - { - params.operatorSet = operatorSet; - params.strategies = strategies; - params.newMagnitudes = new uint64[](params.strategies.length); - - for (uint i = 0; i < params.strategies.length; i++) { - IStrategy strategy = params.strategies[i]; - params.newMagnitudes[i] = allocationManager.getEncumberedMagnitude(address(operator), strategy) / 2; - } - } - - /// @dev Generates params for a full deallocation from all strategies the operator is allocated to in the operator set - function _genDeallocation_Full(User operator, OperatorSet memory operatorSet) internal view returns (AllocateParams memory params) { - return _genDeallocation_Full(operator, operatorSet, allocationManager.getStrategiesInOperatorSet(operatorSet)); - } - - /// @dev Generates params for a full deallocation from all strategies the operator is allocated to in the operator set - function _genDeallocation_Full(User, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - pure - returns (AllocateParams memory params) - { - params.operatorSet = operatorSet; - params.strategies = strategies; - params.newMagnitudes = new uint64[](params.strategies.length); - } - - /// Generate random slashing between 1 and 99% - function _genSlashing_Rand(User operator, OperatorSet memory operatorSet) internal returns (SlashingParams memory params) { - params.operator = address(operator); - params.operatorSetId = operatorSet.id; - params.description = "genSlashing_Rand"; - params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort(); - params.wadsToSlash = new uint[](params.strategies.length); - - /// 1% * rand(1, 99) - uint slashWad = 1e16 * _randUint({min: 1, max: 99}); - - for (uint i = 0; i < params.wadsToSlash.length; i++) { - params.wadsToSlash[i] = slashWad; - } - } - - function _genSlashing_Half(User operator, OperatorSet memory operatorSet) internal view returns (SlashingParams memory params) { - params.operator = address(operator); - params.operatorSetId = operatorSet.id; - params.description = "genSlashing_Half"; - params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort(); - params.wadsToSlash = new uint[](params.strategies.length); - - // slash 50% - for (uint i = 0; i < params.wadsToSlash.length; i++) { - params.wadsToSlash[i] = 5e17; - } - } - - function _genSlashing_Full(User operator, OperatorSet memory operatorSet) internal view returns (SlashingParams memory params) { - params.operator = address(operator); - params.operatorSetId = operatorSet.id; - params.description = "_genSlashing_Full"; - params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort(); - params.wadsToSlash = new uint[](params.strategies.length); - - // slash 100% - for (uint i = 0; i < params.wadsToSlash.length; i++) { - params.wadsToSlash[i] = 1e18; - } - } - - function _genSlashing_Custom(User operator, OperatorSet memory operatorSet, uint wadsToSlash) - internal - view - returns (SlashingParams memory params) - { - params.operator = address(operator); - params.operatorSetId = operatorSet.id; - params.description = "_genSlashing_Custom"; - params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort(); - params.wadsToSlash = new uint[](params.strategies.length); - - for (uint i = 0; i < params.wadsToSlash.length; i++) { - params.wadsToSlash[i] = wadsToSlash; - } - } - - function _randWadToSlash() internal returns (uint) { - return _randUint({min: 0.01 ether, max: 1 ether}); - } - - function _strategiesAndWadsForFullSlash(OperatorSet memory operatorSet) - internal - view - returns (IStrategy[] memory strategies, uint[] memory wadsToSlash) - { - // Get list of all strategies in an operator set. - strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); - - wadsToSlash = new uint[](strategies.length); - - for (uint i; i < strategies.length; ++i) { - wadsToSlash[i] = 1 ether; - } - - return (strategies.sort(), wadsToSlash); - } - - function _strategiesAndWadsForRandFullSlash(OperatorSet memory operatorSet) - internal - returns (IStrategy[] memory strategies, uint[] memory wadsToSlash) - { - // Get list of all strategies in an operator set. - strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); - - // Randomly select a subset of strategies to slash. - uint len = _randUint({min: 1, max: strategies.length}); - - // Update length of strategies array. - assembly { - mstore(strategies, len) - } - - wadsToSlash = new uint[](len); - - // Fully slash each selected strategy - for (uint i; i < len; ++i) { - wadsToSlash[i] = 1 ether; - } - - return (strategies.sort(), wadsToSlash); - } - - function _randMagnitudes(uint64 sum, uint len) internal returns (uint64[] memory magnitudes) { - magnitudes = new uint64[](len); - - if (sum == 0 || len == 0) return magnitudes; - - uint64 remaining = sum; - - for (uint i; i < len; ++i) { - if (i == len - 1) { - magnitudes[i] = remaining; - } else { - magnitudes[i] = uint64(_randUint(0, remaining / (len - i))); - remaining -= magnitudes[i]; - } - } - } - - function _maxMagnitudes(OperatorSet memory operatorSet, User operator) internal view returns (uint64[] memory magnitudes) { - IStrategy[] memory strategies = allocationManager.getStrategiesInOperatorSet(operatorSet); - uint len = strategies.length; - magnitudes = new uint64[](len); - - if (len == 0) return magnitudes; - - for (uint i; i < len; ++i) { - magnitudes[i] = allocationManager.getMaxMagnitude(address(operator), strategies[i]); - } - } - - function _randWithdrawal(IStrategy[] memory strategies, uint[] memory shares) internal returns (IStrategy[] memory, uint[] memory) { - uint stratsToWithdraw = _randUint({min: 1, max: strategies.length}); - - IStrategy[] memory withdrawStrats = new IStrategy[](stratsToWithdraw); - uint[] memory withdrawShares = new uint[](stratsToWithdraw); - - for (uint i = 0; i < stratsToWithdraw; i++) { - uint sharesToWithdraw; - - if (strategies[i] == BEACONCHAIN_ETH_STRAT) { - // For native eth, withdraw a random amount of gwei (at least 1) - uint portion = _randUint({min: 1, max: shares[i] / GWEI_TO_WEI}); - portion *= GWEI_TO_WEI; - - sharesToWithdraw = shares[i] - portion; - } else { - // For LSTs, withdraw a random amount of shares (at least 1) - uint portion = _randUint({min: 1, max: shares[i]}); - - sharesToWithdraw = shares[i] - portion; - } - - withdrawStrats[i] = strategies[i]; - withdrawShares[i] = sharesToWithdraw; - } - - return (withdrawStrats, withdrawShares); - } - - /** - * Helpful getters: - */ - function _randSlashType() internal returns (BeaconChainMock.SlashType) { - return BeaconChainMock.SlashType(_randUint({min: 0, max: 2})); - } - - function _randBalanceUpdate(User staker, IStrategy[] memory strategies) internal returns (int[] memory, int[] memory, int[] memory) { - int[] memory tokenDeltas = new int[](strategies.length); - int[] memory stakerShareDeltas = new int[](strategies.length); - int[] memory operatorShareDeltas = new int[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - IStrategy strat = strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) { - // For native ETH, we're either going to slash the staker's validators, - // or award them consensus rewards. In either case, the magnitude of - // the balance update depends on the staker's active validator count - uint activeValidatorCount = staker.pod().activeValidatorCount(); - int64 deltaGwei; - if (_randBool()) { - uint40[] memory validators = staker.getActiveValidators(); - emit log_named_uint("slashing validators", validators.length); - - deltaGwei = -int64(beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor)); - beaconChain.advanceEpoch_NoRewards(); - - emit log_named_int("slashed amount", deltaGwei); - } else { - emit log("generating consensus rewards for validators"); - - deltaGwei = int64(uint64(activeValidatorCount) * beaconChain.CONSENSUS_REWARD_AMOUNT_GWEI()); - beaconChain.advanceEpoch_NoWithdraw(); - } - - tokenDeltas[i] = int(deltaGwei) * int(GWEI_TO_WEI); - - stakerShareDeltas[i] = tokenDeltas[i]; - operatorShareDeltas[i] = _calcNativeETHOperatorShareDelta(staker, stakerShareDeltas[i]); - - emit log_named_int("beacon balance delta (gwei): ", deltaGwei); - emit log_named_int("staker share delta (gwei): ", stakerShareDeltas[i] / int(GWEI_TO_WEI)); - emit log_named_int("operator share delta (gwei): ", operatorShareDeltas[i] / int(GWEI_TO_WEI)); - } else { - // For LSTs, mint a random token amount - uint portion = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); - StdCheats.deal(address(strat.underlyingToken()), address(staker), portion); - - int delta = int(portion); - tokenDeltas[i] = delta; - stakerShareDeltas[i] = int(strat.underlyingToShares(uint(delta))); - operatorShareDeltas[i] = int(strat.underlyingToShares(uint(delta))); - } - } - return (tokenDeltas, stakerShareDeltas, operatorShareDeltas); - } - - function _calcNativeETHOperatorShareDelta(User staker, int shareDelta) internal view returns (int) { - // TODO: Maybe we update parent method to have an M2 and Slashing version? - int curPodOwnerShares; - if (!isUpgraded) curPodOwnerShares = IEigenPodManager_DeprecatedM2(address(eigenPodManager)).podOwnerShares(address(staker)); - else curPodOwnerShares = eigenPodManager.podOwnerDepositShares(address(staker)); - int newPodOwnerShares = curPodOwnerShares + shareDelta; - - if (curPodOwnerShares <= 0) { - // if the shares started negative and stayed negative, then there cannot have been an increase in delegateable shares - if (newPodOwnerShares <= 0) return 0; - // if the shares started negative and became positive, then the increase in delegateable shares is the ending share amount - else return newPodOwnerShares; - } else { - // if the shares started positive and became negative, then the decrease in delegateable shares is the starting share amount - if (newPodOwnerShares <= 0) return (-curPodOwnerShares); - // if the shares started positive and stayed positive, then the change in delegateable shares - // is the difference between starting and ending amounts - else return (newPodOwnerShares - curPodOwnerShares); - } - } - - function _calculateExpectedShares(Withdrawal memory withdrawal) internal view returns (uint[] memory) { - bytes32 root = delegationManager.calculateWithdrawalRoot(withdrawal); - - (, uint[] memory shares) = delegationManager.getQueuedWithdrawal(root); - return shares; - } - - /// @dev For some strategies/underlying token balances, calculate the expected shares received - /// from depositing all tokens - function _calculateExpectedShares(IStrategy[] memory strategies, uint[] memory tokenBalances) internal returns (uint[] memory) { - uint[] memory expectedShares = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - IStrategy strat = strategies[i]; - - uint tokenBalance = tokenBalances[i]; - if (strat == BEACONCHAIN_ETH_STRAT) expectedShares[i] = tokenBalance; - else expectedShares[i] = strat.underlyingToShares(tokenBalance); - } - - return expectedShares; - } - - /// @dev For some strategies/underlying token balances, calculate the expected shares received - /// from depositing all tokens - function _calculateExpectedTokens(IStrategy[] memory strategies, uint[] memory shares) internal returns (uint[] memory) { - uint[] memory expectedTokens = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - IStrategy strat = strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) { - // We round down expected tokens to the nearest gwei - expectedTokens[i] = (shares[i] / GWEI_TO_WEI) * GWEI_TO_WEI; - } else { - expectedTokens[i] = strat.sharesToUnderlying(shares[i]); - } - } - - return expectedTokens; - } - - function _getWithdrawalHashes(Withdrawal[] memory withdrawals) internal view returns (bytes32[] memory) { - bytes32[] memory withdrawalRoots = new bytes32[](withdrawals.length); - - for (uint i = 0; i < withdrawals.length; i++) { - withdrawalRoots[i] = delegationManager.calculateWithdrawalRoot(withdrawals[i]); - } - - return withdrawalRoots; - } - - /// @dev Converts a list of strategies to underlying tokens - function _getUnderlyingTokens(IStrategy[] memory strategies) internal view returns (IERC20[] memory) { - IERC20[] memory tokens = new IERC20[](strategies.length); - - for (uint i = 0; i < tokens.length; i++) { - IStrategy strat = strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) tokens[i] = NATIVE_ETH; - else tokens[i] = strat.underlyingToken(); - } - - return tokens; - } - - modifier timewarp() { - uint curState = timeMachine.travelToLast(); - _; - timeMachine.travel(curState); - } - - /// @dev Rolls forward by the minimum withdrawal delay blocks. - function _rollBlocksForCompleteWithdrawals(Withdrawal[] memory withdrawals) internal { - uint latest; - for (uint i = 0; i < withdrawals.length; ++i) { - if (withdrawals[i].startBlock > latest) latest = withdrawals[i].startBlock; - } - cheats.roll(latest + delegationManager.minWithdrawalDelayBlocks() + 1); - } - - function _rollForward_AllocationDelay(User operator) internal { - uint32 delay = _getExistingAllocationDelay(operator); - rollForward(delay); - } - - function _rollBackward_AllocationDelay(User operator) internal { - uint32 delay = _getExistingAllocationDelay(operator); - rollBackward(delay); - } - - function _rollForward_DeallocationDelay() internal { - rollForward(allocationManager.DEALLOCATION_DELAY() + 1); - } - - function _rollBackward_DeallocationDelay() internal { - rollBackward(allocationManager.DEALLOCATION_DELAY() + 1); - } - - /// @dev Rolls forward by the default allocation delay blocks. - function _rollBlocksForCompleteAllocation(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) internal { - uint latest; - for (uint i = 0; i < strategies.length; ++i) { - uint effectBlock = allocationManager.getAllocation(address(operator), operatorSet, strategies[i]).effectBlock; - if (effectBlock > latest) latest = effectBlock; - } - cheats.roll(latest + 1); - } - - /// @dev Rolls forward by the default allocation delay blocks. - function _rollBlocksForCompleteAllocation(User operator, OperatorSet[] memory operatorSets, IStrategy[] memory strategies) internal { - uint latest; - for (uint i = 0; i < operatorSets.length; ++i) { - for (uint j = 0; j < strategies.length; ++j) { - uint effectBlock = allocationManager.getAllocation(address(operator), operatorSets[i], strategies[j]).effectBlock; - if (effectBlock > latest) latest = effectBlock; - } - } - cheats.roll(latest + 1); - } - - /// @dev Uses timewarp modifier to get the operator set strategy allocations at the last snapshot. - function _getPrevAllocations(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - timewarp - returns (Allocation[] memory) - { - return _getAllocations(operator, operatorSet, strategies); - } - - /// @dev Looks up each strategy for an operator set and returns a list of operator allocations. - function _getAllocations(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (Allocation[] memory allocations) - { - allocations = new Allocation[](strategies.length); - for (uint i = 0; i < strategies.length; ++i) { - allocations[i] = allocationManager.getAllocation(address(operator), operatorSet, strategies[i]); - } - } - - function _getPrevAllocatedStrats(User operator, OperatorSet memory operatorSet) internal timewarp returns (IStrategy[] memory) { - return _getAllocatedStrats(operator, operatorSet); - } - - function _getAllocatedStrats(User operator, OperatorSet memory operatorSet) internal view returns (IStrategy[] memory) { - return allocationManager.getAllocatedStrategies(address(operator), operatorSet); - } - - function _getPrevAllocatedSets(User operator) internal timewarp returns (OperatorSet[] memory) { - return _getAllocatedSets(operator); - } - - function _getAllocatedSets(User operator) internal view returns (OperatorSet[] memory) { - return allocationManager.getAllocatedSets(address(operator)); - } - - function _getPrevRegisteredSets(User operator) internal timewarp returns (OperatorSet[] memory) { - return _getRegisteredSets(operator); - } - - function _getRegisteredSets(User operator) internal view returns (OperatorSet[] memory) { - return allocationManager.getRegisteredSets(address(operator)); - } - - function _getPrevMembers(OperatorSet memory operatorSet) internal timewarp returns (address[] memory) { - return _getMembers(operatorSet); - } - - function _getMembers(OperatorSet memory operatorSet) internal view returns (address[] memory) { - return allocationManager.getMembers(operatorSet); - } - - struct Magnitudes { - uint encumbered; - uint allocatable; - uint max; - } - - function _getPrevMagnitudes(User operator, IStrategy[] memory strategies) internal timewarp returns (Magnitudes[] memory) { - return _getMagnitudes(operator, strategies); - } - - function _getMagnitudes(User operator, IStrategy[] memory strategies) internal view returns (Magnitudes[] memory magnitudes) { - magnitudes = new Magnitudes[](strategies.length); - for (uint i = 0; i < strategies.length; ++i) { - magnitudes[i] = Magnitudes({ - encumbered: allocationManager.getEncumberedMagnitude(address(operator), strategies[i]), - allocatable: allocationManager.getAllocatableMagnitude(address(operator), strategies[i]), - max: allocationManager.getMaxMagnitude(address(operator), strategies[i]) - }); - } - } - - function _getMaxMagnitudes(User operator, IStrategy[] memory strategies) internal view returns (uint64[] memory) { - return allocationManager.getMaxMagnitudes(address(operator), strategies); - } - - function _getMaxMagnitudes(User operator, IStrategy[] memory strategies, uint32 blockNum) internal view returns (uint64[] memory) { - return allocationManager.getMaxMagnitudesAtBlock(address(operator), strategies, blockNum); - } - - function _getPrevMinSlashableStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - timewarp - returns (uint[] memory) - { - return _getMinSlashableStake(operator, operatorSet, strategies); - } - - function _getPrevMinSlashableStake(address operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - timewarp - returns (uint[] memory) - { - return _getMinSlashableStake(operator, operatorSet, strategies); - } - - function _getMinSlashableStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (uint[] memory) - { - return allocationManager.getMinimumSlashableStake({ - operatorSet: operatorSet, - operators: address(operator).toArray(), - strategies: strategies, - futureBlock: uint32(block.number) - })[0]; - } - - function _getMinSlashableStake(address operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (uint[] memory) - { - return allocationManager.getMinimumSlashableStake({ - operatorSet: operatorSet, - operators: address(operator).toArray(), - strategies: strategies, - futureBlock: uint32(block.number) - })[0]; - } - - function _getPrevAllocatedStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - timewarp - returns (uint[] memory) - { - return _getAllocatedStake(operator, operatorSet, strategies); - } - - function _getAllocatedStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) - internal - view - returns (uint[] memory) - { - return allocationManager.getAllocatedStake({ - operatorSet: operatorSet, - operators: address(operator).toArray(), - strategies: strategies - })[0]; - } - - function _getStrategyAllocations(User operator, IStrategy strategy) - internal - view - returns (OperatorSet[] memory operatorSets, Allocation[] memory allocations) - { - (operatorSets, allocations) = allocationManager.getStrategyAllocations(address(operator), strategy); - } - - function _getStrategyAllocations(address operator, IStrategy strategy) - internal - view - returns (OperatorSet[] memory operatorSets, Allocation[] memory allocations) - { - (operatorSets, allocations) = allocationManager.getStrategyAllocations(operator, strategy); - } - - function _getPrevIsSlashable(User operator, OperatorSet memory operatorSet) internal timewarp returns (bool) { - return _getIsSlashable(operator, operatorSet); - } - - function _getIsSlashable(User operator, OperatorSet memory operatorSet) internal view returns (bool) { - return allocationManager.isOperatorSlashable(address(operator), operatorSet); - } - - function _getPrevIsMemberOfSet(User operator, OperatorSet memory operatorSet) internal timewarp returns (bool) { - return _getIsMemberOfSet(operator, operatorSet); - } - - function _getIsMemberOfSet(User operator, OperatorSet memory operatorSet) internal view returns (bool) { - return allocationManager.isMemberOfOperatorSet(address(operator), operatorSet); - } - - function _getPrevBurnableShares(IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getBurnableShares(strategies); - } - - function _getBurnableShares(IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory burnableShares = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - if (strategies[i] == beaconChainETHStrategy) burnableShares[i] = eigenPodManager.burnableETHShares(); - else burnableShares[i] = strategyManager.getBurnableShares(strategies[i]); - } - - return burnableShares; - } - - function _getPrevSlashableSharesInQueue(User operator, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getSlashableSharesInQueue(operator, strategies); - } - - function _getSlashableSharesInQueue(User operator, IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory slashableShares = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - slashableShares[i] = delegationManager.getSlashableSharesInQueue(address(operator), strategies[i]); - } - - return slashableShares; - } - - /// @dev Uses timewarp modifier to get operator shares at the last snapshot - function _getPrevOperatorShares(User operator, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getOperatorShares(operator, strategies); - } - - /// @dev Looks up each strategy and returns a list of the operator's shares - function _getOperatorShares(User operator, IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory curShares = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - curShares[i] = delegationManager.operatorShares(address(operator), strategies[i]); - } - - return curShares; - } - - /// @dev Uses timewarp modifier to get staker shares at the last snapshot - function _getPrevStakerDepositShares(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getStakerDepositShares(staker, strategies); - } - - /// @dev Looks up each strategy and returns a list of the staker's shares - 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++) { - IStrategy strat = strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) { - // 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.podOwnerDepositShares(address(staker)); - - if (shares < 0) revert("_getStakerDepositShares: negative shares"); - - curShares[i] = uint(shares); - } else { - curShares[i] = strategyManager.stakerDepositShares(address(staker), strat); - } - } - - return curShares; - } - - /// @dev Uses timewarp modifier to get staker shares at the last snapshot - function _getPrevStakerDepositSharesInt(User staker, IStrategy[] memory strategies) internal timewarp returns (int[] memory) { - return _getStakerDepositSharesInt(staker, strategies); - } - - /// @dev Looks up each strategy and returns a list of the staker's shares - 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.podOwnerDepositShares(address(staker)); - else curShares[i] = int(strategyManager.stakerDepositShares(address(staker), strat)); - } - - return curShares; - } - - function _getStakerStrategyList(User staker) internal view returns (IStrategy[] memory) { - return strategyManager.getStakerStrategyList(address(staker)); - } - - 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) { - (uint[] memory withdrawableShares,) = delegationManager.getWithdrawableShares(address(staker), strategies); - return withdrawableShares; - } - - function _calcWithdrawable(User staker, IStrategy[] memory strategies, uint[] memory depositSharesToWithdraw) - internal - view - returns (uint[] memory) - { - uint[] memory withdrawableShares = new uint[](strategies.length); - uint[] memory depositScalingFactors = _getDepositScalingFactors(staker, strategies); - for (uint i = 0; i < strategies.length; i++) { - withdrawableShares[i] = - depositSharesToWithdraw[i].mulWad(depositScalingFactors[i]).mulWad(_getSlashingFactor(staker, strategies[i])); - } - 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); - } - - function _getCumulativeWithdrawals(User staker) internal view returns (uint) { - return delegationManager.cumulativeWithdrawalsQueued(address(staker)); - } - - function _getPrevTokenBalances(User staker, IERC20[] memory tokens) internal timewarp returns (uint[] memory) { - return _getTokenBalances(staker, tokens); - } - - 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; - else balances[i] = tokens[i].balanceOf(address(staker)); - } - - return balances; - } - - function _getPrevTotalStrategyShares(IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getTotalStrategyShares(strategies); - } - - function _getTotalStrategyShares(IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory shares = new uint[](strategies.length); - - for (uint i = 0; i < strategies.length; i++) { - if (strategies[i] != BEACONCHAIN_ETH_STRAT) shares[i] = strategies[i].totalShares(); - // BeaconChainETH strategy doesn't keep track of global strategy shares, so we ignore - } - - return shares; - } - - function _getDepositScalingFactors(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory depositScalingFactors = new uint[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { - depositScalingFactors[i] = _getDepositScalingFactor(staker, strategies[i]); - } - return depositScalingFactors; - } - - function _getDepositScalingFactor(User staker, IStrategy strategy) internal view returns (uint) { - return delegationManager.depositScalingFactor(address(staker), strategy); - } - - function _getPrevDepositScalingFactors(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getDepositScalingFactors(staker, strategies); - } - - function _getExpectedDSFUndelegate(User staker) internal view returns (uint expectedDepositScalingFactor) { - return WAD.divWad(_getBeaconChainSlashingFactor(staker)); - } - - function _getExpectedDSFDeposit(User staker, User operator, IStrategy strategy) - internal - view - returns (uint expectedDepositScalingFactor) - { - if (strategy == BEACONCHAIN_ETH_STRAT) { - return WAD.divWad(allocationManager.getMaxMagnitude(address(operator), strategy).mulWad(_getBeaconChainSlashingFactor(staker))); - } else { - return WAD.divWad(allocationManager.getMaxMagnitude(address(operator), strategy)); - } - } - - function _getExpectedWithdrawableSharesUndelegate(User staker, IStrategy[] memory strategies, uint[] memory shares) - internal - view - returns (uint[] memory) - { - uint[] memory expectedWithdrawableShares = new uint[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { - if (strategies[i] == BEACONCHAIN_ETH_STRAT) { - expectedWithdrawableShares[i] = - shares[i].mulWad(_getExpectedDSFUndelegate(staker)).mulWad(_getBeaconChainSlashingFactor(staker)); - } else { - expectedWithdrawableShares[i] = shares[i]; - } - } - return expectedWithdrawableShares; - } - - function _getExpectedDSFsDelegate(User staker, User operator, IStrategy[] memory strategies) internal returns (uint[] memory) { - uint[] memory expectedDepositScalingFactors = new uint[](strategies.length); - uint[] memory oldDepositScalingFactors = _getPrevDepositScalingFactors(staker, strategies); - uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { - expectedDepositScalingFactors[i] = oldDepositScalingFactors[i].divWad(maxMagnitudes[i]); - } - return expectedDepositScalingFactors; - } - - function _getExpectedWithdrawableSharesDelegate(User staker, User operator, IStrategy[] memory strategies, uint[] memory depositShares) - internal - returns (uint[] memory) - { - uint[] memory expectedWithdrawableShares = new uint[](strategies.length); - uint[] memory expectedDSFs = _getExpectedDSFsDelegate(staker, operator, strategies); - uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, strategies); - for (uint i = 0; i < strategies.length; i++) { - if (strategies[i] == BEACONCHAIN_ETH_STRAT) { - expectedWithdrawableShares[i] = - depositShares[i].mulWad(expectedDSFs[i]).mulWad(maxMagnitudes[i].mulWad(_getBeaconChainSlashingFactor(staker))); - } else { - expectedWithdrawableShares[i] = depositShares[i].mulWad(expectedDSFs[i]).mulWad(maxMagnitudes[i]); - } - } - return expectedWithdrawableShares; - } - - function _getExpectedWithdrawableSharesDeposit(User staker, User operator, IStrategy strategy, uint depositShares) - internal - view - returns (uint) - { - return depositShares.mulWad(_getExpectedDSFDeposit(staker, operator, strategy)).mulWad(_getSlashingFactor(staker, strategy)); - } - - function _getSlashingFactor(User staker, IStrategy strategy) internal view returns (uint) { - address operator = delegationManager.delegatedTo(address(staker)); - uint64 maxMagnitude = allocationManager.getMaxMagnitudes(operator, strategy.toArray())[0]; - if (strategy == beaconChainETHStrategy) return maxMagnitude.mulWad(eigenPodManager.beaconChainSlashingFactor(address(staker))); - return maxMagnitude; - } - - function _getPrevSlashingFactor(User staker, IStrategy strategy) internal timewarp returns (uint) { - return _getSlashingFactor(staker, strategy); - } - - function _getSlashingFactors(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { - address operator = delegationManager.delegatedTo(address(staker)); - uint64[] memory maxMagnitudes = allocationManager.getMaxMagnitudes(operator, strategies); - uint[] memory slashingFactors = new uint[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { - if (strategies[i] == beaconChainETHStrategy) { - slashingFactors[i] = maxMagnitudes[i].mulWad(eigenPodManager.beaconChainSlashingFactor(address(staker))); - } else { - slashingFactors[i] = maxMagnitudes[i]; - } - } - return slashingFactors; - } - - function _getPrevSlashingFactors(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getSlashingFactors(staker, strategies); - } - - function _getPrevWithdrawableShares(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { - return _getWithdrawableShares(staker, strategies); - } - - function _getWithdrawableShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory withdrawableShares) { - (withdrawableShares,) = delegationManager.getWithdrawableShares(address(staker), strategies); - } - - function _getWithdrawableShares(User staker, IStrategy strategy) internal view returns (uint withdrawableShares) { - (uint[] memory _withdrawableShares,) = delegationManager.getWithdrawableShares(address(staker), strategy.toArray()); - return _withdrawableShares[0]; - } - - /// @dev Assumes that the staker has one withdrawal queued - function _getWithdrawableSharesAfterCompletion(User staker) internal view returns (uint[] memory withdrawableShares) { - bytes32 root = delegationManager.getQueuedWithdrawalRoots(address(staker))[0]; - (, withdrawableShares) = delegationManager.getQueuedWithdrawal(root); - } - - function _getActiveValidatorCount(User staker) internal view returns (uint) { - EigenPod pod = staker.pod(); - return pod.activeValidatorCount(); - } - - function _getPrevActiveValidatorCount(User staker) internal timewarp returns (uint) { - return _getActiveValidatorCount(staker); - } - - function _getValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal view returns (VALIDATOR_STATUS[] memory) { - EigenPod pod = staker.pod(); - VALIDATOR_STATUS[] memory statuses = new VALIDATOR_STATUS[](pubkeyHashes.length); - - for (uint i = 0; i < statuses.length; i++) { - statuses[i] = pod.validatorStatus(pubkeyHashes[i]); - } - - return statuses; - } - - function _getPrevValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal timewarp returns (VALIDATOR_STATUS[] memory) { - return _getValidatorStatuses(staker, pubkeyHashes); - } - - function _getCheckpointTimestamp(User staker) internal view returns (uint64) { - EigenPod pod = staker.pod(); - return pod.currentCheckpointTimestamp(); - } - - function _getPrevCheckpointTimestamp(User staker) internal timewarp returns (uint64) { - return _getCheckpointTimestamp(staker); - } - - function _getLastCheckpointTimestamp(User staker) internal view returns (uint64) { - EigenPod pod = staker.pod(); - return pod.lastCheckpointTimestamp(); - } - - function _getPrevLastCheckpointTimestamp(User staker) internal timewarp returns (uint64) { - return _getLastCheckpointTimestamp(staker); - } - - function _getWithdrawableRestakedGwei(User staker) internal view returns (uint64) { - EigenPod pod = staker.pod(); - return pod.withdrawableRestakedExecutionLayerGwei(); - } - - function _getPrevWithdrawableRestakedGwei(User staker) internal timewarp returns (uint64) { - return _getWithdrawableRestakedGwei(staker); - } - - function _getCheckpointPodBalanceGwei(User staker) internal view returns (uint64) { - EigenPod pod = staker.pod(); - return uint64(pod.currentCheckpoint().podBalanceGwei); - } - - function _getPrevCheckpointPodBalanceGwei(User staker) internal timewarp returns (uint64) { - return _getCheckpointPodBalanceGwei(staker); - } - - function _getCheckpointBalanceExited(User staker, uint64 checkpointTimestamp) internal view returns (uint64) { - EigenPod pod = staker.pod(); - return pod.checkpointBalanceExitedGwei(checkpointTimestamp); - } - - function _getPrevCheckpointBalanceExited(User staker, uint64 checkpointTimestamp) internal timewarp returns (uint64) { - return _getCheckpointBalanceExited(staker, checkpointTimestamp); - } - - function _getQueuedWithdrawals(User staker) internal view returns (Withdrawal[] memory) { - (Withdrawal[] memory withdrawals,) = delegationManager.getQueuedWithdrawals(address(staker)); - return withdrawals; + assertEq(_getBeaconChainSlashingFactor(staker), _getPrevBeaconChainSlashingFactor(staker), err); } } diff --git a/src/test/integration/IntegrationChecks.t.sol b/src/test/integration/IntegrationChecks.t.sol index 1da2e36ab6..1020eeb7af 100644 --- a/src/test/integration/IntegrationChecks.t.sol +++ b/src/test/integration/IntegrationChecks.t.sol @@ -1,23 +1,65 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/IntegrationBase.t.sol"; +import "src/test/integration/IntegrationUtils.t.sol"; import "src/test/integration/users/User.t.sol"; import "src/test/integration/users/User_M1.t.sol"; import "src/test/integration/users/User_M2.t.sol"; /// @notice Contract that provides utility functions to reuse common test blocks & checks -contract IntegrationCheckUtils is IntegrationBase { +contract IntegrationChecks is IntegrationUtils { using ArrayLib for *; - using SlashingLib for *; using StdStyle for *; + AVS avs; + SlashingParams slashParams; + SlashingParams slashingParams; + + User operator; + OperatorSet operatorSet; + AllocateParams allocateParams; + + User staker; + IERC20[] tokens; + IStrategy[] strategies; + uint[] initTokenBalances; + uint[] initDepositShares; + uint[] withdrawableShares; + // Withdrawal[] withdrawals; // cannot copy from memory to storage easily + bytes32[] withdrawalRoots; + uint[] numTokensRemaining; + + uint64 beaconBalanceGwei; + uint40[] validators; + uint40[] slashedValidators; + uint64 slashedGwei; + uint64 slashedAmountGwei; + + function _completeWithdrawal( + User staker, + User operator, + Withdrawal[] memory withdrawals, + IStrategy[] memory strategies, + uint[] memory withdrawalShares, + uint[] memory expectedTokens + ) internal { + for (uint i = 0; i < withdrawals.length; i++) { + if (_randBool()) { + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawalShares, expectedTokens); + } else { + staker.completeWithdrawalAsShares(withdrawals[i]); + check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawalShares); + } + } + } + /** * * EIGENPOD CHECKS * */ - function check_VerifyWC_State(User staker, uint40[] memory validators, uint64 beaconBalanceGwei) internal { + function check_VerifyWC_State(User staker, uint40[] memory validators, uint64 beaconBalanceGwei) public { uint beaconBalanceWei = beaconBalanceGwei * GWEI_TO_WEI; assert_DepositShares_GTE_WithdrawableShares( staker, BEACONCHAIN_ETH_STRAT.toArray(), "deposit shares should be greater than or equal to withdrawable shares" @@ -31,18 +73,18 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Added_ActiveValidators(staker, validators, "validators should each be active"); } - function check_StartCheckpoint_State(User staker) internal { + function check_StartCheckpoint_State(User staker) public { assert_ProofsRemainingEqualsActive(staker, "checkpoint proofs remaining should equal active validator count"); assert_Snap_Created_Checkpoint(staker, "staker should have created a new checkpoint"); } - function check_StartCheckpoint_WithPodBalance_State(User staker, uint64 expectedPodBalanceGwei) internal { + function check_StartCheckpoint_WithPodBalance_State(User staker, uint64 expectedPodBalanceGwei) public { check_StartCheckpoint_State(staker); assert_CheckpointPodBalance(staker, expectedPodBalanceGwei, "checkpoint podBalanceGwei should equal expected"); } - function check_StartCheckpoint_NoValidators_State(User staker, uint64 sharesAddedGwei) internal { + function check_StartCheckpoint_NoValidators_State(User staker, uint64 sharesAddedGwei) public { assert_Snap_Added_Staker_DepositShares( staker, BEACONCHAIN_ETH_STRAT, sharesAddedGwei * GWEI_TO_WEI, "should have added staker shares" ); @@ -53,7 +95,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_Checkpoint(staker, "current checkpoint timestamp should be unchanged"); } - function check_CompleteCheckpoint_State(User staker) internal { + function check_CompleteCheckpoint_State(User staker) public { assert_DepositShares_GTE_WithdrawableShares( staker, BEACONCHAIN_ETH_STRAT.toArray(), "deposit shares should be greater than or equal to withdrawable shares" ); @@ -62,7 +104,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Added_PodBalanceToWithdrawable(staker, "pod balance should have been added to withdrawable restaked exec layer gwei"); } - function check_CompleteCheckpoint_EarnOnBeacon_State(User staker, uint64 beaconBalanceAdded) internal { + function check_CompleteCheckpoint_EarnOnBeacon_State(User staker, uint64 beaconBalanceAdded) public { check_CompleteCheckpoint_State(staker); uint balanceAddedWei = beaconBalanceAdded * GWEI_TO_WEI; @@ -72,7 +114,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_BCSF(staker, "BCSF should be unchanged"); } - function check_CompleteCheckpoint_WithPodBalance_State(User staker, uint64 expectedPodBalanceGwei) internal { + function check_CompleteCheckpoint_WithPodBalance_State(User staker, uint64 expectedPodBalanceGwei) public { check_CompleteCheckpoint_State(staker); assert_Snap_Added_WithdrawableGwei( @@ -81,7 +123,7 @@ contract IntegrationCheckUtils is IntegrationBase { } /// @dev Common checks for all slashing states, irrespective of validator exits - function check_CompleteCheckpoint_WithSlashing_State_Base(User staker) internal { + function check_CompleteCheckpoint_WithSlashing_State_Base(User staker) public { check_CompleteCheckpoint_State(staker); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have decreased"); @@ -90,7 +132,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_SlashableStake_Decrease_BCSlash(staker); } - function check_CompleteCheckpoint_WithSlashing_Exits_State_Base(User staker, uint40[] memory slashedValidators) internal { + function check_CompleteCheckpoint_WithSlashing_Exits_State_Base(User staker, uint40[] memory slashedValidators) public { check_CompleteCheckpoint_WithSlashing_State_Base(staker); // Validator exits @@ -104,9 +146,7 @@ contract IntegrationCheckUtils is IntegrationBase { } /// @dev Includes validator exits - function check_CompleteCheckpoint_WithSlashing_State(User staker, uint40[] memory slashedValidators, uint64 slashedAmountGwei) - internal - { + function check_CompleteCheckpoint_WithSlashing_State(User staker, uint40[] memory slashedValidators, uint64 slashedAmountGwei) public { check_CompleteCheckpoint_WithSlashing_Exits_State_Base(staker, slashedValidators); // Prove withdrawable shares decrease @@ -116,9 +156,7 @@ contract IntegrationCheckUtils is IntegrationBase { } /// @dev Same as above, but BCSF must be zero on a full slash - function check_CompleteCheckpoint_FullySlashed_State(User staker, uint40[] memory slashedValidators, uint64 slashedAmountGwei) - internal - { + function check_CompleteCheckpoint_FullySlashed_State(User staker, uint40[] memory slashedValidators, uint64 slashedAmountGwei) public { check_CompleteCheckpoint_WithSlashing_State(staker, slashedValidators, slashedAmountGwei); assert_Zero_BCSF(staker, "BCSF should be 0"); } @@ -127,7 +165,7 @@ contract IntegrationCheckUtils is IntegrationBase { User staker, uint40[] memory slashedValidators, uint64 slashedAmountGwei - ) internal { + ) public { check_CompleteCheckpoint_WithSlashing_Exits_State_Base(staker, slashedValidators); assert_Snap_Removed_Staker_WithdrawableShares_AtLeast( @@ -140,7 +178,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @notice Used for edge cases where rounding behaviors of magnitudes close to 1 are tested. /// Normal - function check_CompleteCheckPoint_WithSlashing_LowMagnitude_State(User staker, uint64 slashedAmountGwei) internal { + function check_CompleteCheckPoint_WithSlashing_LowMagnitude_State(User staker, uint64 slashedAmountGwei) public { check_CompleteCheckpoint_State(staker); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have decreased"); assert_Snap_Removed_Staker_WithdrawableShares_AtLeast( @@ -154,7 +192,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_DSF(staker, BEACONCHAIN_ETH_STRAT.toArray(), "DSF should be unchanged"); } - function check_CompleteCheckpoint_WithCLSlashing_State(User staker, uint64 slashedAmountGwei) internal { + function check_CompleteCheckpoint_WithCLSlashing_State(User staker, uint64 slashedAmountGwei) public { check_CompleteCheckpoint_WithSlashing_State_Base(staker); assert_Snap_Removed_Staker_WithdrawableShares( @@ -163,7 +201,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); } - function check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State(User staker, uint64 slashedAmountGwei) internal { + function check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State(User staker, uint64 slashedAmountGwei) public { check_CompleteCheckpoint_WithSlashing_State_Base(staker); assert_Snap_Removed_Staker_WithdrawableShares_AtLeast( @@ -175,7 +213,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); } - function check_CompleteCheckpoint_WithExits_State(User staker, uint40[] memory exitedValidators, uint64 exitedBalanceGwei) internal { + function check_CompleteCheckpoint_WithExits_State(User staker, uint40[] memory exitedValidators, uint64 exitedBalanceGwei) public { check_CompleteCheckpoint_WithPodBalance_State(staker, exitedBalanceGwei); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker should not have changed shares"); @@ -184,7 +222,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Removed_ActiveValidators(staker, exitedValidators, "exited validators should each be WITHDRAWN"); } - function check_CompleteCheckpoint_ZeroBalanceDelta_State(User staker) internal { + function check_CompleteCheckpoint_ZeroBalanceDelta_State(User staker) public { check_CompleteCheckpoint_State(staker); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker deposit shares should not have decreased"); @@ -199,7 +237,7 @@ contract IntegrationCheckUtils is IntegrationBase { * LST/DELEGATION CHECKS * */ - function check_Deposit_State(User staker, IStrategy[] memory strategies, uint[] memory shares) internal { + function check_Deposit_State(User staker, IStrategy[] memory strategies, uint[] memory shares) public { /// Deposit into strategies: // For each of the assets held by the staker (either StrategyManager or EigenPodManager), // the staker calls the relevant deposit function, depositing all held assets. @@ -213,8 +251,8 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Added_Staker_DepositShares(staker, strategies, shares, "staker should expect shares in each strategy after depositing"); assert_StrategiesInStakerStrategyList(staker, strategies, "staker strategy list should contain all strategies"); - if (delegationManager.isDelegated(address(staker))) { - User operator = User(payable(delegationManager.delegatedTo(address(staker)))); + if (delegationManager().isDelegated(address(staker))) { + User operator = User(payable(delegationManager().delegatedTo(address(staker)))); assert_Snap_Expected_Staker_WithdrawableShares_Deposit( staker, operator, strategies, shares, "staker should have received expected withdrawable shares" ); @@ -229,7 +267,7 @@ contract IntegrationCheckUtils is IntegrationBase { IStrategy[] memory strategies, uint[] memory shares, uint[] memory tokenBalances - ) internal { + ) public { /// Deposit into strategies: // For each of the assets held by the staker (either StrategyManager or EigenPodManager), // the staker calls the relevant deposit function, depositing some subset of held assets @@ -245,8 +283,8 @@ contract IntegrationCheckUtils is IntegrationBase { staker, strategies, shares, "staker should expected shares in each strategy after depositing" ); - if (delegationManager.isDelegated(address(staker))) { - User operator = User(payable(delegationManager.delegatedTo(address(staker)))); + if (delegationManager().isDelegated(address(staker))) { + User operator = User(payable(delegationManager().delegatedTo(address(staker)))); assert_Snap_Expected_Staker_WithdrawableShares_Deposit( staker, operator, strategies, shares, "staker should have received expected withdrawable shares" ); @@ -256,13 +294,13 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_DSF_State_Deposit(staker, strategies, "staker's DSF not updated correctly"); } - function check_Delegation_State(User staker, User operator, IStrategy[] memory strategies, uint[] memory depositShares) internal { + function check_Delegation_State(User staker, User operator, IStrategy[] memory strategies, uint[] memory depositShares) public { /// Delegate to an operator: // // ... check that the staker is now delegated to the operator, and that the operator // was awarded the staker shares - assertTrue(delegationManager.isDelegated(address(staker)), "staker should be delegated"); - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should be delegated to operator"); + 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, depositShares, "staker should still have expected shares after delegating"); assert_DepositShares_GTE_WithdrawableShares( staker, strategies, "deposit shares should be greater than or equal to withdrawable shares" @@ -277,7 +315,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_DSF_State_Delegation(staker, strategies, delegatableShares, "staker's DSF not updated correctly"); } - function check_Added_SlashableStake(User operator, IStrategy[] memory strategies) internal { + function check_Added_SlashableStake(User operator, IStrategy[] memory strategies) public { for (uint i = 0; i < strategies.length; i++) { (OperatorSet[] memory operatorSets, Allocation[] memory allocations) = _getStrategyAllocations(operator, strategies[i]); for (uint j = 0; j < operatorSets.length; j++) { @@ -298,7 +336,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint[] memory withdrawableShares, Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots - ) internal { + ) public { // The staker will queue one or more withdrawals for the selected strategies and shares // // ... check that each withdrawal was successfully enqueued, that the returned roots @@ -306,7 +344,7 @@ contract IntegrationCheckUtils is IntegrationBase { // reduced shares. _check_QueuedWithdrawal_State_NotDelegated(staker, strategies, depositShares, withdrawableShares, withdrawals, withdrawalRoots); - if (delegationManager.isDelegated(address(staker))) { + if (delegationManager().isDelegated(address(staker))) { assert_Snap_Removed_OperatorShares( operator, strategies, withdrawableShares, "check_QueuedWithdrawal_State: failed to remove operator shares" ); @@ -363,7 +401,7 @@ contract IntegrationCheckUtils is IntegrationBase { } } - function check_Decreased_SlashableStake(User operator, uint[] memory withdrawableShares, IStrategy[] memory strategies) internal { + function check_Decreased_SlashableStake(User operator, uint[] memory withdrawableShares, IStrategy[] memory strategies) public { for (uint i = 0; i < strategies.length; i++) { if (withdrawableShares[i] > 0) { (OperatorSet[] memory operatorSets, Allocation[] memory allocations) = _getStrategyAllocations(operator, strategies[i]); @@ -388,14 +426,14 @@ contract IntegrationCheckUtils is IntegrationBase { bytes32[] memory withdrawalRoots, IStrategy[] memory strategies, uint[] memory stakerDelegatedShares - ) internal { + ) public { /// Undelegate from an operator // // ... check that the staker is undelegated, all strategies from which the staker is deposited are unqueued, // that the returned root matches the hashes for each strategy and share amounts, and that the staker // and operator have reduced shares assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares"); - assertFalse(delegationManager.isDelegated(address(staker)), "check_Undelegate_State: staker should not be delegated"); + assertFalse(delegationManager().isDelegated(address(staker)), "check_Undelegate_State: staker should not be delegated"); assert_ValidWithdrawalHashes( withdrawals, withdrawalRoots, "check_Undelegate_State: calculated withdrawal should match returned root" ); @@ -418,18 +456,18 @@ contract IntegrationCheckUtils is IntegrationBase { User staker, User oldOperator, User newOperator, - IDelegationManagerTypes.Withdrawal[] memory withdrawals, + Withdrawal[] memory withdrawals, bytes32[] memory withdrawalRoots, IStrategy[] memory strategies, uint[] memory stakerDelegatedShares - ) internal { + ) public { /// Redelegate to a new operator // // ... check that the staker is delegated to new operator, all strategies from which the staker is deposited are unqueued, // that the returned root matches the hashes for each strategy and share amounts, and that the staker // and operator have reduced shares - assertTrue(delegationManager.isDelegated(address(staker)), "check_Redelegate_State: staker should not be delegated"); - assertEq(address(newOperator), delegationManager.delegatedTo(address(staker)), "staker should be delegated to operator"); + assertTrue(delegationManager().isDelegated(address(staker)), "check_Redelegate_State: staker should not be delegated"); + assertEq(address(newOperator), delegationManager().delegatedTo(address(staker)), "staker should be delegated to operator"); assert_HasExpectedShares( staker, strategies, new uint[](strategies.length), "staker should not have deposit shares after redelegation" ); @@ -458,30 +496,28 @@ contract IntegrationCheckUtils is IntegrationBase { * @param staker The staker who completed the withdrawal. * @param operator The operator address, which can be a non-user type like address(0). * @param withdrawal The details of the withdrawal that was completed. - * @param strategies The strategies from which the withdrawal was made. * @param shares The number of shares involved in the withdrawal. - * @param tokens The tokens received after the withdrawal. * @param expectedTokens The expected tokens to be received after the withdrawal. */ function check_Withdrawal_AsTokens_State( User staker, User operator, Withdrawal memory withdrawal, - IStrategy[] memory strategies, uint[] memory shares, - IERC20[] memory tokens, uint[] memory expectedTokens - ) internal { + ) public { // Common checks - assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + assert_WithdrawalNotPending( + delegationManager().calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending" + ); assert_DepositShares_GTE_WithdrawableShares( - staker, strategies, "deposit shares should be greater than or equal to withdrawable shares" + staker, withdrawal.strategies, "deposit shares should be greater than or equal to withdrawable shares" ); - assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens"); + assert_Snap_Added_TokenBalances(staker, withdrawal.strategies, expectedTokens, "staker should have received expected tokens"); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); - assert_Snap_Unchanged_DSF(staker, strategies, "dsf should not be changed"); - assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented"); + assert_Snap_Unchanged_DSF(staker, withdrawal.strategies, "dsf should not be changed"); + assert_Snap_Removed_StrategyShares(withdrawal.strategies, shares, "strategies should have total shares decremented"); // Checks specific to an operator that the Staker has delegated to if (operator != User(payable(0))) { @@ -496,9 +532,11 @@ contract IntegrationCheckUtils is IntegrationBase { Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory withdrawableShares - ) internal { + ) public { // Common checks applicable to both user and non-user operator types - assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + assert_WithdrawalNotPending( + delegationManager().calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending" + ); assert_DepositShares_GTE_WithdrawableShares( staker, strategies, "deposit shares should be greater than or equal to withdrawable shares" ); @@ -526,14 +564,16 @@ contract IntegrationCheckUtils is IntegrationBase { Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory withdrawableShares - ) internal { + ) public { /// Complete withdrawal(s): // The staker will complete the withdrawal as shares // // ... check that the withdrawal is not pending, that the token balances of the staker and operator are unchanged, // that the withdrawer received the expected shares, and that that the total shares of each o // strategy withdrawn remains unchanged - assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + assert_WithdrawalNotPending( + delegationManager().calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending" + ); assert_DepositShares_GTE_WithdrawableShares( staker, strategies, "deposit shares should be greater than or equal to withdrawable shares" ); @@ -558,14 +598,16 @@ contract IntegrationCheckUtils is IntegrationBase { Withdrawal memory withdrawal, IStrategy[] memory strategies, uint[] memory withdrawableShares - ) internal { + ) public { /// Complete withdrawal(s): // The staker will complete the withdrawal as shares // // ... check that the withdrawal is not pending, that the token balances of the staker and operator are unchanged, // that the withdrawer received the expected shares, and that that the total shares of each o // strategy withdrawn remains unchanged - assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + assert_WithdrawalNotPending( + delegationManager().calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending" + ); assert_DepositShares_GTE_WithdrawableShares( staker, strategies, "deposit shares should be greater than or equal to withdrawable shares" ); @@ -579,7 +621,9 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Expected_Staker_WithdrawableShares_Deposit( staker, newOperator, strategies, withdrawableShares, "staker should have received expected withdrawable shares" ); + } + function check_Withdrawal_AsShares_Redelegated_State(User staker, IStrategy[] memory strategies) internal { assert_Snap_DSF_State_WithdrawalAsShares(staker, strategies, "staker's DSF not updated correctly"); } @@ -619,13 +663,13 @@ contract IntegrationCheckUtils is IntegrationBase { } /// @dev Check global max magnitude invariants - these should ALWAYS hold - function check_MaxMag_Invariants(User operator) internal view { + function check_MaxMag_Invariants(User operator) public view { assert_MaxMagsEqualMaxMagsAtCurrentBlock(operator, allStrats, "max magnitudes should equal upperlookup at current block"); assert_MaxEqualsAllocatablePlusEncumbered(operator, "max magnitude should equal encumbered plus allocatable"); } /// @dev Check that the last call to modifyAllocations resulted in a non-pending modification - function check_ActiveModification_State(User operator, AllocateParams memory params) internal view { + function check_ActiveModification_State(User operator, AllocateParams memory params) public view { OperatorSet memory operatorSet = params.operatorSet; IStrategy[] memory strategies = params.strategies; @@ -633,14 +677,14 @@ contract IntegrationCheckUtils is IntegrationBase { assert_NoPendingModification(operator, operatorSet, strategies, "there should not be a pending modification for any strategy"); } - function check_IsSlashable_State(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) internal view { + function check_IsSlashable_State(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) public view { assert_IsSlashable(operator, operatorSet, "operator should be slashable for operator set"); assert_CurMinSlashableEqualsMinAllocated( operator, operatorSet, strategies, "minimum slashable stake should equal allocated stake at current block" ); } - function check_NotSlashable_State(User operator, OperatorSet memory operatorSet) internal view { + function check_NotSlashable_State(User operator, OperatorSet memory operatorSet) public view { assert_NotSlashable(operator, operatorSet, "operator should not be slashable for operator set"); assert_NoSlashableStake(operator, operatorSet, "operator should not have any slashable stake"); } @@ -654,9 +698,9 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Basic invariants that should hold after EVERY call to `registerForOperatorSets` /// NOTE: These are only slightly modified from check_Base_Deregistration_State /// If you add invariants here, consider adding them there (and vice-versa) - function check_Base_Registration_State(User operator, OperatorSet memory operatorSet) internal { + function check_Base_Registration_State(User operator, OperatorSet memory operatorSet) public { check_MaxMag_Invariants(operator); - check_IsSlashable_State(operator, operatorSet, allocationManager.getStrategiesInOperatorSet(operatorSet)); + check_IsSlashable_State(operator, operatorSet, allocationManager().getStrategiesInOperatorSet(operatorSet)); // Registration SHOULD register the operator, making them slashable and adding them as a member of the set assert_Snap_Became_Registered(operator, operatorSet, "operator should not have been registered before, and is now registered"); @@ -677,9 +721,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Check invariants for registerForOperatorSets given a set of strategies /// for which NO allocation exists (currentMag/pendingDiff are 0) /// @param unallocated For the given operatorSet, a list of strategies for which NO allocation exists - function check_Registration_State_NoAllocation(User operator, OperatorSet memory operatorSet, IStrategy[] memory unallocated) - internal - { + function check_Registration_State_NoAllocation(User operator, OperatorSet memory operatorSet, IStrategy[] memory unallocated) public { check_Base_Registration_State(operator, operatorSet); /// The operator is NOT allocated, ensure their slashable stake and magnitudes are unchanged @@ -695,7 +737,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// ASSUMES: /// - the effect block for `params` has already passed /// - params.newMagnitudes does NOT contain any `0` entries - function check_Registration_State_ActiveAllocation(User operator, AllocateParams memory active) internal { + function check_Registration_State_ActiveAllocation(User operator, AllocateParams memory active) public { OperatorSet memory operatorSet = active.operatorSet; IStrategy[] memory strategies = active.strategies; @@ -716,7 +758,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Check registration invariants. Assumes the operator has a PENDING allocation /// to the set, but that the allocation's effect block has not yet been reached - function check_Registration_State_PendingAllocation(User operator, AllocateParams memory params) internal { + function check_Registration_State_PendingAllocation(User operator, AllocateParams memory params) public { OperatorSet memory operatorSet = params.operatorSet; IStrategy[] memory strategies = params.strategies; @@ -742,7 +784,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Basic invariants that should hold after EVERY call to `deregisterFromOperatorSets` /// NOTE: These are only slightly modified from check_Base_Registration_State /// If you add invariants here, consider adding them there (and vice-versa) - function check_Base_Deregistration_State(User operator, OperatorSet memory operatorSet) internal { + function check_Base_Deregistration_State(User operator, OperatorSet memory operatorSet) public { check_MaxMag_Invariants(operator); // Deregistration SHOULD remove the operator as a member of the set @@ -767,7 +809,7 @@ contract IntegrationCheckUtils is IntegrationBase { _rollBackward_DeallocationDelay(); } - function check_Deregistration_State_NoAllocation(User operator, OperatorSet memory operatorSet) internal { + function check_Deregistration_State_NoAllocation(User operator, OperatorSet memory operatorSet) public { check_Base_Deregistration_State(operator, operatorSet); assert_Snap_Unchanged_AllocatedStake(operator, operatorSet, allStrats, "should not have updated allocated stake in any way"); @@ -776,7 +818,7 @@ contract IntegrationCheckUtils is IntegrationBase { ); } - function check_Deregistration_State_ActiveAllocation(User operator, OperatorSet memory operatorSet) internal { + function check_Deregistration_State_ActiveAllocation(User operator, OperatorSet memory operatorSet) public { check_Base_Deregistration_State(operator, operatorSet); assert_Snap_Unchanged_AllocatedStake(operator, operatorSet, allStrats, "should not have updated allocated stake in any way"); @@ -785,7 +827,7 @@ contract IntegrationCheckUtils is IntegrationBase { ); } - function check_Deregistration_State_PendingAllocation(User operator, OperatorSet memory operatorSet) internal { + function check_Deregistration_State_PendingAllocation(User operator, OperatorSet memory operatorSet) public { check_Base_Deregistration_State(operator, operatorSet); assert_Snap_Unchanged_AllocatedStake(operator, operatorSet, allStrats, "should not have updated allocated stake in any way"); @@ -802,7 +844,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Basic invariants that should hold after all calls to `modifyAllocations` /// where the input `params` represent an _increase_ in magnitude - function check_Base_IncrAlloc_State(User operator, AllocateParams memory params) internal { + function check_Base_IncrAlloc_State(User operator, AllocateParams memory params) public { check_MaxMag_Invariants(operator); OperatorSet memory operatorSet = params.operatorSet; @@ -824,7 +866,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Invariants for modifyAllocations. Use when: /// - operator is NOT slashable for this operator set /// - last call to modifyAllocations created an INCREASE in allocation - function check_IncrAlloc_State_NotSlashable(User operator, AllocateParams memory params) internal { + function check_IncrAlloc_State_NotSlashable(User operator, AllocateParams memory params) public { check_Base_IncrAlloc_State(operator, params); check_NotSlashable_State(operator, params.operatorSet); @@ -872,7 +914,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Invariants for modifyAllocations. Use when: /// - operator IS slashable for this operator set /// - last call to modifyAllocations created an INCREASE in allocation - function check_IncrAlloc_State_Slashable(User operator, AllocateParams memory params) internal { + function check_IncrAlloc_State_Slashable(User operator, AllocateParams memory params) public { check_Base_IncrAlloc_State(operator, params); check_IsSlashable_State(operator, params.operatorSet, params.strategies); @@ -887,7 +929,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// - operator IS slashable for this operator set /// - last call to modifyAllocations created an INCREASE in allocation /// - operator has no delegated shares/stake so their slashable stake remains UNCHANGED - function check_IncrAlloc_State_Slashable_NoDelegatedStake(User operator, AllocateParams memory params) internal { + function check_IncrAlloc_State_Slashable_NoDelegatedStake(User operator, AllocateParams memory params) public { check_Base_IncrAlloc_State(operator, params); check_IsSlashable_State(operator, params.operatorSet, params.strategies); @@ -955,7 +997,7 @@ contract IntegrationCheckUtils is IntegrationBase { /// @dev Basic invariants that should hold after all calls to `modifyAllocations` /// where the input `params` represent a decrease in magnitude - function check_Base_DecrAlloc_State(User operator, AllocateParams memory params) internal { + function check_Base_DecrAlloc_State(User operator, AllocateParams memory params) public { check_MaxMag_Invariants(operator); OperatorSet memory operatorSet = params.operatorSet; @@ -968,7 +1010,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_MaxMagnitude(operator, allStrats, "should not have updated max magnitudes in any way"); } - function check_DecrAlloc_State_NotSlashable(User operator, AllocateParams memory params) internal { + function check_DecrAlloc_State_NotSlashable(User operator, AllocateParams memory params) public { OperatorSet memory operatorSet = params.operatorSet; IStrategy[] memory strategies = params.strategies; @@ -983,7 +1025,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Deallocated_Magnitude(operator, strategies, "should have deallocated magnitude"); } - function check_DecrAlloc_State_Slashable(User operator, AllocateParams memory params) internal { + function check_DecrAlloc_State_Slashable(User operator, AllocateParams memory params) public { check_Base_DecrAlloc_State(operator, params); check_IsSlashable_State(operator, params.operatorSet, params.strategies); @@ -1027,7 +1069,7 @@ contract IntegrationCheckUtils is IntegrationBase { } function check_FullyDeallocated_State(User operator, AllocateParams memory allocateParams, AllocateParams memory deallocateParams) - internal + public { OperatorSet memory operatorSet = allocateParams.operatorSet; assert_NoSlashableStake(operator, operatorSet, "should not have any slashable stake"); @@ -1052,7 +1094,7 @@ contract IntegrationCheckUtils is IntegrationBase { * ALM - SLASHING * */ - function check_Base_Slashing_State(User operator, AllocateParams memory allocateParams, SlashingParams memory slashParams) internal { + function check_Base_Slashing_State(User operator, AllocateParams memory allocateParams, SlashingParams memory slashParams) public { OperatorSet memory operatorSet = allocateParams.operatorSet; check_MaxMag_Invariants(operator); @@ -1080,13 +1122,13 @@ contract IntegrationCheckUtils is IntegrationBase { AllocateParams memory allocateParams, SlashingParams memory slashParams, Withdrawal[] memory withdrawals - ) internal { + ) public { check_Base_Slashing_State(operator, allocateParams, slashParams); assert_Snap_Decreased_SlashableSharesInQueue(operator, slashParams, withdrawals, "slash should decrease slashable shares in queue"); } /// Slashing invariants when the operator has been fully slashed for every strategy in the operator set - function check_FullySlashed_State(User operator, AllocateParams memory allocateParams, SlashingParams memory slashParams) internal { + function check_FullySlashed_State(User operator, AllocateParams memory allocateParams, SlashingParams memory slashParams) public { check_Base_Slashing_State(operator, allocateParams, slashParams); assert_Snap_Removed_AllocatedSet(operator, allocateParams.operatorSet, "should not have updated allocated sets"); @@ -1107,7 +1149,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint64 slashedBalanceGwei, AllocateParams memory allocateParams, SlashingParams memory slashingParams - ) internal { + ) public { check_CompleteCheckpoint_WithSlashing_Exits_State_Base(staker, slashedValidators); // From the original shares to the BC slash (AVS slash in between), the shares should have decreased by at least the BC slash amount @@ -1132,7 +1174,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint extraValidatorShares, AllocateParams memory allocateParams, SlashingParams memory slashingParams - ) internal { + ) public { // Checkpoint State check_CompleteCheckpoint_WithSlashing_Exits_State_Base(staker, slashedValidators); @@ -1152,7 +1194,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint40[] memory slashedValidators, uint64 slashedBalanceGwei, uint beaconSharesAddedGwei - ) internal { + ) public { // Checkpoint State - can't use base check since a BC balance decrease isn't occurring check_CompleteCheckpoint_State(staker); assert_Snap_Removed_ActiveValidatorCount(staker, slashedValidators.length, "should have decreased active validator count"); @@ -1178,7 +1220,7 @@ contract IntegrationCheckUtils is IntegrationBase { uint40[] memory slashedValidators, AllocateParams memory allocateParams, SlashingParams memory slashingParams - ) internal { + ) public { check_CompleteCheckpoint_WithSlashing_Exits_State_Base(staker, slashedValidators); // Assert no withdrawable shares diff --git a/src/test/integration/IntegrationDeployer.t.sol b/src/test/integration/IntegrationDeployer.t.sol index 9906a49759..f4f5800216 100644 --- a/src/test/integration/IntegrationDeployer.t.sol +++ b/src/test/integration/IntegrationDeployer.t.sol @@ -1,128 +1,91 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -// Imports -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 "forge-std/Test.sol"; +import {MockERC20} from "forge-std/mocks/MockERC20.sol"; -import "src/contracts/core/DelegationManager.sol"; -import "src/contracts/core/AllocationManager.sol"; -import "src/contracts/core/StrategyManager.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/mocks/EmptyContract.sol"; -import "src/test/mocks/ETHDepositMock.sol"; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/governance/TimelockController.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 "src/test/integration/users/User_M2.t.sol"; +import "src/test/mocks/BeaconChainMock.t.sol"; +import "src/test/mocks/EmptyContract.sol"; +import "src/test/utils/Constants.t.sol"; +import "src/test/Config.t.sol"; -import "script/utils/ExistingDeploymentParser.sol"; - -IStrategy constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - -abstract contract IntegrationDeployer is ExistingDeploymentParser { +abstract contract IntegrationDeployer is ConfigGetters, Logger { + using ConfigParser for *; using StdStyle for *; using ArrayLib for *; - // Fork ids for specific fork tests - bool isUpgraded; - uint mainnetForkBlock = 21_616_692; // Post Protocol Council upgrade - - string version = "v9.9.9"; - - // 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 = 1_606_824_023; - uint64 BEACON_GENESIS_TIME; // set after forkType is decided - - // Beacon chain deposit contract. The BeaconChainMock contract etchs ETHPOSDepositMock code here. - IETHPOSDeposit constant DEPOSIT_CONTRACT = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); - - uint8 constant NUM_LST_STRATS = 32; - // Lists of strategies used in the system - // - // 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[] allStrats; // just a combination of the above 2 lists - IERC20[] allTokens; // `allStrats`, but contains all of the underlying tokens instead - uint maxUniqueAssetsHeld; - - // If a token is in this mapping, then we will ignore this LST as it causes issues with reading balanceOf + // TODO get rid of this storage + /// @dev AllocationManager + uint32 constant DEALLOCATION_DELAY = 50; + uint32 constant ALLOCATION_CONFIGURATION_DELAY = 75; + + /// @dev DelegationManager + uint32 constant DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = 50; + + /// @dev RewardsCoordinator + uint32 constant REWARDS_COORDINATOR_MAX_REWARDS_DURATION = 6_048_000; + uint32 constant REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = 7_776_000; + uint32 constant REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = 2_592_000; + uint32 constant REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = 1_710_979_200; + uint32 constant REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = 86_400; + + /// ----------------------------------------------------------------------- + /// State + /// ----------------------------------------------------------------------- + + /// @dev Returns the semver for test environments. + string constant SEMVER = "v9.9.9-test"; + + /// @notice Returns the genesis time for the beacon chain. Depends on the fork type. + uint64 public BEACON_GENESIS_TIME; + + /// @notice Returns whether the contracts have been upgraded or not. + bool public isUpgraded; + /// @notice Returns the allowed asset types for the tests. + uint public assetTypes = HOLDS_LST | HOLDS_ETH | HOLDS_ALL; + /// @notice Returns types of users to be randomly selected during tests + uint public userTypes = DEFAULT | ALT_METHODS; + + /// @notice Returns an array of deployed LST strategies. + IStrategy[] public lstStrats; + /// @notice Returns an array of all deployed strategies. + IStrategy[] public allStrats; + /// @notice Returns an array of all underlying tokens corresponding to strategies in `allStrats`. + IERC20[] public allTokens; + + /// @notice Returns the maximum number of unique assets a user holds. + uint public maxUniqueAssetsHeld; + /// @dev Returns true if a token should be excluded from testing + /// If a token is in this mapping, we will ignore this LST as it causes issues with reading balanceOf mapping(address => bool) public tokensNotTested; - // Mock Contracts to deploy - TimeMachine public timeMachine; - BeaconChainMock public beaconChain; - - // Admin Addresses - address constant pauser = address(555); - address constant unpauser = address(556); + EmptyContract public emptyContract; - // Randomness state vars - bytes32 random; - // After calling `_configRand`, these are the allowed "variants" on users that will - // be returned from `_randUser`. - bytes assetTypes; - bytes userTypes; - // Set only once in setUp, if FORK_MAINNET env is set - uint forkType; + string public profile; - /// @dev used to configure randomness and default user/asset types - /// - /// Tests that want alternate user/asset types can still use this modifier, - /// and then configure user/asset types individually using the methods: - /// _configAssetTypes(...) - /// _configUserTypes(...) - /// - /// (Alternatively, this modifier can be overwritten) - modifier rand(uint24 r) virtual { - _configRand({_randomSeed: r, _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, _userTypes: DEFAULT | ALT_METHODS}); + ForkConfig public forkConfig; - // Used to create shared setups between tests - _init(); - - _; - } + /// ----------------------------------------------------------------------- + /// Setup + /// ----------------------------------------------------------------------- constructor() { - address stETH_Holesky = 0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034; - address stETH_Mainnet = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; - address OETH_Mainnet = 0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3; - address osETH_Holesky = 0xF603c5A3F774F05d4D848A9bB139809790890864; - address osETH_Mainnet = 0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38; - address cbETH_Holesky = 0x8720095Fa5739Ab051799211B146a2EEE4Dd8B37; - tokensNotTested[stETH_Holesky] = true; - tokensNotTested[stETH_Mainnet] = true; - tokensNotTested[OETH_Mainnet] = true; - tokensNotTested[osETH_Holesky] = true; - tokensNotTested[osETH_Mainnet] = true; - tokensNotTested[cbETH_Holesky] = true; - + // QUESTION: Why is this needed? Shouldn't we have coverage for weird ERC20s? + tokensNotTested[address(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84)] = true; // stETH mainnet + tokensNotTested[address(0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3)] = true; // oETH mainnet + tokensNotTested[address(0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38)] = true; // osETH mainnet // Use current contracts by default. Upgrade tests are only run with mainnet fork tests // using the `UpgradeTest.t.sol` mixin. isUpgraded = 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. @@ -131,503 +94,445 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { * Note that forkIds are also created so you can make explicit fork tests using cheats.selectFork(forkId) */ function setUp() public virtual { - bool forkMainnet = isForktest(); + _setUp(true); + } - if (forkMainnet) { - forkType = MAINNET; - _setUpMainnet(); - } else { - forkType = LOCAL; + function _setUp(bool upgrade) internal virtual { + profile = FOUNDRY_PROFILE(); + forkConfig = ConfigParser.parseForkConfig(profile); + emptyContract = new EmptyContract(); + + if (eq(profile, "default")) { + // Assumes nothing has been deployed yet. _setUpLocal(); + } else if (eq(profile, "forktest-zeus")) { + // Assumes the proxy contracts have already been deployed. + config = ConfigParser.parseZeus(); + config.label(); + _setUpFork(upgrade); + } else { + // Assumes the proxy contracts have already been deployed. + config = ConfigParser.parse(string.concat("script/configs/", profile, ".toml")); + config.label(); + _setUpFork(upgrade); } + + _init(); } - /// @dev Used to create shared setup between tests. This method is called - /// when the `rand` modifier is run, before a test starts + /// ----------------------------------------------------------------------- + /// Helpers + /// ----------------------------------------------------------------------- + + /// @dev Override this method in derived test contracts to implement custom initialization logic. + /// This method is called at the end of the setUp() function after all contracts are deployed and initialized. + /// It allows test contracts to perform additional setup steps without having to override the entire setUp() function. function _init() internal virtual { return; } - /** - * env FOUNDRY_PROFILE=forktest forge t --mc Integration - * - * Running foundry like this will trigger the fork test profile, - * lowering fuzz runs and using a remote RPC to test against mainnet state - */ - function isForktest() public view returns (bool) { - return _hash("forktest") == _hash(cheats.envOr(string("FOUNDRY_PROFILE"), string("default"))); + /// @dev Configures the possible asset and user types for the random users. + function _configRand(uint _assetTypes, uint _userTypes) internal virtual { + _configAssetTypes(_assetTypes); + _configUserTypes(_userTypes); } - /// Deploy EigenLayer locally - function _setUpLocal() public virtual noTracing { - console.log("Setting up `%s` integration tests:", "LOCAL".yellow().bold()); + /// @dev Configures the possible asset types for the random users. + function _configAssetTypes(uint _assetTypes) internal virtual { + assertTrue((assetTypes = _assetTypes) != 0, "_configAssetTypes: no asset types selected"); + } - // Deploy ProxyAdmin - eigenLayerProxyAdmin = new ProxyAdmin(); - executorMultisig = address(eigenLayerProxyAdmin.owner()); + /// @dev Configures the possible user types for the random users. + function _configUserTypes(uint _userTypes) internal virtual { + assertTrue((userTypes = _userTypes) != 0, "_configUserTypes: no user types selected"); + } - // Deploy PauserRegistry - address[] memory pausers = new address[](1); - pausers[0] = pauser; - eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); + /// @dev Configures the maximum number of unique assets a user can hold. + function _configAssetAmounts(uint _maxUniqueAssetsHeld) internal virtual { + if (_maxUniqueAssetsHeld > allStrats.length) _maxUniqueAssetsHeld = allStrats.length; + assertTrue((maxUniqueAssetsHeld = _maxUniqueAssetsHeld) != 0, "_configAssetAmounts: invalid 0"); + } - // Deploy mocks - emptyContract = new EmptyContract(); + function FOUNDRY_PROFILE() internal view returns (string memory) { + return cheats.envOr(string("FOUNDRY_PROFILE"), string("default")); + } - // Matching parameters to testnet - DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = 50; - DEALLOCATION_DELAY = 50; - ALLOCATION_CONFIGURATION_DELAY = 75; + function eq(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } + + /// ----------------------------------------------------------------------- + /// Environment Setup + /// ----------------------------------------------------------------------- - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = 86_400; - REWARDS_COORDINATOR_MAX_REWARDS_DURATION = 6_048_000; - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = 7_776_000; - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = 2_592_000; - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = 1_710_979_200; + /// @dev Sets up the integration tests for local. + function _setUpLocal() public virtual { + console.log("Setting up `%s` integration tests:", "LOCAL".yellow().bold()); + + // Deploy ProxyAdmin, PauserRegistry, and executorMultisig. + config.governance.proxyAdmin = new ProxyAdmin(); + config.governance.pauserRegistry = new PauserRegistry(PAUSER.toArray(), UNPAUSER); + config.governance.executorMultisig = address(proxyAdmin().owner()); _deployProxies(); - _deployImplementations(); _upgradeProxies(); _initializeProxies(); // Place native ETH first in `allStrats` - // This ensures when we select a nonzero number of strategies from this array, we always - // have beacon chain ETH - ethStrats.push(BEACONCHAIN_ETH_STRAT); + // This ensures when we select a nonzero number of strategies from this array, we always have beacon chain ETH. allStrats.push(BEACONCHAIN_ETH_STRAT); allTokens.push(NATIVE_ETH); - // Deploy and configure strategies and tokens + // Deploy and configure strategies and tokens, deploy half of them using the strategy factory. for (uint i = 1; i < NUM_LST_STRATS + 1; ++i) { string memory name = string.concat("LST-Strat", cheats.toString(i), " token"); string memory symbol = string.concat("lstStrat", cheats.toString(i)); - // Deploy half of the strategies using the factory. _newStrategyAndToken(name, symbol, 10e50, address(this), i % 2 == 0); } + // Whitelist the strategies + cheats.prank(strategyManager().strategyWhitelister()); + strategyManager().addStrategiesToDepositWhitelist(allStrats); + maxUniqueAssetsHeld = allStrats.length; // Create time machine and beacon chain. Set block time to beacon chain genesis time and starting block number BEACON_GENESIS_TIME = GENESIS_TIME_LOCAL; cheats.warp(BEACON_GENESIS_TIME); cheats.roll(10_000); - timeMachine = new TimeMachine(); - beaconChain = new BeaconChainMock(eigenPodManager, BEACON_GENESIS_TIME); - + _deployTimeMachineAndBeaconChain(); // Set the `pectraForkTimestamp` on the EigenPodManager. Use pectra state - cheats.startPrank(executorMultisig); - eigenPodManager.setProofTimestampSetter(executorMultisig); - eigenPodManager.setPectraForkTimestamp(BEACON_GENESIS_TIME); + cheats.startPrank(executorMultisig()); + eigenPodManager().setProofTimestampSetter(executorMultisig()); + eigenPodManager().setPectraForkTimestamp(BEACON_GENESIS_TIME); cheats.stopPrank(); } - /// Parse existing contracts from mainnet - function _setUpMainnet() public virtual noTracing { - console.log("Setting up `%s` integration tests:", "MAINNET_FORK".green().bold()); - console.log("RPC:", cheats.rpcUrl("mainnet")); - console.log("Block:", mainnetForkBlock); + function _setUpFork() public virtual { + _setUpFork(true); + } - cheats.createSelectFork(cheats.rpcUrl("mainnet"), mainnetForkBlock); + /// @dev Sets up the integration tests for mainnet. + function _setUpFork(bool upgrade) public virtual { + if (forkConfig.forkBlock != 0) cheats.createSelectFork(cheats.rpcUrl(profile), forkConfig.forkBlock); + else cheats.createSelectFork(cheats.rpcUrl(profile)); - string memory deploymentInfoPath = "script/configs/mainnet/mainnet-addresses.config.json"; - _parseDeployedContracts(deploymentInfoPath); - string memory existingDeploymentParams = "script/configs/mainnet.json"; - _parseParamsForIntegrationUpgrade(existingDeploymentParams); + if (forkConfig.upgradeBeforeTesting && upgrade) { + if (forkConfig.timelockPayload.length > 0 && eq(profile, "mainnet")) { + _executeTimelockUpgrade(); + } else { + _deployProxies(); // Only deploys what doesn't exist. + _upgradeProxies(); + } + } - // Place native ETH first in `allStrats` - // This ensures when we select a nonzero number of strategies from this array, we always - // have beacon chain ETH - ethStrats.push(BEACONCHAIN_ETH_STRAT); - allStrats.push(BEACONCHAIN_ETH_STRAT); - allTokens.push(NATIVE_ETH); + if (forkConfig.supportEigenPodTests) { + allStrats.push(BEACONCHAIN_ETH_STRAT); + allTokens.push(NATIVE_ETH); + config.strategies.strategyAddresses.push(BEACONCHAIN_ETH_STRAT); + } - // Add deployed strategies to lstStrats and allStrats - for (uint i; i < deployedStrategyArray.length; i++) { - IStrategy strategy = IStrategy(deployedStrategyArray[i]); + uint n = totalStrategies(); + for (uint i; i < n; ++i) { + IStrategy strategy = strategyAddresses(i); - if (tokensNotTested[address(strategy.underlyingToken())]) continue; + if (strategy == BEACONCHAIN_ETH_STRAT) continue; + IERC20 token = strategy.underlyingToken(); + if (tokensNotTested[address(token)]) continue; // Add to lstStrats and allStrats lstStrats.push(strategy); allStrats.push(strategy); - allTokens.push(strategy.underlyingToken()); + allTokens.push(token); } maxUniqueAssetsHeld = allStrats.length; // Create time machine and mock beacon chain BEACON_GENESIS_TIME = GENESIS_TIME_MAINNET; - timeMachine = new TimeMachine(); - beaconChain = new BeaconChainMock(eigenPodManager, BEACON_GENESIS_TIME); + _deployTimeMachineAndBeaconChain(); - // Since we haven't done the slashing upgrade on mainnet yet, upgrade mainnet contracts - // prior to test. `isUpgraded` is true by default, but is set to false in `UpgradeTest.t.sol` - if (isUpgraded) { - _upgradeMainnetContracts(); + if (eq(profile, "mainnet") && isUpgraded) _upgradeMainnetContracts(); + // Mainnet doesn't yet support this. + if (isUpgraded && forkConfig.supportEigenPodTests) { // Set the `pectraForkTimestamp` on the EigenPodManager. Use pectra state - cheats.startPrank(executorMultisig); - eigenPodManager.setProofTimestampSetter(executorMultisig); - eigenPodManager.setPectraForkTimestamp(BEACON_GENESIS_TIME); + cheats.startPrank(executorMultisig()); + eigenPodManager().setProofTimestampSetter(executorMultisig()); + eigenPodManager().setPectraForkTimestamp(BEACON_GENESIS_TIME); cheats.stopPrank(); } } + /// @dev Upgrades the mainnet contracts. function _upgradeMainnetContracts() public virtual { - cheats.startPrank(address(executorMultisig)); - - // First, deploy the new contracts as empty contracts - emptyContract = new EmptyContract(); - allocationManager = - AllocationManager(address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), ""))); - permissionController = - PermissionController(address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), ""))); - - emit log_named_uint("EPM pause status", eigenPodManager.paused()); - - // Deploy new implementation contracts and upgrade all proxies to point to them - _deployImplementations(); + cheats.startPrank(executorMultisig()); _upgradeProxies(); - - emit log_named_uint("EPM pause status", eigenPodManager.paused()); - - // Initialize the newly-deployed proxy - allocationManager.initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); - cheats.stopPrank(); } - function _deployProxies() public { - delegationManager = - 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), ""))); - rewardsCoordinator = - RewardsCoordinator(address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), ""))); - avsDirectory = AVSDirectory(address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), ""))); - 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), ""))); - eigenPodBeacon = new UpgradeableBeacon(address(emptyContract)); - strategyBeacon = new UpgradeableBeacon(address(emptyContract)); - } - - /// Deploy an implementation contract for each contract in the system - function _deployImplementations() public { - allocationManagerImplementation = new AllocationManager( - delegationManager, eigenLayerPauserReg, permissionController, DEALLOCATION_DELAY, ALLOCATION_CONFIGURATION_DELAY, version - ); - permissionControllerImplementation = new PermissionController(version); - delegationManagerImplementation = new DelegationManager( - strategyManager, - eigenPodManager, - allocationManager, - eigenLayerPauserReg, - permissionController, - DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, - version - ); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenLayerPauserReg, version); - rewardsCoordinatorImplementation = new RewardsCoordinator( - IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams({ - delegationManager: delegationManager, - strategyManager: strategyManager, - allocationManager: allocationManager, - pauserRegistry: eigenLayerPauserReg, - permissionController: permissionController, - CALCULATION_INTERVAL_SECONDS: REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, - MAX_REWARDS_DURATION: REWARDS_COORDINATOR_MAX_REWARDS_DURATION, - MAX_RETROACTIVE_LENGTH: REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, - MAX_FUTURE_LENGTH: REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP: REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP, - version: version - }) - ); - avsDirectoryImplementation = new AVSDirectory(delegationManager, eigenLayerPauserReg, version); - eigenPodManagerImplementation = - new EigenPodManager(DEPOSIT_CONTRACT, eigenPodBeacon, delegationManager, eigenLayerPauserReg, "v9.9.9"); - strategyFactoryImplementation = new StrategyFactory(strategyManager, eigenLayerPauserReg, "v9.9.9"); - - // Beacon implementations - eigenPodImplementation = new EigenPod(DEPOSIT_CONTRACT, eigenPodManager, BEACON_GENESIS_TIME, "v9.9.9"); - baseStrategyImplementation = new StrategyBase(strategyManager, eigenLayerPauserReg, "v9.9.9"); + function _executeTimelockUpgrade() internal { + // Warp forward to elapse the timelock queue. + cheats.warp(block.timestamp + 21 days); - // Pre-longtail StrategyBaseTVLLimits implementation - // TODO - need to update ExistingDeploymentParser - } + // Execute the timelock upgrade. + cheats.startPrank(protocolCouncil()); + timelock().execute({target: executorMultisig(), value: 0, payload: forkConfig.timelockPayload, predecessor: 0, salt: 0}); + cheats.stopPrank(); - function _upgradeProxies() public noTracing { - // DelegationManager - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(delegationManager))), address(delegationManagerImplementation) - ); + console.log("SIMULATED TIMELOCK UPGRADE".yellow().bold()); - // StrategyManager - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation) - ); + isUpgraded = true; + } - // EigenPodManager - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) - ); + /// ----------------------------------------------------------------------- + /// + /// ----------------------------------------------------------------------- + + /// @dev Returns a new transparent proxy without an implementation set. + function _emptyProxy() internal returns (address) { + return address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin()), "")); + } + + /// @dev Upgrades a proxy to a new implementation. + function _upgradeProxy(address proxy, address implementation) internal { + proxyAdmin().upgrade(ITransparentUpgradeableProxy(payable(proxy)), implementation); + } + + /// @dev Deploys a new transparent proxy without an implementation set for each contract in the system. + function _deployProxies() internal { + // Core contracts + if (address(config.core.allocationManager) == address(0)) config.core.allocationManager = AllocationManager(_emptyProxy()); + if (address(config.core.avsDirectory) == address(0)) config.core.avsDirectory = AVSDirectory(_emptyProxy()); + if (address(config.core.delegationManager) == address(0)) config.core.delegationManager = DelegationManager(_emptyProxy()); + if (address(config.core.permissionController) == address(0)) config.core.permissionController = PermissionController(_emptyProxy()); + if (address(config.core.rewardsCoordinator) == address(0)) config.core.rewardsCoordinator = RewardsCoordinator(_emptyProxy()); + if (address(config.core.strategyManager) == address(0)) config.core.strategyManager = StrategyManager(_emptyProxy()); + // Pod contracts + if (address(config.pods.eigenPodBeacon) == address(0)) config.pods.eigenPodBeacon = new UpgradeableBeacon(address(emptyContract)); + if (address(config.pods.eigenPodManager) == address(0)) config.pods.eigenPodManager = EigenPodManager(_emptyProxy()); + // Strategy contracts + if (address(config.strategies.strategyFactory) == address(0)) config.strategies.strategyFactory = StrategyFactory(_emptyProxy()); + if (address(config.strategies.strategyFactoryBeacon) == address(0)) { + config.strategies.strategyFactoryBeacon = new UpgradeableBeacon(address(emptyContract)); + } + } - // RewardsCoordinator - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))), address(rewardsCoordinatorImplementation) + /// @dev Upgrades all proxies to their implementation contracts. + function _upgradeProxies() public { + // Core contracts + _upgradeProxy( + address(allocationManager()), + address( + new AllocationManager( + delegationManager(), + pauserRegistry(), + permissionController(), + DEALLOCATION_DELAY, + ALLOCATION_CONFIGURATION_DELAY, + SEMVER + ) + ) ); - - // AVSDirectory - eigenLayerProxyAdmin.upgrade(ITransparentUpgradeableProxy(payable(address(avsDirectory))), address(avsDirectoryImplementation)); - - // AllocationManager - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(allocationManager))), address(allocationManagerImplementation) + _upgradeProxy(address(avsDirectory()), address(new AVSDirectory(delegationManager(), pauserRegistry(), SEMVER))); + _upgradeProxy( + address(delegationManager()), + address( + new DelegationManager( + strategyManager(), + eigenPodManager(), + allocationManager(), + pauserRegistry(), + permissionController(), + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + SEMVER + ) + ) ); - - // PermissionController - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(permissionController))), address(permissionControllerImplementation) + _upgradeProxy(address(permissionController()), address(new PermissionController(SEMVER))); + _upgradeProxy( + address(rewardsCoordinator()), + address( + new RewardsCoordinator( + IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams( + delegationManager(), + strategyManager(), + allocationManager(), + pauserRegistry(), + 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, + SEMVER + ) + ) + ) ); + _upgradeProxy(address(strategyManager()), address(new StrategyManager(delegationManager(), pauserRegistry(), SEMVER))); - // StrategyFactory - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(strategyFactory))), address(strategyFactoryImplementation) + // Pod contracts + eigenPodBeacon().upgradeTo(address(new EigenPod(DEPOSIT_CONTRACT, eigenPodManager(), BEACON_GENESIS_TIME, "v9.9.9"))); + _upgradeProxy( + address(eigenPodManager()), + address(new EigenPodManager(DEPOSIT_CONTRACT, eigenPodBeacon(), delegationManager(), pauserRegistry(), "v9.9.9")) ); - // EigenPod beacon - eigenPodBeacon.upgradeTo(address(eigenPodImplementation)); - - // StrategyBase Beacon - strategyBeacon.upgradeTo(address(baseStrategyImplementation)); - - // Upgrade All deployed strategy contracts to new base strategy - for (uint i = 0; i < numStrategiesDeployed; i++) { - // Upgrade existing strategy - eigenLayerProxyAdmin.upgrade( - ITransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), address(baseStrategyImplementation) - ); + // Strategy contracts + _upgradeProxy(address(strategyFactory()), address(new StrategyFactory(strategyManager(), pauserRegistry(), "v9.9.9"))); + address baseStrategyImpl = address(new StrategyBase(strategyManager(), pauserRegistry(), "v9.9.9")); + strategyFactoryBeacon().upgradeTo(baseStrategyImpl); + for (uint i = 0; i < totalStrategies(); ++i) { + IStrategy strategy = strategyAddresses(i); + if (strategyAddresses(i) == BEACONCHAIN_ETH_STRAT) continue; + _upgradeProxy(address(strategyAddresses(i)), address(baseStrategyImpl)); } - } - function _initializeProxies() public noTracing { - delegationManager.initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); + isUpgraded = true; + } - strategyManager.initialize({ + /// @dev Initializes all proxies. + function _initializeProxies() public { + address executorMultisig = executorMultisig(); + allocationManager().initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); + avsDirectory().initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); + delegationManager().initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); + eigenPodManager().initialize({initialOwner: executorMultisig, _initPausedStatus: 0}); + rewardsCoordinator().initialize({ initialOwner: executorMultisig, - initialStrategyWhitelister: address(strategyFactory), + initialPausedStatus: 0, + _rewardsUpdater: executorMultisig, + _activationDelay: 0, + _defaultSplitBips: 0 + }); + strategyFactory().initialize({_initialOwner: executorMultisig, _initialPausedStatus: 0, _strategyBeacon: strategyFactoryBeacon()}); + strategyManager().initialize({ + initialOwner: executorMultisig, + initialStrategyWhitelister: address(strategyFactory()), initialPausedStatus: 0 }); - - eigenPodManager.initialize({initialOwner: executorMultisig, _initPausedStatus: 0}); - - avsDirectory.initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); - - allocationManager.initialize({initialOwner: executorMultisig, initialPausedStatus: 0}); - - strategyFactory.initialize({_initialOwner: executorMultisig, _initialPausedStatus: 0, _strategyBeacon: strategyBeacon}); } - /// @dev Deploy a strategy and its underlying token, push to global lists of tokens/strategies, and whitelist - /// strategy in strategyManager + /// @dev Deploys a new strategy and token with given parameters. function _newStrategyAndToken(string memory tokenName, string memory tokenSymbol, uint initialSupply, address owner, bool useFactory) internal - noTracing { - IERC20 underlyingToken = new ERC20PresetFixedSupply(tokenName, tokenSymbol, initialSupply, owner); - - StrategyBase strategy; - - if (useFactory) { - strategy = StrategyBase(address(strategyFactory.deployNewStrategy(underlyingToken))); - } else { - strategy = StrategyBase( + // Deploy mock token, avoid using OZ for test speed. + MockERC20 token = new MockERC20(); + token.initialize(tokenName, tokenSymbol, 18); + IERC20 underlyingToken = IERC20(address(token)); + deal(address(underlyingToken), address(owner), initialSupply); + // Deploy strategy using factory or directly. + StrategyBase strategy = useFactory + ? StrategyBase(address(strategyFactory().deployNewStrategy(underlyingToken))) + : StrategyBase( address( new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), + address(strategyFactoryBeacon().implementation()), + address(proxyAdmin()), abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken) ) ) ); - } - - // Whitelist strategy - IStrategy[] memory strategies = new IStrategy[](1); - strategies[0] = strategy; - - cheats.prank(strategyManager.strategyWhitelister()); - strategyManager.addStrategiesToDepositWhitelist(strategies); - // Add to lstStrats and allStrats lstStrats.push(strategy); allStrats.push(strategy); allTokens.push(underlyingToken); + config.strategies.strategyAddresses.push(strategy); } - function _configRand(uint24 _randomSeed, uint _assetTypes, uint _userTypes) private noTracing { - // 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. - random = _hash(_randomSeed); - - // Convert flag bitmaps to bytes of set bits for easy use with _randUint - _configAssetTypes(_assetTypes); - _configUserTypes(_userTypes); + /// @dev Deploy the time machine and beacon chain to fixed addresses. + function _deployTimeMachineAndBeaconChain() internal virtual { + cheats.pauseTracing(); + cheats.etch(address(timeMachine), type(TimeMachine).runtimeCode); + cheats.etch(address(beaconChain), type(BeaconChainMock).runtimeCode); + cheats.label(address(timeMachine), "TimeMachine"); + cheats.label(address(beaconChain), "BeaconChain"); + cheats.allowCheatcodes(address(timeMachine)); + cheats.allowCheatcodes(address(beaconChain)); + beaconChain.initialize(eigenPodManager(), BEACON_GENESIS_TIME); + cheats.resumeTracing(); } - function _configAssetTypes(uint _assetTypes) internal { - assetTypes = _bitmapToBytes(_assetTypes); - assertTrue(assetTypes.length != 0, "_configRand: no asset types selected"); - } - - function _configAssetAmounts(uint _maxUniqueAssetsHeld) internal { - if (_maxUniqueAssetsHeld > allStrats.length) _maxUniqueAssetsHeld = allStrats.length; - - maxUniqueAssetsHeld = _maxUniqueAssetsHeld; - require(maxUniqueAssetsHeld != 0, "_configAssetAmounts: invalid 0"); - } - - function _configUserTypes(uint _userTypes) internal { - userTypes = _bitmapToBytes(_userTypes); - assertTrue(userTypes.length != 0, "_configRand: no user types selected"); - } - - /** - * @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 noTracing returns (User, IStrategy[] memory, uint[] memory) { - // Deploy new User contract - uint userType = _randUserType(); - User user = _genRandUser(name, userType); - - // For the specific asset selection we made, get a random assortment of strategies - // and deal the user some corresponding underlying token balances - uint assetType = _randAssetType(); - IStrategy[] memory strategies = _selectRandAssets(assetType); - uint[] memory tokenBalances = _dealRandAmounts(user, strategies); - + /// ----------------------------------------------------------------------- + /// + /// ----------------------------------------------------------------------- + + /// @dev Creates a new user with a random config. + function _randUser(string memory name) internal returns (User user, IStrategy[] memory strategies, uint[] memory tokenBalances) { + (uint userType, uint assetType) = (_randUserType(), _randAssetType()); + user = _genRandUser(name, userType); + strategies = _selectRandAssets(assetType); + tokenBalances = _dealRandAmounts(user, strategies); print.user(name, assetType, userType, strategies, tokenBalances); - return (user, strategies, tokenBalances); } - function _randUser(string memory name, IStrategy[] memory strategies) internal noTracing returns (User, uint[] memory) { - // Deploy new User contract + /// @dev Creates a new user with a random config and a given list of strategies. + function _randUser(string memory name, IStrategy[] memory strategies) internal returns (User user, uint[] memory tokenBalances) { uint userType = _randUserType(); - User user = _genRandUser(name, userType); - - // Deal the user some corresponding underlying token balances - uint[] memory tokenBalances = _dealRandAmounts(user, strategies); - + user = _genRandUser(name, userType); + tokenBalances = _dealRandAmounts(user, strategies); print.user(name, HOLDS_ALL, userType, strategies, tokenBalances); - return (user, tokenBalances); - } - - /// @dev Create a new user without native ETH. See _randUser above for standard usage - function _randUser_NoETH(string memory name) internal noTracing returns (User, IStrategy[] memory, uint[] memory) { - // Deploy new User contract - uint userType = _randUserType(); - User user = _genRandUser(name, userType); - - // Pick the user's asset distribution, removing "native ETH" as an option - // I'm sorry if this eventually leads to a bug that's really hard to track down - uint assetType = _randAssetType(); - if (assetType == HOLDS_ETH) assetType = NO_ASSETS; - else if (assetType == HOLDS_ALL || assetType == HOLDS_MAX) assetType = HOLDS_LST; - - // For the specific asset selection we made, get a random assortment of strategies - // and deal the user some corresponding underlying token balances - IStrategy[] memory strategies = _selectRandAssets(assetType); - uint[] memory tokenBalances = _dealRandAmounts(user, strategies); - - print.user(name, assetType, userType, strategies, tokenBalances); - return (user, strategies, tokenBalances); } /// @dev Creates a new user without any assets - function _randUser_NoAssets(string memory name) internal noTracing returns (User) { - // Deploy new User contract + function _randUser_NoAssets(string memory name) internal returns (User user) { uint userType = _randUserType(); - User user = _genRandUser(name, userType); - + user = _genRandUser(name, userType); print.user(name, NO_ASSETS, userType, new IStrategy[](0), new uint[](0)); - return user; } + /// @dev Generates a new user with a given name and user type. function _genRandUser(string memory name, uint userType) internal returns (User user) { - // Create User contract based on userType: - if (forkType == LOCAL || (forkType == MAINNET && isUpgraded)) { - user = new User(name); - - if (userType == DEFAULT) { - user = new User(name); - } else if (userType == ALT_METHODS) { - // User will use nonstandard methods like `depositIntoStrategyWithSignature` - user = User(new User_AltMethods(name)); - } else { - revert("_randUser: unimplemented userType"); - } - } else if (forkType == MAINNET && !isUpgraded) { - if (userType == DEFAULT) { - user = User(new User_M2(name)); - } else if (userType == ALT_METHODS) { - // User will use nonstandard methods like `depositIntoStrategyWithSignature` - user = User(new User_M2(name)); - } else { - revert("_randUser: unimplemented userType"); - } - } else { - revert("_randUser: unimplemented forkType"); - } + assertTrue(userType == DEFAULT || userType == ALT_METHODS, "_randUser: unimplemented userType"); + + // string memory profile = FOUNDRY_PROFILE(); + + user = userType == DEFAULT ? new User(name) : User(new User_AltMethods(name)); + + assertTrue(address(user) != address(0), "User is not initialized"); + // if (eq(profile, "default") || eq(profile, "mainnet") || (eq(profile, "forktest") && isUpgraded)) { + // user = userType == DEFAULT ? new User(name) : User(new User_AltMethods(name)); + // } else if (eq(profile, "forktest") && !isUpgraded) { + // user = User(new User_M2(name)); + // } } - 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 revert("_genRandAVS: unimplemented forkType"); + /// @dev Generates a new AVS. + function _genRandAVS(string memory name) internal returns (AVS) { + return new AVS(name); } + /// ----------------------------------------------------------------------- + /// + /// ----------------------------------------------------------------------- + /// Given an assetType, select strategies the user will be dealt assets in - function _selectRandAssets(uint assetType) internal noTracing returns (IStrategy[] memory) { + function _selectRandAssets(uint assetType) internal returns (IStrategy[] memory strategies) { if (assetType == NO_ASSETS) return new IStrategy[](0); - - /// Select only ETH - if (assetType == HOLDS_ETH) return beaconChainETHStrategy.toArray(); - - /// Select multiple LSTs, and maybe add ETH: - + if (assetType == HOLDS_ETH) return BEACONCHAIN_ETH_STRAT.toArray(); // Select number of assets: // HOLDS_LST can hold at most all LSTs. HOLDS_ALL and HOLDS_MAX also hold ETH. // Clamp number of assets to maxUniqueAssetsHeld (guaranteed to be at least 1) uint assetPoolSize = assetType == HOLDS_LST ? lstStrats.length : allStrats.length; uint maxAssets = assetPoolSize > maxUniqueAssetsHeld ? maxUniqueAssetsHeld : assetPoolSize; - uint numAssets = assetType == HOLDS_MAX ? maxAssets : _randUint(1, maxAssets); - IStrategy[] memory strategies = new IStrategy[](numAssets); - for (uint i = 0; i < strategies.length; i++) { - if (assetType == HOLDS_LST) { - strategies[i] = lstStrats[i]; - } else { - // allStrats[0] is the beaconChainETHStrategy - strategies[i] = allStrats[i]; - } + strategies = new IStrategy[](numAssets); + + for (uint i = 0; i < numAssets; ++i) { + strategies[i] = assetType == HOLDS_LST ? lstStrats[i] : allStrats[i]; } - return strategies; + return strategies.sort(); } /// Given an input list of strategies, deal random underlying token amounts to a user - function _dealRandAmounts(User user, IStrategy[] memory strategies) internal noTracing returns (uint[] memory) { - uint[] memory tokenBalances = new uint[](strategies.length); - - for (uint i = 0; i < tokenBalances.length; i++) { + function _dealRandAmounts(User user, IStrategy[] memory strategies) internal returns (uint[] memory tokenBalances) { + assertTrue(address(user) != address(0), "User is not initialized"); + tokenBalances = new uint[](strategies.length); + for (uint i = 0; i < tokenBalances.length; ++i) { IStrategy strategy = strategies[i]; uint balance; @@ -638,128 +543,52 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { balance = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(user), balance); } else { - IERC20 underlyingToken = strategy.underlyingToken(); balance = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); - - StdCheats.deal(address(underlyingToken), address(user), balance); + StdCheats.deal(address(strategy.underlyingToken()), address(user), balance); } tokenBalances[i] = balance; } - - return tokenBalances; } - /// Given an array of strategies and an array of amounts, deal the amounts to the user - function _dealAmounts(User user, IStrategy[] memory strategies, uint[] memory amounts) internal noTracing { - for (uint i = 0; i < amounts.length; i++) { - IStrategy strategy = strategies[i]; - - if (strategy == BEACONCHAIN_ETH_STRAT) { - cheats.deal(address(user), amounts[i]); - } else { - IERC20 underlyingToken = strategy.underlyingToken(); - StdCheats.deal(address(underlyingToken), address(user), amounts[i]); - } - } - } - - /// @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) { - uint range = max - min + 1; - - // calculate the number of bits needed for the range - uint bitsNeeded = 0; - uint tempRange = range; - while (tempRange > 0) { - bitsNeeded++; - tempRange >>= 1; - } - - // create a mask for the required number of bits - // and extract the value from the hash - uint mask = (1 << bitsNeeded) - 1; - uint value = uint(random) & mask; - - // in case value is out of range, wrap around or retry - while (value >= range) value = (value - range) & mask; - - // Hash `random` with itself so the next value we generate is different - random = _hash(uint(random)); - return min + value; + return cheats.randomUint(min, max); } function _randBool() internal returns (bool) { - return _randUint({min: 0, max: 1}) == 0; + return cheats.randomBool(); } function _randAssetType() internal returns (uint) { - 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 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); + bool supportsEth = !eq(profile, "sepolia") && !eq(profile, "hoodi"); - for (uint i; i < numOpSets; ++i) { - IStrategy[] memory randomStrategies = _shuffle(allStrats); - uint numStrategies = _randUint({min: 1, max: maxUniqueAssetsHeld}); + uint[] memory options = new uint[](supportsEth ? 5 : 2); // We have 2-5 possible asset types + uint count = 0; - // Modify the length of the array in memory (thus ignoring remaining elements). - assembly { - mstore(randomStrategies, numStrategies) - } + if (assetTypes & NO_ASSETS != 0) options[count++] = NO_ASSETS; + if (assetTypes & HOLDS_LST != 0) options[count++] = HOLDS_LST; - strategies[i] = randomStrategies; + if (supportsEth) { + if (assetTypes & HOLDS_ETH != 0) options[count++] = HOLDS_ETH; + if (assetTypes & HOLDS_ALL != 0) options[count++] = HOLDS_ALL; + if (assetTypes & HOLDS_MAX != 0) options[count++] = HOLDS_MAX; } - } - /** - * @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) { - for (uint i = 0; i < 256; ++i) { - // Mask for i-th bit - uint mask = uint(1 << i); + // If there are no options, skip the test. + if (count == 0) cheats.skip(true); - // 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))); - } - return bytesArray; + return options[cheats.randomUint(0, count - 1)]; } - function _hash(string memory x) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(x)); + function _randUserType() internal returns (uint) { + uint[] memory options = new uint[](2); // We have 2 possible user types + uint count = 0; + if (userTypes & DEFAULT != 0) options[count++] = DEFAULT; + if (userTypes & ALT_METHODS != 0) options[count++] = ALT_METHODS; + return options[cheats.randomUint(0, count - 1)]; } - function _hash(uint x) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(x)); + function NAME() public view virtual override returns (string memory) { + return "Integration Deployer"; } } diff --git a/src/test/integration/IntegrationGetters.t.sol b/src/test/integration/IntegrationGetters.t.sol new file mode 100644 index 0000000000..834d68a5fb --- /dev/null +++ b/src/test/integration/IntegrationGetters.t.sol @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {ICoreTypes} from "src/contracts/interfaces/ICore.sol"; + +import "src/test/integration/IntegrationDeployer.t.sol"; + +contract IntegrationGetters is IntegrationDeployer, ICoreTypes { + using ArrayLib for *; + using SlashingLib for *; + + struct Magnitudes { + uint encumbered; + uint allocatable; + uint max; + } + + modifier timewarp() { + uint curState = timeMachine.travelToLast(); + _; + timeMachine.travel(curState); + } + + /// ----------------------------------------------------------------------- + /// Timewarp functions + /// ----------------------------------------------------------------------- + + function _getPrevAllocations(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + timewarp + returns (Allocation[] memory) + { + return _getAllocations(operator, operatorSet, strategies); + } + + function _getAllocations(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (Allocation[] memory allocations) + { + allocations = new Allocation[](strategies.length); + for (uint i = 0; i < strategies.length; ++i) { + allocations[i] = allocationManager().getAllocation(address(operator), operatorSet, strategies[i]); + } + } + + function _getPrevAllocatedStrats(User operator, OperatorSet memory operatorSet) internal timewarp returns (IStrategy[] memory) { + return _getAllocatedStrats(operator, operatorSet); + } + + function _getAllocatedStrats(User operator, OperatorSet memory operatorSet) internal view returns (IStrategy[] memory) { + return allocationManager().getAllocatedStrategies(address(operator), operatorSet); + } + + function _getPrevAllocatedSets(User operator) internal timewarp returns (OperatorSet[] memory) { + return _getAllocatedSets(operator); + } + + function _getAllocatedSets(User operator) internal view returns (OperatorSet[] memory) { + return allocationManager().getAllocatedSets(address(operator)); + } + + function _getPrevRegisteredSets(User operator) internal timewarp returns (OperatorSet[] memory) { + return _getRegisteredSets(operator); + } + + function _getRegisteredSets(User operator) internal view returns (OperatorSet[] memory) { + return allocationManager().getRegisteredSets(address(operator)); + } + + function _getPrevMembers(OperatorSet memory operatorSet) internal timewarp returns (address[] memory) { + return _getMembers(operatorSet); + } + + function _getMembers(OperatorSet memory operatorSet) internal view returns (address[] memory) { + return allocationManager().getMembers(operatorSet); + } + + function _getPrevMagnitudes(User operator, IStrategy[] memory strategies) internal timewarp returns (Magnitudes[] memory) { + return _getMagnitudes(operator, strategies); + } + + function _getMagnitudes(User operator, IStrategy[] memory strategies) internal view returns (Magnitudes[] memory magnitudes) { + magnitudes = new Magnitudes[](strategies.length); + for (uint i = 0; i < strategies.length; ++i) { + magnitudes[i] = Magnitudes({ + encumbered: allocationManager().getEncumberedMagnitude(address(operator), strategies[i]), + allocatable: allocationManager().getAllocatableMagnitude(address(operator), strategies[i]), + max: allocationManager().getMaxMagnitude(address(operator), strategies[i]) + }); + } + } + + function _getPrevMinSlashableStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + timewarp + returns (uint[] memory) + { + return _getMinSlashableStake(operator, operatorSet, strategies); + } + + function _getPrevMinSlashableStake(address operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + timewarp + returns (uint[] memory) + { + return _getMinSlashableStake(operator, operatorSet, strategies); + } + + function _getMinSlashableStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (uint[] memory) + { + return allocationManager().getMinimumSlashableStake({ + operatorSet: operatorSet, + operators: address(operator).toArray(), + strategies: strategies, + futureBlock: uint32(block.number) + })[0]; + } + + function _getMinSlashableStake(address operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (uint[] memory) + { + return allocationManager().getMinimumSlashableStake({ + operatorSet: operatorSet, + operators: address(operator).toArray(), + strategies: strategies, + futureBlock: uint32(block.number) + })[0]; + } + + function _getPrevAllocatedStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + timewarp + returns (uint[] memory) + { + return _getAllocatedStake(operator, operatorSet, strategies); + } + + function _getAllocatedStake(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (uint[] memory) + { + return allocationManager().getAllocatedStake({ + operatorSet: operatorSet, + operators: address(operator).toArray(), + strategies: strategies + })[0]; + } + + function _getPrevIsSlashable(User operator, OperatorSet memory operatorSet) internal timewarp returns (bool) { + return _getIsSlashable(operator, operatorSet); + } + + function _getIsSlashable(User operator, OperatorSet memory operatorSet) internal view returns (bool) { + return allocationManager().isOperatorSlashable(address(operator), operatorSet); + } + + function _getPrevIsMemberOfSet(User operator, OperatorSet memory operatorSet) internal timewarp returns (bool) { + return _getIsMemberOfSet(operator, operatorSet); + } + + function _getIsMemberOfSet(User operator, OperatorSet memory operatorSet) internal view returns (bool) { + return allocationManager().isMemberOfOperatorSet(address(operator), operatorSet); + } + + function _getPrevBurnableShares(IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getBurnableShares(strategies); + } + + function _getBurnableShares(IStrategy[] memory strategies) internal view returns (uint[] memory) { + uint[] memory burnableShares = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + if (strategies[i] == BEACONCHAIN_ETH_STRAT) burnableShares[i] = eigenPodManager().burnableETHShares(); + else burnableShares[i] = strategyManager().getBurnableShares(strategies[i]); + } + + return burnableShares; + } + + function _getPrevSlashableSharesInQueue(User operator, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getSlashableSharesInQueue(operator, strategies); + } + + function _getSlashableSharesInQueue(User operator, IStrategy[] memory strategies) internal view returns (uint[] memory) { + uint[] memory slashableShares = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + slashableShares[i] = delegationManager().getSlashableSharesInQueue(address(operator), strategies[i]); + } + + return slashableShares; + } + + function _getPrevOperatorShares(User operator, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getOperatorShares(operator, strategies); + } + + function _getOperatorShares(User operator, IStrategy[] memory strategies) internal view returns (uint[] memory) { + uint[] memory curShares = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + curShares[i] = delegationManager().operatorShares(address(operator), strategies[i]); + } + + return curShares; + } + + function _getPrevStakerDepositShares(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getStakerDepositShares(staker, strategies); + } + + 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++) { + IStrategy strat = strategies[i]; + + if (strat == BEACONCHAIN_ETH_STRAT) { + int shares = eigenPodManager().podOwnerDepositShares(address(staker)); + + if (shares < 0) revert("_getStakerDepositShares: negative shares"); + + curShares[i] = uint(shares); + } else { + curShares[i] = strategyManager().stakerDepositShares(address(staker), strat); + } + } + + return curShares; + } + + function _getPrevStakerDepositSharesInt(User staker, IStrategy[] memory strategies) internal timewarp returns (int[] memory) { + return _getStakerDepositSharesInt(staker, strategies); + } + + 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().podOwnerDepositShares(address(staker)); + else 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) { + (uint[] memory withdrawableShares,) = delegationManager().getWithdrawableShares(address(staker), strategies); + return withdrawableShares; + } + + function _getPrevBeaconChainSlashingFactor(User staker) internal timewarp returns (uint64) { + return _getBeaconChainSlashingFactor(staker); + } + + function _getBeaconChainSlashingFactor(User staker) internal view returns (uint64) { + return eigenPodManager().beaconChainSlashingFactor(address(staker)); + } + + function _getPrevCumulativeWithdrawals(User staker) internal timewarp returns (uint) { + return _getCumulativeWithdrawals(staker); + } + + function _getCumulativeWithdrawals(User staker) internal view returns (uint) { + return delegationManager().cumulativeWithdrawalsQueued(address(staker)); + } + + function _getPrevTokenBalances(User staker, IERC20[] memory tokens) internal timewarp returns (uint[] memory) { + return _getTokenBalances(staker, tokens); + } + + 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; + else balances[i] = tokens[i].balanceOf(address(staker)); + } + + return balances; + } + + function _getPrevTotalStrategyShares(IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getTotalStrategyShares(strategies); + } + + function _getTotalStrategyShares(IStrategy[] memory strategies) internal view returns (uint[] memory) { + uint[] memory shares = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + if (strategies[i] != BEACONCHAIN_ETH_STRAT) shares[i] = strategies[i].totalShares(); + } + + return shares; + } + + function _getDepositScalingFactors(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { + uint[] memory depositScalingFactors = new uint[](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + depositScalingFactors[i] = _getDepositScalingFactor(staker, strategies[i]); + } + return depositScalingFactors; + } + + function _getDepositScalingFactor(User staker, IStrategy strategy) internal view returns (uint) { + return delegationManager().depositScalingFactor(address(staker), strategy); + } + + function _getPrevDepositScalingFactors(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getDepositScalingFactors(staker, strategies); + } + + function _getPrevWithdrawableShares(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getWithdrawableShares(staker, strategies); + } + + function _getWithdrawableShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory withdrawableShares) { + (withdrawableShares,) = delegationManager().getWithdrawableShares(address(staker), strategies); + } + + function _getWithdrawableShares(User staker, IStrategy strategy) internal view returns (uint withdrawableShares) { + (uint[] memory _withdrawableShares,) = delegationManager().getWithdrawableShares(address(staker), strategy.toArray()); + return _withdrawableShares[0]; + } + + function _getActiveValidatorCount(User staker) internal view returns (uint) { + EigenPod pod = staker.pod(); + return pod.activeValidatorCount(); + } + + function _getPrevActiveValidatorCount(User staker) internal timewarp returns (uint) { + return _getActiveValidatorCount(staker); + } + + function _getValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal view returns (VALIDATOR_STATUS[] memory) { + EigenPod pod = staker.pod(); + VALIDATOR_STATUS[] memory statuses = new VALIDATOR_STATUS[](pubkeyHashes.length); + + for (uint i = 0; i < statuses.length; i++) { + statuses[i] = pod.validatorStatus(pubkeyHashes[i]); + } + + return statuses; + } + + function _getPrevValidatorStatuses(User staker, bytes32[] memory pubkeyHashes) internal timewarp returns (VALIDATOR_STATUS[] memory) { + return _getValidatorStatuses(staker, pubkeyHashes); + } + + function _getCheckpointTimestamp(User staker) internal view returns (uint64) { + EigenPod pod = staker.pod(); + return pod.currentCheckpointTimestamp(); + } + + function _getPrevCheckpointTimestamp(User staker) internal timewarp returns (uint64) { + return _getCheckpointTimestamp(staker); + } + + function _getLastCheckpointTimestamp(User staker) internal view returns (uint64) { + EigenPod pod = staker.pod(); + return pod.lastCheckpointTimestamp(); + } + + function _getPrevLastCheckpointTimestamp(User staker) internal timewarp returns (uint64) { + return _getLastCheckpointTimestamp(staker); + } + + function _getWithdrawableRestakedGwei(User staker) internal view returns (uint64) { + EigenPod pod = staker.pod(); + return pod.withdrawableRestakedExecutionLayerGwei(); + } + + function _getPrevWithdrawableRestakedGwei(User staker) internal timewarp returns (uint64) { + return _getWithdrawableRestakedGwei(staker); + } + + function _getCheckpointPodBalanceGwei(User staker) internal view returns (uint64) { + EigenPod pod = staker.pod(); + return uint64(pod.currentCheckpoint().podBalanceGwei); + } + + function _getPrevCheckpointPodBalanceGwei(User staker) internal timewarp returns (uint64) { + return _getCheckpointPodBalanceGwei(staker); + } + + function _getCheckpointBalanceExited(User staker, uint64 checkpointTimestamp) internal view returns (uint64) { + EigenPod pod = staker.pod(); + return pod.checkpointBalanceExitedGwei(checkpointTimestamp); + } + + function _getPrevCheckpointBalanceExited(User staker, uint64 checkpointTimestamp) internal timewarp returns (uint64) { + return _getCheckpointBalanceExited(staker, checkpointTimestamp); + } + + function _getSlashingFactors(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { + address operator = delegationManager().delegatedTo(address(staker)); + uint64[] memory maxMagnitudes = allocationManager().getMaxMagnitudes(operator, strategies); + uint[] memory slashingFactors = new uint[](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + if (strategies[i] == BEACONCHAIN_ETH_STRAT) { + slashingFactors[i] = maxMagnitudes[i].mulWad(eigenPodManager().beaconChainSlashingFactor(address(staker))); + } else { + slashingFactors[i] = maxMagnitudes[i]; + } + } + return slashingFactors; + } + + function _getPrevSlashingFactors(User staker, IStrategy[] memory strategies) internal timewarp returns (uint[] memory) { + return _getSlashingFactors(staker, strategies); + } + + /// ----------------------------------------------------------------------- + /// Non-timewarp functions + /// ----------------------------------------------------------------------- + + function _calcNativeETHOperatorShareDelta(User staker, int shareDelta) internal view returns (int) { + // TODO: Maybe we update parent method to have an M2 and Slashing version? + int curPodOwnerShares; + if (!isUpgraded) curPodOwnerShares = IEigenPodManager_DeprecatedM2(address(eigenPodManager())).podOwnerShares(address(staker)); + else curPodOwnerShares = eigenPodManager().podOwnerDepositShares(address(staker)); + int newPodOwnerShares = curPodOwnerShares + shareDelta; + + if (curPodOwnerShares <= 0) { + // if the shares started negative and stayed negative, then there cannot have been an increase in delegateable shares + if (newPodOwnerShares <= 0) return 0; + // if the shares started negative and became positive, then the increase in delegateable shares is the ending share amount + else return newPodOwnerShares; + } else { + // if the shares started positive and became negative, then the decrease in delegateable shares is the starting share amount + if (newPodOwnerShares <= 0) return (-curPodOwnerShares); + // if the shares started positive and stayed positive, then the change in delegateable shares + // is the difference between starting and ending amounts + else return (newPodOwnerShares - curPodOwnerShares); + } + } + + function _calculateExpectedShares(Withdrawal memory withdrawal) internal view returns (uint[] memory) { + bytes32 root = delegationManager().calculateWithdrawalRoot(withdrawal); + + (, uint[] memory shares) = delegationManager().getQueuedWithdrawal(root); + return shares; + } + + /// @dev For some strategies/underlying token balances, calculate the expected shares received + /// from depositing all tokens + function _calculateExpectedShares(IStrategy[] memory strategies, uint[] memory tokenBalances) internal returns (uint[] memory) { + uint[] memory expectedShares = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + IStrategy strat = strategies[i]; + + uint tokenBalance = tokenBalances[i]; + if (strat == BEACONCHAIN_ETH_STRAT) expectedShares[i] = tokenBalance; + else expectedShares[i] = strat.underlyingToShares(tokenBalance); + } + + return expectedShares; + } + + /// @dev For some strategies/underlying token balances, calculate the expected shares received + /// from depositing all tokens + function _calculateExpectedTokens(IStrategy[] memory strategies, uint[] memory shares) internal returns (uint[] memory) { + uint[] memory expectedTokens = new uint[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + IStrategy strat = strategies[i]; + + if (strat == BEACONCHAIN_ETH_STRAT) { + // We round down expected tokens to the nearest gwei + expectedTokens[i] = (shares[i] / GWEI_TO_WEI) * GWEI_TO_WEI; + } else { + expectedTokens[i] = strat.sharesToUnderlying(shares[i]); + } + } + + return expectedTokens; + } + + function _getWithdrawalHashes(Withdrawal[] memory withdrawals) internal view returns (bytes32[] memory) { + bytes32[] memory withdrawalRoots = new bytes32[](withdrawals.length); + + for (uint i = 0; i < withdrawals.length; i++) { + withdrawalRoots[i] = delegationManager().calculateWithdrawalRoot(withdrawals[i]); + } + + return withdrawalRoots; + } + + /// @dev Converts a list of strategies to underlying tokens + function _getUnderlyingTokens(IStrategy[] memory strategies) internal view returns (IERC20[] memory) { + IERC20[] memory tokens = new IERC20[](strategies.length); + + for (uint i = 0; i < tokens.length; i++) { + IStrategy strat = strategies[i]; + + if (strat == BEACONCHAIN_ETH_STRAT) tokens[i] = NATIVE_ETH; + else tokens[i] = strat.underlyingToken(); + } + + return tokens; + } + + function _getMaxMagnitudes(User operator, IStrategy[] memory strategies) internal view returns (uint64[] memory) { + return allocationManager().getMaxMagnitudes(address(operator), strategies); + } + + function _getMaxMagnitudes(User operator, IStrategy[] memory strategies, uint32 blockNum) internal view returns (uint64[] memory) { + return allocationManager().getMaxMagnitudesAtBlock(address(operator), strategies, blockNum); + } + + function _getStrategyAllocations(User operator, IStrategy strategy) + internal + view + returns (OperatorSet[] memory operatorSets, Allocation[] memory allocations) + { + (operatorSets, allocations) = allocationManager().getStrategyAllocations(address(operator), strategy); + } + + function _getStrategyAllocations(address operator, IStrategy strategy) + internal + view + returns (OperatorSet[] memory operatorSets, Allocation[] memory allocations) + { + (operatorSets, allocations) = allocationManager().getStrategyAllocations(operator, strategy); + } + + function _getStakerStrategyList(User staker) internal view returns (IStrategy[] memory) { + return strategyManager().getStakerStrategyList(address(staker)); + } + + function _calcWithdrawable(User staker, IStrategy[] memory strategies, uint[] memory depositSharesToWithdraw) + internal + view + returns (uint[] memory) + { + uint[] memory withdrawableShares = new uint[](strategies.length); + uint[] memory depositScalingFactors = _getDepositScalingFactors(staker, strategies); + for (uint i = 0; i < strategies.length; i++) { + withdrawableShares[i] = + depositSharesToWithdraw[i].mulWad(depositScalingFactors[i]).mulWad(_getSlashingFactor(staker, strategies[i])); + } + return withdrawableShares; + } + + function _getExpectedDSFUndelegate(User staker) internal view returns (uint expectedDepositScalingFactor) { + return WAD.divWad(_getBeaconChainSlashingFactor(staker)); + } + + function _getExpectedDSFDeposit(User staker, User operator, IStrategy strategy) + internal + view + returns (uint expectedDepositScalingFactor) + { + if (strategy == BEACONCHAIN_ETH_STRAT) { + return + WAD.divWad(allocationManager().getMaxMagnitude(address(operator), strategy).mulWad(_getBeaconChainSlashingFactor(staker))); + } else { + return WAD.divWad(allocationManager().getMaxMagnitude(address(operator), strategy)); + } + } + + function _getExpectedWithdrawableSharesUndelegate(User staker, IStrategy[] memory strategies, uint[] memory shares) + internal + view + returns (uint[] memory) + { + uint[] memory expectedWithdrawableShares = new uint[](strategies.length); + for (uint i = 0; i < strategies.length; i++) { + if (strategies[i] == BEACONCHAIN_ETH_STRAT) { + expectedWithdrawableShares[i] = + shares[i].mulWad(_getExpectedDSFUndelegate(staker)).mulWad(_getBeaconChainSlashingFactor(staker)); + } else { + expectedWithdrawableShares[i] = shares[i]; + } + } + return expectedWithdrawableShares; + } + + function _getExpectedDSFsDelegate(User staker, User operator, IStrategy[] memory strategies) internal returns (uint[] memory) { + uint[] memory expectedDepositScalingFactors = new uint[](strategies.length); + uint[] memory oldDepositScalingFactors = _getPrevDepositScalingFactors(staker, strategies); + uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, strategies); + for (uint i = 0; i < strategies.length; i++) { + expectedDepositScalingFactors[i] = oldDepositScalingFactors[i].divWad(maxMagnitudes[i]); + } + return expectedDepositScalingFactors; + } + + function _getExpectedWithdrawableSharesDelegate(User staker, User operator, IStrategy[] memory strategies, uint[] memory depositShares) + internal + returns (uint[] memory) + { + uint[] memory expectedWithdrawableShares = new uint[](strategies.length); + uint[] memory expectedDSFs = _getExpectedDSFsDelegate(staker, operator, strategies); + uint64[] memory maxMagnitudes = _getMaxMagnitudes(operator, strategies); + for (uint i = 0; i < strategies.length; i++) { + if (strategies[i] == BEACONCHAIN_ETH_STRAT) { + expectedWithdrawableShares[i] = + depositShares[i].mulWad(expectedDSFs[i]).mulWad(maxMagnitudes[i].mulWad(_getBeaconChainSlashingFactor(staker))); + } else { + expectedWithdrawableShares[i] = depositShares[i].mulWad(expectedDSFs[i]).mulWad(maxMagnitudes[i]); + } + } + return expectedWithdrawableShares; + } + + function _getExpectedWithdrawableSharesDeposit(User staker, User operator, IStrategy strategy, uint depositShares) + internal + view + returns (uint) + { + return depositShares.mulWad(_getExpectedDSFDeposit(staker, operator, strategy)).mulWad(_getSlashingFactor(staker, strategy)); + } + + function _getSlashingFactor(User staker, IStrategy strategy) internal view returns (uint) { + address operator = delegationManager().delegatedTo(address(staker)); + uint64 maxMagnitude = allocationManager().getMaxMagnitudes(operator, strategy.toArray())[0]; + if (strategy == BEACONCHAIN_ETH_STRAT) return maxMagnitude.mulWad(eigenPodManager().beaconChainSlashingFactor(address(staker))); + return maxMagnitude; + } + + /// @dev Assumes that the staker has one withdrawal queued + function _getWithdrawableSharesAfterCompletion(User staker) internal view returns (uint[] memory withdrawableShares) { + bytes32 root = delegationManager().getQueuedWithdrawalRoots(address(staker))[0]; + (, withdrawableShares) = delegationManager().getQueuedWithdrawal(root); + } + + function _getQueuedWithdrawals(User staker) internal view returns (Withdrawal[] memory) { + (Withdrawal[] memory withdrawals,) = delegationManager().getQueuedWithdrawals(address(staker)); + return withdrawals; + } + + /// @dev Fetches the opreator's allocation delay; asserts that it is set + function _getExistingAllocationDelay(User operator) internal view returns (uint32) { + (bool isSet, uint32 delay) = allocationManager().getAllocationDelay(address(operator)); + assertTrue(isSet, "_getExistingAllocationDelay: expected allocation delay to be set"); + + return delay; + } +} diff --git a/src/test/integration/IntegrationUtils.t.sol b/src/test/integration/IntegrationUtils.t.sol new file mode 100644 index 0000000000..3075e65b45 --- /dev/null +++ b/src/test/integration/IntegrationUtils.t.sol @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/test/integration/IntegrationBase.t.sol"; + +contract IntegrationUtils is IntegrationBase { + using ArrayLib for *; + + uint numStakers; + uint numOperators; + uint numAVSs; + + // Lists of operators created before the m2 (not slashing) upgrade + // + // When we call _upgradeEigenLayerContracts, we iterate over + // these lists and migrate perform the standard migration actions + // for each user + User[] operatorsToMigrate; + User[] stakersToMigrate; + + /// ----------------------------------------------------------------------- + /// + /// ----------------------------------------------------------------------- + + /** + * @dev Create a new user according to configured random variants. + * This user is ready to deposit into some strategies and has some underlying token balances + */ + function _newRandomStaker() internal returns (User, IStrategy[] memory, uint[] memory) { + (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _randUser(_getStakerName()); + + if (!isUpgraded) stakersToMigrate.push(staker); + + assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "_newRandomStaker: failed to award token balances"); + return (staker, strategies, tokenBalances); + } + + /// Given a list of strategies, creates a new user with random token balances in each underlying token + function _newStaker(IStrategy[] memory strategies) internal returns (User, uint[] memory) { + (User staker, uint[] memory tokenBalances) = _randUser(_getStakerName(), strategies); + + if (!isUpgraded) stakersToMigrate.push(staker); + + assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "_newStaker: failed to award token balances"); + return (staker, tokenBalances); + } + + /// @dev Creates a new operator with no assets + function _newRandomOperator() internal returns (User) { + User operator = _randUser_NoAssets(_getOperatorName()); + + /// Registration flow differs for M2 vs Slashing release + if (!isUpgraded) { + User_M2(payable(operator)).registerAsOperator_M2(); + + operatorsToMigrate.push(operator); + } else { + operator.registerAsOperator(); + + rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); + } + + assertTrue(delegationManager().isOperator(address(operator)), "_newRandomOperator: operator should be registered"); + assertEq(delegationManager().delegatedTo(address(operator)), address(operator), "_newRandomOperator: should be self-delegated"); + return operator; + } + + function _newRandomAVS() internal returns (AVS avs) { + string memory avsName = string.concat("avs", cheats.toString(numAVSs)); + avs = _genRandAVS(avsName); + avs.updateAVSMetadataURI("https://example.com"); + ++numAVSs; + } + + /// @dev Name a newly-created staker ("staker1", "staker2", ...) + function _getStakerName() private returns (string memory) { + numStakers++; + + string memory stakerNum = cheats.toString(numStakers); + string memory namePrefix = isUpgraded ? "staker" : "m2-staker"; + + return string.concat(namePrefix, stakerNum); + } + + /// @dev Name a newly-created operator ("operator1", "operator2", ...) + function _getOperatorName() private returns (string memory) { + numOperators++; + + string memory operatorNum = cheats.toString(numOperators); + string memory namePrefix = isUpgraded ? "operator" : "m2-operator"; + + return string.concat(namePrefix, operatorNum); + } + + /// @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. + /// + /// Total sent == `gweiSent + remainderSent` + function _sendRandomETH(address destination) internal returns (uint64 gweiSent, uint remainderSent) { + gweiSent = uint64(_randUint({min: 1, max: 10})); + remainderSent = _randUint({min: 1, max: 100}); + uint totalSent = (gweiSent * GWEI_TO_WEI) + remainderSent; + + cheats.deal(address(this), address(this).balance + totalSent); + bool r; + bytes memory d; + (r, d) = destination.call{value: totalSent}(""); + + return (gweiSent, remainderSent); + } + + /// @dev Choose a random subset of validators (selects AT LEAST ONE) + function _choose(uint40[] memory validators) internal returns (uint40[] memory) { + return validators.setLength(_randUint({min: 1, max: validators.length > 1 ? validators.length - 1 : 1})); + } + + /// ----------------------------------------------------------------------- + /// + /// ----------------------------------------------------------------------- + + /// @dev Generate params to allocate all available magnitude to each strategy in the operator set + function _genAllocation_AllAvailable(User operator, OperatorSet memory operatorSet) + internal + view + returns (AllocateParams memory params) + { + return _genAllocation_AllAvailable({ + operator: operator, + operatorSet: operatorSet, + strategies: allocationManager().getStrategiesInOperatorSet(operatorSet) + }); + } + + /// @dev Generate params to allocate all available magnitude to each strategy in the operator set + function _genAllocation_AllAvailable(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (AllocateParams memory params) + { + params.operatorSet = operatorSet; + params.strategies = strategies; + params.newMagnitudes = new uint64[](params.strategies.length); + + for (uint i = 0; i < params.strategies.length; i++) { + IStrategy strategy = params.strategies[i]; + params.newMagnitudes[i] = allocationManager().getMaxMagnitude(address(operator), strategy); + } + } + + /// @dev Gen params to allocate half of available magnitude to each strategy in the operator set + /// returns the params to complete this allocation + function _genAllocation_HalfAvailable(User operator, OperatorSet memory operatorSet) + internal + view + returns (AllocateParams memory params) + { + return _genAllocation_HalfAvailable({ + operator: operator, + operatorSet: operatorSet, + strategies: allocationManager().getStrategiesInOperatorSet(operatorSet) + }); + } + + /// @dev Gen params to allocate half of available magnitude to each strategy in the operator set + /// returns the params to complete this allocation + function _genAllocation_HalfAvailable(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (AllocateParams memory params) + { + params.operatorSet = operatorSet; + params.strategies = strategies; + params.newMagnitudes = new uint64[](params.strategies.length); + + Allocation[] memory allocations = _getAllocations(operator, operatorSet, strategies); + Magnitudes[] memory magnitudes = _getMagnitudes(operator, strategies); + + for (uint i = 0; i < params.strategies.length; i++) { + uint64 halfAvailable = uint64(magnitudes[i].allocatable) / 2; + params.newMagnitudes[i] = allocations[i].currentMagnitude + halfAvailable; + } + } + + /// @dev Generate params to allocate a random portion of available magnitude to each strategy + /// in the operator set. All strategies will have a nonzero allocation, and the minimum allocation + /// will be 10% of available magnitude + function _genAllocation_Rand(User operator, OperatorSet memory operatorSet) internal returns (AllocateParams memory params) { + params.operatorSet = operatorSet; + params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.newMagnitudes = new uint64[](params.strategies.length); + + Allocation[] memory allocations = _getAllocations(operator, operatorSet, params.strategies); + Magnitudes[] memory magnitudes = _getMagnitudes(operator, params.strategies); + + for (uint i = 0; i < params.strategies.length; i++) { + // minimum of 10%, maximum of 100%. increments of 10%. + uint r = _randUint({min: 1, max: 10}); + uint64 allocation = uint64(magnitudes[i].allocatable) / uint64(r); + + params.newMagnitudes[i] = allocations[i].currentMagnitude + allocation; + } + } + + /// @dev Generates params for a half deallocation from all strategies the operator is allocated to in the operator set + function _genDeallocation_HalfRemaining(User operator, OperatorSet memory operatorSet) + internal + view + returns (AllocateParams memory params) + { + return _genDeallocation_HalfRemaining({ + operator: operator, + operatorSet: operatorSet, + strategies: allocationManager().getStrategiesInOperatorSet(operatorSet) + }); + } + + /// @dev Generates params for a half deallocation from all strategies the operator is allocated to in the operator set + function _genDeallocation_HalfRemaining(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + view + returns (AllocateParams memory params) + { + params.operatorSet = operatorSet; + params.strategies = strategies; + params.newMagnitudes = new uint64[](params.strategies.length); + + for (uint i = 0; i < params.strategies.length; i++) { + IStrategy strategy = params.strategies[i]; + params.newMagnitudes[i] = allocationManager().getEncumberedMagnitude(address(operator), strategy) / 2; + } + } + + /// @dev Generates params for a full deallocation from all strategies the operator is allocated to in the operator set + function _genDeallocation_Full(User operator, OperatorSet memory operatorSet) internal view returns (AllocateParams memory params) { + return _genDeallocation_Full(operator, operatorSet, allocationManager().getStrategiesInOperatorSet(operatorSet)); + } + + /// @dev Generates params for a full deallocation from all strategies the operator is allocated to in the operator set + function _genDeallocation_Full(User, OperatorSet memory operatorSet, IStrategy[] memory strategies) + internal + pure + returns (AllocateParams memory params) + { + params.operatorSet = operatorSet; + params.strategies = strategies; + params.newMagnitudes = new uint64[](params.strategies.length); + } + + /// Generate random slashing between 1 and 99% + function _genSlashing_Rand(User operator, OperatorSet memory operatorSet) internal returns (SlashingParams memory params) { + params.operator = address(operator); + params.operatorSetId = operatorSet.id; + params.description = "genSlashing_Rand"; + params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.wadsToSlash = new uint[](params.strategies.length); + + /// 1% * rand(1, 99) + uint slashWad = 1e16 * _randUint({min: 1, max: 99}); + + for (uint i = 0; i < params.wadsToSlash.length; i++) { + params.wadsToSlash[i] = slashWad; + } + } + + function _genSlashing_Half(User operator, OperatorSet memory operatorSet) internal view returns (SlashingParams memory params) { + params.operator = address(operator); + params.operatorSetId = operatorSet.id; + params.description = "genSlashing_Half"; + params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.wadsToSlash = new uint[](params.strategies.length); + + // slash 50% + for (uint i = 0; i < params.wadsToSlash.length; i++) { + params.wadsToSlash[i] = 5e17; + } + } + + function _genSlashing_Full(User operator, OperatorSet memory operatorSet) internal view returns (SlashingParams memory params) { + params.operator = address(operator); + params.operatorSetId = operatorSet.id; + params.description = "_genSlashing_Full"; + params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.wadsToSlash = new uint[](params.strategies.length); + + // slash 100% + for (uint i = 0; i < params.wadsToSlash.length; i++) { + params.wadsToSlash[i] = 1e18; + } + } + + function _genSlashing_Custom(User operator, OperatorSet memory operatorSet, uint wadsToSlash) + internal + view + returns (SlashingParams memory params) + { + params.operator = address(operator); + params.operatorSetId = operatorSet.id; + params.description = "_genSlashing_Custom"; + params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.wadsToSlash = new uint[](params.strategies.length); + + for (uint i = 0; i < params.wadsToSlash.length; i++) { + params.wadsToSlash[i] = wadsToSlash; + } + } + + function _randBalanceUpdate(User staker, IStrategy[] memory strategies) internal returns (int[] memory, int[] memory, int[] memory) { + int[] memory tokenDeltas = new int[](strategies.length); + int[] memory stakerShareDeltas = new int[](strategies.length); + int[] memory operatorShareDeltas = new int[](strategies.length); + + for (uint i = 0; i < strategies.length; i++) { + IStrategy strat = strategies[i]; + + if (strat == BEACONCHAIN_ETH_STRAT) { + // For native ETH, we're either going to slash the staker's validators, + // or award them consensus rewards. In either case, the magnitude of + // the balance update depends on the staker's active validator count + uint activeValidatorCount = staker.pod().activeValidatorCount(); + int64 deltaGwei; + if (_randBool()) { + uint40[] memory validators = staker.getActiveValidators(); + emit log_named_uint("slashing validators", validators.length); + + deltaGwei = -int64(beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor)); + beaconChain.advanceEpoch_NoRewards(); + + emit log_named_int("slashed amount", deltaGwei); + } else { + emit log("generating consensus rewards for validators"); + + deltaGwei = int64(uint64(activeValidatorCount) * beaconChain.CONSENSUS_REWARD_AMOUNT_GWEI()); + beaconChain.advanceEpoch_NoWithdraw(); + } + + tokenDeltas[i] = int(deltaGwei) * int(GWEI_TO_WEI); + + stakerShareDeltas[i] = tokenDeltas[i]; + operatorShareDeltas[i] = _calcNativeETHOperatorShareDelta(staker, stakerShareDeltas[i]); + + emit log_named_int("beacon balance delta (gwei): ", deltaGwei); + emit log_named_int("staker share delta (gwei): ", stakerShareDeltas[i] / int(GWEI_TO_WEI)); + emit log_named_int("operator share delta (gwei): ", operatorShareDeltas[i] / int(GWEI_TO_WEI)); + } else { + // For LSTs, mint a random token amount + uint portion = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); + StdCheats.deal(address(strat.underlyingToken()), address(staker), portion); + + int delta = int(portion); + tokenDeltas[i] = delta; + stakerShareDeltas[i] = int(strat.underlyingToShares(uint(delta))); + operatorShareDeltas[i] = int(strat.underlyingToShares(uint(delta))); + } + } + return (tokenDeltas, stakerShareDeltas, operatorShareDeltas); + } + + /// @dev Rolls forward by the minimum withdrawal delay blocks. + function _rollBlocksForCompleteWithdrawals(Withdrawal[] memory withdrawals) internal { + uint latest; + for (uint i = 0; i < withdrawals.length; ++i) { + if (withdrawals[i].startBlock > latest) latest = withdrawals[i].startBlock; + } + cheats.roll(latest + delegationManager().minWithdrawalDelayBlocks() + 1); + } + + function _rollForward_AllocationDelay(User operator) internal { + uint32 delay = _getExistingAllocationDelay(operator); + rollForward(delay); + } + + function _rollBackward_AllocationDelay(User operator) internal { + uint32 delay = _getExistingAllocationDelay(operator); + rollBackward(delay); + } + + function _rollForward_DeallocationDelay() internal { + rollForward(allocationManager().DEALLOCATION_DELAY() + 1); + } + + function _rollBackward_DeallocationDelay() internal { + rollBackward(allocationManager().DEALLOCATION_DELAY() + 1); + } + + /// @dev Rolls forward by the default allocation delay blocks. + function _rollBlocksForCompleteAllocation(User operator, OperatorSet memory operatorSet, IStrategy[] memory strategies) internal { + uint latest; + for (uint i = 0; i < strategies.length; ++i) { + uint effectBlock = allocationManager().getAllocation(address(operator), operatorSet, strategies[i]).effectBlock; + if (effectBlock > latest) latest = effectBlock; + } + cheats.roll(latest + 1); + } + + /// @dev Rolls forward by the default allocation delay blocks. + function _rollBlocksForCompleteAllocation(User operator, OperatorSet[] memory operatorSets, IStrategy[] memory strategies) internal { + uint latest; + for (uint i = 0; i < operatorSets.length; ++i) { + for (uint j = 0; j < strategies.length; ++j) { + uint effectBlock = allocationManager().getAllocation(address(operator), operatorSets[i], strategies[j]).effectBlock; + if (effectBlock > latest) latest = effectBlock; + } + } + cheats.roll(latest + 1); + } +} diff --git a/src/test/integration/README.md b/src/test/integration/README.md index 2a2be0b633..4a01ccb2b5 100644 --- a/src/test/integration/README.md +++ b/src/test/integration/README.md @@ -28,7 +28,7 @@ During the test, the config passed into `_configRand` will randomly generate onl Here's an example: ```solidity -function testFuzz_deposit_delegate_EXAMPLE(uint24 _random) public { +function testFuzz_deposit_delegate_EXAMPLE(uint24) public { // When new Users are created, they will choose a random configuration from these params. // `_randomSeed` will be the starting seed for all random lookups. _configRand({ @@ -47,8 +47,8 @@ function testFuzz_deposit_delegate_EXAMPLE(uint24 _random) public { (User operator, ,) = _newRandomOperator(); // Because of the `userTypes` flags above, this user might be using either: - // - `strategyManager.depositIntoStrategy` - // - `strategyManager.depositIntoStrategyWithSignature` + // - `strategyManager().depositIntoStrategy` + // - `strategyManager().depositIntoStrategyWithSignature` staker.depositIntoEigenlayer(strategies, tokenBalances); // assertions go here } @@ -105,7 +105,7 @@ Speaking of, the `TimeMachine` is a global contract that controls the time, fate This means that tests can perform user actions with very little setup or "reading prior state", and perform all the important assertions after each action. For example: ```solidity -function testFuzz_deposit_delegate_EXAMPLE(uint24 _random) public { +function testFuzz_deposit_delegate_EXAMPLE(uint24) public { // ... test setup goes above here // This snapshots state before the deposit. @@ -145,5 +145,5 @@ Currently our mainnet fork tests spam whatever RPC we use. We can improve this i `anvil -f RPC_URL ` You can use `anvil -h` for more info on what it can do. -> Then in your test you use the vm.createSelectFork command in your setup with the argument to point to your local anvil node which is basically a copy of the rpc you set it up as. +> Then in your test you use the cheats.createSelectFork command in your setup with the argument to point to your local anvil node which is basically a copy of the rpc you set it up as. > If you want to do some setup before running your tests you can write a script file and broadcast the setup transactions to your local anvil node (make sure to use one of the private keys anvil gives you) \ No newline at end of file diff --git a/src/test/integration/UpgradeTest.t.sol b/src/test/integration/UpgradeTest.t.sol deleted file mode 100644 index 65df41cf91..0000000000 --- a/src/test/integration/UpgradeTest.t.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/test/integration/IntegrationDeployer.t.sol"; -import "src/test/integration/IntegrationChecks.t.sol"; -import "src/test/integration/mocks/BeaconChainMock_Deneb.t.sol"; - -abstract contract UpgradeTest is IntegrationCheckUtils { - /// Only run upgrade tests on mainnet forks - function setUp() public virtual override { - if (!isForktest()) { - cheats.skip(true); - } else { - isUpgraded = false; - super.setUp(); - - // Use Deneb Beacon Chain Mock as Pectra state is not live on mainnet - beaconChain = BeaconChainMock(new BeaconChainMock_DenebForkable(eigenPodManager, BEACON_GENESIS_TIME)); - } - } - - /// Deploy current implementation contracts and upgrade existing proxies - function _upgradeEigenLayerContracts() public virtual { - require(forkType == MAINNET, "_upgradeEigenLayerContracts: somehow running upgrade test locally"); - require(!isUpgraded, "_upgradeEigenLayerContracts: already performed upgrade"); - - emit log("_upgradeEigenLayerContracts: upgrading mainnet to slashing"); - - _upgradeMainnetContracts(); - _handlePectraFork(); - - // Bump block.timestamp forward to allow verifyWC proofs for migrated pods - emit log("advancing block time to start of next epoch:"); - - beaconChain.advanceEpoch_NoRewards(); - - emit log("======"); - - isUpgraded = true; - emit log("_upgradeEigenLayerContracts: slashing upgrade complete"); - } - - // Set the fork timestamp sufficiently in the future to keep using Deneb proofs - // `Prooftra.t.sol` will handle the Deneb -> Pectra transition - function _handlePectraFork() internal { - // 1. Set proof timestamp setter to operations multisig - cheats.prank(eigenPodManager.owner()); - eigenPodManager.setProofTimestampSetter(address(operationsMultisig)); - - // 2. Set Proof timestamp - cheats.prank(eigenPodManager.proofTimestampSetter()); - eigenPodManager.setPectraForkTimestamp(type(uint64).max); - } -} diff --git a/src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol b/src/test/integration/deprecated/mainnet/BeaconChainProofs.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/BeaconChainProofs.sol rename to src/test/integration/deprecated/mainnet/BeaconChainProofs.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol b/src/test/integration/deprecated/mainnet/IBeaconChainOracle.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IBeaconChainOracle.sol rename to src/test/integration/deprecated/mainnet/IBeaconChainOracle.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol b/src/test/integration/deprecated/mainnet/IDelayedWithdrawalRouter.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IDelayedWithdrawalRouter.sol rename to src/test/integration/deprecated/mainnet/IDelayedWithdrawalRouter.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol b/src/test/integration/deprecated/mainnet/IDelegationManager.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IDelegationManager.sol rename to src/test/integration/deprecated/mainnet/IDelegationManager.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol b/src/test/integration/deprecated/mainnet/IEigenPod.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IEigenPod.sol rename to src/test/integration/deprecated/mainnet/IEigenPod.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol b/src/test/integration/deprecated/mainnet/IEigenPodManager.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IEigenPodManager.sol rename to src/test/integration/deprecated/mainnet/IEigenPodManager.sol diff --git a/src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol b/src/test/integration/deprecated/mainnet/IStrategyManager.sol similarity index 100% rename from src/test/integration/deprecatedInterfaces/mainnet/IStrategyManager.sol rename to src/test/integration/deprecated/mainnet/IStrategyManager.sol diff --git a/src/test/integration/tests/ALM_Multi.t.sol b/src/test/integration/tests/ALM_Multi.t.sol index f7af35f002..64a6a75eb0 100644 --- a/src/test/integration/tests/ALM_Multi.t.sol +++ b/src/test/integration/tests/ALM_Multi.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_ALM_Multi is IntegrationCheckUtils { +contract Integration_ALM_Multi is IntegrationChecks { using StdStyle for *; enum Action { @@ -24,14 +24,8 @@ contract Integration_ALM_Multi is IntegrationCheckUtils { REG_FULLY_ALLOC } - AVS avs; - OperatorSet operatorSet; - - IStrategy[] strategies; - /// iteration idx -> list of operators in each state mapping(uint => mapping(State => User[])) operators; - /// operator -> list of strategies they have delegated assets in mapping(User => IStrategy[]) allocatedStrats; /// Last modifyAllocations params made by the operator @@ -44,13 +38,13 @@ contract Integration_ALM_Multi is IntegrationCheckUtils { function _init() internal virtual override { _configAssetAmounts(NUM_UNIQUE_ASSETS); - (avs,) = _newRandomAVS(); + avs = _newRandomAVS(); operatorSet = avs.createOperatorSet(allStrats); for (uint i = 0; i < NUM_OPERATORS; i++) { (User staker, IStrategy[] memory _strategies, uint[] memory initTokenBalances) = _newRandomStaker(); - User operator = _newRandomOperator_NoAssets(); + operator = _newRandomOperator(); // 1. Deposit into strategies staker.depositIntoEigenlayer(_strategies, initTokenBalances); @@ -67,11 +61,7 @@ contract Integration_ALM_Multi is IntegrationCheckUtils { } } - /// Reduce fuzz runs because this test is thiccc: - /// - /// forge-config: default.fuzz.runs = 5 - /// forge-config: forktest.fuzz.runs = 3 - function test_Multi(uint24 _r) public rand(_r) { + function test_Multi() public { // Do 20 iterations for (uint i = 1; i <= NUM_ITERATIONS; i++) { console.log("%s: %d", "iter".green().italic(), i - 1); 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 af569e3f82..0d2c59e257 100644 --- a/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol @@ -4,28 +4,29 @@ 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 rand(_random) { +contract Integration_Delegate_Deposit_Queue_Complete is IntegrationChecks { + function _init() internal override { + _configAssetTypes(HOLDS_LST); + } + + function testFuzz_delegate_deposit_queue_completeAsShares(uint24) public { // Create a staker and an operator with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); // 1. Delegate to operator staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, new uint[](strategies.length)); // Initial shares are zero // 2. Deposit into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - - // Check that the deposit increased operator shares the staker is delegated to + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); - assert_Snap_Added_OperatorShares(operator, strategies, shares, "operator should have received shares"); // 3. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal @@ -36,35 +37,32 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { } } - function testFuzz_delegate_deposit_queue_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_delegate_deposit_queue_completeAsTokens(uint24) public { // Create a staker and an operator with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); // 1. Delegate to operator staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, new uint[](strategies.length)); // Initial shares are zero // 2. Deposit into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - - // 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"); // 3. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], shares, expectedTokens); } } } diff --git a/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol b/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol index 68749392a8..cde2f9f137 100644 --- a/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol @@ -5,27 +5,13 @@ import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; import {console} from "forge-std/console.sol"; -contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is IntegrationCheckUtils { - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - IERC20[] tokens; - uint[] initTokenBalances; - uint[] initDepositShares; - - uint[] numTokensRemaining; - +contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is IntegrationChecks { function _init() internal override { _configUserTypes(DEFAULT); (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); tokens = _getUnderlyingTokens(strategies); uint[] memory tokensToDeposit = new uint[](initTokenBalances.length); @@ -69,7 +55,7 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); } - function testFuzz_fullSlash_undelegate_complete_redeposit(uint24 _random) public rand(_random) { + function testFuzz_fullSlash_undelegate_complete_redeposit(uint24) public { // 4. Fully slash operator SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet); avs.slashOperator(slashParams); @@ -78,16 +64,14 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat // 5. Undelegate from an operator uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 6. Complete withdrawal. Staker should receive 0 shares/tokens after a full slash _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], strategies, new uint[](strategies.length), tokens, new uint[](strategies.length) - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], new uint[](strategies.length), new uint[](strategies.length)); } // 7. Redeposit @@ -96,12 +80,12 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_Deposit_State(staker, strategies, depositShares); } - function testFuzz_undelegate_fullSlash_complete_redeposit(uint24 _random) public rand(_random) { + function testFuzz_undelegate_fullSlash_complete_redeposit(uint24) public { // 4. Undelegate from an operator uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 5. Fully slash operator SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet); @@ -114,8 +98,8 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, expectedShares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } // 7. Redeposit @@ -124,7 +108,7 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_Deposit_State(staker, strategies, depositShares); } - function testFuzz_depositFull_fullSlash_undelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_depositFull_fullSlash_undelegate_completeAsShares(uint24) public { uint[] memory depositShares = _calculateExpectedShares(strategies, numTokensRemaining); staker.depositIntoEigenlayer(strategies, numTokensRemaining); check_Deposit_State(staker, strategies, depositShares); @@ -142,8 +126,8 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat // 5. Undelegate from an operator uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // 6. Complete withdrawal as shares // Fast forward to when we can complete the withdrawal @@ -151,12 +135,12 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat for (uint i = 0; i < withdrawals.length; ++i) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); - tokens = staker.completeWithdrawalAsShares(withdrawals[i]); + staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares); } } - function testFuzz_deposit_delegate_allocate_partialSlash_redeposit_queue_complete(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_allocate_partialSlash_redeposit_queue_complete(uint24) public { // Partially slash operator SlashingParams memory slashParams = _genSlashing_Half(operator, operatorSet); avs.slashOperator(slashParams); @@ -172,9 +156,9 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat } // Queue withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // Complete withdrawal @@ -182,19 +166,17 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_deposit_delegate_undelegate_partialSlash_complete(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_undelegate_partialSlash_complete(uint24) public { // Undelegate from operator uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); // Partially slash operator SlashingParams memory slashParams = _genSlashing_Half(operator, operatorSet); @@ -206,14 +188,12 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_deposit_delegate_deallocate_partialSlash_queue_complete(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_deallocate_partialSlash_queue_complete(uint24) public { // Deallocate from operator set AllocateParams memory deallocateParams = _genDeallocation_Full(operator, operatorSet); operator.modifyAllocations(deallocateParams); @@ -225,9 +205,9 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_Base_Slashing_State(operator, allocateParams, slashParams); // Queue withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // Complete withdrawal @@ -235,14 +215,12 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_deposit_delegate_deregister_partialSlash_queue_complete(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_deregister_partialSlash_queue_complete(uint24) public { // Deregister operator from operator set operator.deregisterFromOperatorSet(operatorSet); check_Deregistration_State_ActiveAllocation(operator, operatorSet); @@ -253,9 +231,9 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_Base_Slashing_State(operator, allocateParams, slashParams); // Queue withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // Complete withdrawal @@ -263,14 +241,12 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); - tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_delegate_zeroShares_partialSlash_deposit_undelegate_complete(uint24 r) public rand(r) { + function testFuzz_delegate_zeroShares_partialSlash_deposit_undelegate_complete(uint24) public { // Create a new staker with 0 shares (User zeroSharesStaker, uint[] memory tokensToDeposit) = _newStaker(strategies); @@ -290,22 +266,20 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat // Undelegate uint[] memory shares = _getStakerWithdrawableShares(zeroSharesStaker, strategies); Withdrawal[] memory withdrawals = zeroSharesStaker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(zeroSharesStaker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(zeroSharesStaker, operator, withdrawals, withdrawalRoots, strategies, shares); // Complete withdrawal _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); - tokens = zeroSharesStaker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - zeroSharesStaker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + zeroSharesStaker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(zeroSharesStaker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_deposit_delegate_allocate_partialSlash_deallocate(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_allocate_partialSlash_deallocate(uint24) public { // Partially slash operator SlashingParams memory slashParams = _genSlashing_Half(operator, operatorSet); avs.slashOperator(slashParams); @@ -317,7 +291,7 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_DecrAlloc_State_Slashable(operator, deallocateParams); } - function testFuzz_fullSlash_undelegate_redeposit_complete(uint24 _random) public rand(_random) { + function testFuzz_fullSlash_undelegate_redeposit_complete(uint24) public { initDepositShares = _getStakerDepositShares(staker, strategies); // 4. Fully slash operator @@ -326,9 +300,9 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_FullySlashed_State(operator, allocateParams, slashParams); // 5. Undelegate from an operator - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 6. Redeposit @@ -338,20 +312,15 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat // 7. Complete withdrawal. Staker should receive 0 shares/tokens after a full slash _rollBlocksForCompleteWithdrawals(withdrawals); - for (uint i = 0; i < withdrawals.length; ++i) { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares); } - - // Final state checks - assert_HasExpectedShares(staker, strategies, shares, "staker should have expected shares after redeposit"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_fullSlash_redelegate_redeposit_complete(uint24 _random) public rand(_random) { - (User operator2,,) = _newRandomOperator(); + function testFuzz_fullSlash_redelegate_redeposit_complete(uint24) public { + User operator2 = _newRandomOperator(); initDepositShares = _getStakerDepositShares(staker, strategies); // 4. Fully slash operator @@ -360,9 +329,9 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat check_FullySlashed_State(operator, allocateParams, slashParams); // 5. Undelegate from an operator - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.redelegate(operator2); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 6. Redeposit @@ -378,9 +347,5 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares); } - - // Final state checks - assert_HasExpectedShares(staker, strategies, shares, "staker should have expected shares after redeposit"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } } diff --git a/src/test/integration/tests/ALM_RegisterAndModify.t.sol b/src/test/integration/tests/Deposit_Delegate_Modify.t.sol similarity index 81% rename from src/test/integration/tests/ALM_RegisterAndModify.t.sol rename to src/test/integration/tests/Deposit_Delegate_Modify.t.sol index dbe8d0161f..9ebc231494 100644 --- a/src/test/integration/tests/ALM_RegisterAndModify.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Modify.t.sol @@ -3,18 +3,7 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_ALMBase is IntegrationCheckUtils { - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - +contract Integration_Deposit_Delegate_Modify is IntegrationChecks { /// Shared setup: /// /// 1. Generate staker with deposited assets, operator, and AVS @@ -22,8 +11,8 @@ contract Integration_ALMBase is IntegrationCheckUtils { /// 3. AVS creates an operator set containing the strategies held by the staker function _init() internal virtual override { (staker, strategies, initTokenBalances) = _newRandomStaker(); - operator = _newRandomOperator_NoAssets(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); // 1. Deposit Into Strategies staker.depositIntoEigenlayer(strategies, initTokenBalances); @@ -37,20 +26,12 @@ contract Integration_ALMBase is IntegrationCheckUtils { // 3. Create an operator set containing the strategies held by the staker operatorSet = avs.createOperatorSet(strategies); } -} - -contract Integration_InitRegistered is Integration_ALMBase { - /// @dev Integration test variants that start with the operator being registered - /// for the operator set - function _init() internal virtual override { - super._init(); + function testFuzz_deposit_delegate_register_allocate_deallocate_deregister(uint24) public { // Register for operator set before allocating to any strategies operator.registerForOperatorSet(operatorSet); check_Registration_State_NoAllocation(operator, operatorSet, allStrats); - } - function testFuzz_allocate_deallocate_deregister(uint24 _r) public rand(_r) { // 1. Allocate to the operator set allocateParams = _genAllocation_Rand(operator, operatorSet); operator.modifyAllocations(allocateParams); @@ -73,7 +54,11 @@ contract Integration_InitRegistered is Integration_ALMBase { check_FullyDeallocated_State(operator, allocateParams, deallocateParams); } - function testFuzz_allocate_deallocate_waitDeallocate_deregister(uint24 _r) public rand(_r) { + function testFuzz_deposit_delegate_register_allocate_deallocate_waitDeallocate_deregister(uint24) public { + // Register for operator set before allocating to any strategies + operator.registerForOperatorSet(operatorSet); + check_Registration_State_NoAllocation(operator, operatorSet, allStrats); + // 1. Allocate to the operator set allocateParams = _genAllocation_Rand(operator, operatorSet); operator.modifyAllocations(allocateParams); @@ -96,7 +81,11 @@ contract Integration_InitRegistered is Integration_ALMBase { check_Deregistration_State_NoAllocation(operator, operatorSet); } - function testFuzz_deregister_waitDeregister_allocate_deallocate(uint24 _r) public rand(_r) { + function testFuzz_deposit_delegate_register_deregister_waitDeregister_allocate_deallocate(uint24) public { + // Register for operator set before allocating to any strategies + operator.registerForOperatorSet(operatorSet); + check_Registration_State_NoAllocation(operator, operatorSet, allStrats); + // 1. Deregister from operator set operator.deregisterFromOperatorSet(operatorSet); check_Deregistration_State_NoAllocation(operator, operatorSet); @@ -119,7 +108,11 @@ contract Integration_InitRegistered is Integration_ALMBase { check_FullyDeallocated_State(operator, allocateParams, deallocateParams); } - function testFuzz_deregister_allocate_waitAllocate_deallocate(uint24 _r) public rand(_r) { + function testFuzz_deposit_delegate_register_deregister_allocate_waitAllocate_deallocate(uint24) public { + // Register for operator set before allocating to any strategies + operator.registerForOperatorSet(operatorSet); + check_Registration_State_NoAllocation(operator, operatorSet, allStrats); + // 1. Deregister from operator set operator.deregisterFromOperatorSet(operatorSet); check_Deregistration_State_NoAllocation(operator, operatorSet); @@ -143,7 +136,11 @@ contract Integration_InitRegistered is Integration_ALMBase { check_FullyDeallocated_State(operator, allocateParams, deallocateParams); } - function testFuzz_deregister_allocate_waitDeregister_deallocate(uint24 _r) public rand(_r) { + function testFuzz_deposit_delegate_register_deregister_allocate_waitDeregister_deallocate(uint24) public { + // Register for operator set before allocating to any strategies + operator.registerForOperatorSet(operatorSet); + check_Registration_State_NoAllocation(operator, operatorSet, allStrats); + // 1. Deregister from operator set operator.deregisterFromOperatorSet(operatorSet); check_Deregistration_State_NoAllocation(operator, operatorSet); @@ -163,21 +160,13 @@ contract Integration_InitRegistered is Integration_ALMBase { check_DecrAlloc_State_NotSlashable(operator, deallocateParams); check_FullyDeallocated_State(operator, allocateParams, deallocateParams); } -} - -contract Integration_InitAllocated is Integration_ALMBase { - /// @dev Integration test variants that start with the operator being allocated - /// for the operator set - function _init() internal virtual override { - super._init(); + function testFuzz_deposit_delegate_allocate_register_deallocate_deregister(uint24) public { // Allocate fully to operator set allocateParams = _genAllocation_AllAvailable(operator, operatorSet); operator.modifyAllocations(allocateParams); check_IncrAlloc_State_NotSlashable(operator, allocateParams); - } - function testFuzz_register_deallocate_deregister(uint24 _r) public rand(_r) { // 1. Register for the operator set operator.registerForOperatorSet(operatorSet); check_Registration_State_PendingAllocation(operator, allocateParams); @@ -199,7 +188,12 @@ contract Integration_InitAllocated is Integration_ALMBase { check_FullyDeallocated_State(operator, allocateParams, deallocateParams); } - function testFuzz_waitAllocation_register_deallocate(uint24 _r) public rand(_r) { + function testFuzz_deposit_delegate_allocate_waitAllocation_register_deallocate(uint24) public { + // Allocate fully to operator set + allocateParams = _genAllocation_AllAvailable(operator, operatorSet); + operator.modifyAllocations(allocateParams); + check_IncrAlloc_State_NotSlashable(operator, allocateParams); + _rollForward_AllocationDelay(operator); // 1. Register for the operator set. The allocation immediately becomes slashable 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 7af3ac45bc..fe64866472 100644 --- a/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; -contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { +contract Integration_Deposit_Delegate_Queue_Complete is IntegrationChecks { /** * * FULL WITHDRAWALS @@ -17,22 +17,18 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a ALL shares /// 4. completes the queued withdrawal as tokens - function testFuzz_deposit_delegate_queue_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_queue_completeAsTokens(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) // // ... check that the staker has no delegatable shares and isn't currently delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - 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"); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); // 1. Deposit Into Strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Delegate to an operator @@ -40,9 +36,9 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, shares); // 3. Queue Withdrawals - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete withdrawal @@ -51,15 +47,9 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { for (uint i = 0; i < withdrawals.length; i++) { 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], strategies, shares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], shares, expectedTokens); } - - // Check final state: - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); - assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares"); - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token balances"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } /// Generates a random staker and operator. The staker: @@ -67,22 +57,19 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a ALL shares /// 4. completes the queued withdrawal as shares - function testFuzz_deposit_delegate_queue_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_queue_completeAsShares(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) // // ... check that the staker has no delegatable shares and isn't currently delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); - 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"); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); // 1. Deposit Into Strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Delegate to an operator @@ -90,9 +77,9 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, shares); // 3. Queue Withdrawals - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete withdrawal @@ -103,118 +90,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], strategies, shares); } - - // Check final state: - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); - assert_HasExpectedShares(staker, strategies, shares, "staker should have all original shares"); - assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker not have any underlying tokens"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); - } - - /** - * - * RANDOM WITHDRAWALS - * - */ - - /// Generates a random staker and operator. The staker: - /// 1. deposits all assets into strategies - /// 2. delegates to an operator - /// 3. queues a withdrawal for a random subset of shares - /// 4. completes the queued withdrawal as tokens - function testFuzz_deposit_delegate_queueRand_completeAsTokens(uint24 _random) public rand(_random) { - /// 0. Create an operator and a staker with: - // - some nonzero underlying token balances - // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) - // - // ... check that the staker has no delegatable shares and isn't currently delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - 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"); - - // 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); - - // 3. Queue Withdrawals - // Randomly select one or more assets to withdraw - (IStrategy[] memory withdrawStrats, uint[] memory withdrawShares) = _randWithdrawal(strategies, shares); - - Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_QueuedWithdrawal_State(staker, operator, withdrawStrats, withdrawShares, withdrawShares, withdrawals, withdrawalRoots); - - // 4. Complete withdrawals - // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(withdrawals); - for (uint i = 0; i < withdrawals.length; i++) { - 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], withdrawStrats, withdrawShares, tokens, expectedTokens); - } - - // Check final state: - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); - } - - /// Generates a random staker and operator. The staker: - /// 1. deposits all assets into strategies - /// 2. delegates to an operator - /// 3. queues a withdrawal for a random subset of shares - /// 4. completes the queued withdrawal as shares - function testFuzz_deposit_delegate_queueRand_completeAsShares(uint24 _random) public rand(_random) { - /// 0. Create an operator and a staker with: - // - some nonzero underlying token balances - // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) - // - // ... check that the staker has no delegatable shares and isn't currently delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - 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"); - - // 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); - - // 3. Queue Withdrawals - // Randomly select one or more assets to withdraw - (IStrategy[] memory withdrawStrats, uint[] memory withdrawShares) = _randWithdrawal(strategies, shares); - - Withdrawal[] memory withdrawals = staker.queueWithdrawals(withdrawStrats, withdrawShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_QueuedWithdrawal_State(staker, operator, withdrawStrats, withdrawShares, withdrawShares, withdrawals, withdrawalRoots); - - // 4. Complete withdrawal - // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(withdrawals); - - for (uint i = 0; i < withdrawals.length; i++) { - staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], withdrawStrats, withdrawShares); - } - - // Check final state: - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); - assert_HasExpectedShares(staker, strategies, shares, "staker should have all original shares"); - assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker not have any underlying tokens"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } /** @@ -229,25 +104,21 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// /// ... we check that the final step fails - function testFuzz_deposit_delegate_revert_alreadyDelegated(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_revert_alreadyDelegated(uint24) public { _configAssetTypes(NO_ASSETS | HOLDS_LST | HOLDS_ETH | HOLDS_ALL); /// 0. Create a staker and operator - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); - assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); - assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); // 1. Deposit Into Strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Register staker as an operator staker.registerAsOperator(); - assertTrue(delegationManager.isDelegated(address(staker)), "staker should be delegated"); // 3. Attempt to delegate to an operator // This should fail as the staker is already delegated to themselves. 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 bc090f34eb..a88265d90e 100644 --- a/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUtils { +contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationChecks { using ArrayLib for *; /// Randomly generates a user with different held assets. Then: @@ -15,26 +15,23 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti /// 5. delegate to a new operator /// 5. queueWithdrawal /// 7. complete their queued withdrawal as tokens - function testFuzz_deposit_delegate_reDelegate_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_reDelegate_completeAsTokens(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); //delegatable shares equals deposit shares here because no bc slashing uint[] memory delegatableShares = shares; - 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); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Delegate to an operator @@ -43,7 +40,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as shares @@ -59,10 +56,9 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 5. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, shares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); // 6. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); withdrawals = staker.queueWithdrawals(strategies, shares); withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); @@ -74,33 +70,28 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // Complete withdrawals for (uint i = 0; i < withdrawals.length; i++) { 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].scaledShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } } - function testFuzz_deposit_delegate_reDelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_reDelegate_completeAsShares(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); //delegatable shares equals deposit shares here because no bc slashing uint[] memory delegatableShares = shares; - 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); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Delegate to an operator @@ -109,7 +100,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as shares @@ -125,10 +116,10 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 5. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, shares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); + assertNotEq(address(operator1), delegationManager().delegatedTo(address(staker)), "staker should not be delegated to operator1"); // 6. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); withdrawals = staker.queueWithdrawals(strategies, shares); withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); @@ -138,21 +129,14 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti _rollBlocksForCompleteWithdrawals(withdrawals); // Complete all but last withdrawal as tokens - for (uint i = 0; i < withdrawals.length - 1; i++) { - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); + for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - check_Withdrawal_AsTokens_State(staker, staker, withdrawals[i], strategies, shares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, staker, withdrawals[i], shares, expectedTokens); } - - // Complete last withdrawal as shares - IERC20[] memory finalWithdrawaltokens = staker.completeWithdrawalAsTokens(withdrawals[withdrawals.length - 1]); - uint[] memory finalExpectedTokens = _calculateExpectedTokens(strategies, shares); - check_Withdrawal_AsTokens_State( - staker, operator2, withdrawals[withdrawals.length - 1], strategies, shares, finalWithdrawaltokens, finalExpectedTokens - ); } - function testFuzz_deposit_delegate_reDelegate_depositAfterRedelegate(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_reDelegate_depositAfterRedelegate(uint24) public { _configAssetTypes(HOLDS_LST); // not holding ETH since we can only deposit 32 ETH multiples /// 0. Create an operator and a staker with: @@ -161,22 +145,18 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); - - 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"); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); { // Divide shares by 2 in new array to do deposits after redelegate - uint[] memory numTokensToDeposit = new uint[](tokenBalances.length); - uint[] memory numTokensRemaining = new uint[](tokenBalances.length); + uint[] memory numTokensToDeposit = new uint[](initTokenBalances.length); + uint[] memory numTokensRemaining = new uint[](initTokenBalances.length); for (uint i = 0; i < shares.length; i++) { - numTokensToDeposit[i] = tokenBalances[i] / 2; - numTokensRemaining[i] = tokenBalances[i] - numTokensToDeposit[i]; + numTokensToDeposit[i] = initTokenBalances[i] / 2; + numTokensRemaining[i] = initTokenBalances[i] - numTokensToDeposit[i]; } uint[] memory halfShares = _calculateExpectedShares(strategies, numTokensToDeposit); //delegatable shares equals deposit shares here because no bc slashing @@ -192,7 +172,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as shares @@ -208,18 +188,18 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 5. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, halfShares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); + assertNotEq(address(operator1), delegationManager().delegatedTo(address(staker)), "staker should not be delegated to operator1"); // 6. Deposit into Strategies uint[] memory sharesAdded = _calculateExpectedShares(strategies, numTokensRemaining); staker.depositIntoEigenlayer(strategies, numTokensRemaining); - tokenBalances = _calculateExpectedTokens(strategies, shares); + initTokenBalances = _calculateExpectedTokens(strategies, shares); check_Deposit_State(staker, strategies, sharesAdded); } { // 7. Queue Withdrawal - shares = _calculateExpectedShares(strategies, tokenBalances); + shares = _calculateExpectedShares(strategies, initTokenBalances); Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, shares); bytes32[] memory newWithdrawalRoots = _getWithdrawalHashes(newWithdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, shares, newWithdrawals, newWithdrawalRoots); @@ -231,13 +211,13 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // Complete withdrawals for (uint i = 0; i < newWithdrawals.length; i++) { 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); + staker.completeWithdrawalAsTokens(newWithdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, newWithdrawals[i], shares, expectedTokens); } } } - function testFuzz_deposit_delegate_reDelegate_depositBeforeRedelegate(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_reDelegate_depositBeforeRedelegate(uint24) public { _configAssetTypes(HOLDS_LST); // not holding ETH since we can only deposit 32 ETH multiples /// 0. Create an operator and a staker with: @@ -246,22 +226,18 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); uint[] memory totalShares = new uint[](strategies.length); - - assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); - assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); - { // Divide shares by 2 in new array to do deposits after redelegate - uint[] memory numTokensToDeposit = new uint[](tokenBalances.length); - uint[] memory numTokensRemaining = new uint[](tokenBalances.length); + uint[] memory numTokensToDeposit = new uint[](initTokenBalances.length); + uint[] memory numTokensRemaining = new uint[](initTokenBalances.length); for (uint i = 0; i < strategies.length; i++) { - numTokensToDeposit[i] = tokenBalances[i] / 2; - numTokensRemaining[i] = tokenBalances[i] - numTokensToDeposit[i]; + numTokensToDeposit[i] = initTokenBalances[i] / 2; + numTokensRemaining[i] = initTokenBalances[i] - numTokensToDeposit[i]; } { uint[] memory sharesFromFirstDeposit = _calculateExpectedShares(strategies, numTokensToDeposit); @@ -278,7 +254,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as shares @@ -298,19 +274,19 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti } staker.depositIntoEigenlayer(strategies, numTokensRemaining); - tokenBalances = _calculateExpectedTokens(strategies, totalShares); + initTokenBalances = _calculateExpectedTokens(strategies, totalShares); check_Deposit_State(staker, strategies, sharesFromSecondDeposit); } // 6. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, totalShares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); + assertNotEq(address(operator1), delegationManager().delegatedTo(address(staker)), "staker should not be delegated to operator1"); } { // 7. Queue Withdrawal - totalShares = _calculateExpectedShares(strategies, tokenBalances); + totalShares = _calculateExpectedShares(strategies, initTokenBalances); Withdrawal[] memory newWithdrawals = staker.queueWithdrawals(strategies, totalShares); bytes32[] memory newWithdrawalRoots = _getWithdrawalHashes(newWithdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, totalShares, totalShares, newWithdrawals, newWithdrawalRoots); @@ -322,27 +298,24 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // Complete withdrawals for (uint i = 0; i < newWithdrawals.length; i++) { 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, totalShares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(newWithdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, newWithdrawals[i], totalShares, expectedTokens); } } } - function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsTokens(uint24) public { /// 0. Create operators and a staker - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); //delegatable shares equals deposit shares here because no bc slashing uint[] memory delegatableShares = shares; - 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); + staker.depositIntoEigenlayer(strategies, initTokenBalances); uint[] memory withdrawnTokenBalances = _calculateExpectedTokens(strategies, shares); check_Deposit_State(staker, strategies, shares); @@ -352,7 +325,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as tokens @@ -360,10 +333,8 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { 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].scaledShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } //5. Deposit into Strategies @@ -374,11 +345,11 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 6. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, shares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); + assertNotEq(address(operator1), delegationManager().delegatedTo(address(staker)), "staker should not be delegated to operator1"); { // 7. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); withdrawals = staker.queueWithdrawals(strategies, shares); withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator2, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); @@ -391,26 +362,23 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // Complete withdrawals as tokens for (uint i = 0; i < withdrawals.length; i++) { 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); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], shares, expectedTokens); } } - function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsShares(uint24) public { /// 0. Create operators and a staker - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator1,,) = _newRandomOperator(); - (User operator2,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + User operator1 = _newRandomOperator(); + User operator2 = _newRandomOperator(); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); //delegatable shares equals deposit shares here because no bc slashing uint[] memory delegatableShares = shares; - 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); + staker.depositIntoEigenlayer(strategies, initTokenBalances); uint[] memory withdrawnTokenBalances = _calculateExpectedTokens(strategies, shares); check_Deposit_State(staker, strategies, shares); @@ -420,7 +388,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator1, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal as Tokens @@ -428,10 +396,8 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { 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].scaledShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator1, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } // 5. Deposit into Strategies @@ -442,7 +408,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti // 6. Delegate to a new operator staker.delegateTo(operator2); check_Delegation_State(staker, operator2, strategies, shares); - assertNotEq(address(operator1), delegationManager.delegatedTo(address(staker)), "staker should not be delegated to operator1"); + assertNotEq(address(operator1), delegationManager().delegatedTo(address(staker)), "staker should not be delegated to operator1"); // 7. Queue Withdrawal shares = _calculateExpectedShares(strategies, withdrawnTokenBalances); 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 440a95984b..3982371a2c 100644 --- a/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol @@ -4,40 +4,42 @@ 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 - /// 3. undelegates from the operator - /// 4. complete their queued withdrawal as tokens - function testFuzz_deposit_undelegate_completeAsTokens(uint24 _random) public rand(_random) { - /// 0. Create an operator and a staker with: - // - some nonzero underlying token balances - // - corresponding to a random number of strategies - // - // ... check that the staker has no deleagatable shares and isn't delegated +contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationChecks { + uint[] shares; + uint[] delegatableShares; - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); + function _init() internal virtual override { + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + shares = _calculateExpectedShares(strategies, initTokenBalances); //delegatable shares equals deposit shares here because no bc slashing - uint[] memory delegatableShares = shares; - - assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); - assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); + delegatableShares = shares; /// 1. Deposit Into Strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Delegate to an operator staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, shares); + } + + /// Randomly generates a user with different held assets. Then: + /// 1. deposit into strategy + /// 2. delegate to an operator + /// 3. undelegates from the operator + /// 4. complete their queued withdrawal as tokens + function testFuzz_deposit_undelegate_completeAsTokens(uint24) public { + /// 0. Create an operator and a staker with: + // - some nonzero underlying token balances + // - corresponding to a random number of strategies + // + // ... check that the staker has no deleagatable shares and isn't delegated // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal @@ -47,16 +49,9 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti // Complete withdrawal for (uint i = 0; i < withdrawals.length; ++i) { 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].scaledShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } - - // Check Final State - assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares"); - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token balances"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } /// Randomly generates a user with different held assets. Then: @@ -64,34 +59,16 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti /// 2. delegate to an operator /// 3. undelegates from the operator /// 4. complete their queued withdrawal as shares - function testFuzz_deposit_undelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_undelegate_completeAsShares(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - //delegatable shares equals deposit shares here because no bc slashing - uint[] memory delegatableShares = shares; - - 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); - - // 2. Delegate to an operator - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); - // 3. Undelegate from an operator Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal @@ -104,41 +81,18 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares ); } - - // Check final state: - assert_HasExpectedShares(staker, strategies, shares, "staker should have all original shares"); - assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker not have any underlying tokens"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deposit_delegate_forceUndelegate_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_forceUndelegate_completeAsTokens(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - //delegatable shares equals deposit shares here because no bc slashing - uint[] memory delegatableShares = shares; - - 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); - - // 2. Delegate to an operator - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); - // 3. Force undelegate Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal @@ -147,46 +101,21 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti for (uint i = 0; i < withdrawals.length; ++i) { 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].scaledShares, tokens, expectedTokens - ); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } - - // Check Final State - assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares"); - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token balances"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deposit_delegate_forceUndelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_delegate_forceUndelegate_completeAsShares(uint24) public { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies // // ... check that the staker has no deleagatable shares and isn't delegated - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - //delegatable shares equals deposit shares here because no bc slashing - uint[] memory delegatableShares = shares; - - 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); - - // 2. Delegate to an operator - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); - // 3. Force undelegate Withdrawal[] memory withdrawals = operator.forceUndelegate(staker); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); // 4. Complete withdrawal @@ -198,57 +127,44 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawals[i].scaledShares ); } - - // Check final state: - assert_HasExpectedShares(staker, strategies, shares, "staker should have all original shares"); - assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker not have any underlying tokens"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deposit_delegate_undelegate_completeAsTokens_Max_Strategies(uint24 _random) public rand(_random) { - _configAssetTypes(HOLDS_MAX); + function test_deposit_delegate_undelegate_completeAsTokens_Max_Strategies() public { + if (eq(FOUNDRY_PROFILE(), "default")) { + _configAssetTypes(HOLDS_MAX); - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); + operator = _newRandomOperator(); - if (forkType == LOCAL) assertEq(strategies.length, 33, "sanity"); + assertEq(strategies.length, 9, "sanity"); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - //delegatable shares equals deposit shares here because no bc slashing - uint[] memory delegatableShares = shares; + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); + //delegatable shares equals deposit shares here because no bc slashing + uint[] memory delegatableShares = shares; - 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, initTokenBalances); + 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. Undelegate from an operator - Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); + // 3. Undelegate from an operator + Withdrawal[] memory withdrawals = staker.undelegate(); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatableShares); - // 4. Complete withdrawal - // Fast forward to when we can complete the withdrawal - _rollBlocksForCompleteWithdrawals(withdrawals); + // 4. Complete withdrawal + // Fast forward to when we can complete the withdrawal + _rollBlocksForCompleteWithdrawals(withdrawals); - // Complete withdrawal - for (uint i = 0; i < withdrawals.length; ++i) { - 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].scaledShares, tokens, expectedTokens - ); + // Complete withdrawal + for (uint i = 0; i < withdrawals.length; ++i) { + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); + } } - - // Check Final State - assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares"); - assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token tokenBalances"); - assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } } diff --git a/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol b/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol index 07caad29df..978c86bcdd 100644 --- a/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_UpdateBalance.t.sol @@ -4,7 +4,7 @@ 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 { +contract Integration_Deposit_Delegate_UpdateBalance is IntegrationChecks { // TODO: fix for slashing /// Generates a random stake and operator. The staker: /// 1. deposits all assets into strategies @@ -12,7 +12,7 @@ contract Integration_Deposit_Delegate_UpdateBalance is IntegrationCheckUtils { /// 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 { +// function testFuzz_deposit_delegate_updateBalance_completeAsTokens(uint24) public { // _configRand({ // _randomSeed: _random, // _assetTypes: HOLDS_ETH, // HOLDS_LST | HOLDS_ETH | HOLDS_ALL, @@ -23,19 +23,19 @@ contract Integration_Deposit_Delegate_UpdateBalance is IntegrationCheckUtils { // ( // User staker, // IStrategy[] memory strategies, -// uint[] memory tokenBalances +// uint[] memory initTokenBalances // ) = _newRandomStaker(); // (User operator, ,) = _newRandomOperator(); // // Upgrade contracts if forkType is not local // _upgradeEigenLayerContracts(); -// uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); +// uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); // assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing"); -// assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated"); +// assertFalse(delegationManager().isDelegated(address(staker)), "staker should not be delegated"); // /// 1. Deposit into strategies -// staker.depositIntoEigenlayer(strategies, tokenBalances); +// staker.depositIntoEigenlayer(strategies, initTokenBalances); // check_Deposit_State(staker, strategies, shares); // /// 2. Delegate to an operator @@ -44,7 +44,7 @@ contract Integration_Deposit_Delegate_UpdateBalance is IntegrationCheckUtils { // /// 3. Queue withdrawals for ALL shares // Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); -// bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); +// withdrawalRoots = _getWithdrawalHashes(withdrawals); // check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); // // Generate a random balance update: @@ -68,7 +68,7 @@ contract Integration_Deposit_Delegate_UpdateBalance is IntegrationCheckUtils { // // 5. Complete queued withdrawals as tokens // staker.completeWithdrawalsAsTokens(withdrawals); -// assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator"); +// 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 908b5f6bd2..cadded458c 100644 --- a/src/test/integration/tests/Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Queue_Complete.t.sol @@ -4,22 +4,22 @@ 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 { +contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationChecks { /// 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 rand(_random) { + function testFuzz_deposit_queueWithdrawal_completeAsTokens(uint24) public { // Create a staker with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); // 1. Deposit into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // Ensure staker is not delegated to anyone post deposit - assertFalse(delegationManager.isDelegated(address(staker)), "Staker should not be delegated after deposit"); + assertFalse(delegationManager().isDelegated(address(staker)), "Staker should not be delegated after deposit"); // 2. Queue Withdrawal Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); @@ -28,25 +28,25 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, User(payable(0)), withdrawals[i], strategies, shares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, User(payable(0)), withdrawals[i], shares, expectedTokens); } // Ensure staker is still not delegated to anyone post withdrawal completion - assertFalse(delegationManager.isDelegated(address(staker)), "Staker should still not be delegated after withdrawal"); + assertFalse(delegationManager().isDelegated(address(staker)), "Staker should still not be delegated after withdrawal"); } - function testFuzz_deposit_queueWithdrawal_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_queueWithdrawal_completeAsShares(uint24) public { // Create a staker with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); // 1. Deposit into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // Ensure staker is not delegated to anyone post deposit - assertFalse(delegationManager.isDelegated(address(staker)), "Staker should not be delegated after deposit"); + assertFalse(delegationManager().isDelegated(address(staker)), "Staker should not be delegated after deposit"); // 2. Queue Withdrawal Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); @@ -59,36 +59,37 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { } // Ensure staker is still not delegated to anyone post withdrawal completion - assertFalse(delegationManager.isDelegated(address(staker)), "Staker should still not be delegated after withdrawal"); + assertFalse(delegationManager().isDelegated(address(staker)), "Staker should still not be delegated after withdrawal"); } /// @notice Regression test to ensure that depositSharesToRemove is not allowed to overflow. Previously /// this vulnerability would allow a staker to queue a withdrawal overflowing amount of deposit shares to withdraw /// resulting them in inflating their existing deposit shares. They could then inflate an operators delegated shares as much as they wanted. - function testFuzz_deposit_revertOverflow_queueWithdrawal(uint24 _random) public rand(_random) { + function testFuzz_deposit_revertOverflow_queueWithdrawal(uint24) public { _configAssetTypes(HOLDS_ETH); // Create a staker with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory initDepositShares) = _newRandomStaker(); - cheats.assume(initDepositShares[0] >= 64 ether); - - // Deposit staker by verifying withdrawal credentials - (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); - beaconChain.advanceEpoch_NoRewards(); - staker.verifyWithdrawalCredentials(validators); - check_VerifyWC_State(staker, validators, beaconBalanceGwei); - - // Queue withdrawal for depositSharesToRemove that overflows - int podOwnerDepositSharesBefore = eigenPodManager.podOwnerDepositShares(address(staker)); - assertEq(uint(podOwnerDepositSharesBefore), initDepositShares[0]); - - uint[] memory depositSharesToRemove = new uint[](1); - depositSharesToRemove[0] = uint(type(int).max) + 100_000e18; - - cheats.expectRevert("SafeCast: value doesn't fit in an int256"); - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositSharesToRemove); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - - int podOwnerDepositSharesAfter = eigenPodManager.podOwnerDepositShares(address(staker)); - assertEq(podOwnerDepositSharesAfter, podOwnerDepositSharesBefore); + cheats.assume(initDepositShares.length != 0); + if (initDepositShares[0] >= 64 ether) { + // Deposit staker by verifying withdrawal credentials + (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); + beaconChain.advanceEpoch_NoRewards(); + staker.verifyWithdrawalCredentials(validators); + check_VerifyWC_State(staker, validators, beaconBalanceGwei); + + // Queue withdrawal for depositSharesToRemove that overflows + int podOwnerDepositSharesBefore = eigenPodManager().podOwnerDepositShares(address(staker)); + assertEq(uint(podOwnerDepositSharesBefore), initDepositShares[0]); + + uint[] memory depositSharesToRemove = new uint[](1); + depositSharesToRemove[0] = uint(type(int).max) + 100_000e18; + + cheats.expectRevert("SafeCast: value doesn't fit in an int256"); + Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositSharesToRemove); + bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + + int podOwnerDepositSharesAfter = eigenPodManager().podOwnerDepositShares(address(staker)); + assertEq(podOwnerDepositSharesAfter, podOwnerDepositSharesBefore); + } } } 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 782422b841..3bc62d3265 100644 --- a/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol @@ -4,24 +4,24 @@ pragma solidity ^0.8.27; import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationCheckUtils { - function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsShares(uint24 _random) public rand(_random) { +contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationChecks { + function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsShares(uint24) public { // Create a staker with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); // 1. Staker deposits into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Staker registers as an operator staker.registerAsOperator(); - assertTrue(delegationManager.isOperator(address(staker)), "Staker should be registered as an operator"); + assertTrue(delegationManager().isOperator(address(staker)), "Staker should be registered as an operator"); // 3. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, staker, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal as Shares @@ -32,31 +32,30 @@ contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationChe } } - function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsTokens(uint24) public { // Create a staker with a nonzero balance and corresponding strategies - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); // 1. Staker deposits into strategy - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, shares); // 2. Staker registers as an operator staker.registerAsOperator(); - assertTrue(delegationManager.isOperator(address(staker)), "Staker should be registered as an operator"); + assertTrue(delegationManager().isOperator(address(staker)), "Staker should be registered as an operator"); // 3. Queue Withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, staker, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots); // 4. Complete Queued Withdrawal as Tokens _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - - check_Withdrawal_AsTokens_State(staker, staker, withdrawals[i], strategies, shares, tokens, expectedTokens); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, staker, withdrawals[i], shares, expectedTokens); } } } diff --git a/src/test/integration/tests/FullySlashed_Operator.t.sol b/src/test/integration/tests/FullySlashed_Operator.t.sol index f0c2f17125..b69ea4030a 100644 --- a/src/test/integration/tests/FullySlashed_Operator.t.sol +++ b/src/test/integration/tests/FullySlashed_Operator.t.sol @@ -3,28 +3,13 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_FullySlashed_Operator is IntegrationCheckUtils { - AVS avs; - User staker; - User operator; - - OperatorSet operatorSet; - - AllocateParams allocateParams; - SlashingParams slashParams; - - IStrategy[] strategies; - IERC20[] tokens; - - uint[] initTokenBalances; - uint[] initDepositShares; - +contract Integration_FullySlashed_Operator is IntegrationChecks { function _init() internal virtual override { _configAssetTypes(HOLDS_LST); (staker, strategies, initTokenBalances) = _newRandomStaker(); - operator = _newRandomOperator_NoAssets(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); operatorSet = avs.createOperatorSet(strategies); tokens = _getUnderlyingTokens(strategies); @@ -47,38 +32,38 @@ contract Integration_FullySlashed_Operator is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); } - function testFuzz_register_allocate_fullSlash_deposit_delegate(uint24 r) public rand(r) { + function testFuzz_register_allocate_fullSlash_deposit_delegate(uint24) public { // 5) Staker deposits into strategies. staker.depositIntoEigenlayer(strategies, initTokenBalances); initDepositShares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, initDepositShares); // 6) Staker delegates to operator who is fully slashed, should fail. - vm.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); staker.delegateTo(operator); } - function testFuzz_register_allocate_fullSlash_delegate_deposit(uint24 r) public rand(r) { + function testFuzz_register_allocate_fullSlash_delegate_deposit(uint24) public { // 5) Staker delegates to operator who is fully slashed. staker.delegateTo(operator); // NOTE: We didn't use check_Delegation_State as it leads to division by zero. - assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should be delegated to operator"); + assertEq(address(operator), delegationManager().delegatedTo(address(staker)), "staker should be delegated to operator"); // 6) Staker deposits into strategies, should fail. - vm.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); staker.depositIntoEigenlayer(strategies, initTokenBalances); } - function testFuzz_register_allocate_fullSlash_delegate_redelegate_deposit(uint24 r) public rand(r) { + function testFuzz_register_allocate_fullSlash_delegate_redelegate_deposit(uint24) public { // 5) Staker delegates to operator who is fully slashed staker.delegateTo(operator); - User newOperator = _newRandomOperator_NoAssets(); + User newOperator = _newRandomOperator(); newOperator.registerForOperatorSet(operatorSet); // 6) Staker redelegates to new operator. Withdrawal[] memory withdrawals = staker.redelegate(newOperator); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Redelegate_State(staker, operator, newOperator, withdrawals, withdrawalRoots, strategies, new uint[](strategies.length)); for (uint i = 0; i < withdrawals.length; i++) { for (uint j = 0; j < withdrawals[i].strategies.length; j++) { diff --git a/src/test/integration/tests/HighDSF_Multiple_Deposits.t.sol b/src/test/integration/tests/HighDSF_Multiple_Deposits.t.sol index fe68972a41..e300dd8f54 100644 --- a/src/test/integration/tests/HighDSF_Multiple_Deposits.t.sol +++ b/src/test/integration/tests/HighDSF_Multiple_Deposits.t.sol @@ -4,22 +4,9 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; /// @notice Testing the rounding behavior when the DSF is high and there are multiple deposits -contract Integration_HighDSF_Multiple_Deposits is IntegrationCheckUtils { +contract Integration_HighDSF_Multiple_Deposits is IntegrationChecks { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - SlashingParams slashParams; - - User staker; - IStrategy[] strategies; - IERC20[] tokens; // underlying token for each strategy - uint[] initTokenBalances; - uint[] initDepositShares; - /** * Shared setup: * 1. create a new staker, operator, and avs @@ -31,8 +18,8 @@ contract Integration_HighDSF_Multiple_Deposits is IntegrationCheckUtils { // 1. create a new staker, operator, and avs _configAssetTypes(HOLDS_LST); (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); // 2. Create an operator set and register an operator, allocate all magnitude to the operator set operatorSet = avs.createOperatorSet(strategies); @@ -55,32 +42,35 @@ contract Integration_HighDSF_Multiple_Deposits is IntegrationCheckUtils { assertEq(slashingFactor, 1, "slashing factor should be 1"); } + function _dealAmounts(User user, IStrategy[] memory strategies, uint[] memory amounts) internal { + for (uint i = 0; i < amounts.length; i++) { + IStrategy strategy = strategies[i]; + if (strategy == BEACONCHAIN_ETH_STRAT) cheats.deal(address(user), amounts[i]); + else deal(address(strategy.underlyingToken()), address(user), amounts[i]); + } + } + /// @notice Test setup with a staker with slashingFactor of 1 (maxMagnitude = 1) /// with repeat deposits to increase the DSF. Limiting number of fuzzed runs to speed up tests since this /// for loops several times. - /// forge-config: default.fuzz.runs = 10 - function test_multiple_deposits(uint24 _r) public rand(_r) { + function test_multiple_deposits() public { // deposit initial assets into strategies staker.depositIntoEigenlayer(strategies, initTokenBalances); initDepositShares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, initDepositShares); // Repeat the deposit 50 times - // Gas intensive so we pause gas metering for this loop - cheats.pauseGasMetering(); for (uint i = 0; i < 50; i++) { _dealAmounts(staker, strategies, initTokenBalances); staker.depositIntoEigenlayer(strategies, initTokenBalances); - initDepositShares = _calculateExpectedShares(strategies, initTokenBalances); check_Deposit_State(staker, strategies, initDepositShares); } - cheats.resumeGasMetering(); // Check that the DSF is still bounded without overflow for (uint i = 0; i < strategies.length; i++) { - assertGe(delegationManager.depositScalingFactor(address(staker), strategies[i]), WAD, "DSF should be >= WAD"); + assertGe(delegationManager().depositScalingFactor(address(staker), strategies[i]), WAD, "DSF should be >= WAD"); // theoretical upper bound on DSF is 1e74 - assertLt(delegationManager.depositScalingFactor(address(staker), strategies[i]), 1e74, "DSF should be < 1e74"); + assertLt(delegationManager().depositScalingFactor(address(staker), strategies[i]), 1e74, "DSF should be < 1e74"); } } } diff --git a/src/test/integration/tests/SlashingWithdrawals.t.sol b/src/test/integration/tests/SlashingWithdrawals.t.sol index d5ce080389..1bf38cdbfc 100644 --- a/src/test/integration/tests/SlashingWithdrawals.t.sol +++ b/src/test/integration/tests/SlashingWithdrawals.t.sol @@ -3,20 +3,7 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; -contract Integration_ALMSlashBase is IntegrationCheckUtils { - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - SlashingParams slashParams; - - User staker; - IStrategy[] strategies; - IERC20[] tokens; // underlying token for each strategy - uint[] initTokenBalances; - uint[] initDepositShares; - +contract Integration_ALMSlashBase is IntegrationChecks { /// Shared setup: /// /// 1. Generate staker, operator, and AVS @@ -27,8 +14,8 @@ contract Integration_ALMSlashBase is IntegrationCheckUtils { /// NOTE: Steps 4 and 5 are done in random order, as these should not have an outcome on the test function _init() internal virtual override { (staker, strategies, initTokenBalances) = _newRandomStaker(); - operator = _newRandomOperator_NoAssets(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); tokens = _getUnderlyingTokens(strategies); // 1. Deposit Into Strategies @@ -91,7 +78,7 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { /// be checked via invariants. { // Create operatorB - operatorB = _newRandomOperator_NoAssets(); + operatorB = _newRandomOperator(); // Create stakerB, deposit, and delegate to operatorB (stakerB, initTokenBalancesB) = _newStaker(strategies); @@ -144,45 +131,45 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { } } - function testFuzz_undelegate_completeAsTokens(uint24 _r) public rand(_r) { - /// Undelegate from operatorA - uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); - Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); - - _rollBlocksForCompleteWithdrawals(withdrawals); - - /// Complete withdrawal as tokens - uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - staker.completeWithdrawalsAsTokens(withdrawals); - for (uint i = 0; i < withdrawals.length; i++) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens); - } - } - - function testFuzz_redelegate_completeAsTokens(uint24 _r) public rand(_r) { - /// Redelegate to operatorB - uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); - Withdrawal[] memory withdrawals = staker.redelegate(operatorB); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Redelegate_State(staker, operator, operatorB, withdrawals, roots, strategies, shares); - - _rollBlocksForCompleteWithdrawals(withdrawals); - - /// Complete withdrawal as tokens - uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - staker.completeWithdrawalsAsTokens(withdrawals); - for (uint i = 0; i < withdrawals.length; i++) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens); - } - } - - function testFuzz_queueFull_completeAsTokens(uint24 _r) public rand(_r) { + // function testFuzz_undelegate_completeAsTokens(uint24) public { + // /// Undelegate from operatorA + // uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); + // Withdrawal[] memory withdrawals = staker.undelegate(); + // withdrawalRoots = _getWithdrawalHashes(withdrawals); + // check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); + + // _rollBlocksForCompleteWithdrawals(withdrawals); + + // /// Complete withdrawal as tokens + // uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); + // staker.completeWithdrawalsAsTokens(withdrawals); + // for (uint i = 0; i < withdrawals.length; i++) { + // check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], shares, expectedTokens); + // } + // } + + // function testFuzz_redelegate_completeAsTokens(uint24) public { + // /// Redelegate to operatorB + // uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); + // Withdrawal[] memory withdrawals = staker.redelegate(operatorB); + // withdrawalRoots = _getWithdrawalHashes(withdrawals); + // check_Redelegate_State(staker, operator, operatorB, withdrawals, withdrawalRoots, strategies, shares); + + // _rollBlocksForCompleteWithdrawals(withdrawals); + + // /// Complete withdrawal as tokens + // uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); + // staker.completeWithdrawalsAsTokens(withdrawals); + // for (uint i = 0; i < withdrawals.length; i++) { + // check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], shares, expectedTokens); + // } + // } + + function testFuzz_queueFull_completeAsTokens(uint24) public { // Queue a withdrawal for all shares - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); _rollBlocksForCompleteWithdrawals(withdrawals); @@ -192,18 +179,16 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares, tokens, expectedTokens - ); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } } - function testFuzz_undelegate_completeAsShares(uint24 _r) public rand(_r) { + function testFuzz_undelegate_completeAsShares(uint24) public { // Undelegate from operatorA uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, shares); _rollBlocksForCompleteWithdrawals(withdrawals); @@ -214,12 +199,12 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { } } - function testFuzz_redelegate_completeAsShares(uint24 _r) public rand(_r) { + function testFuzz_redelegate_completeAsShares(uint24) public { // Redelegate to operatorB uint[] memory shares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.redelegate(operatorB); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); - check_Redelegate_State(staker, operator, operatorB, withdrawals, roots, strategies, shares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Redelegate_State(staker, operator, operatorB, withdrawals, withdrawalRoots, strategies, shares); _rollBlocksForCompleteWithdrawals(withdrawals); @@ -230,11 +215,11 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { } } - function testFuzz_queueFull_completeAsShares(uint24 _r) public rand(_r) { + function testFuzz_queueFull_completeAsShares(uint24) public { // Queue a withdrawal for all shares - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); _rollBlocksForCompleteWithdrawals(withdrawals); @@ -248,11 +233,11 @@ contract Integration_SlashThenWithdraw is Integration_ALMSlashBase { } contract Integration_QueueWithdrawalThenSlash is Integration_ALMSlashBase { - function testFuzz_queue_slash_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queue_slash_completeAsTokens(uint24) public { // 4. Queue withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // 5. Slash operator @@ -267,7 +252,7 @@ contract Integration_QueueWithdrawalThenSlash is Integration_ALMSlashBase { uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, expectedShares); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, expectedShares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], expectedShares, expectedTokens); } // Check Final State @@ -276,11 +261,11 @@ contract Integration_QueueWithdrawalThenSlash is Integration_ALMSlashBase { assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_queue_slash_completeAsShares(uint24 _r) public rand(_r) { + function testFuzz_queue_slash_completeAsShares(uint24) public { // 4. Queue withdrawal - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // 5. Slash operator @@ -306,7 +291,7 @@ contract Integration_QueueWithdrawalThenSlash is Integration_ALMSlashBase { } contract Integration_DeallocateThenSlash is Integration_ALMSlashBase { - function testFuzz_deallocate_slash_queue_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_deallocate_slash_queue_completeAsTokens(uint24) public { // 4. Deallocate all. AllocateParams memory deallocateParams = _genDeallocation_Full(operator, operatorSet); operator.modifyAllocations(deallocateParams); @@ -321,9 +306,9 @@ contract Integration_DeallocateThenSlash is Integration_ALMSlashBase { // TODO - staker variants? // 6. Queue withdrawals - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // 7. Complete withdrawal @@ -331,7 +316,7 @@ contract Integration_DeallocateThenSlash is Integration_ALMSlashBase { for (uint i = 0; i < withdrawals.length; ++i) { uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, initDepositShares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], initDepositShares, expectedTokens); } // Check Final State @@ -339,7 +324,7 @@ contract Integration_DeallocateThenSlash is Integration_ALMSlashBase { assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deregister_slash(uint24 _r) public rand(_r) { + function testFuzz_deregister_slash(uint24) public { // 4. Deregister. operator.deregisterFromOperatorSet(operatorSet); check_Deregistration_State_PendingAllocation(operator, operatorSet); diff --git a/src/test/integration/tests/Timing.t.sol b/src/test/integration/tests/Timing.t.sol index e4f61b90d3..55dd78d2f9 100644 --- a/src/test/integration/tests/Timing.t.sol +++ b/src/test/integration/tests/Timing.t.sol @@ -18,7 +18,7 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { /** * @notice Test that a slash works correctly just before a _partial_ withdrawal is completed */ - function testFuzz_queuePartialWithdrawal_slashBeforeWithdrawalDelay_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queuePartialWithdrawal_slashBeforeWithdrawalDelay_completeAsTokens(uint24) public { uint[] memory depositSharesToWithdraw = new uint[](initDepositShares.length); /// 0. Calculate partial withdrawal amounts for (uint i = 0; i < initDepositShares.length; ++i) { @@ -30,7 +30,7 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { /// 1. Queue withdrawal uint[] memory withdrawableShares = _calcWithdrawable(staker, strategies, depositSharesToWithdraw); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositSharesToWithdraw); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); // Validate correctly queued withdrawals check_QueuedWithdrawal_State( @@ -40,11 +40,11 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { /// 2. Move time forward to _just before_ withdrawal block // Expected behavior: Withdrawals are still pending and cannot be completed, but slashes can still be performed _rollBlocksForCompleteWithdrawals(withdrawals); - vm.roll(block.number - 1); + cheats.roll(block.number - 1); // Verify that the withdrawals are _still_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) <= slashableUntil); } @@ -56,11 +56,11 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { check_Base_Slashing_State(operator, allocateParams, slashingParams); /// 4. Move time forward to withdrawal block - vm.roll(block.number + 1); + cheats.roll(block.number + 1); // Verify that the withdrawals are _no longer_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) > slashableUntil); } @@ -72,24 +72,24 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals were completed correctly for (uint i = 0; i < withdrawals.length; ++i) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, withdrawableShares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, expectedTokens); } /// 6. Check final state // Assert that all strategies have some shares remaining - (IStrategy[] memory strats,) = delegationManager.getDepositedShares(address(staker)); + (IStrategy[] memory strats,) = delegationManager().getDepositedShares(address(staker)); assertEq(strats.length, strategies.length, "all strategies should have some shares remaining"); } /** * @notice Test that a slash works correctly just before a _total_ withdrawal is completed */ - function testFuzz_queueTotalWithdrawal_slashBeforeWithdrawalDelay_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queueTotalWithdrawal_slashBeforeWithdrawalDelay_completeAsTokens(uint24) public { /// 1. Queue withdrawal uint[] memory withdrawableShares = _calcWithdrawable(staker, strategies, initDepositShares); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); // Validate correctly queued withdrawals check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); @@ -97,11 +97,11 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { /// 2. Move time forward to _just before_ withdrawal block // Expected behavior: Withdrawals are still pending and cannot be completed, but slashes can still be performed _rollBlocksForCompleteWithdrawals(withdrawals); - vm.roll(block.number - 1); + cheats.roll(block.number - 1); // Verify that the withdrawals are _still_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) <= slashableUntil); } @@ -113,11 +113,11 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { check_Base_Slashing_State(operator, allocateParams, slashingParams); /// 4. Move time forward to withdrawal block - vm.roll(block.number + 1); + cheats.roll(block.number + 1); // Verify that the withdrawals are _no longer_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) > slashableUntil); } @@ -129,20 +129,20 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals were completed correctly for (uint i = 0; i < withdrawals.length; ++i) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, withdrawableShares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, expectedTokens); } /// 6. Check final state // Assert that all strategies have some shares remaining - (IStrategy[] memory strats,) = delegationManager.getDepositedShares(address(staker)); + (IStrategy[] memory strats,) = delegationManager().getDepositedShares(address(staker)); assertEq(strats.length, 0, "all strategies should have no shares remaining"); } /** * @notice Test that a staker can still complete a partial withdrawal even after a slash has been performed */ - function testFuzz_queuePartialWithdrawal_slashAfterWithdrawalDelay_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queuePartialWithdrawal_slashAfterWithdrawalDelay_completeAsTokens(uint24) public { uint[] memory depositSharesToWithdraw = new uint[](initDepositShares.length); /// 0. Calculate partial withdrawal amounts for (uint i = 0; i < initDepositShares.length; ++i) { @@ -154,7 +154,7 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { /// 1. Queue withdrawal uint[] memory withdrawableShares = _calcWithdrawable(staker, strategies, depositSharesToWithdraw); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositSharesToWithdraw); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); // Validate correctly queued withdrawals check_QueuedWithdrawal_State( @@ -167,7 +167,7 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals are _no longer_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) > slashableUntil); } @@ -185,24 +185,24 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals were completed correctly for (uint i = 0; i < withdrawals.length; ++i) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, withdrawableShares, tokens, expectedTokens); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, expectedTokens); } /// 5. Check final state // Assert that all strategies have some shares remaining - (IStrategy[] memory strats,) = delegationManager.getDepositedShares(address(staker)); + (IStrategy[] memory strats,) = delegationManager().getDepositedShares(address(staker)); assertEq(strats.length, strategies.length, "all strategies should have some shares remaining"); } /** * @notice Test that a staker is unaffected by a slash after the withdrawal delay has passed */ - function testFuzz_queueTotalWithdrawal_slashAfterWithdrawalDelay_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queueTotalWithdrawal_slashAfterWithdrawalDelay_completeAsTokens(uint24) public { /// 1. Queue withdrawal uint[] memory withdrawableShares = _calcWithdrawable(staker, strategies, initDepositShares); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); // Validate correctly queued withdrawals check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); @@ -213,7 +213,7 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals are _no longer_ slashable for (uint i = 0; i < withdrawals.length; ++i) { - uint32 slashableUntil = withdrawals[i].startBlock + delegationManager.minWithdrawalDelayBlocks(); + uint32 slashableUntil = withdrawals[i].startBlock + delegationManager().minWithdrawalDelayBlocks(); assert(uint32(block.number) > slashableUntil); } @@ -229,13 +229,13 @@ contract Integration_WithdrawalTiming is Integration_ALMSlashBase { // Verify that the withdrawals were completed correctly for (uint i = 0; i < withdrawals.length; ++i) { - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, withdrawableShares, tokens, initTokenBalances); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, initTokenBalances); } /// 5. Check final state // Assert that all strategies have some shares remaining - (IStrategy[] memory strats,) = delegationManager.getDepositedShares(address(staker)); + (IStrategy[] memory strats,) = delegationManager().getDepositedShares(address(staker)); assertEq(strats.length, 0, "all strategies should have no shares remaining"); } } @@ -250,7 +250,7 @@ contract Integration_OperatorDeallocationTiming is Integration_ALMSlashBase { /// OPERATOR DEALLOCATION TIMING TESTS /// ////////////////////////////////////////// - function testFuzz_deallocateFully_slashBeforeDelay(uint24 _r) public rand(_r) { + function testFuzz_deallocateFully_slashBeforeDelay(uint24) public { /// 1. Deallocate AllocateParams memory deallocateParams = _genDeallocation_Full(operator, operatorSet); operator.modifyAllocations(deallocateParams); @@ -271,7 +271,7 @@ contract Integration_OperatorDeallocationTiming is Integration_ALMSlashBase { check_Base_Slashing_State(operator, allocateParams, slashParams); } - function testFuzz_deallocateFully_slashAfterDelay(uint24 _r) public rand(_r) { + function testFuzz_deallocateFully_slashAfterDelay(uint24) public { /// 1. Deallocate AllocateParams memory deallocateParams = _genDeallocation_Full(operator, operatorSet); operator.modifyAllocations(deallocateParams); @@ -300,7 +300,7 @@ contract Integration_OperatorDeregistrationTiming is Integration_ALMSlashBase { /// OPERATOR DEREGISTRATION TIMING TESTS /// //////////////////////////////////////////// - function testFuzz_deregister_slashBeforeDelay(uint24 _r) public rand(_r) { + function testFuzz_deregister_slashBeforeDelay(uint24) public { /// 1. Deregister operator.deregisterFromOperatorSet(operatorSet); // Validate the deregistration @@ -319,7 +319,7 @@ contract Integration_OperatorDeregistrationTiming is Integration_ALMSlashBase { check_Base_Slashing_State(operator, allocateParams, slashParams); } - function testFuzz_deregister_slashAfterDelay(uint24 _r) public rand(_r) { + function testFuzz_deregister_slashAfterDelay(uint24) public { /// 1. Deregister operator.deregisterFromOperatorSet(operatorSet); // Validate the deregistration @@ -333,31 +333,18 @@ contract Integration_OperatorDeregistrationTiming is Integration_ALMSlashBase { /// 3. Slash operator // Note: Unlike the deallocation case, the operator is no longer registered, so a slash will revert entirely. slashParams = _genSlashing_Rand(operator, operatorSet); - vm.expectRevert(IAllocationManagerErrors.OperatorNotSlashable.selector); + cheats.expectRevert(IAllocationManagerErrors.OperatorNotSlashable.selector); avs.slashOperator(slashParams); } } /** * @notice These tests check for specific allocation correctness around timing - * @dev These tests inherit from IntegrationCheckUtils instead of Integration_ALMSlashBase because they require a + * @dev These tests inherit from IntegrationChecks instead of Integration_ALMSlashBase because they require a * different initialization -- specifically, the allocation must be performed within the tests. As such, there are no * assumptions and many state variables are declared below. */ -contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { - AVS avs; - User operator; - OperatorSet operatorSet; - - AllocateParams allocateParams; - SlashingParams slashParams; - - User staker; - IStrategy[] strategies; - IERC20[] tokens; - uint[] initTokenBalances; - uint[] initDepositShares; - +contract Integration_OperatorAllocationTiming is IntegrationChecks { //////////////////////////////////////// /// OPERATOR ALLOCATION TIMING TESTS /// //////////////////////////////////////// @@ -366,8 +353,8 @@ contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { /// 0. Instantiate relevant objects _configAssetTypes(HOLDS_LST); (staker, strategies, initTokenBalances) = _newRandomStaker(); - operator = _newRandomOperator_NoAssets(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); tokens = _getUnderlyingTokens(strategies); /// 1. Deposit into strategies @@ -384,10 +371,10 @@ contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { /// 3. Create an operator set and register an operator. operatorSet = avs.createOperatorSet(strategies); // Validate that the operator set was correctly created - assertTrue(allocationManager.isOperatorSet(operatorSet)); + assertTrue(allocationManager().isOperatorSet(operatorSet)); } - function testFuzz_register_allocate_slashBeforeDelay(uint24 _r) public rand(_r) { + function testFuzz_register_allocate_slashBeforeDelay(uint24) public { /// 1. Create and register operator operator.registerForOperatorSet(operatorSet); // Validate registration @@ -415,7 +402,7 @@ contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, emptySlashParams); } - function testFuzz_allocate_register_slashBeforeDelay(uint24 _r) public rand(_r) { + function testFuzz_allocate_register_slashBeforeDelay(uint24) public { /// 1. Allocate allocateParams = _genAllocation_AllAvailable(operator, operatorSet); operator.modifyAllocations(allocateParams); @@ -443,7 +430,7 @@ contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, emptySlashParams); } - function testFuzz_register_allocate_slashAfterDelay(uint24 _r) public rand(_r) { + function testFuzz_register_allocate_slashAfterDelay(uint24) public { /// 1. Create and register operator operator.registerForOperatorSet(operatorSet); // Validate the registration @@ -465,7 +452,7 @@ contract Integration_OperatorAllocationTiming is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); } - function testFuzz_allocate_register_slashAfterDelay(uint24 _r) public rand(_r) { + function testFuzz_allocate_register_slashAfterDelay(uint24) public { /// 1. Allocate allocateParams = _genAllocation_AllAvailable(operator, operatorSet); operator.modifyAllocations(allocateParams); diff --git a/src/test/integration/tests/Upgrade_Setup.t.sol b/src/test/integration/tests/Upgrade_Setup.t.sol deleted file mode 100644 index 3823c570dc..0000000000 --- a/src/test/integration/tests/Upgrade_Setup.t.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/test/integration/IntegrationChecks.t.sol"; - -contract IntegrationMainnetFork_UpgradeSetup is IntegrationCheckUtils { - // /// @notice Test upgrade setup is correct - // /// forge-config: default.fuzz.runs = 1 - // function test_mainnet_upgrade_setup(uint24 _random) public { - // _configRand({ - // _randomSeed: _random, - // _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - // _userTypes: DEFAULT | ALT_METHODS - // }); - - // // 1. Check proper state pre-upgrade - // _verifyContractPointers(); - // _verifyImplementations(); - // _verifyContractsInitialized(false); - // _verifyInitializationParams(); - - // // 2. Upgrade mainnet contracts - // _upgradeEigenLayerContracts(); - // _parseInitialDeploymentParams("script/configs/mainnet/M2_mainnet_upgrade.config.json"); - - // // 2. Verify upgrade setup - // _verifyContractPointers(); - // _verifyImplementations(); - // _verifyContractsInitialized(false); - // _verifyInitializationParams(); - // } - - // /// @notice Test upgrade setup is correct - // /// forge-config: default.fuzz.runs = 1 - // function test_holesky_upgrade_setup(uint24 _random) public { - // _configRand({ - // _randomSeed: _random, - // _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - // _userTypes: DEFAULT | ALT_METHODS, - // _forkTypes: HOLESKY - // }); - - // // // 1. Check proper state pre-upgrade - // // _verifyContractPointers(); - // // _verifyImplementations(); - // // _verifyContractsInitialized(true); - // // _verifyInitializationParams(); - - // // 2. Upgrade holesky contracts - // _upgradeEigenLayerContracts(); - // _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); - - // // 3. Verify upgrade setup - // _verifyContractPointers(); - // _verifyImplementations(); - // _verifyContractsInitialized(true); - // _verifyInitializationParams(); - // } - - /// @notice Ensure contracts point at each other correctly via constructors - /// override to remove ethPOSDeposit contract check - function _verifyContractPointers() internal view virtual override { - // AVSDirectory - require(avsDirectory.delegation() == delegationManager, "avsDirectory: delegationManager address not set correctly"); - // DelegationManager - require(delegationManager.strategyManager() == strategyManager, "delegationManager: strategyManager address not set correctly"); - require(delegationManager.eigenPodManager() == eigenPodManager, "delegationManager: eigenPodManager address not set correctly"); - // StrategyManager - require(strategyManager.delegation() == delegationManager, "strategyManager: delegationManager address not set correctly"); - // EPM - require(eigenPodManager.eigenPodBeacon() == eigenPodBeacon, "eigenPodManager: eigenPodBeacon contract address not set correctly"); - require( - eigenPodManager.delegationManager() == delegationManager, - "eigenPodManager: delegationManager contract address not set correctly" - ); - } -} diff --git a/src/test/integration/tests/DualSlashing.t.sol b/src/test/integration/tests/eigenpod/DualSlashing.t.sol similarity index 91% rename from src/test/integration/tests/DualSlashing.t.sol rename to src/test/integration/tests/eigenpod/DualSlashing.t.sol index 29d065b887..5af9529896 100644 --- a/src/test/integration/tests/DualSlashing.t.sol +++ b/src/test/integration/tests/eigenpod/DualSlashing.t.sol @@ -1,32 +1,21 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; /// @notice Tests where we slash native eth on the Beacon Chain and by an OperatorSet -contract Integration_DualSlashing_Base is IntegrationCheckUtils { +contract Integration_EigenPod_DualSlashing_Base is EigenPodTest { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - - User staker; - uint64 beaconBalanceGwei; - uint40[] validators; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - function _init() internal virtual override { + super._init(); + _configAssetTypes(HOLDS_ETH); // Create staker, operator, and avs (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); // 1. Deposit into strategies (validators, beaconBalanceGwei,) = staker.startValidators(); @@ -55,8 +44,8 @@ contract Integration_DualSlashing_Base is IntegrationCheckUtils { } } -contract Integration_DualSlashing_BeaconChainFirst is Integration_DualSlashing_Base { - function testFuzz_bcSlash_checkpoint_avsSlash(uint24 _random) public rand(_random) { +contract Integration_DualSlashing_BeaconChainFirst is Integration_EigenPod_DualSlashing_Base { + function testFuzz_bcSlash_checkpoint_avsSlash(uint24) public { // 6. Slash staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -81,11 +70,9 @@ contract Integration_DualSlashing_BeaconChainFirst is Integration_DualSlashing_B } } -contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { +contract Integration_DualSlashing_AVSFirst is Integration_EigenPod_DualSlashing_Base { using ArrayLib for *; - SlashingParams slashingParams; - function _init() internal virtual override { super._init(); @@ -101,7 +88,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { } /// @dev Validates behavior of "restaking", ie. that the funds can be slashed twice - function testFuzz_avsSlash_bcSlash_checkpoint(uint24 _random) public rand(_random) { + function testFuzz_avsSlash_bcSlash_checkpoint(uint24) public { // 7. Slash Staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -117,7 +104,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { /// @notice Because the validator is proven prior to the BC slash, the system applies the new balance /// to the BC and AVS slash combined - function testFuzz_avsSlash_verifyValidator_bcSlash_checkpoint(uint24 _random) public rand(_random) { + function testFuzz_avsSlash_verifyValidator_bcSlash_checkpoint(uint24) public { // 7. Verify Validator cheats.deal(address(staker), 32 ether); (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei,) = staker.startValidators(); @@ -146,7 +133,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { } /// @dev Same as above, but validator is proven after BC slash (this ordering doesn't matter to EL) - function testFuzz_avsSlash_bcSlash_verifyValidator_checkpoint(uint24 _random) public rand(_random) { + function testFuzz_avsSlash_bcSlash_verifyValidator_checkpoint(uint24) public { // 7. Slash Staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -175,7 +162,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { } /// @notice The validator proven should not be affected by the BC or AVS slashes - function testFuzz_avsSlash_bcSlash_checkpoint_verifyValidator(uint24 _rand) public rand(_rand) { + function testFuzz_avsSlash_bcSlash_checkpoint_verifyValidator(uint24) public { // 7. Slash Staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -205,7 +192,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { /// @notice The balance increase results in the pods not processing the beacon slash as a slash, given /// that the checkpoint had a positive delta - function testFuzz_avsSlash_bcSlash_balanceIncrease_checkpoint(uint24 _rand) public rand(_rand) { + function testFuzz_avsSlash_bcSlash_balanceIncrease_checkpoint(uint24) public { // 7. Slash Staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -226,7 +213,7 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { } /// @notice The balance increase occurs after the slashings are processed, so it should be unaffected by the slashings - function testFuzz_avsSlash_bcSlash_checkpoint_balanceIncrease(uint24 _rand) public rand(_rand) { + function testFuzz_avsSlash_bcSlash_checkpoint_balanceIncrease(uint24) public { // 7. Slash Staker on BC uint64 slashedAmountGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoRewards(); @@ -254,15 +241,11 @@ contract Integration_DualSlashing_AVSFirst is Integration_DualSlashing_Base { } } -contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { +contract Integration_DualSlashing_FullSlashes is Integration_EigenPod_DualSlashing_Base { using ArrayLib for *; using SlashingLib for *; using Math for uint; - SlashingParams slashingParams; - uint64 slashedAmountGwei; - IERC20[] tokens; - function _init() internal virtual override { super._init(); tokens = _getUnderlyingTokens(strategies); @@ -300,7 +283,7 @@ contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { } } - function testFuzz_fullDualSlash_undelegate_verifyValidator_checkpoint_exitEverything(uint24 _random) public rand(_random) { + function testFuzz_fullDualSlash_undelegate_verifyValidator_checkpoint_exitEverything(uint24) public { // 8. Undelegate staker, so we don't revert when verifying a validator Withdrawal[] memory withdrawals = staker.undelegate(); bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); @@ -337,9 +320,7 @@ contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, uint(0).toArrayU256(), tokens, uint(0).toArrayU256() - ); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], uint(0).toArrayU256(), uint(0).toArrayU256()); } // 13. Queue withdrawal for all remaining shares @@ -354,9 +335,7 @@ contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { uint[] memory expectedTokens = _calculateExpectedTokens(strategies, withdrawableShares2); for (uint i = 0; i < withdrawals2.length; ++i) { staker.completeWithdrawalAsTokens(withdrawals2[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals2[i], withdrawals2[i].strategies, withdrawableShares2, tokens, expectedTokens - ); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals2[i], withdrawableShares2, expectedTokens); } // Sanity check that balance locked in pod and depositShares are 0 @@ -364,7 +343,7 @@ contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { assertEq(address(staker.pod()).balance, depositShares[0] - expectedTokens[0], "staker withdrew more than expected"); } - function testFuzz_fullDualSlash_redeposit_revertCheckpoint(uint24 _random) public rand(_random) { + function testFuzz_fullDualSlash_redeposit_revertCheckpoint(uint24) public { // 8. Deposit ETH into pod, doesn't matter how large it is, we'll still revert uint ethToDeposit = 1000 ether; cheats.deal(address(staker), ethToDeposit); @@ -381,7 +360,7 @@ contract Integration_DualSlashing_FullSlashes is Integration_DualSlashing_Base { staker.completeCheckpoint(); } - function testFuzz_fullDualSlash_checkpoint(uint24 _random) public rand(_random) { + function testFuzz_fullDualSlash_checkpoint(uint24) public { // 8. Checkpoint staker.startCheckpoint(); check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedAmountGwei); diff --git a/src/test/integration/tests/eigenpod/EigenPod.t.sol b/src/test/integration/tests/eigenpod/EigenPod.t.sol new file mode 100644 index 0000000000..3618f3a64c --- /dev/null +++ b/src/test/integration/tests/eigenpod/EigenPod.t.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/test/integration/IntegrationChecks.t.sol"; + +contract EigenPodTest is IntegrationChecks { + function _init() internal virtual override { + if (!forkConfig.supportEigenPodTests) cheats.skip(true); + } +} diff --git a/src/test/integration/tests/eigenpod/FullySlashed_EigenPod.t.sol b/src/test/integration/tests/eigenpod/FullySlashed_EigenPod.t.sol index a163ce077d..ac251f2d87 100644 --- a/src/test/integration/tests/eigenpod/FullySlashed_EigenPod.t.sol +++ b/src/test/integration/tests/eigenpod/FullySlashed_EigenPod.t.sol @@ -1,22 +1,22 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; -contract Integration_FullySlashedEigenpod_Base is IntegrationCheckUtils { +contract Integration_EigenPod_FullySlashedEigenpod_Base is EigenPodTest { using ArrayLib for *; - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - uint64 slashedGwei; - uint40[] validators; - function _init() internal virtual override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initTokenBalances) = _newRandomStaker(); - cheats.assume(initTokenBalances[0] >= 64 ether); + + // Ensure the staker has at least 64 ETH to deposit. + if (initTokenBalances[0] < 64 ether) { + initTokenBalances[0] = 64 ether; + cheats.deal(address(staker), 64 ether); + } // Deposit staker uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); @@ -31,7 +31,7 @@ contract Integration_FullySlashedEigenpod_Base is IntegrationCheckUtils { } } -contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlashedEigenpod_Base { +contract Integration_EigenPod_FullySlashedEigenpod_Checkpointed is Integration_EigenPod_FullySlashedEigenpod_Base { function _init() internal override { super._init(); @@ -42,15 +42,15 @@ contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlash check_CompleteCheckpoint_FullySlashed_State(staker, validators, slashedGwei); } - function testFuzz_fullSlash_Delegate(uint24 _rand) public rand(_rand) { - (User operator,,) = _newRandomOperator(); + function testFuzz_fullSlash_Delegate(uint24) public { + operator = _newRandomOperator(); // Delegate to an operator - should succeed given that delegation only checks the operator's slashing factor staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, initDepositShares); } - function testFuzz_fullSlash_Revert_Redeposit(uint24 _rand) public rand(_rand) { + function testFuzz_fullSlash_Revert_Redeposit(uint24) public { // Start a new validator & verify withdrawal credentials cheats.deal(address(staker), 32 ether); (uint40[] memory newValidators,,) = staker.startValidators(); @@ -61,7 +61,7 @@ contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlash staker.verifyWithdrawalCredentials(newValidators); } - function testFuzz_fullSlash_registerStakerAsOperator_Revert_Redeposit(uint24 _rand) public rand(_rand) { + function testFuzz_fullSlash_registerStakerAsOperator_Revert_Redeposit(uint24) public { // Register staker as operator staker.registerAsOperator(); @@ -75,7 +75,7 @@ contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlash staker.verifyWithdrawalCredentials(newValidators); } - function testFuzz_fullSlash_registerStakerAsOperator_delegate_undelegate_completeAsShares(uint24 _rand) public rand(_rand) { + function testFuzz_fullSlash_registerStakerAsOperator_delegate_undelegate_completeAsShares(uint24) public { // Register staker as operator staker.registerAsOperator(); User operator = User(payable(address(staker))); @@ -92,7 +92,7 @@ contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlash // Register as operator and undelegate - the equivalent of redelegating to yourself Withdrawal[] memory withdrawals = staker2.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker2, operator, withdrawals, withdrawalRoots, strategies2, shares); // Complete withdrawals as shares @@ -104,9 +104,9 @@ contract Integration_FullySlashedEigenpod_Checkpointed is Integration_FullySlash } } -contract Integration_FullySlashedEigenpod_NotCheckpointed is Integration_FullySlashedEigenpod_Base { +contract Integration_EigenPod_FullySlashedEigenpod_NotCheckpointed is Integration_EigenPod_FullySlashedEigenpod_Base { /// @dev Adding funds prior to checkpointing allows the pod to not be "bricked" - function testFuzz_proveValidator_checkpoint_queue_completeAsTokens(uint24 _rand) public rand(_rand) { + function testFuzz_proveValidator_checkpoint_queue_completeAsTokens(uint24) public { // Deal ETH to staker uint amount = 32 ether; cheats.deal(address(staker), amount); @@ -128,7 +128,7 @@ contract Integration_FullySlashedEigenpod_NotCheckpointed is Integration_FullySl uint[] memory depositShares = _getStakerDepositShares(staker, strategies); uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State( staker, User(payable(address(0))), strategies, depositShares, withdrawableShares, withdrawals, withdrawalRoots ); @@ -139,13 +139,11 @@ contract Integration_FullySlashedEigenpod_NotCheckpointed is Integration_FullySl IERC20[] memory tokens = _getUnderlyingTokens(withdrawals[i].strategies); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, User(payable(address(0))), withdrawals[i], withdrawals[i].strategies, withdrawableShares, tokens, expectedTokens - ); + check_Withdrawal_AsTokens_State(staker, User(payable(address(0))), withdrawals[i], withdrawableShares, expectedTokens); } } - function testFuzz_depositMinimumAmount_checkpoint(uint24 _rand) public rand(_rand) { + function testFuzz_depositMinimumAmount_checkpoint(uint24) public { // Deal ETH to staker, minimum amount to be checkpointed uint64 podBalanceGwei = 1; uint amountToDeal = 1 * GWEI_TO_WEI; diff --git a/src/test/integration/tests/eigenpod/Register_Allocate_Slash_VerifyWC_.t.sol b/src/test/integration/tests/eigenpod/Register_Allocate_Slash_VerifyWC_.t.sol index f5a30769e2..d3ddd89a48 100644 --- a/src/test/integration/tests/eigenpod/Register_Allocate_Slash_VerifyWC_.t.sol +++ b/src/test/integration/tests/eigenpod/Register_Allocate_Slash_VerifyWC_.t.sol @@ -1,27 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/mocks/BeaconChainMock.t.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; /// @notice Testing the rounding behavior when operator magnitude is initially 1 -contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { +contract Integration_EigenPod_Register_Allocate_Slash_VerifyWC is EigenPodTest { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - - User operator; - IAllocationManagerTypes.AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - // uint[] initTokenBalances; - uint[] initDepositShares; - uint40[] validators; - uint64 beaconBalanceGwei; - uint64 slashedGwei; - /** * 1. Create an operatorSet and register the operator allocating all magnitude * 2. slash operator to 1 magnitude remaining @@ -29,12 +15,18 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * 4. deposit (verify withdrawal credentials) */ function _init() internal override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initDepositShares) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); - cheats.assume(initDepositShares[0] >= 64 ether); + // Ensure the staker has at least 64 ETH to deposit. + if (initDepositShares[0] < 64 ether) { + initDepositShares[0] = 64 ether; + cheats.deal(address(staker), 64 ether); + } // 1. Create an operator set and register an operator operatorSet = avs.createOperatorSet(strategies); @@ -53,7 +45,7 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { // 3. Delegate to an operator staker.delegateTo(operator); - // delegate staker without any depositShares in beaconChainETHStrategy yet + // delegate staker without any depositShares in BEACONCHAIN_ETH_STRAT yet IStrategy[] memory emptyStrategies; uint[] memory emptyTokenBalances; check_Delegation_State(staker, operator, emptyStrategies, emptyTokenBalances); @@ -74,12 +66,11 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * and calculating a non-WAD BCSF, their slashing factor should be rounded down to 0. Resulting in * the staker having 0 withdrawable shares. */ - function test_slashBC_startCompleteCP_queue_complete(uint24 _r) public rand(_r) { + function testFuzz_slashBC_startCompleteCP_queue_complete(uint24) public { // 4. slash validators on beacon chain (start/complete checkpoint) uint40[] memory slashedValidators = _choose(validators); - slashedGwei = beaconChain.slashValidators(slashedValidators, BeaconChainMock.SlashType.Minor); + slashedGwei = beaconChain.slashValidators(slashedValidators, BeaconChainMock.SlashType.Half); // ensure non zero amount slashed gwei so that we can test rounding down behavior - cheats.assume(slashedGwei > 0); beaconChain.advanceEpoch_NoWithdrawNoRewards(); // start and complete checkpoint staker.startCheckpoint(); @@ -89,10 +80,9 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { check_CompleteCheckPoint_WithSlashing_LowMagnitude_State(staker, slashedGwei); // 5. queue withdrawal - (, uint[] memory withdrawShares) = _randWithdrawal(strategies, initDepositShares); - + uint[] memory withdrawShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, withdrawShares); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State({ staker: staker, operator: operator, @@ -100,16 +90,16 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { depositShares: withdrawShares, // amount of deposit shares to withdraw withdrawableShares: 0.toArrayU256(), // amount of withdrawable shares is 0 due to slashing factor being 0 withdrawals: withdrawals, - withdrawalRoots: roots + withdrawalRoots: withdrawalRoots }); // Operator's maxMagnitude is 1 and staker was slashed to non-WAD BCSF. Therefore // staker should have been rounded down to 0 - uint slashingFactor = staker.getSlashingFactor(beaconChainETHStrategy); + uint slashingFactor = staker.getSlashingFactor(BEACONCHAIN_ETH_STRAT); assertEq(slashingFactor, 0, "slashing factor should be rounded down to 0"); // 6. complete withdrawal - // only strategy is beaconChainETHStrategy + // only strategy is BEACONCHAIN_ETH_STRAT _rollBlocksForCompleteWithdrawals(withdrawals); staker.completeWithdrawalAsShares(withdrawals[0]); @@ -124,7 +114,7 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * This is testing when an operator is fully slashed with 0 magnitude, the staker can still undelegate * and "redeposit" to Eigenlayer. */ - function test_slash_undelegate_redeposit(uint24 _r) public rand(_r) { + function testFuzz_slash_undelegate_redeposit(uint24) public { // 4. AVS slashes operator again to 0 magnitude and fully slashed SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet); slashParams.wadsToSlash[0] = WAD; @@ -132,9 +122,9 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); // 5. undelegate results in 0 delegated shares removed since operator has 0 magnitude and staker is fully slashed too - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); @@ -166,7 +156,7 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * This is testing when an operator is fully slashed with 0 magnitude, the staker can still undelegate, * complete withdrawals as shares(0 shares though), and redeposit to Eigenlayer. */ - function test_slash_undelegate_completeAsShares_startCompleteCP(uint24 _r) public rand(_r) { + function testFuzz_slash_undelegate_completeAsShares_startCompleteCP(uint24) public { // 4. AVS slashes operator again to 0 magnitude and fully slashed SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet); slashParams.wadsToSlash[0] = WAD; @@ -174,9 +164,9 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); // 5. undelegate results in 0 delegated shares removed since operator has 0 magnitude and staker is fully slashed too - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 6. complete withdrawals as shares(although amount 0 from fully slashed operator) @@ -203,7 +193,7 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * This is testing when an operator is fully slashed with 0 magnitude, the staker can still undelegate, * complete withdrawals as tokens(0 tokens though), and redeposit to Eigenlayer. */ - function test_slash_undelegate_completeAsTokens_verifyWC(uint24 _r) public rand(_r) { + function testFuzz_slash_undelegate_completeAsTokens_verifyWC(uint24) public { // 4. AVS slashes operator again to 0 magnitude and fully slashed SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet); slashParams.wadsToSlash[0] = WAD; @@ -211,16 +201,16 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); // 5. undelegate results in 0 delegated shares removed since operator has 0 magnitude and staker is fully slashed too - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 6. complete withdrawals as tokens(although amount 0 from fully slashed operator) // This also exits validators on the beacon chain _rollBlocksForCompleteWithdrawals(withdrawals); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[0]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[0], strategies, 0.toArrayU256(), tokens, 0.toArrayU256()); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[0], 0.toArrayU256(), 0.toArrayU256()); // 7. deposit/verify withdrawal credentials // randomly startup 1-10 validators @@ -237,11 +227,11 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { * This is testing a staker can queue a withdrawal and complete as tokens even * though the operator has 1 maxMagnitude */ - function test_queueAllShares_completeAsTokens(uint24 _r) public rand(_r) { + function testFuzz_queueAllShares_completeAsTokens(uint24) public { // 4. queue withdrawal // ( , uint[] memory withdrawShares) = _randWithdrawal(strategies, initDepositShares); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory roots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State({ staker: staker, operator: operator, @@ -249,7 +239,7 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { depositShares: initDepositShares, withdrawableShares: initDepositShares, withdrawals: withdrawals, - withdrawalRoots: roots + withdrawalRoots: withdrawalRoots }); // 5. complete withdrawal as tokens @@ -258,6 +248,6 @@ contract Integration_Register_Allocate_Slash_VerifyWC is IntegrationCheckUtils { // - starts/completes checkpoint _rollBlocksForCompleteWithdrawals(withdrawals); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[0]); - check_Withdrawal_AsTokens_State(staker, operator, withdrawals[0], strategies, initDepositShares, tokens, initDepositShares); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[0], initDepositShares, initDepositShares); } } diff --git a/src/test/integration/tests/eigenpod/SlashBC_OneBCSF.t.sol b/src/test/integration/tests/eigenpod/SlashBC_OneBCSF.t.sol index 724b3ee198..a76ac58819 100644 --- a/src/test/integration/tests/eigenpod/SlashBC_OneBCSF.t.sol +++ b/src/test/integration/tests/eigenpod/SlashBC_OneBCSF.t.sol @@ -1,26 +1,14 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/mocks/BeaconChainMock.t.sol"; import "src/test/harnesses/EigenPodManagerWrapper.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; /// @notice Testing the rounding behavior when beacon chain slashing factor is initially 1 -contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { +contract Integration_EigenPod_SlashBC_OneBCSF is EigenPodTest { using ArrayLib for *; - - AVS avs; - OperatorSet operatorSet; - - User operator; - IAllocationManagerTypes.AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - uint[] initDepositShares; - uint40[] validators; - uint64 beaconBalanceGwei; - uint64 slashedGwei; + using ConfigParser for *; /** * Shared setup: @@ -32,22 +20,28 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { * 3. start validators and verify withdrawal credentials */ function _init() internal override { + super._init(); + // 1. etch a new implementation to set staker's beaconChainSlashingFactor to 1 EigenPodManagerWrapper eigenPodManagerWrapper = - new EigenPodManagerWrapper(DEPOSIT_CONTRACT, eigenPodBeacon, delegationManager, eigenLayerPauserReg, "v9.9.9"); - address targetAddr = address(eigenPodManagerImplementation); + new EigenPodManagerWrapper(DEPOSIT_CONTRACT, eigenPodBeacon(), delegationManager(), pauserRegistry(), "v9.9.9"); + address targetAddr = eigenPodManagerImpl(); cheats.etch(targetAddr, address(eigenPodManagerWrapper).code); // 2. create a new staker, operator, and avs _configAssetTypes(HOLDS_ETH); (staker, strategies, initDepositShares) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); - cheats.assume(initDepositShares[0] >= 64 ether); + // Ensure the staker has at least 64 ETH to deposit. + if (initDepositShares[0] < 64 ether) { + initDepositShares[0] = 64 ether; + cheats.deal(address(staker), 64 ether); + } - EigenPodManagerWrapper(address(eigenPodManager)).setBeaconChainSlashingFactor(address(staker), 1); - assertEq(eigenPodManager.beaconChainSlashingFactor(address(staker)), 1); + EigenPodManagerWrapper(address(eigenPodManager())).setBeaconChainSlashingFactor(address(staker), 1); + assertEq(eigenPodManager().beaconChainSlashingFactor(address(staker)), 1); // 3. start validators and verify withdrawal credentials (validators, beaconBalanceGwei,) = staker.startValidators(); @@ -57,7 +51,7 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { } /// @notice Test that a staker can still verify WC, start/complete CP even if the operator has 1 magnitude remaining - function test_verifyWC_startCompleteCP(uint24 _r) public rand(_r) { + function testFuzz_verifyWC_startCompleteCP(uint24) public { // 4. start validators and verify withdrawal credentials (validators, beaconBalanceGwei,) = staker.startValidators(uint8(_randUint(1, 10))); beaconChain.advanceEpoch_NoRewards(); @@ -73,14 +67,15 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { check_CompleteCheckpoint_State(staker); // 6. Assert BCSF is still 1 - assertEq(eigenPodManager.beaconChainSlashingFactor(address(staker)), 1); + assertEq(eigenPodManager().beaconChainSlashingFactor(address(staker)), 1); } /// @notice Test that a staker is slashed to 0 BCSF from a minor slash and that they can't deposit more shares /// from their EigenPod (either through verifyWC or start/complete CP) - function test_slashFullyBC_revert_deposit(uint24 _r) public rand(_r) { + function testFuzz_slashFullyBC_revert_deposit(uint24) public { // 4. slash validators on beacon chain (start/complete checkpoint) uint40[] memory slashedValidators = _choose(validators); + slashedGwei = beaconChain.slashValidators(slashedValidators, BeaconChainMock.SlashType.Minor); beaconChain.advanceEpoch_NoWithdrawNoRewards(); @@ -88,7 +83,7 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { staker.completeCheckpoint(); check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State(staker, slashedGwei); // BCSF should be 0 now - assertEq(eigenPodManager.beaconChainSlashingFactor(address(staker)), 0); + assertEq(eigenPodManager().beaconChainSlashingFactor(address(staker)), 0); // 5. deposit expecting revert (randomly pick to verifyWC, start/complete CP) if (_randBool()) { @@ -99,15 +94,16 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); staker.verifyWithdrawalCredentials(validators); } else { - // Start/complete CP - // Ensure that not all validators were slashed so that some rewards can be generated when - // we advance epoch - cheats.assume(slashedValidators.length < validators.length); - beaconChain.advanceEpoch(); - staker.startCheckpoint(); - - cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); - staker.completeCheckpoint(); + // Commenting out until this vm.assume can be removed, almost always leads to too-many-rejects error. + // // Start/complete CP + // // Ensure that not all validators were slashed so that some rewards can be generated when + // // we advance epoch + // cheats.assume(slashedValidators.length < validators.length); + // beaconChain.advanceEpoch(); + // staker.startCheckpoint(); + + // cheats.expectRevert(IDelegationManagerErrors.FullySlashed.selector); + // staker.completeCheckpoint(); } } @@ -120,7 +116,7 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { * 6. delegate to operator * 7. deposit expecting revert (randomly pick to verifyWC, start/complete CP) */ - function test_slashAVS_delegate_revert_startCompleteCP(uint24 _r) public rand(_r) { + function testFuzz_slashAVS_delegate_revert_startCompleteCP(uint24) public { // 4. Create an operator set and register an operator operatorSet = avs.createOperatorSet(strategies); operator.registerForOperatorSet(operatorSet); @@ -137,7 +133,7 @@ contract Integration_SlashBC_OneBCSF is IntegrationCheckUtils { check_Base_Slashing_State(operator, allocateParams, slashParams); // assert operator has 1 magnitude remaining - assertEq(allocationManager.getMaxMagnitude(address(operator), beaconChainETHStrategy), 1); + assertEq(allocationManager().getMaxMagnitude(address(operator), BEACONCHAIN_ETH_STRAT), 1); // 6. delegate to operator staker.delegateTo(operator); diff --git a/src/test/integration/tests/Slashed_Eigenpod_AVS.t.sol b/src/test/integration/tests/eigenpod/Slashed_Eigenpod_AVS.t.sol similarity index 86% rename from src/test/integration/tests/Slashed_Eigenpod_AVS.t.sol rename to src/test/integration/tests/eigenpod/Slashed_Eigenpod_AVS.t.sol index abceecc08d..32f85f08df 100644 --- a/src/test/integration/tests/Slashed_Eigenpod_AVS.t.sol +++ b/src/test/integration/tests/eigenpod/Slashed_Eigenpod_AVS.t.sol @@ -1,32 +1,26 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; -contract Integration_SlashedEigenpod_AVS_Base is IntegrationCheckUtils { +contract Integration_EigenPod_SlashedEigenpod_AVS_Base is EigenPodTest { using ArrayLib for *; using SlashingLib for *; using Math for uint; - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - SlashingParams slashParams; - - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - function _init() internal virtual override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); - cheats.assume(initTokenBalances[0] >= 64 ether); + // Ensure the staker has at least 64 ETH to deposit. + if (initTokenBalances[0] < 64 ether) { + initTokenBalances[0] = 64 ether; + cheats.deal(address(staker), 64 ether); + } // 1. Deposit Into Strategies staker.depositIntoEigenlayer(strategies, initTokenBalances); @@ -52,7 +46,7 @@ contract Integration_SlashedEigenpod_AVS_Base is IntegrationCheckUtils { } } -contract Integration_SlashedEigenpod_AVS_Checkpoint is Integration_SlashedEigenpod_AVS_Base { +contract Integration_EigenPod_SlashedEigenpod_AVS_Checkpoint is Integration_EigenPod_SlashedEigenpod_AVS_Base { function _init() internal override { super._init(); @@ -65,7 +59,7 @@ contract Integration_SlashedEigenpod_AVS_Checkpoint is Integration_SlashedEigenp } /// @dev Asserts that the DSF isn't updated after a slash & checkpoint with 0 balance - function testFuzz_deposit_delegate_allocate_slash_checkpointZeroBalance(uint24 _rand) public rand(_rand) { + function testFuzz_deposit_delegate_allocate_slash_checkpointZeroBalance(uint24) public { // 7. Start & complete checkpoint staker.startCheckpoint(); check_StartCheckpoint_State(staker); @@ -74,7 +68,7 @@ contract Integration_SlashedEigenpod_AVS_Checkpoint is Integration_SlashedEigenp } } -contract Integration_SlashedEigenpod_AVS_Withdraw is Integration_SlashedEigenpod_AVS_Base { +contract Integration_EigenPod_SlashedEigenpod_AVS_Withdraw is Integration_EigenPod_SlashedEigenpod_AVS_Base { using Math for uint; using SlashingLib for uint; @@ -120,7 +114,7 @@ contract Integration_SlashedEigenpod_AVS_Withdraw is Integration_SlashedEigenpod /// @dev Asserts that the DSF isn't updated after a slash/queue and a checkpoint with 0 balance. /// @dev The staker should subsequently not be able to inflate their withdrawable shares - function testFuzz_deposit_delegate_allocate_slashAndQueue_checkpoint_redeposit(uint24 _rand) public rand(_rand) { + function testFuzz_deposit_delegate_allocate_slashAndQueue_checkpoint_redeposit(uint24) public { // 9. Start & complete checkpoint. staker.startCheckpoint(); check_StartCheckpoint_State(staker); @@ -136,7 +130,7 @@ contract Integration_SlashedEigenpod_AVS_Withdraw is Integration_SlashedEigenpod } /// @dev Asserts that the staker cannot inflate withdrawable shares after redepositing - function testFuzz_deposit_delegate_allocate_slashAndQueue_completeAsTokens_redeposit(uint24 _rand) public rand(_rand) { + function testFuzz_deposit_delegate_allocate_slashAndQueue_completeAsTokens_redeposit(uint24) public { Withdrawal[] memory withdrawals = _getQueuedWithdrawals(staker); _rollBlocksForCompleteWithdrawals(withdrawals); @@ -145,9 +139,7 @@ contract Integration_SlashedEigenpod_AVS_Withdraw is Integration_SlashedEigenpod IERC20[] memory tokens = _getUnderlyingTokens(withdrawals[i].strategies); uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableSharesAfterSlash); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], strategies, withdrawals[i].scaledShares, tokens, expectedTokens - ); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawals[i].scaledShares, expectedTokens); } // 10. Redeposit @@ -159,7 +151,7 @@ contract Integration_SlashedEigenpod_AVS_Withdraw is Integration_SlashedEigenpod } /// @dev Asserts that the staker cannot inflate withdrawable shares after checkpointing & completing as shares - function testFuzz_deposit_delegate_allocate_slashAndQueue_checkPoint_completeAsShares(uint24 _rand) public rand(_rand) { + function testFuzz_deposit_delegate_allocate_slashAndQueue_checkPoint_completeAsShares(uint24) public { Withdrawal[] memory withdrawals = _getQueuedWithdrawals(staker); _rollBlocksForCompleteWithdrawals(withdrawals); uint[] memory withdrawableShares = _calcWithdrawable(staker, strategies, initDepositShares); diff --git a/src/test/integration/tests/eigenpod/Slashed_Eigenpod_BC.t.sol b/src/test/integration/tests/eigenpod/Slashed_Eigenpod_BC.t.sol index 83feb5b011..669349d0a3 100644 --- a/src/test/integration/tests/eigenpod/Slashed_Eigenpod_BC.t.sol +++ b/src/test/integration/tests/eigenpod/Slashed_Eigenpod_BC.t.sol @@ -1,33 +1,25 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; -contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { +contract Integration_EigenPod_SlashedEigenpod_BC is EigenPodTest { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint64 beaconBalanceGwei; - uint64 slashedGwei; - IERC20[] tokens; - uint40[] validators; - uint40[] slashedValidators; - function _init() internal virtual override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); tokens = _getUnderlyingTokens(strategies); // Should only return ETH - cheats.assume(initTokenBalances[0] >= 64 ether); + + // Ensure the staker has at least 64 ETH to deposit. + if (initTokenBalances[0] < 64 ether) { + initTokenBalances[0] = 64 ether; + cheats.deal(address(staker), 64 ether); + } // Deposit staker uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); @@ -46,7 +38,7 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { check_CompleteCheckpoint_WithCLSlashing_HandleRoundDown_State(staker, slashedGwei); } - function testFuzz_delegateSlashedStaker_dsfWad(uint24 _random) public rand(_random) { + function testFuzz_delegateSlashedStaker_dsfWad(uint24) public { uint[] memory initDelegatableShares = _getWithdrawableShares(staker, strategies); uint[] memory initDepositShares = _getStakerDepositShares(staker, strategies); @@ -55,8 +47,8 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, initDepositShares); // Undelegate from an operator - IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + Withdrawal[] memory withdrawals = staker.undelegate(); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, initDelegatableShares); // Complete withdrawal as shares @@ -68,14 +60,14 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } (uint[] memory withdrawableSharesAfter, uint[] memory depositSharesAfter) = - delegationManager.getWithdrawableShares(address(staker), strategies); + delegationManager().getWithdrawableShares(address(staker), strategies); assertEq(depositSharesAfter[0], initDelegatableShares[0], "Deposit shares should reset to reflect slash(es)"); assertApproxEqAbs( withdrawableSharesAfter[0], depositSharesAfter[0], 100, "Withdrawable shares should equal deposit shares after withdrawal" ); } - function testFuzz_delegateSlashedStaker_dsfNonWad(uint24 _random) public rand(_random) { + function testFuzz_delegateSlashedStaker_dsfNonWad(uint24) public { //Additional deposit on beacon chain so dsf is nonwad uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(staker), amount); @@ -91,8 +83,8 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { check_Delegation_State(staker, operator, strategies, initDepositShares); // Undelegate from an operator - IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + Withdrawal[] memory withdrawals = staker.undelegate(); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, initDelegatableShares); // Complete withdrawal as shares @@ -104,14 +96,14 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } (uint[] memory withdrawableSharesAfter, uint[] memory depositSharesAfter) = - delegationManager.getWithdrawableShares(address(staker), strategies); + delegationManager().getWithdrawableShares(address(staker), strategies); assertEq(depositSharesAfter[0], initDelegatableShares[0], "Deposit shares should reset to reflect slash(es)"); assertApproxEqAbs( withdrawableSharesAfter[0], depositSharesAfter[0], 1000, "Withdrawable shares should equal deposit shares after withdrawal" ); } - function testFuzz_delegateSlashedStaker_slashedOperator(uint24 _random) public rand(_random) { + function testFuzz_delegateSlashedStaker_slashedOperator(uint24) public { (User staker2,,) = _newRandomStaker(); (uint40[] memory validators2,,) = staker2.startValidators(); beaconChain.advanceEpoch_NoWithdrawNoRewards(); @@ -144,21 +136,20 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); //Slash operator before delegation - IAllocationManagerTypes.SlashingParams memory slashingParams; - uint wadToSlash = _randWadToSlash(); - slashingParams = avs.slashOperator(operator, operatorSet.id, strategies, wadToSlash.toArrayU256()); + SlashingParams memory slashingParams = _genSlashing_Half(operator, operatorSet); + avs.slashOperator(slashingParams); assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); uint[] memory initDepositShares = _getStakerDepositShares(staker, strategies); // Delegate to an operator staker.delegateTo(operator); - (uint[] memory delegatedShares,) = delegationManager.getWithdrawableShares(address(staker), strategies); + (uint[] memory delegatedShares,) = delegationManager().getWithdrawableShares(address(staker), strategies); check_Delegation_State(staker, operator, strategies, initDepositShares); // Undelegate from an operator - IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + Withdrawal[] memory withdrawals = staker.undelegate(); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatedShares); // Complete withdrawal as shares @@ -170,15 +161,15 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } (uint[] memory withdrawableSharesAfter, uint[] memory depositSharesAfter) = - delegationManager.getWithdrawableShares(address(staker), strategies); + delegationManager().getWithdrawableShares(address(staker), strategies); assertEq(depositSharesAfter[0], delegatedShares[0], "Deposit shares should reset to reflect slash(es)"); assertApproxEqAbs( withdrawableSharesAfter[0], depositSharesAfter[0], 1000, "Withdrawable shares should equal deposit shares after withdrawal" ); } - function testFuzz_delegateSlashedStaker_redelegate_complete(uint24 _random) public rand(_random) { - (User operator2,,) = _newRandomOperator(); + function testFuzz_delegateSlashedStaker_redelegate_complete(uint24) public { + User operator2 = _newRandomOperator(); //Additional deposit on beacon chain so dsf is nonwad uint amount = 32 ether * _randUint({min: 1, max: 5}); @@ -192,11 +183,11 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { // Delegate to an operator staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, initDepositShares); - (uint[] memory delegatedShares,) = delegationManager.getWithdrawableShares(address(staker), strategies); + (uint[] memory delegatedShares,) = delegationManager().getWithdrawableShares(address(staker), strategies); // Undelegate from an operator - IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.redelegate(operator2); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + Withdrawal[] memory withdrawals = staker.redelegate(operator2); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, delegatedShares); // Complete withdrawal as shares @@ -210,14 +201,14 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } (uint[] memory withdrawableSharesAfter, uint[] memory depositSharesAfter) = - delegationManager.getWithdrawableShares(address(staker), strategies); + delegationManager().getWithdrawableShares(address(staker), strategies); assertEq(depositSharesAfter[0], delegatedShares[0], "Deposit shares should reset to reflect slash(es)"); assertApproxEqAbs( withdrawableSharesAfter[0], depositSharesAfter[0], 1000, "Withdrawable shares should equal deposit shares after withdrawal" ); } - function testFuzz_delegateSlashedStaker_slashedOperator_withdrawAllShares_complete(uint24 _random) public rand(_random) { + function testFuzz_delegateSlashedStaker_slashedOperator_withdrawAllShares_complete(uint24) public { //Additional deposit on beacon chain so dsf is nonwad uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(staker), amount); @@ -233,15 +224,14 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { check_Registration_State_NoAllocation(operator, operatorSet, strategies); // Slash operator before delegation - SlashingParams memory slashingParams; - uint wadToSlash = _randWadToSlash(); - slashingParams = avs.slashOperator(operator, operatorSet.id, strategies, wadToSlash.toArrayU256()); + SlashingParams memory slashingParams = _genSlashing_Full(operator, operatorSet); + avs.slashOperator(slashingParams); assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); // Delegate to an operator staker.delegateTo(operator); check_Delegation_State(staker, operator, strategies, initDepositShares); - (uint[] memory delegatedShares,) = delegationManager.getWithdrawableShares(address(staker), strategies); + (uint[] memory delegatedShares,) = delegationManager().getWithdrawableShares(address(staker), strategies); // Allocate to operator set allocateParams = _genAllocation_AllAvailable(operator, operatorSet, strategies); @@ -250,9 +240,9 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); // Withdraw all shares - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, initDepositShares, withdrawableShares, withdrawals, withdrawalRoots); // Complete withdrawal as shares @@ -264,14 +254,14 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } (uint[] memory withdrawableSharesAfter, uint[] memory depositSharesAfter) = - delegationManager.getWithdrawableShares(address(staker), strategies); + delegationManager().getWithdrawableShares(address(staker), strategies); assertEq(depositSharesAfter[0], delegatedShares[0], "Deposit shares should reset to reflect slash(es)"); assertApproxEqAbs( withdrawableSharesAfter[0], depositSharesAfter[0], 1000, "Withdrawable shares should equal deposit shares after withdrawal" ); } - function testFuzz_redeposit_queue_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_redeposit_queue_completeAsTokens(uint24) public { // Prove an additional validator uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(staker), amount); @@ -282,9 +272,9 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { // Queue withdrawal for all tokens uint[] memory depositShares = _getStakerDepositShares(staker, strategies); - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State( staker, User(payable(address(0))), strategies, depositShares, withdrawableShares, withdrawals, withdrawalRoots ); @@ -295,13 +285,11 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { for (uint i = 0; i < withdrawals.length; ++i) { uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawableShares, tokens, expectedTokens - ); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, expectedTokens); } } - function testFuzz_redeposit_queue_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_redeposit_queue_completeAsShares(uint24) public { // Prove an additional validator uint amount = 32 ether * _randUint({min: 1, max: 5}); cheats.deal(address(staker), amount); @@ -312,9 +300,9 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { // Queue withdrawal for all uint[] memory depositShares = _getStakerDepositShares(staker, strategies); - uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies); + withdrawableShares = _getStakerWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, depositShares); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State( staker, User(payable(address(0))), strategies, depositShares, withdrawableShares, withdrawals, withdrawalRoots ); @@ -328,7 +316,7 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } } - function testFuzz_verifyAdditionalValidator_delegateSlashedStaker(uint24 _random) public rand(_random) { + function testFuzz_verifyAdditionalValidator_delegateSlashedStaker(uint24) public { // Create operatorSet operatorSet = avs.createOperatorSet(strategies); @@ -363,25 +351,16 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils { } /// @notice This is not considered dual slashing since the operator is pre-slashed -contract Integration_SlashedOperator_SlashedEigenpod_Base is IntegrationCheckUtils { +contract Integration_EigenPod_SlashedOperator_SlashedEigenpod_Base is EigenPodTest { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - AllocateParams allocateParams; - - User operator; - - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - function _init() internal virtual override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initTokenBalances) = _newRandomStaker(); - operator = _newRandomOperator_NoAssets(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); // 1. Deposit Into Strategies staker.depositIntoEigenlayer(strategies, initTokenBalances); @@ -417,7 +396,7 @@ contract Integration_SlashedOperator_SlashedEigenpod_Base is IntegrationCheckUti } } -contract Integration_SlashedOperator_SlashedEigenpod is Integration_SlashedOperator_SlashedEigenpod_Base { +contract Integration_EigenPod_SlashedOperator_SlashedEigenpod is Integration_EigenPod_SlashedOperator_SlashedEigenpod_Base { function _init() internal virtual override { // 1-5 super._init(); @@ -445,95 +424,88 @@ contract Integration_SlashedOperator_SlashedEigenpod is Integration_SlashedOpera initDepositShares = _getStakerDepositShares(staker, strategies); // Deposit shares increased after verifying validator } - function testFuzz_slashOnBC_delegate_verifyValidator_undelegate_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_slashOnBC_delegate_verifyValidator_undelegate_completeAsTokens(uint24) public { // 9. Undelegate - uint[] memory stakerWithdrawableShares = _getWithdrawableShares(staker, strategies); + uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, stakerWithdrawableShares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 10. Complete withdrawal as tokens _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, stakerWithdrawableShares); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares, tokens, expectedTokens - ); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], withdrawableShares, expectedTokens); } } - function testFuzz_slashOnBC_delegate_verifyValidator_undelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_slashOnBC_delegate_verifyValidator_undelegate_completeAsShares(uint24) public { // 9. Undelegate - uint[] memory stakerWithdrawableShares = _getWithdrawableShares(staker, strategies); + uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.undelegate(); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, stakerWithdrawableShares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 10. Complete withdrawal as shares _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); - check_Withdrawal_AsShares_Undelegated_State( - staker, operator, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares - ); + check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, withdrawableShares); } } - function testFuzz_slashOnBC_delegate_verifyValidator_redelegate_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_slashOnBC_delegate_verifyValidator_redelegate_completeAsTokens(uint24) public { // Create new operator - User operator2 = _newRandomOperator_NoAssets(); + User operator2 = _newRandomOperator(); // Randomly give the operator a non-WAD magnitude if (_randBool()) _giveOperatorNonWadMagnitude(operator2); // 9. Redelegate - uint[] memory stakerWithdrawableShares = _getWithdrawableShares(staker, strategies); + uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.redelegate(operator2); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, stakerWithdrawableShares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 10. Complete withdrawal as tokens _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, stakerWithdrawableShares); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares, tokens, expectedTokens - ); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawableShares, expectedTokens); } } - function testFuzz_slashOnBC_delegate_verifyValidator_redelegate_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_slashOnBC_delegate_verifyValidator_redelegate_completeAsShares(uint24) public { // Create new operator - User operator2 = _newRandomOperator_NoAssets(); + User operator2 = _newRandomOperator(); // Randomly give the operator a non-WAD magnitude if (_randBool()) _giveOperatorNonWadMagnitude(operator2); // 9. Redelegate - uint[] memory stakerWithdrawableShares = _getWithdrawableShares(staker, strategies); + uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.redelegate(operator2); - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, stakerWithdrawableShares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 10. Complete withdrawal as shares _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Redelegated_State( - staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares + staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, withdrawableShares ); } } } -contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_SlashedOperator_SlashedEigenpod_Base { +contract Integration_EigenPod_Redelegate_SlashOperator_SlashEigenpod is Integration_EigenPod_SlashedOperator_SlashedEigenpod_Base { using ArrayLib for *; User operator2; Withdrawal withdrawal; - uint64 slashedGwei; function _init() internal virtual override { // 1-5. @@ -544,16 +516,16 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash check_Delegation_State(staker, operator, strategies, initDepositShares); // 7. Create new operator & randomly give it a non-WAD magnitude - operator2 = _newRandomOperator_NoAssets(); + operator2 = _newRandomOperator(); if (_randBool()) _giveOperatorNonWadMagnitude(operator2); // 8. Redelegate - uint[] memory stakerWithdrawableShares = _getWithdrawableShares(staker, strategies); + uint[] memory withdrawableShares = _getWithdrawableShares(staker, strategies); Withdrawal[] memory withdrawals = staker.redelegate(operator2); require(withdrawals.length == 1, "Expected 1 withdrawal"); withdrawal = withdrawals[0]; - bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); - check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, stakerWithdrawableShares); + withdrawalRoots = _getWithdrawalHashes(withdrawals); + check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, withdrawableShares); // 9. Slash original operator SlashingParams memory slashParams = _genSlashing_Half(operator, operatorSet); @@ -569,7 +541,7 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash staker.completeCheckpoint(); } - function testFuzz_delegate_redelegate_slashAVS_slashBC_verifyValidator_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_delegate_redelegate_slashAVS_slashBC_verifyValidator_completeAsShares(uint24) public { // Populate withdrawal array Withdrawal[] memory withdrawals = new Withdrawal[](1); withdrawals[0] = withdrawal; @@ -583,17 +555,17 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash check_VerifyWC_State(staker, newValidators, beaconBalanceAddedGwei); // 12. Complete withdrawal as shares - uint[] memory stakerWithdrawableShares = _getWithdrawableSharesAfterCompletion(staker); + uint[] memory withdrawableShares = _getWithdrawableSharesAfterCompletion(staker); _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Redelegated_State( - staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares + staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, withdrawableShares ); } } - function testFuzz_delegate_redelegate_slashAVS_slashBC_verifyValidator_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_delegate_redelegate_slashAVS_slashBC_verifyValidator_completeAsTokens(uint24) public { // Populate withdrawal array Withdrawal[] memory withdrawals = new Withdrawal[](1); withdrawals[0] = withdrawal; @@ -608,28 +580,26 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash // 12. Complete withdrawal as tokens _rollBlocksForCompleteWithdrawals(withdrawals); - uint[] memory stakerWithdrawableShares = _getWithdrawableSharesAfterCompletion(staker); + uint[] memory withdrawableShares = _getWithdrawableSharesAfterCompletion(staker); for (uint i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, stakerWithdrawableShares); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares, tokens, expectedTokens - ); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawableShares, expectedTokens); } } - function testFuzz_delegate_redelegate_slashAVS_slashBC_completeAsShares_verifyValidator(uint24 _random) public rand(_random) { + function testFuzz_delegate_redelegate_slashAVS_slashBC_completeAsShares_verifyValidator(uint24) public { // Populate withdrawal array Withdrawal[] memory withdrawals = new Withdrawal[](1); withdrawals[0] = withdrawal; // 11. Complete withdrawal as shares - uint[] memory stakerWithdrawableShares = _getWithdrawableSharesAfterCompletion(staker); + uint[] memory withdrawableShares = _getWithdrawableSharesAfterCompletion(staker); _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; ++i) { staker.completeWithdrawalAsShares(withdrawals[i]); check_Withdrawal_AsShares_Redelegated_State( - staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares + staker, operator, operator2, withdrawals[i], withdrawals[i].strategies, withdrawableShares ); } @@ -642,20 +612,18 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash check_VerifyWC_State(staker, newValidators, beaconBalanceAddedGwei); } - function testFuzz_delegate_redelegate_slashAVS_slashBC_completeAsTokens_verifyValidator(uint24 _random) public rand(_random) { + function testFuzz_delegate_redelegate_slashAVS_slashBC_completeAsTokens_verifyValidator(uint24) public { // Populate withdrawal array Withdrawal[] memory withdrawals = new Withdrawal[](1); withdrawals[0] = withdrawal; // 11. Complete withdrawal as tokens _rollBlocksForCompleteWithdrawals(withdrawals); - uint[] memory stakerWithdrawableShares = _getWithdrawableSharesAfterCompletion(staker); + uint[] memory withdrawableShares = _getWithdrawableSharesAfterCompletion(staker); for (uint i = 0; i < withdrawals.length; ++i) { - uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, stakerWithdrawableShares); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); - check_Withdrawal_AsTokens_State( - staker, operator2, withdrawals[i], withdrawals[i].strategies, stakerWithdrawableShares, tokens, expectedTokens - ); + uint[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawableShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State(staker, operator2, withdrawals[i], withdrawableShares, expectedTokens); } // 12. Verify additional validator @@ -668,27 +636,16 @@ contract Integration_Redelegate_SlashOperator_SlashEigenpod is Integration_Slash } } -contract Integration_SlashedEigenpod_BC_HalfSlash is IntegrationCheckUtils { +contract Integration_EigenPod_SlashedEigenpod_BC_HalfSlash is EigenPodTest { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - - User operator; - AllocateParams allocateParams; - - User staker; - IStrategy[] strategies; - uint[] initTokenBalances; - uint[] initDepositShares; - uint64 slashedGwei; - uint40[] slashedValidators; - function _init() internal override { + super._init(); + _configAssetTypes(HOLDS_ETH); (staker, strategies, initTokenBalances) = _newRandomStaker(); - (operator,,) = _newRandomOperator(); - (avs,) = _newRandomAVS(); + operator = _newRandomOperator(); + avs = _newRandomAVS(); // 1. Deposit staker uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); @@ -712,7 +669,7 @@ contract Integration_SlashedEigenpod_BC_HalfSlash is IntegrationCheckUtils { * @notice Test sets up an EigenPod which has a non-WAD BCSF. After queue withdrawing all depositShares * which sets it to 0, they can then complete checkpoints repeatedly with 0 shares increase to increase the staker DSF each time */ - function test_completeCP_withNoAddedShares(uint24 _rand) public rand(_rand) { + function test_completeCP_withNoAddedShares() public { // 4. queue withdraw all depositShares having it set to 0 uint withdrawableSharesBefore = _getStakerWithdrawableShares(staker, strategies)[0]; Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, initDepositShares); @@ -727,8 +684,8 @@ contract Integration_SlashedEigenpod_BC_HalfSlash is IntegrationCheckUtils { // Staker deposit shares should be 0 from queue withdrawing all depositShares // therefore the depositScalingFactor should also be reset WAD - assertEq(eigenPodManager.podOwnerDepositShares(address(staker)), 0); - assertEq(delegationManager.depositScalingFactor(address(staker), beaconChainETHStrategy), WAD); + assertEq(eigenPodManager().podOwnerDepositShares(address(staker)), 0); + assertEq(delegationManager().depositScalingFactor(address(staker), BEACONCHAIN_ETH_STRAT), WAD); // 6. deposit: can either verify wc or start/complete cp or complete the withdrawals as shares _rollBlocksForCompleteWithdrawals(withdrawals); @@ -739,7 +696,7 @@ contract Integration_SlashedEigenpod_BC_HalfSlash is IntegrationCheckUtils { // End state: staker and operator have much higher inflated withdrawable and delegated shares respectively // The staker's withdrawable shares should be <= from withdrawable shares before (should be equal but could be less due to rounding) uint withdrawableSharesAfter = _getStakerWithdrawableShares(staker, strategies)[0]; - uint operatorShares = delegationManager.operatorShares(address(operator), strategies[0]); + uint operatorShares = delegationManager().operatorShares(address(operator), strategies[0]); assertLe( withdrawableSharesAfter, withdrawableSharesBefore, "staker withdrawable shares should be <= from withdrawable shares before" ); 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 0dad998bee..5885d7534e 100644 --- a/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol +++ b/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol @@ -1,16 +1,17 @@ // 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"; +import "src/test/integration/tests/eigenpod/EigenPod.t.sol"; -contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { +contract Integration_EigenPod_VerifyWC_StartCP_CompleteCP is EigenPodTest { function _init() internal override { + super._init(); + _configAssetTypes(HOLDS_ETH); _configUserTypes(DEFAULT); } - function test_GasMetering() public rand(0) { + function test_GasMetering() public { (User staker,,) = _newRandomStaker(); // Deal user 20 full stakers worth of ETH @@ -74,7 +75,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -93,7 +94,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 1. Verify validators' withdrawal credentials /// 2. Verify validators' withdrawal credentials again /// => This should fail - function test_VerifyWC_VerifyWC_Fails(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_VerifyWC_Fails(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -110,7 +111,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. start a checkpoint again /// => This should fail - function test_VerifyWC_StartCP_StartCP_Fails(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_StartCP_Fails(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -131,7 +132,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 3. complete a checkpoint /// 4. start a checkpoint without advancing a block /// => this should fail - function test_VerifyWC_StartCP_CompleteCP_StartCP_Fails(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_CompleteCP_StartCP_Fails(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -155,7 +156,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_Advance_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_Advance_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -179,7 +180,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- move forward 1 or more epochs /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_Advance_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_Advance_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -208,7 +209,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Fully exit validators before verifying withdrawal credentials /// 1. Verify validators' withdrawal credentials /// => This should fail - function test_ExitValidators_VerifyWC_Fails(uint24 _rand) public rand(_rand) { + function testFuzz_ExitValidators_VerifyWC_Fails(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators,,) = staker.startValidators(); @@ -224,7 +225,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_ExitValidators_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_ExitValidators_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -254,7 +255,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => exited balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_ExitValidators_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_ExitValidators_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -291,7 +292,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- get slashed on beacon chain /// 1. Try to verify validators' withdrawal credentials /// => this should fail - function test_SlashToPod_VerifyWC_Fails(uint24 _rand) public rand(_rand) { + function testFuzz_SlashToPod_VerifyWC_Fails(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators,,) = staker.startValidators(); @@ -308,7 +309,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToPod_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_SlashToPod_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -337,7 +338,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => slashed balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_SlashToPod_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_SlashToPod_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -369,7 +370,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 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 rand(_rand) { + function testFuzz_VerifyWC_Slash_StartCP_VerifyWC_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -408,7 +409,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToPod_VerifyStale_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_SlashToPod_VerifyStale_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -433,7 +434,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToCL_VerifyStale_CompleteCP_SlashAgain(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_SlashToCL_VerifyStale_CompleteCP_SlashAgain(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -473,7 +474,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => slashed balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_SlashToPod_CompleteCP_VerifyStale(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_SlashToPod_CompleteCP_VerifyStale(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -511,7 +512,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards earned on beacon chain - function test_EarnOnBeacon_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_EarnOnBeacon_VerifyWC_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); @@ -540,7 +541,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards earned on beacon chain - function test_VerifyWC_EarnOnBeacon_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_EarnOnBeacon_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -565,7 +566,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- earn rewards on beacon chain (not withdrawn to pod) /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_EarnOnBeacon_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_EarnOnBeacon_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -596,7 +597,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards withdrawn to pod - function test_EarnToPod_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_EarnToPod_VerifyWC_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); @@ -624,7 +625,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards withdrawn to pod - function test_VerifyWC_EarnToPod_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_EarnToPod_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); @@ -649,7 +650,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- earn rewards on beacon chain (withdrawn to pod) /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_EarnToPod_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_EarnToPod_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); @@ -683,7 +684,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Pod receives native ETH via fallback /// 1. start a checkpoint /// => checkpoint should auto-complete, awarding shares for ETH in pod - function test_NativeETH_StartCP(uint24 _rand) public rand(_rand) { + function testFuzz_NativeETH_StartCP(uint24) public { (User staker,,) = _newRandomStaker(); // Send a random amount of ETH to staker's fallback @@ -702,7 +703,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should account for native ETH - function test_NativeETH_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_NativeETH_VerifyWC_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -729,7 +730,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should account for native ETH - function test_VerifyWC_NativeETH_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_NativeETH_StartCP_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); @@ -756,7 +757,7 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Pod receives native ETH via fallback /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_NativeETH_CompleteCP(uint24 _rand) public rand(_rand) { + function testFuzz_VerifyWC_StartCP_NativeETH_CompleteCP(uint24) public { (User staker,,) = _newRandomStaker(); (uint40[] memory validators, uint64 beaconBalanceGwei,) = staker.startValidators(); diff --git a/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol b/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol index 97b9c71bcf..7735eb9c18 100644 --- a/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol +++ b/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/UpgradeTest.t.sol"; +import "src/test/integration/tests/upgrade/UpgradeTest.t.sol"; contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base is UpgradeTest { struct TestState { User staker; User operator; IStrategy[] strategies; - uint[] tokenBalances; + uint[] initTokenBalances; uint[] shares; uint[] withdrawalShares; uint[] expectedTokens; @@ -19,15 +19,15 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base is UpgradeTest function _init_(bool withOperator, bool withDelegation) internal virtual returns (TestState memory state) { // Create staker - (state.staker, state.strategies, state.tokenBalances) = _newRandomStaker(); - state.shares = _calculateExpectedShares(state.strategies, state.tokenBalances); + (state.staker, state.strategies, state.initTokenBalances) = _newRandomStaker(); + state.shares = _calculateExpectedShares(state.strategies, state.initTokenBalances); // Delegate staker to operator - state.operator = withOperator ? _newRandomOperator_NoAssets() : User(payable(0)); + state.operator = withOperator ? _newRandomOperator() : User(payable(0)); if (withDelegation) state.staker.delegateTo(state.operator); // Deposit into EigenLayer - state.staker.depositIntoEigenlayer(state.strategies, state.tokenBalances); + state.staker.depositIntoEigenlayer(state.strategies, state.initTokenBalances); // Setup withdrawal shares (full or partial) state.isPartial = _randBool(); @@ -43,15 +43,9 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base is UpgradeTest function _completeWithdrawal(TestState memory state) internal { for (uint i = 0; i < state.withdrawals.length; i++) { if (state.completeAsTokens) { - IERC20[] memory tokens = state.staker.completeWithdrawalAsTokens(state.withdrawals[i]); + state.staker.completeWithdrawalAsTokens(state.withdrawals[i]); check_Withdrawal_AsTokens_State( - state.staker, - state.operator, - state.withdrawals[i], - state.strategies, - state.withdrawalShares, - tokens, - state.expectedTokens + state.staker, state.operator, state.withdrawals[i], state.withdrawalShares, state.expectedTokens ); } else { state.staker.completeWithdrawalAsShares(state.withdrawals[i]); @@ -64,7 +58,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base is UpgradeTest } contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base { - function testFuzz_deposit_queue_upgrade_complete(uint24 r) public rand(r) { + function testFuzz_deposit_queue_upgrade_complete(uint24) public { TestState memory state = _init_({withOperator: false, withDelegation: false}); state.withdrawals = state.staker.queueWithdrawals(state.strategies, state.withdrawalShares); _upgradeEigenLayerContracts(); @@ -72,7 +66,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgr _completeWithdrawal(state); } - function testFuzz_delegate_deposit_queue_upgrade_complete(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_upgrade_complete(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); state.withdrawals = state.staker.queueWithdrawals(state.strategies, state.withdrawalShares); _upgradeEigenLayerContracts(); @@ -80,7 +74,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgr _completeWithdrawal(state); } - function testFuzz_upgrade_delegate_queuePartial_complete(uint24 r) public rand(r) { + function testFuzz_upgrade_delegate_queuePartial_complete(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: false}); _upgradeEigenLayerContracts(); state.staker.delegateTo(state.operator); @@ -89,12 +83,12 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgr _completeWithdrawal(state); } - function testFuzz_delegate_deposit_queue_completeBeforeUpgrade(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_completeBeforeUpgrade(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); state.withdrawals = state.staker.queueWithdrawals(state.strategies, state.withdrawalShares); _rollBlocksForCompleteWithdrawals(state.withdrawals); // We must roll forward by the delay twice since pre-upgrade delay is half as long as post-upgrade delay. - rollForward(delegationManager.minWithdrawalDelayBlocks() + 1); + rollForward(delegationManager().minWithdrawalDelayBlocks() + 1); _upgradeEigenLayerContracts(); _completeWithdrawal(state); } @@ -103,10 +97,6 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgr contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integration_Upgrade_Complete_PreSlashing_Withdrawal_Base { using ArrayLib for *; - AVS avs; - OperatorSet operatorSet; - AllocateParams allocateParams; - function _init_(bool withOperator, bool withDelegation) internal override returns (TestState memory state) { // Initialize state, queue a full withdrawal state = super._init_({withOperator: withOperator, withDelegation: withDelegation}); @@ -119,7 +109,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integratio // Set allocation delay, register for operatorSet & allocate fully state.operator.setAllocationDelay(1); rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); - (avs,) = _newRandomAVS(); + avs = _newRandomAVS(); operatorSet = avs.createOperatorSet(state.strategies); allocateParams = _genAllocation_AllAvailable(state.operator, operatorSet); @@ -131,7 +121,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integratio _rollBlocksForCompleteAllocation(state.operator, operatorSet, state.strategies); } - function testFuzz_delegate_deposit_queue_upgrade_slashFully_revertCompleteAsShares(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_upgrade_slashFully_revertCompleteAsShares(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); // Slash operator by AVS @@ -146,7 +136,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integratio state.staker.completeWithdrawalsAsShares(state.withdrawals); } - function testFuzz_delegate_deposit_queue_upgrade_slashFully_completeAsTokens(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_upgrade_slashFully_completeAsTokens(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); // Slash operator by AVS @@ -160,7 +150,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integratio _completeWithdrawal(state); } - function testFuzz_delegate_deposit_queue_upgrade_slash_completeAsShares(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_upgrade_slash_completeAsShares(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); // Slash operator by AVS @@ -175,7 +165,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal_Slash is Integratio _completeWithdrawal(state); } - function testFuzz_delegate_deposit_queue_upgrade_slash_completeAsTokens(uint24 r) public rand(r) { + function testFuzz_delegate_deposit_queue_upgrade_slash_completeAsTokens(uint24) public { TestState memory state = _init_({withOperator: true, withDelegation: true}); // Slash operator by AVS diff --git a/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol b/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol index 6f96bce584..0aaaaf7b84 100644 --- a/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol +++ b/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/UpgradeTest.t.sol"; +import "src/test/integration/tests/upgrade/UpgradeTest.t.sol"; contract Integration_Upgrade_Deposit_Delegate_Allocate is UpgradeTest { struct TestState { @@ -9,19 +9,19 @@ contract Integration_Upgrade_Deposit_Delegate_Allocate is UpgradeTest { User operator; AVS avs; IStrategy[] strategies; - uint[] tokenBalances; + uint[] initTokenBalances; OperatorSet operatorSet; AllocateParams allocateParams; } function _init_() internal returns (TestState memory state) { - (state.staker, state.strategies, state.tokenBalances) = _newRandomStaker(); - (state.operator,,) = _newRandomOperator(); + (state.staker, state.strategies, state.initTokenBalances) = _newRandomStaker(); + state.operator = _newRandomOperator(); // Pre-upgrade: // 1. Create staker and operator with assets, then deposit into EigenLayer // 2. Delegate to operator - state.staker.depositIntoEigenlayer(state.strategies, state.tokenBalances); + state.staker.depositIntoEigenlayer(state.strategies, state.initTokenBalances); state.staker.delegateTo(state.operator); } @@ -36,19 +36,15 @@ contract Integration_Upgrade_Deposit_Delegate_Allocate is UpgradeTest { check_Registration_State_NoAllocation(state.operator, state.operatorSet, allStrats); // 5. Allocate to operator set. - state.allocateParams = AllocateParams({ - operatorSet: state.operatorSet, - strategies: state.strategies, - newMagnitudes: _randMagnitudes({sum: 1 ether, len: state.strategies.length}) - }); + state.allocateParams = _genAllocation_Rand(state.operator, state.operatorSet); state.operator.modifyAllocations(state.allocateParams); check_IncrAlloc_State_Slashable(state.operator, state.allocateParams); } - function testFuzz_deposit_delegate_upgrade_allocate(uint24 r) public rand(r) { + function testFuzz_deposit_delegate_upgrade_allocate(uint24) public { TestState memory state = _init_(); _upgradeEigenLayerContracts(); - (state.avs,) = _newRandomAVS(); + state.avs = _newRandomAVS(); _setupAllocation(state); } } diff --git a/src/test/integration/tests/upgrade/EigenPod.t.sol b/src/test/integration/tests/upgrade/EigenPod.t.sol index 7ec724f87d..c9d3f77825 100644 --- a/src/test/integration/tests/upgrade/EigenPod.t.sol +++ b/src/test/integration/tests/upgrade/EigenPod.t.sol @@ -1,192 +1,182 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/test/integration/UpgradeTest.t.sol"; - -contract Integration_Upgrade_EigenPod_Base is UpgradeTest { - User staker; - IStrategy[] strategies; - uint[] tokenBalances; - uint[] shares; - - function _init() internal virtual override { - _configAssetTypes(HOLDS_ETH); - _configUserTypes(DEFAULT); - - /// 0. Create a staker with underlying assets - (staker, strategies, tokenBalances) = _newRandomStaker(); - shares = _calculateExpectedShares(strategies, tokenBalances); - - /// 1. Deposit into strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); - } -} - -contract Integration_Upgrade_EigenPod_SlashAfterUpgrade is Integration_Upgrade_EigenPod_Base { - uint40[] validators; - uint64 slashedGwei; - - function testFuzz_deposit_upgrade_slash_completeCheckpoint(uint24 _rand) public rand(_rand) { - uint64 initBeaconBalanceGwei = uint64(tokenBalances[0] / GWEI_TO_WEI); - - /// 2. Upgrade contracts - _upgradeEigenLayerContracts(); - - /// 3. Slash the staker partially - validators = staker.getActiveValidators(); - slashedGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); - beaconChain.advanceEpoch_NoRewards(); // Withdraw slashed validators to pod - - // 4. Start and complete a checkpoint - staker.startCheckpoint(); - check_StartCheckpoint_WithPodBalance_State(staker, initBeaconBalanceGwei - slashedGwei); - staker.completeCheckpoint(); - check_CompleteCheckpoint_WithSlashing_HandleRoundDown_State(staker, validators, slashedGwei); - } -} - -contract Integration_Upgrade_EigenPod_FullSlash is Integration_Upgrade_EigenPod_Base { - uint40[] validators; - uint64 slashedGwei; - - function _init() internal override { - super._init(); - - /// 2. Fully slash the staker - validators = staker.getActiveValidators(); - slashedGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Full); - beaconChain.advanceEpoch_NoRewards(); // Withdraw slashed validators to pod - - /// 3. Upgrade contracts - _upgradeEigenLayerContracts(); - } - - function testFuzz_deposit_fullSlash_upgrade_delegate(uint24 _rand) public rand(_rand) { - /// 4. Delegate to operator - (User operator,,) = _newRandomOperator(); - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); - } - - function testFuzz_deposit_fullSlash_upgrade_deposit_delegate(uint24 _rand) public rand(_rand) { - // 5. Start a new validator & verify withdrawal credentials - cheats.deal(address(staker), 32 ether); - tokenBalances[0] = tokenBalances[0] + 32 ether; - (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei,) = staker.startValidators(); - beaconChain.advanceEpoch_NoRewards(); - staker.verifyWithdrawalCredentials(newValidators); - check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei); - shares = _calculateExpectedShares(strategies, tokenBalances); - - // 6. Delegate to operator - (User operator,,) = _newRandomOperator(); - staker.delegateTo(operator); - check_Delegation_State(staker, operator, strategies, shares); - } -} - -contract Integration_Upgrade_EigenPod_NegativeShares is Integration_Upgrade_EigenPod_Base { - User operator; - Withdrawal withdrawal; - int[] tokenDeltas; - int[] balanceUpdateShareDelta; - - function _init() internal override { - super._init(); - - // 3. Delegate to operator - (operator,,) = _newRandomOperator(); - staker.delegateTo(operator); - - /// 4. Queue a withdrawal for all shares - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); - withdrawal = withdrawals[0]; - - /// 5. Update balance randomly (can be positive or negative) - (tokenDeltas, balanceUpdateShareDelta,) = _randBalanceUpdate(staker, strategies); - staker.updateBalances(strategies, tokenDeltas); - - /// 6. Upgrade contracts - _upgradeEigenLayerContracts(); - } - - function testFuzz_deposit_delegate_updateBalance_upgrade_completeAsShares(uint24 _rand) public rand(_rand) { - /// 7. Complete the withdrawal as shares - Withdrawal[] memory withdrawals = new Withdrawal[](1); - withdrawals[0] = withdrawal; - _rollBlocksForCompleteWithdrawals(withdrawals); - staker.completeWithdrawalAsShares(withdrawal); - - // Manually complete checks since we could still negative shares prior to the upgrade, causing a revert in the share check - (uint[] memory expectedOperatorShareDelta, int[] memory expectedStakerShareDelta) = - _getPostWithdrawalExpectedShareDeltas(balanceUpdateShareDelta[0], withdrawal); - 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_OperatorShares( - operator, withdrawal.strategies, expectedOperatorShareDelta, "operator should have received shares" - ); - assert_Snap_Delta_StakerShares(staker, strategies, expectedStakerShareDelta, "staker should have received expected shares"); - } - - function testFuzz_deposit_delegate_updateBalance_upgrade_completeAsTokens(uint24 _rand) public rand(_rand) { - /// 7. Complete the withdrawal as tokens - Withdrawal[] memory withdrawals = new Withdrawal[](1); - withdrawals[0] = withdrawal; - _rollBlocksForCompleteWithdrawals(withdrawals); - IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawal); - uint[] memory expectedTokens = _getPostWithdrawalExpectedTokenDeltas(balanceUpdateShareDelta[0], withdrawal); - - // Manually complete checks since we could still negative shares prior to the upgrade, causing a revert in the share check - 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_OperatorShares(operator, "operator shares should not have changed"); - - // If we had a positive balance update, then the staker shares should not have changed - if (balanceUpdateShareDelta[0] > 0) { - assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); - } - // Else, the staker shares should have increased by the magnitude of the negative share delta - else { - int[] memory expectedStakerShareDelta = new int[](1); - expectedStakerShareDelta[0] = -balanceUpdateShareDelta[0]; - assert_Snap_Delta_StakerShares(staker, strategies, expectedStakerShareDelta, "staker should have received expected shares"); - } - } - - function _getPostWithdrawalExpectedShareDeltas(int _balanceUpdateShareDelta, Withdrawal memory _withdrawal) - internal - pure - returns (uint[] memory, int[] memory) - { - uint[] memory operatorShareDelta = new uint[](1); - int[] memory stakerShareDelta = new int[](1); - // The staker share delta is the withdrawal scaled shares since it can go from negative to positive - stakerShareDelta[0] = int(_withdrawal.scaledShares[0]); - - if (_balanceUpdateShareDelta > 0) { - // If balanceUpdateShareDelta is positive, then the operator delta is the withdrawal scaled shares - operatorShareDelta[0] = _withdrawal.scaledShares[0]; - } else { - // Operator shares never went negative, so we can just add the withdrawal scaled shares and the negative share delta - operatorShareDelta[0] = uint(int(_withdrawal.scaledShares[0]) + _balanceUpdateShareDelta); - } - - return (operatorShareDelta, stakerShareDelta); - } - - function _getPostWithdrawalExpectedTokenDeltas(int _balanceUpdateShareDelta, Withdrawal memory _withdrawal) - internal - pure - returns (uint[] memory) - { - uint[] memory expectedTokenDeltas = new uint[](1); - if (_balanceUpdateShareDelta > 0) { - // If we had a positive balance update, then the expected token delta is the withdrawal scaled shares - expectedTokenDeltas[0] = _withdrawal.scaledShares[0]; - } else { - // If we had a negative balance update, then the expected token delta is the withdrawal scaled shares plus the negative share delta - expectedTokenDeltas[0] = uint(int(_withdrawal.scaledShares[0]) + _balanceUpdateShareDelta); - } - return expectedTokenDeltas; - } -} +// // SPDX-License-Identifier: BUSL-1.1 +// pragma solidity ^0.8.27; + +// import "src/test/integration/tests/upgrade/UpgradeTest.t.sol"; + +// contract Integration_Upgrade_EigenPod_Base is UpgradeTest { +// uint[] shares; + +// function _init() internal virtual override { +// _configAssetTypes(HOLDS_ETH); +// _configUserTypes(DEFAULT); + +// /// 0. Create a staker with underlying assets +// (staker, strategies, initTokenBalances) = _newRandomStaker(); +// shares = _calculateExpectedShares(strategies, initTokenBalances); + +// /// 1. Deposit into strategies +// staker.depositIntoEigenlayer(strategies, initTokenBalances); +// } +// } + +// contract Integration_Upgrade_EigenPod_SlashAfterUpgrade is Integration_Upgrade_EigenPod_Base { +// function testFuzz_deposit_upgrade_slash_completeCheckpoint(uint24) public { +// uint64 initBeaconBalanceGwei = uint64(initTokenBalances[0] / GWEI_TO_WEI); + +// /// 2. Upgrade contracts +// _upgradeEigenLayerContracts(); + +// /// 3. Slash the staker partially +// validators = staker.getActiveValidators(); +// slashedGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Minor); +// beaconChain.advanceEpoch_NoRewards(); // Withdraw slashed validators to pod + +// // 4. Start and complete a checkpoint +// staker.startCheckpoint(); +// check_StartCheckpoint_WithPodBalance_State(staker, initBeaconBalanceGwei - slashedGwei); +// staker.completeCheckpoint(); +// check_CompleteCheckpoint_WithSlashing_HandleRoundDown_State(staker, validators, slashedGwei); +// } +// } + +// contract Integration_Upgrade_EigenPod_FullSlash is Integration_Upgrade_EigenPod_Base { +// function _init() internal override { +// super._init(); + +// /// 2. Fully slash the staker +// validators = staker.getActiveValidators(); +// slashedGwei = beaconChain.slashValidators(validators, BeaconChainMock.SlashType.Full); +// beaconChain.advanceEpoch_NoRewards(); // Withdraw slashed validators to pod + +// /// 3. Upgrade contracts +// _upgradeEigenLayerContracts(); +// } + +// function testFuzz_deposit_fullSlash_upgrade_delegate(uint24) public { +// /// 4. Delegate to operator +// operator = _newRandomOperator(); +// staker.delegateTo(operator); +// check_Delegation_State(staker, operator, strategies, shares); +// } + +// function testFuzz_deposit_fullSlash_upgrade_deposit_delegate(uint24) public { +// // 5. Start a new validator & verify withdrawal credentials +// cheats.deal(address(staker), 32 ether); +// initTokenBalances[0] = initTokenBalances[0] + 32 ether; +// (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei,) = staker.startValidators(); +// beaconChain.advanceEpoch_NoRewards(); +// staker.verifyWithdrawalCredentials(newValidators); +// check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei); +// shares = _calculateExpectedShares(strategies, initTokenBalances); + +// // 6. Delegate to operator +// operator = _newRandomOperator(); +// staker.delegateTo(operator); +// check_Delegation_State(staker, operator, strategies, shares); +// } +// } + +// contract Integration_Upgrade_EigenPod_NegativeShares is Integration_Upgrade_EigenPod_Base { +// int[] tokenDeltas; +// int[] balanceUpdateShareDelta; +// Withdrawal withdrawal; + +// function _init() internal override { +// super._init(); + +// // 3. Delegate to operator +// operator = _newRandomOperator(); +// staker.delegateTo(operator); + +// /// 4. Queue a withdrawal for all shares +// Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); +// withdrawal = withdrawals[0]; + +// /// 5. Update balance randomly (can be positive or negative) +// (tokenDeltas, balanceUpdateShareDelta,) = _randBalanceUpdate(staker, strategies); +// staker.updateBalances(strategies, tokenDeltas); + +// /// 6. Upgrade contracts +// _upgradeEigenLayerContracts(); +// } + +// function testFuzz_deposit_delegate_updateBalance_upgrade_completeAsShares(uint24) public { +// /// 7. Complete the withdrawal as shares +// Withdrawal[] memory withdrawals = new Withdrawal[](1); +// withdrawals[0] = withdrawal; +// _rollBlocksForCompleteWithdrawals(withdrawals); +// staker.completeWithdrawalAsShares(withdrawal); + +// // Manually complete checks since we could still negative shares prior to the upgrade, causing a revert in the share check +// (uint[] memory expectedOperatorShareDelta, int[] memory expectedStakerShareDelta) = +// _getPostWithdrawalExpectedShareDeltas(balanceUpdateShareDelta[0], withdrawal); +// 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_OperatorShares( +// operator, withdrawal.strategies, expectedOperatorShareDelta, "operator should have received shares" +// ); +// assert_Snap_Delta_StakerShares(staker, strategies, expectedStakerShareDelta, "staker should have received expected shares"); +// } + +// function testFuzz_deposit_delegate_updateBalance_upgrade_completeAsTokens(uint24) public { +// /// 7. Complete the withdrawal as tokens +// Withdrawal[] memory withdrawals = new Withdrawal[](1); +// withdrawals[0] = withdrawal; +// _rollBlocksForCompleteWithdrawals(withdrawals); +// IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawal); +// uint[] memory expectedTokens = _getPostWithdrawalExpectedTokenDeltas(balanceUpdateShareDelta[0], withdrawal); + +// // Manually complete checks since we could still negative shares prior to the upgrade, causing a revert in the share check +// 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_OperatorShares(operator, "operator shares should not have changed"); + +// // If we had a positive balance update, then the staker shares should not have changed +// if (balanceUpdateShareDelta[0] > 0) { +// assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); +// } +// // Else, the staker shares should have increased by the magnitude of the negative share delta +// else { +// int[] memory expectedStakerShareDelta = new int[](1); +// expectedStakerShareDelta[0] = -balanceUpdateShareDelta[0]; +// assert_Snap_Delta_StakerShares(staker, strategies, expectedStakerShareDelta, "staker should have received expected shares"); +// } +// } + +// function _getPostWithdrawalExpectedShareDeltas(int _balanceUpdateShareDelta, Withdrawal memory _withdrawal) +// internal +// pure +// returns (uint[] memory, int[] memory) +// { +// uint[] memory operatorShareDelta = new uint[](1); +// int[] memory stakerShareDelta = new int[](1); +// // The staker share delta is the withdrawal scaled shares since it can go from negative to positive +// stakerShareDelta[0] = int(_withdrawal.scaledShares[0]); + +// if (_balanceUpdateShareDelta > 0) { +// // If balanceUpdateShareDelta is positive, then the operator delta is the withdrawal scaled shares +// operatorShareDelta[0] = _withdrawal.scaledShares[0]; +// } else { +// // Operator shares never went negative, so we can just add the withdrawal scaled shares and the negative share delta +// operatorShareDelta[0] = uint(int(_withdrawal.scaledShares[0]) + _balanceUpdateShareDelta); +// } + +// return (operatorShareDelta, stakerShareDelta); +// } + +// function _getPostWithdrawalExpectedTokenDeltas(int _balanceUpdateShareDelta, Withdrawal memory _withdrawal) +// internal +// pure +// returns (uint[] memory) +// { +// uint[] memory expectedTokenDeltas = new uint[](1); +// if (_balanceUpdateShareDelta > 0) { +// // If we had a positive balance update, then the expected token delta is the withdrawal scaled shares +// expectedTokenDeltas[0] = _withdrawal.scaledShares[0]; +// } else { +// // If we had a negative balance update, then the expected token delta is the withdrawal scaled shares plus the negative share delta +// expectedTokenDeltas[0] = uint(int(_withdrawal.scaledShares[0]) + _balanceUpdateShareDelta); +// } +// return expectedTokenDeltas; +// } +// } diff --git a/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol b/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol index 5206700884..7178ce5ae6 100644 --- a/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol +++ b/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol @@ -1,81 +1,77 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/test/integration/UpgradeTest.t.sol"; - -contract Integration_Upgrade_EigenPod_Slashing_Migration is UpgradeTest, EigenPodPausingConstants { - User staker; - uint40[] validators; - uint[] shares; - IStrategy[] strategies; - uint[] tokenBalances; - - function _init() internal override { - _configAssetTypes(HOLDS_ETH); - _configUserTypes(DEFAULT); - - /// 0. Create a staker with underlying assets - (staker, strategies, tokenBalances) = _newRandomStaker(); - shares = _calculateExpectedShares(strategies, tokenBalances); - - /// 1. Deposit into strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); - validators = staker.getActiveValidators(); - } - - function _completeEigenpodMigration() internal { - // Start a checkpoint - staker.startCheckpoint(); - - // Pause checkpoint starting - cheats.prank(pauserMultisig); - eigenPodManager.pause(2 ** PAUSED_START_CHECKPOINT); - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); - staker.startCheckpoint(); - - // Complete in progress checkpoint - staker.completeCheckpoint(); - - // Upgrade Contracts for slashing - _upgradeEigenLayerContracts(); - - // Unpause EigenPodManager - cheats.prank(eigenLayerPauserReg.unpauser()); - eigenPodManager.unpause(0); - } - - function testFuzz_earnRewards_migrate_exit(uint24 _rand) public rand(_rand) { - // 2. Advance epoch, generating consensus rewards and withdrawing anything over 32 ETH - beaconChain.advanceEpoch(); - - // 3. Migrate & Upgrade - _completeEigenpodMigration(); - - // 4. Exit validators - // Fully exit one or more validators and advance epoch without generating rewards - uint40[] memory subset = _choose(validators); - uint64 exitedBalanceGwei = staker.exitValidators(subset); - beaconChain.advanceEpoch_NoRewards(); - - staker.startCheckpoint(); - check_StartCheckpoint_WithPodBalance_State(staker, exitedBalanceGwei); - staker.completeCheckpoint(); - check_CompleteCheckpoint_WithExits_State(staker, subset, exitedBalanceGwei); - } - - function testFuzz_slash_migrate(uint24 _rand) public rand(_rand) { - // 2. Slash validators - uint40[] memory subset = _choose(validators); - uint64 slashedGwei = beaconChain.slashValidators(subset, _randSlashType()); - beaconChain.advanceEpoch_NoRewards(); - shares[0] = shares[0] - slashedGwei * GWEI_TO_WEI; // Shares should decrease by slashed amount - - // 3. Migrate & Upgrade - _completeEigenpodMigration(); - - // Assertions - assert_BCSF_WAD(staker, "BCSF should be WAD"); - assert_ActiveValidatorCount(staker, validators.length - subset.length, "validator count should decrease"); - assert_HasExpectedShares(staker, strategies, shares, "shares should decrease by slashed amount"); - } -} +// // SPDX-License-Identifier: BUSL-1.1 +// pragma solidity ^0.8.27; + +// import "src/test/integration/tests/upgrade/UpgradeTest.t.sol"; + +// contract Integration_Upgrade_EigenPod_Slashing_Migration is UpgradeTest, EigenPodPausingConstants { +// uint[] shares; + +// function _init() internal override { +// _configAssetTypes(HOLDS_ETH); +// _configUserTypes(DEFAULT); + +// /// 0. Create a staker with underlying assets +// (staker, strategies, initTokenBalances) = _newRandomStaker(); +// shares = _calculateExpectedShares(strategies, initTokenBalances); + +// /// 1. Deposit into strategies +// staker.depositIntoEigenlayer(strategies, initTokenBalances); +// validators = staker.getActiveValidators(); +// } + +// function _completeEigenpodMigration() internal { +// // Start a checkpoint +// staker.startCheckpoint(); + +// // Pause checkpoint starting +// cheats.prank(pauserMultisig); +// eigenPodManager().pause(2 ** PAUSED_START_CHECKPOINT); +// cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); +// staker.startCheckpoint(); + +// // Complete in progress checkpoint +// staker.completeCheckpoint(); + +// // Upgrade Contracts for slashing +// _upgradeEigenLayerContracts(); + +// // Unpause EigenPodManager +// cheats.prank(eigenLayerPauserReg.unpauser()); +// eigenPodManager().unpause(0); +// } + +// function testFuzz_earnRewards_migrate_exit(uint24) public { +// // 2. Advance epoch, generating consensus rewards and withdrawing anything over 32 ETH +// beaconChain.advanceEpoch(); + +// // 3. Migrate & Upgrade +// _completeEigenpodMigration(); + +// // 4. Exit validators +// // Fully exit one or more validators and advance epoch without generating rewards +// uint40[] memory subset = _choose(validators); +// uint64 exitedBalanceGwei = staker.exitValidators(subset); +// beaconChain.advanceEpoch_NoRewards(); + +// staker.startCheckpoint(); +// check_StartCheckpoint_WithPodBalance_State(staker, exitedBalanceGwei); +// staker.completeCheckpoint(); +// check_CompleteCheckpoint_WithExits_State(staker, subset, exitedBalanceGwei); +// } + +// function testFuzz_slash_migrate(uint24) public { +// // 2. Slash validators +// uint40[] memory subset = _choose(validators); +// uint64 slashedGwei = beaconChain.slashValidators(subset, BeaconChainMock.SlashType(_randUint({min: 0, max: 2}))); +// beaconChain.advanceEpoch_NoRewards(); +// shares[0] = shares[0] - slashedGwei * GWEI_TO_WEI; // Shares should decrease by slashed amount + +// // 3. Migrate & Upgrade +// _completeEigenpodMigration(); + +// // Assertions +// assert_BCSF_WAD(staker, "BCSF should be WAD"); +// assert_ActiveValidatorCount(staker, validators.length - subset.length, "validator count should decrease"); +// assert_HasExpectedShares(staker, strategies, shares, "shares should decrease by slashed amount"); +// } +// } diff --git a/src/test/integration/tests/upgrade/Prooftra.t.sol b/src/test/integration/tests/upgrade/Prooftra.t.sol index c8aed1a6b3..2738b09c8b 100644 --- a/src/test/integration/tests/upgrade/Prooftra.t.sol +++ b/src/test/integration/tests/upgrade/Prooftra.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/UpgradeTest.t.sol"; +import "src/test/integration/tests/upgrade/UpgradeTest.t.sol"; contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { function _init() internal override { @@ -9,7 +9,7 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { _configUserTypes(DEFAULT); } - function test_Upgrade_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function test_Upgrade_VerifyWC_StartCP_CompleteCP(uint24) public { // 1. Pause, Fork, and Upgrade _pauseForkAndUpgrade(); @@ -34,7 +34,7 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { check_CompleteCheckpoint_State(staker); } - function test_VerifyWC_StartCP_Fork_CompleteCP(uint24 _rand) public rand(_rand) { + function test_VerifyWC_StartCP_Fork_CompleteCP(uint24) public { // Initialize state (User staker,,) = _newRandomStaker(); (uint40[] memory validators,,) = staker.startValidators(); @@ -57,7 +57,7 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { check_CompleteCheckpoint_State(staker); } - function test_VerifyWC_Fork_EarnToPod_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { + function test_VerifyWC_Fork_EarnToPod_StartCP_CompleteCP(uint24) public { // Initialize state (User staker,,) = _newRandomStaker(); (uint40[] memory validators,,) = staker.startValidators(); @@ -88,8 +88,8 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { function _pauseForkAndUpgrade() internal { // 1. Pause starting checkpoint, completing, and credential proofs - cheats.prank(pauserMultisig); - eigenPodManager.pause( + cheats.prank(pauserMultisig()); + eigenPodManager().pause( 2 ** PAUSED_START_CHECKPOINT | 2 ** PAUSED_EIGENPODS_VERIFY_CREDENTIALS | 2 ** PAUSED_VERIFY_STALE_BALANCE | 2 ** PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS ); @@ -102,14 +102,14 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { _upgradeEigenLayerContracts(); // 4. Set proof timestamp setter to operations multisig - cheats.prank(eigenPodManager.owner()); - eigenPodManager.setProofTimestampSetter(address(operationsMultisig)); + cheats.prank(eigenPodManager().owner()); + eigenPodManager().setProofTimestampSetter(address(operationsMultisig())); } function _setTimestampAndUnpause() internal { // 1. Set Timestamp - cheats.startPrank(eigenPodManager.proofTimestampSetter()); - eigenPodManager.setPectraForkTimestamp(BeaconChainMock_DenebForkable(address(beaconChain)).pectraForkTimestamp()); + cheats.startPrank(eigenPodManager().proofTimestampSetter()); + eigenPodManager().setPectraForkTimestamp(BeaconChainMock_DenebForkable(address(beaconChain)).pectraForkTimestamp()); cheats.stopPrank(); // 2. Randomly warp to just after the fork timestamp @@ -120,7 +120,7 @@ contract Integration_Upgrade_Pectra is UpgradeTest, EigenPodPausingConstants { } // 3. Unpause - cheats.prank(eigenLayerPauserReg.unpauser()); - eigenPodManager.unpause(0); + cheats.prank(pauserRegistry().unpauser()); + eigenPodManager().unpause(0); } } diff --git a/src/test/integration/tests/upgrade/README.md b/src/test/integration/tests/upgrade/README.md index c9844a3143..1b78871755 100644 --- a/src/test/integration/tests/upgrade/README.md +++ b/src/test/integration/tests/upgrade/README.md @@ -17,17 +17,17 @@ Say we want to check that withdrawals initiated before the slashing upgrade are ```solidity contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { - function testFuzz_deposit_queue_upgrade_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_deposit_queue_upgrade_completeAsShares(uint24) public { /// Pre-upgrade: /// 1. Create staker with some assets /// 2. Staker deposits into EigenLayer /// 3. Staker queues a withdrawal - (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + (staker, strategies, initTokenBalances) = _newRandomStaker(); User operator = User(payable(0)); - staker.depositIntoEigenlayer(strategies, tokenBalances); - uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + staker.depositIntoEigenlayer(strategies, initTokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, initTokenBalances); + Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); /// Upgrade to slashing contracts _upgradeEigenLayerContracts(); diff --git a/src/test/integration/tests/upgrade/UpgradeTest.t.sol b/src/test/integration/tests/upgrade/UpgradeTest.t.sol new file mode 100644 index 0000000000..ca419de989 --- /dev/null +++ b/src/test/integration/tests/upgrade/UpgradeTest.t.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/test/mocks/BeaconChainMock_Deneb.t.sol"; +import "src/test/integration/IntegrationChecks.t.sol"; + +abstract contract UpgradeTest is IntegrationChecks { + /// Only run upgrade tests on mainnet forks + function setUp() public virtual override { + // We do not run upgrade tests on local envs or non-mainnet forks... + if (!forkConfig.supportUpgradeTests) { + cheats.skip(true); + } else { + isUpgraded = false; + _setUp(false); + + cheats.etch(address(beaconChain), type(BeaconChainMock_DenebForkable).runtimeCode); + beaconChain.initialize(eigenPodManager(), BEACON_GENESIS_TIME); + } + } + + function _upgradeEigenLayerContracts() public virtual { + require(!isUpgraded, "_upgradeEigenLayerContracts: already performed upgrade"); + + _upgradeMainnetContracts(); + _handlePectraFork(); + + // Bump block.timestamp forward to allow verifyWC proofs for migrated pods + beaconChain.advanceEpoch_NoRewards(); + + isUpgraded = true; + } + + // Set the fork timestamp sufficiently in the future to keep using Deneb proofs + // `Prooftra.t.sol` will handle the Deneb -> Pectra transition + function _handlePectraFork() internal { + // 1. Set proof timestamp setter to operations multisig + cheats.prank(eigenPodManager().owner()); + eigenPodManager().setProofTimestampSetter(address(operationsMultisig())); + + // 2. Set Proof timestamp + cheats.prank(eigenPodManager().proofTimestampSetter()); + eigenPodManager().setPectraForkTimestamp(type(uint64).max); + } +} diff --git a/src/test/integration/users/AVS.t.sol b/src/test/integration/users/AVS.t.sol index 838c4ad25d..1667e4514d 100644 --- a/src/test/integration/users/AVS.t.sol +++ b/src/test/integration/users/AVS.t.sol @@ -2,50 +2,21 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; - -import "src/contracts/core/AllocationManager.sol"; -import "src/contracts/permissions/PermissionController.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/ArrayLib.sol"; -import "src/contracts/interfaces/IAVSRegistrar.sol"; - -interface IAVSDeployer { - function delegationManager() external view returns (DelegationManager); - function allocationManager() external view returns (AllocationManager); - function strategyFactory() external view returns (StrategyFactory); - function permissionController() external view returns (PermissionController); - function timeMachine() external view returns (TimeMachine); -} -contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { +contract AVS is Logger, IAllocationManagerTypes { using print for *; using ArrayLib for *; - IStrategy constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - // TODO: fix later for same reason as User.t.sol - AllocationManager immutable allocationManager; - PermissionController immutable permissionController; - DelegationManager immutable delegationManager; - StrategyFactory immutable strategyFactory; - TimeMachine immutable timeMachine; string _NAME; uint32 totalOperatorSets; + ConfigGetters public config; + constructor(string memory name) { - IAVSDeployer deployer = IAVSDeployer(msg.sender); - allocationManager = deployer.allocationManager(); - permissionController = deployer.permissionController(); - delegationManager = deployer.delegationManager(); - strategyFactory = deployer.strategyFactory(); - timeMachine = deployer.timeMachine(); + config = ConfigGetters(address(msg.sender)); _NAME = name; cheats.label(address(this), NAME_COLORED()); } @@ -61,10 +32,6 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { return _NAME; } - function supportsAVS(address) external pure override returns (bool) { - return true; - } - /// ----------------------------------------------------------------------- /// AllocationManager /// ----------------------------------------------------------------------- @@ -74,9 +41,7 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { console.log("Setting AVS metadata URI to: %s", uri); _tryPrankAppointee_AllocationManager(IAllocationManager.updateAVSMetadataURI.selector); - allocationManager.updateAVSMetadataURI(address(this), uri); - - print.gasUsed(); + config.allocationManager().updateAVSMetadataURI(address(this), uri); } function createOperatorSets(IStrategy[][] memory strategies) public createSnapshot returns (OperatorSet[] memory operatorSets) { @@ -94,9 +59,7 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { print.createOperatorSets(p); - allocationManager.createOperatorSets(address(this), p); - - print.gasUsed(); + config.allocationManager().createOperatorSets(address(this), p); } function createOperatorSet(IStrategy[] memory strategies) public createSnapshot returns (OperatorSet memory operatorSet) { @@ -107,13 +70,12 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { CreateSetParams[] memory p = CreateSetParams({operatorSetId: operatorSet.id, strategies: strategies}).toArray(); print.createOperatorSets(p); - allocationManager.createOperatorSets(address(this), p); - print.gasUsed(); + config.allocationManager().createOperatorSets(address(this), p); } function slashOperator(SlashingParams memory params) public createSnapshot { for (uint i; i < params.strategies.length; ++i) { - string memory strategyName = params.strategies[i] == beaconChainETHStrategy + string memory strategyName = params.strategies[i] == BEACONCHAIN_ETH_STRAT ? "Native ETH" : IERC20Metadata(address(params.strategies[i].underlyingToken())).name(); @@ -127,15 +89,14 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { ", strategy: ", strategyName, ", wadToSlash: ", - params.wadsToSlash[i].asWad(), + cheats.toString(params.wadsToSlash[i]), "}" ) ); } _tryPrankAppointee_AllocationManager(IAllocationManager.slashOperator.selector); - allocationManager.slashOperator(address(this), params); - print.gasUsed(); + config.allocationManager().slashOperator(address(this), params); } function slashOperator(User operator, uint32 operatorSetId, IStrategy[] memory strategies, uint[] memory wadsToSlash) @@ -153,7 +114,7 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { for (uint i; i < strategies.length; ++i) { string memory strategyName = - strategies[i] == beaconChainETHStrategy ? "Native ETH" : IERC20Metadata(address(strategies[i].underlyingToken())).name(); + strategies[i] == BEACONCHAIN_ETH_STRAT ? "Native ETH" : IERC20Metadata(address(strategies[i].underlyingToken())).name(); print.method( "slashOperator", @@ -165,15 +126,14 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { ", strategy: ", strategyName, ", wadToSlash: ", - wadsToSlash[i].asWad(), + cheats.toString(wadsToSlash[i]), "}" ) ); } _tryPrankAppointee_AllocationManager(IAllocationManager.slashOperator.selector); - allocationManager.slashOperator(address(this), p); - print.gasUsed(); + config.allocationManager().slashOperator(address(this), p); } function deregisterFromOperatorSets(User operator, uint32[] memory operatorSetIds) public createSnapshot { @@ -183,16 +143,14 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { print.deregisterFromOperatorSets(p); _tryPrankAppointee_AllocationManager(IAllocationManager.deregisterFromOperatorSets.selector); - allocationManager.deregisterFromOperatorSets(p); - print.gasUsed(); + config.allocationManager().deregisterFromOperatorSets(p); } function setAVSRegistrar(IAVSRegistrar registrar) public createSnapshot { print.method("setAVSRegistrar"); console.log("Setting AVS registrar to: %s", address(registrar)); _tryPrankAppointee_AllocationManager(IAllocationManager.setAVSRegistrar.selector); - allocationManager.setAVSRegistrar(address(this), registrar); - print.gasUsed(); + config.allocationManager().setAVSRegistrar(address(this), registrar); } function addStrategiesToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) public createSnapshot { @@ -204,8 +162,7 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { console.log(" strategy: %s", address(strategies[i])); } _tryPrankAppointee_AllocationManager(IAllocationManager.addStrategiesToOperatorSet.selector); - allocationManager.addStrategiesToOperatorSet(address(this), operatorSetId, strategies); - print.gasUsed(); + config.allocationManager().addStrategiesToOperatorSet(address(this), operatorSetId, strategies); } function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) public createSnapshot { @@ -217,39 +174,31 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar { console.log(" strategy: %s", address(strategies[i])); } _tryPrankAppointee_AllocationManager(IAllocationManager.removeStrategiesFromOperatorSet.selector); - allocationManager.removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies); - print.gasUsed(); + config.allocationManager().removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies); } /// ----------------------------------------------------------------------- /// IAVSRegistrar /// ----------------------------------------------------------------------- - function registerOperator(address operator, address avsIdentifier, uint32[] calldata operatorSetIds, bytes calldata data) - external - override - {} + function registerOperator(address operator, address avsIdentifier, uint32[] calldata operatorSetIds, bytes calldata data) external {} - function deregisterOperator(address operator, address avsIdentifier, uint32[] calldata operatorSetIds) external override {} + function deregisterOperator(address operator, address avsIdentifier, uint32[] calldata operatorSetIds) external {} + + function supportsAVS(address) external pure returns (bool) { + return true; + } /// ----------------------------------------------------------------------- /// Internal Helpers /// ----------------------------------------------------------------------- - // function allocationManager public view returns (AllocationManager) { - // return AllocationManager(address(delegationManager.allocationManager)); - // } - - // function permissionController public view returns (PermissionController) { - // return PermissionController(address(delegationManager.permissionController)); - // } - function _tryPrankAppointee(address target, bytes4 selector) internal { - address[] memory appointees = permissionController.getAppointees(address(this), target, selector); + address[] memory appointees = config.permissionController().getAppointees(address(this), target, selector); if (appointees.length != 0) cheats.prank(appointees[0]); } function _tryPrankAppointee_AllocationManager(bytes4 selector) internal { - return _tryPrankAppointee(address(allocationManager), selector); + return _tryPrankAppointee(address(config.allocationManager()), selector); } } diff --git a/src/test/integration/users/User.t.sol b/src/test/integration/users/User.t.sol index f97904acfc..4bc5d4b663 100644 --- a/src/test/integration/users/User.t.sol +++ b/src/test/integration/users/User.t.sol @@ -2,52 +2,21 @@ 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/permissions/PermissionController.sol"; -import "src/contracts/core/StrategyManager.sol"; -import "src/contracts/pods/EigenPodManager.sol"; -import "src/contracts/pods/EigenPod.sol"; - -import "src/test/integration/TimeMachine.t.sol"; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/utils/Logger.t.sol"; +import "src/test/Config.t.sol"; import "src/test/utils/ArrayLib.sol"; +import "src/test/utils/Constants.t.sol"; +import "src/test/utils/Logger.t.sol"; struct Validator { uint40 index; } -interface IUserDeployer { - function allocationManager() external view returns (AllocationManager); - function delegationManager() external view returns (DelegationManager); - function permissionController() external view returns (PermissionController); - function strategyManager() external view returns (StrategyManager); - function eigenPodManager() external view returns (EigenPodManager); - function timeMachine() external view returns (TimeMachine); - function beaconChain() external view returns (BeaconChainMock); -} - contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { using StdStyle for *; using SlashingLib for *; using ArrayLib for *; using print for *; - IStrategy constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); - - // TODO: fix this and view function getters. These are newly added contracts so these are initially - // 0 addresses for fork tests. To work around this, we read these addresses directly off the delegationManager - // from its immutable addresses. This is a temporary solution until we can figure out a better way to handle this. - // AllocationManager allocationManager; - // PermissionController permissionController; - DelegationManager delegationManager; - StrategyManager strategyManager; - EigenPodManager eigenPodManager; - TimeMachine timeMachine; - BeaconChainMock beaconChain; - uint32 public allocationDelay = 1; string _NAME; @@ -56,20 +25,12 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { EigenPod public pod; uint40[] validators; - constructor(string memory name) { - IUserDeployer deployer = IUserDeployer(msg.sender); + ConfigGetters public config; - // TODO uncommented for reason above - // allocationManager = deployer.allocationManager(); - // permissionController = deployer.permissionController(); - delegationManager = deployer.delegationManager(); - strategyManager = deployer.strategyManager(); - eigenPodManager = deployer.eigenPodManager(); - - timeMachine = deployer.timeMachine(); - beaconChain = deployer.beaconChain(); - - _createPod(); + constructor(string memory name) { + config = ConfigGetters(address(msg.sender)); + ForkConfig memory forkConfig = ConfigParser.parseForkConfig(cheats.envOr("FOUNDRY_PROFILE", string("default"))); + if (forkConfig.supportEigenPodTests) _createPod(); _NAME = name; cheats.label(address(this), NAME_COLORED()); } @@ -89,8 +50,6 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { /// Allocation Manager Methods /// ----------------------------------------------------------------------- - /// @dev Allocates randomly across the operator set's strategies with a sum of `magnitudeSum`. - /// NOTE: Calling more than once will lead to deallocations... function modifyAllocations(AllocateParams memory params) public virtual createSnapshot { print.method( "modifyAllocations", @@ -100,14 +59,13 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { ); _tryPrankAppointee_AllocationManager(IAllocationManager.modifyAllocations.selector); - allocationManager().modifyAllocations(address(this), params.toArray()); - print.gasUsed(); + config.allocationManager().modifyAllocations(address(this), params.toArray()); } function deallocateAll(OperatorSet memory operatorSet) public virtual returns (AllocateParams memory) { AllocateParams memory params; params.operatorSet = operatorSet; - params.strategies = allocationManager().getStrategiesInOperatorSet(operatorSet); + params.strategies = config.allocationManager().getStrategiesInOperatorSet(operatorSet); params.newMagnitudes = new uint64[](params.strategies.length); modifyAllocations(params); @@ -128,10 +86,9 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { ); _tryPrankAppointee_AllocationManager(IAllocationManager.registerForOperatorSets.selector); - allocationManager().registerForOperatorSets( + config.allocationManager().registerForOperatorSets( address(this), RegisterParams({avs: operatorSet.avs, operatorSetIds: operatorSet.id.toArrayU32(), data: ""}) ); - print.gasUsed(); } function deregisterFromOperatorSet(OperatorSet memory operatorSet) public virtual createSnapshot { @@ -141,17 +98,15 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { ); _tryPrankAppointee_AllocationManager(IAllocationManager.deregisterFromOperatorSets.selector); - allocationManager().deregisterFromOperatorSets( + config.allocationManager().deregisterFromOperatorSets( DeregisterParams({operator: address(this), avs: operatorSet.avs, operatorSetIds: operatorSet.id.toArrayU32()}) ); - print.gasUsed(); } function setAllocationDelay(uint32 delay) public virtual createSnapshot { print.method("setAllocationDelay"); _tryPrankAppointee_AllocationManager(IAllocationManager.setAllocationDelay.selector); - allocationManager().setAllocationDelay(address(this), delay); - print.gasUsed(); + config.allocationManager().setAllocationDelay(address(this), delay); allocationDelay = delay; } @@ -162,8 +117,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { function registerAsOperator() public virtual createSnapshot { print.method("registerAsOperator"); - delegationManager.registerAsOperator(address(0), allocationDelay, "metadata"); - print.gasUsed(); + config.delegationManager().registerAsOperator(address(0), allocationDelay, "metadata"); } /// @dev Delegate to the operator without a signature @@ -171,8 +125,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { print.method("delegateTo", operator.NAME_COLORED()); ISignatureUtilsMixinTypes.SignatureWithExpiry memory emptySig; - delegationManager.delegateTo(address(operator), emptySig, bytes32(0)); - print.gasUsed(); + config.delegationManager().delegateTo(address(operator), emptySig, bytes32(0)); } /// @dev Undelegate from operator @@ -181,13 +134,12 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(this)); _tryPrankAppointee_DelegationManager(IDelegationManager.undelegate.selector); - delegationManager.undelegate(address(this)); - print.gasUsed(); + config.delegationManager().undelegate(address(this)); for (uint i = 0; i < expectedWithdrawals.length; i++) { IStrategy strat = expectedWithdrawals[i].strategies[0]; - string memory name = strat == beaconChainETHStrategy ? "Native ETH" : IERC20Metadata(address(strat.underlyingToken())).name(); + string memory name = strat == BEACONCHAIN_ETH_STRAT ? "Native ETH" : IERC20Metadata(address(strat.underlyingToken())).name(); console.log( " Expecting withdrawal with nonce %s of %s for %s scaled shares.", @@ -206,13 +158,12 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(this)); ISignatureUtilsMixinTypes.SignatureWithExpiry memory emptySig; _tryPrankAppointee_DelegationManager(IDelegationManager.redelegate.selector); - delegationManager.redelegate(address(newOperator), emptySig, bytes32(0)); - print.gasUsed(); + config.delegationManager().redelegate(address(newOperator), emptySig, bytes32(0)); for (uint i = 0; i < expectedWithdrawals.length; i++) { IStrategy strat = expectedWithdrawals[i].strategies[0]; - string memory name = strat == beaconChainETHStrategy ? "Native ETH" : IERC20Metadata(address(strat.underlyingToken())).name(); + string memory name = strat == BEACONCHAIN_ETH_STRAT ? "Native ETH" : IERC20Metadata(address(strat.underlyingToken())).name(); console.log( " Expecting withdrawal with nonce %s of %s for %s scaled shares.", @@ -229,8 +180,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { print.method("forceUndelegate", staker.NAME()); Withdrawal[] memory expectedWithdrawals = _getExpectedWithdrawalStructsForStaker(address(staker)); - delegationManager.undelegate(address(staker)); - print.gasUsed(); + config.delegationManager().undelegate(address(staker)); return expectedWithdrawals; } @@ -244,8 +194,8 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { { print.method("queueWithdrawals"); - address operator = delegationManager.delegatedTo(address(this)); - uint nonce = delegationManager.cumulativeWithdrawalsQueued(address(this)); + address operator = config.delegationManager().delegatedTo(address(this)); + uint nonce = config.delegationManager().cumulativeWithdrawalsQueued(address(this)); // Create queueWithdrawals params QueuedWithdrawalParams[] memory params = new QueuedWithdrawalParams[](1); @@ -253,7 +203,8 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { uint[] memory scaledSharesForWithdrawal = new uint[](strategies.length); for (uint i = 0; i < strategies.length; ++i) { - DepositScalingFactor memory dsf = DepositScalingFactor(delegationManager.depositScalingFactor(address(this), strategies[i])); + DepositScalingFactor memory dsf = + DepositScalingFactor(config.delegationManager().depositScalingFactor(address(this), strategies[i])); scaledSharesForWithdrawal[i] = dsf.scaleForQueueWithdrawal(depositShares[i]); } @@ -270,8 +221,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { scaledShares: scaledSharesForWithdrawal }); - bytes32[] memory withdrawalRoots = delegationManager.queueWithdrawals(params); - print.gasUsed(); + bytes32[] memory withdrawalRoots = config.delegationManager().queueWithdrawals(params); // Basic sanity check - we do all other checks outside this file assertEq(withdrawals.length, withdrawalRoots.length, "User.queueWithdrawals: length mismatch"); @@ -404,9 +354,8 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { _verifyWithdrawalCredentials(newValidators); } else { IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokenBalance); - strategyManager.depositIntoStrategy(strat, underlyingToken, tokenBalance); - print.gasUsed(); + underlyingToken.approve(address(config.strategyManager()), tokenBalance); + config.strategyManager().depositIntoStrategy(strat, underlyingToken, tokenBalance); } } } @@ -425,9 +374,8 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { } else { uint tokens = uint(delta); IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokens); - strategyManager.depositIntoStrategy(strat, underlyingToken, tokens); - print.gasUsed(); + underlyingToken.approve(address(config.strategyManager()), tokens); + config.strategyManager().depositIntoStrategy(strat, underlyingToken, tokens); } } } @@ -436,14 +384,6 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { /// View Methods /// ----------------------------------------------------------------------- - function allocationManager() public view returns (AllocationManager) { - return AllocationManager(address(delegationManager.allocationManager())); - } - - function permissionController() public view returns (PermissionController) { - return PermissionController(address(delegationManager.permissionController())); - } - function getSlashingFactor(IStrategy strategy) public view returns (uint) { return _getSlashingFactor(address(this), strategy); } @@ -463,7 +403,7 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { // If we're withdrawing native ETH as tokens && do not have negative shares // stop ALL validators and complete a checkpoint - if (receiveAsTokens && eigenPodManager.podOwnerDepositShares(address(this)) >= 0) { + if (receiveAsTokens && config.eigenPodManager().podOwnerDepositShares(address(this)) >= 0) { console.log("- exiting all validators and completing checkpoint"); _exitValidators(getActiveValidators()); @@ -477,14 +417,13 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { } } - delegationManager.completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); - print.gasUsed(); + config.delegationManager().completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens); return tokens; } function _createPod() internal virtual { - pod = EigenPod(payable(eigenPodManager.createPod())); + pod = EigenPod(payable(config.eigenPodManager().createPod())); } /// @dev Uses any ETH held by the User to start validators on the beacon chain @@ -634,26 +573,26 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { } function _getSlashingFactor(address staker, IStrategy strategy) internal view returns (uint) { - address operator = delegationManager.delegatedTo(staker); - uint64 maxMagnitude = allocationManager().getMaxMagnitudes(operator, strategy.toArray())[0]; - if (strategy == beaconChainETHStrategy) return maxMagnitude.mulWad(eigenPodManager.beaconChainSlashingFactor(staker)); + address operator = config.delegationManager().delegatedTo(staker); + uint64 maxMagnitude = config.allocationManager().getMaxMagnitudes(operator, strategy.toArray())[0]; + if (strategy == BEACONCHAIN_ETH_STRAT) return maxMagnitude.mulWad(config.eigenPodManager().beaconChainSlashingFactor(staker)); return maxMagnitude; } /// @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 (Withdrawal[] memory expectedWithdrawals) { - (IStrategy[] memory strategies,) = delegationManager.getDepositedShares(staker); + (IStrategy[] memory strategies,) = config.delegationManager().getDepositedShares(staker); expectedWithdrawals = new Withdrawal[](strategies.length); - (, uint[] memory depositShares) = delegationManager.getWithdrawableShares(staker, strategies); + (, uint[] memory depositShares) = config.delegationManager().getWithdrawableShares(staker, strategies); - address delegatedTo = delegationManager.delegatedTo(staker); - uint nonce = delegationManager.cumulativeWithdrawalsQueued(staker); + address delegatedTo = config.delegationManager().delegatedTo(staker); + uint nonce = config.delegationManager().cumulativeWithdrawalsQueued(staker); for (uint i = 0; i < strategies.length; ++i) { - DepositScalingFactor memory dsf = DepositScalingFactor(delegationManager.depositScalingFactor(staker, strategies[i])); + DepositScalingFactor memory dsf = DepositScalingFactor(config.delegationManager().depositScalingFactor(staker, strategies[i])); uint scaledShares = dsf.scaleForQueueWithdrawal(depositShares[i]); @@ -691,16 +630,16 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes { } function _tryPrankAppointee(address target, bytes4 selector) internal { - address[] memory appointees = permissionController().getAppointees(address(this), target, selector); + address[] memory appointees = config.permissionController().getAppointees(address(this), target, selector); if (appointees.length != 0) cheats.prank(appointees[0]); } function _tryPrankAppointee_AllocationManager(bytes4 selector) internal { - return _tryPrankAppointee(address(allocationManager()), selector); + return _tryPrankAppointee(address(config.allocationManager()), selector); } function _tryPrankAppointee_DelegationManager(bytes4 selector) internal { - return _tryPrankAppointee(address(delegationManager), selector); + return _tryPrankAppointee(address(config.delegationManager()), selector); } } @@ -726,21 +665,31 @@ contract User_AltMethods is User { } else { // Approve token IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokenBalance); + underlyingToken.approve(address(config.strategyManager()), tokenBalance); // Get signature - uint nonceBefore = strategyManager.nonces(address(this)); + uint nonceBefore = config.strategyManager().nonces(address(this)); bytes32 structHash = keccak256( - abi.encode(strategyManager.DEPOSIT_TYPEHASH(), address(this), strat, underlyingToken, tokenBalance, nonceBefore, expiry) + abi.encode( + config.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", config.strategyManager().domainSeparator(), structHash)); bytes memory signature = bytes(abi.encodePacked(digestHash)); // dummy sig data // Mark hash as signed signedHashes[digestHash] = true; // Deposit - strategyManager.depositIntoStrategyWithSignature(strat, underlyingToken, tokenBalance, address(this), expiry, signature); + config.strategyManager().depositIntoStrategyWithSignature( + strat, underlyingToken, tokenBalance, address(this), expiry, signature + ); // Mark hash as used signedHashes[digestHash] = false; diff --git a/src/test/integration/users/User_M1.t.sol b/src/test/integration/users/User_M1.t.sol index 3e4d31bda5..ccff389d91 100644 --- a/src/test/integration/users/User_M1.t.sol +++ b/src/test/integration/users/User_M1.t.sol @@ -1,21 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 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/deprecated/mainnet/IEigenPod.sol"; +import "src/test/integration/deprecated/mainnet/IEigenPodManager.sol"; +import "src/test/integration/deprecated/mainnet/IStrategyManager.sol"; import "src/test/integration/users/User.t.sol"; -import "src/contracts/mixins/SignatureUtilsMixin.sol"; - -interface IUserM1MainnetForkDeployer { - function delegationManager() external view returns (DelegationManager); - function strategyManager() external view returns (StrategyManager); - function eigenPodManager() external view returns (EigenPodManager); - function timeMachine() external view returns (TimeMachine); - function beaconChain() external view returns (BeaconChainMock); - function strategyManager_M1() external view returns (IStrategyManager_DeprecatedM1); - function eigenPodManager_M1() external view returns (IEigenPodManager_DeprecatedM1); -} /** * @dev User_M1 used for performing mainnet M1 contract methods but also inherits User @@ -26,10 +15,9 @@ contract User_M1 is User { IEigenPodManager_DeprecatedM1 eigenPodManager_M1; constructor(string memory name) User(name) { - IUserM1MainnetForkDeployer deployer = IUserM1MainnetForkDeployer(msg.sender); - - strategyManager_M1 = IStrategyManager_DeprecatedM1(address(deployer.strategyManager())); - eigenPodManager_M1 = IEigenPodManager_DeprecatedM1(address(deployer.eigenPodManager())); + ConfigGetters config = ConfigGetters(msg.sender); + strategyManager_M1 = IStrategyManager_DeprecatedM1(address(config.strategyManager())); + eigenPodManager_M1 = IEigenPodManager_DeprecatedM1(address(config.eigenPodManager())); cheats.label(address(this), NAME_COLORED()); } @@ -50,15 +38,15 @@ contract User_M1 is User { if (strat == BEACONCHAIN_ETH_STRAT) continue; IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokenBalance); - strategyManager.depositIntoStrategy(strat, underlyingToken, tokenBalance); + underlyingToken.approve(address(config.strategyManager()), tokenBalance); + config.strategyManager().depositIntoStrategy(strat, underlyingToken, tokenBalance); } } function _createPod() internal virtual override { - IEigenPodManager_DeprecatedM1(address(eigenPodManager)).createPod(); + IEigenPodManager_DeprecatedM1(address(config.eigenPodManager())).createPod(); // get EigenPod address - pod = EigenPod(payable(address(IEigenPodManager_DeprecatedM1(address(eigenPodManager)).ownerToPod(address(this))))); + pod = EigenPod(payable(address(IEigenPodManager_DeprecatedM1(address(config.eigenPodManager())).ownerToPod(address(this))))); } } @@ -79,13 +67,14 @@ contract User_M1_AltMethods is User_M1 { // Approve token IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokenBalance); + underlyingToken.approve(address(config.strategyManager()), tokenBalance); // Get signature - uint nonceBefore = strategyManager.nonces(address(this)); - bytes32 structHash = - keccak256(abi.encode(strategyManager.DEPOSIT_TYPEHASH(), strat, underlyingToken, tokenBalance, nonceBefore, expiry)); - bytes32 domain_separator = strategyManager.domainSeparator(); + uint nonceBefore = config.strategyManager().nonces(address(this)); + bytes32 structHash = keccak256( + abi.encode(config.strategyManager().DEPOSIT_TYPEHASH(), strat, underlyingToken, tokenBalance, nonceBefore, expiry) + ); + bytes32 domain_separator = config.strategyManager().domainSeparator(); bytes32 digestHash = keccak256(abi.encodePacked("\x19\x01", domain_separator, structHash)); bytes memory signature = bytes(abi.encodePacked(digestHash)); // dummy sig data @@ -93,7 +82,9 @@ contract User_M1_AltMethods is User_M1 { signedHashes[digestHash] = true; // Deposit - strategyManager.depositIntoStrategyWithSignature(strat, underlyingToken, tokenBalance, address(this), expiry, signature); + config.strategyManager().depositIntoStrategyWithSignature( + strat, underlyingToken, tokenBalance, address(this), expiry, signature + ); // Mark hash as used signedHashes[digestHash] = false; diff --git a/src/test/integration/users/User_M2.t.sol b/src/test/integration/users/User_M2.t.sol index 0ddbd653b4..4f860a7133 100644 --- a/src/test/integration/users/User_M2.t.sol +++ b/src/test/integration/users/User_M2.t.sol @@ -2,28 +2,11 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; - -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/deprecatedInterfaces/mainnet/IDelegationManager.sol"; - +import "src/test/integration/deprecated/mainnet/IDelegationManager.sol"; +import "src/test/integration/deprecated/mainnet/IEigenPod.sol"; +import "src/test/integration/deprecated/mainnet/IEigenPodManager.sol"; +import "src/test/integration/deprecated/mainnet/IStrategyManager.sol"; import "src/test/integration/users/User.t.sol"; -import "src/test/integration/TimeMachine.t.sol"; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/utils/Logger.t.sol"; -import "src/test/utils/ArrayLib.sol"; - -interface IUserM2MainnetForkDeployer { - function delegationManager() external view returns (DelegationManager); - function strategyManager() external view returns (StrategyManager); - function eigenPodManager() external view returns (EigenPodManager); - function delegationManager_M2() external view returns (IDelegationManager_DeprecatedM2); - function strategyManager_M2() external view returns (IStrategyManager_DeprecatedM2); - function eigenPodManager_M2() external view returns (IEigenPodManager_DeprecatedM2); - function timeMachine() external view returns (TimeMachine); - function beaconChain() external view returns (BeaconChainMock); -} /** * @dev User_M2 used for performing mainnet M2 contract methods but also inherits User @@ -39,11 +22,10 @@ contract User_M2 is User { IEigenPodManager_DeprecatedM2 eigenPodManager_M2; constructor(string memory name) User(name) { - IUserM2MainnetForkDeployer deployer = IUserM2MainnetForkDeployer(msg.sender); - - delegationManager_M2 = IDelegationManager_DeprecatedM2(address(deployer.delegationManager())); - strategyManager_M2 = IStrategyManager_DeprecatedM2(address(deployer.strategyManager())); - eigenPodManager_M2 = IEigenPodManager_DeprecatedM2(address(deployer.eigenPodManager())); + ConfigGetters config = ConfigGetters(msg.sender); + delegationManager_M2 = IDelegationManager_DeprecatedM2(address(config.delegationManager())); + strategyManager_M2 = IStrategyManager_DeprecatedM2(address(config.strategyManager())); + eigenPodManager_M2 = IEigenPodManager_DeprecatedM2(address(config.eigenPodManager())); cheats.label(address(this), NAME_COLORED()); } @@ -142,7 +124,7 @@ contract User_M2 is User { } else { uint tokens = uint(delta); IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokens); + underlyingToken.approve(address(config.strategyManager()), tokens); strategyManager_M2.depositIntoStrategy(strat, underlyingToken, tokens); } } @@ -218,73 +200,6 @@ contract User_M2 is User { pod.verifyCheckpointProofs({balanceContainerProof: proofs.balanceContainerProof, proofs: proofs.balanceProofs}); cheats.resumeTracing(); } - - function _completeQueuedWithdrawal_M2(IDelegationManager_DeprecatedM2.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++) { - IStrategy strat = withdrawal.strategies[i]; - - if (strat == BEACONCHAIN_ETH_STRAT) { - tokens[i] = NATIVE_ETH; - - // If we're withdrawing native ETH as tokens, stop ALL validators - // and complete a checkpoint - if (receiveAsTokens) { - console.log("- exiting all validators and completing checkpoint"); - _exitValidators(getActiveValidators()); - - beaconChain.advanceEpoch_NoRewards(); - - _startCheckpoint(); - if (pod.activeValidatorCount() != 0) _completeCheckpoint(); - } - } else { - tokens[i] = strat.underlyingToken(); - } - } - - delegationManager_M2.completeQueuedWithdrawal(withdrawal, tokens, 0, receiveAsTokens); - - return tokens; - } - - /// @notice Gets the expected withdrawals to be created when the staker is undelegated via a call to `delegationManager_M2.undelegate()` - /// @notice Assumes staker and withdrawer are the same and that all strategies and shares are withdrawn - function _getExpectedM2WithdrawalStructsForStaker(address staker) - internal - view - returns (IDelegationManager_DeprecatedM2.Withdrawal[] memory) - { - (IStrategy[] memory strategies, uint[] memory shares) = delegationManager_M2.getDelegatableShares(staker); - - IDelegationManager_DeprecatedM2.Withdrawal[] memory expectedWithdrawals = - new IDelegationManager_DeprecatedM2.Withdrawal[](strategies.length); - address delegatedTo = delegationManager_M2.delegatedTo(staker); - uint nonce = delegationManager_M2.cumulativeWithdrawalsQueued(staker); - - for (uint i = 0; i < strategies.length; ++i) { - IStrategy[] memory singleStrategy = new IStrategy[](1); - uint[] memory singleShares = new uint[](1); - singleStrategy[0] = strategies[i]; - singleShares[0] = shares[i]; - expectedWithdrawals[i] = IDelegationManager_DeprecatedM2.Withdrawal({ - staker: staker, - delegatedTo: delegatedTo, - withdrawer: staker, - nonce: (nonce + i), - startBlock: uint32(block.number), - strategies: singleStrategy, - shares: singleShares - }); - } - - return expectedWithdrawals; - } } /// @notice A user contract that calls nonstandard methods (like xBySignature methods) @@ -309,7 +224,7 @@ contract User_M2_AltMethods is User_M2 { } else { // Approve token IERC20 underlyingToken = strat.underlyingToken(); - underlyingToken.approve(address(strategyManager), tokenBalance); + underlyingToken.approve(address(config.strategyManager()), tokenBalance); // Get signature uint nonceBefore = strategyManager_M2.nonces(address(this)); diff --git a/src/test/integration/mocks/BeaconChainMock.t.sol b/src/test/mocks/BeaconChainMock.t.sol similarity index 95% rename from src/test/integration/mocks/BeaconChainMock.t.sol rename to src/test/mocks/BeaconChainMock.t.sol index 09cd3642cd..dd7c62648d 100644 --- a/src/test/integration/mocks/BeaconChainMock.t.sol +++ b/src/test/mocks/BeaconChainMock.t.sol @@ -7,9 +7,10 @@ import "src/contracts/libraries/BeaconChainProofs.sol"; import "src/contracts/libraries/Merkle.sol"; import "src/contracts/pods/EigenPodManager.sol"; +import "src/test/mocks/EIP_4788_Oracle_Mock.t.sol"; import "src/test/mocks/ETHDepositMock.sol"; -import "src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol"; -import "src/test/utils/Logger.t.sol"; + +import "src/test/utils/Constants.t.sol"; struct ValidatorFieldsProof { bytes32[] validatorFields; @@ -47,9 +48,8 @@ struct StaleBalanceProofs { * - Ceiling is Max EB, at which sweeps will be triggered * - No support for consolidations or any execution layer triggerable actions (exits, partial withdrawals) */ -contract BeaconChainMock is Logger { +contract BeaconChainMock { using StdStyle for *; - using print for *; struct Validator { bool isDummy; @@ -70,7 +70,7 @@ contract BeaconChainMock is Logger { } /// @dev All withdrawals are processed with index == 0 - uint constant ZERO_NODES_LENGTH = 100; + uint public constant ZERO_NODES_LENGTH = 100; // Rewards given to each validator during epoch processing uint64 public constant CONSENSUS_REWARD_AMOUNT_GWEI = 1; @@ -78,29 +78,25 @@ contract BeaconChainMock is Logger { // Max effective balance for a validator // see https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#gwei-values - uint public MAX_EFFECTIVE_BALANCE_WEI = 2048 ether; - uint64 public MAX_EFFECTIVE_BALANCE_GWEI = 2048 gwei; + uint public MAX_EFFECTIVE_BALANCE_WEI; + uint64 public MAX_EFFECTIVE_BALANCE_GWEI; /// PROOF CONSTANTS (PROOF LENGTHS, FIELD SIZES): /// @dev Non-constant values will change with the Pectra hard fork // see https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#beaconstate - uint BEACON_STATE_FIELDS = 37; + uint public BEACON_STATE_FIELDS; // see https://eth2book.info/capella/part3/containers/blocks/#beaconblock - uint constant BEACON_BLOCK_FIELDS = 5; - - uint immutable BLOCKROOT_PROOF_LEN = 32 * BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT; - uint VAL_FIELDS_PROOF_LEN = 32 * ((BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.PECTRA_BEACON_STATE_TREE_HEIGHT); - uint BALANCE_CONTAINER_PROOF_LEN = - 32 * (BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT + BeaconChainProofs.PECTRA_BEACON_STATE_TREE_HEIGHT); - uint immutable BALANCE_PROOF_LEN = 32 * (BeaconChainProofs.BALANCE_TREE_HEIGHT + 1); + uint public BEACON_BLOCK_FIELDS; + uint public BLOCKROOT_PROOF_LEN; + uint public VAL_FIELDS_PROOF_LEN; + uint public BALANCE_CONTAINER_PROOF_LEN; + uint public BALANCE_PROOF_LEN; - uint64 genesisTime; + uint64 public genesisTime; uint64 public nextTimestamp; EigenPodManager eigenPodManager; - IETHPOSDeposit constant DEPOSIT_CONTRACT = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); - EIP_4788_Oracle_Mock constant EIP_4788_ORACLE = EIP_4788_Oracle_Mock(0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02); /** * BeaconState containers, used for proofgen: @@ -142,15 +138,23 @@ contract BeaconChainMock is Logger { bytes32[] zeroNodes; - constructor(EigenPodManager _eigenPodManager, uint64 _genesisTime) { + function initialize(EigenPodManager _eigenPodManager, uint64 _genesisTime) external virtual { genesisTime = _genesisTime; eigenPodManager = _eigenPodManager; - // Create mock 4788 oracle cheats.etch(address(DEPOSIT_CONTRACT), type(ETHPOSDepositMock).runtimeCode); cheats.etch(address(EIP_4788_ORACLE), type(EIP_4788_Oracle_Mock).runtimeCode); - // Calculate nodes of empty merkle tree + MAX_EFFECTIVE_BALANCE_WEI = 2048 ether; + MAX_EFFECTIVE_BALANCE_GWEI = 2048 gwei; + BEACON_STATE_FIELDS = 37; + BEACON_BLOCK_FIELDS = 5; + BLOCKROOT_PROOF_LEN = 32 * BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT; + VAL_FIELDS_PROOF_LEN = 32 * ((BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.PECTRA_BEACON_STATE_TREE_HEIGHT); + BALANCE_CONTAINER_PROOF_LEN = + 32 * (BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT + BeaconChainProofs.PECTRA_BEACON_STATE_TREE_HEIGHT); + BALANCE_PROOF_LEN = 32 * (BeaconChainProofs.BALANCE_TREE_HEIGHT + 1); + bytes32 curNode = Merkle.merkleizeSha256(new bytes32[](8)); zeroNodes = new bytes32[](ZERO_NODES_LENGTH); zeroNodes[0] = curNode; @@ -161,10 +165,6 @@ contract BeaconChainMock is Logger { } } - function NAME() public pure virtual override returns (string memory) { - return "BeaconChain"; - } - /** * * EXTERNAL METHODS @@ -176,7 +176,7 @@ contract BeaconChainMock is Logger { /// - Setting their current/effective balance /// - Assigning them a new, unique index function newValidator(bytes memory withdrawalCreds) public payable returns (uint40) { - print.method("newValidator"); + console.log("BeaconChain.newValidator()"); uint balanceWei = msg.value; @@ -212,7 +212,7 @@ contract BeaconChainMock is Logger { /// /// 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) { - print.method("exitValidator"); + console.log("BeaconChain.exitValidator()"); // Update validator.exitEpoch Validator storage v = validators[validatorIndex]; @@ -232,7 +232,7 @@ contract BeaconChainMock is Logger { } function slashValidators(uint40[] memory _validators, SlashType _slashType) public returns (uint64 slashedBalanceGwei) { - print.method("slashValidators"); + console.log("BeaconChain.slashValidators()"); for (uint i = 0; i < _validators.length; i++) { uint40 validatorIndex = _validators[i]; @@ -272,7 +272,7 @@ contract BeaconChainMock is Logger { } function slashValidators(uint40[] memory _validators, uint64 _slashAmountGwei) public { - print.method("slashValidatorsAmountGwei"); + console.log("BeaconChain.slashValidatorsAmountGwei()"); for (uint i = 0; i < _validators.length; i++) { uint40 validatorIndex = _validators[i]; @@ -319,7 +319,7 @@ contract BeaconChainMock is Logger { /// - DOES generate consensus rewards for ALL non-exited validators /// - DOES withdraw in excess of Max EB / if validator is exited function advanceEpoch() public { - print.method("advanceEpoch"); + console.log("BeaconChain.advanceEpoch()"); _generateRewards(); _withdrawExcess(); _advanceEpoch(); @@ -333,7 +333,7 @@ contract BeaconChainMock is Logger { /// - does NOT generate consensus rewards /// - DOES withdraw in excess of Max EB / if validator is exited function advanceEpoch_NoRewards() public { - print.method("advanceEpoch_NoRewards"); + console.log("BeaconChain.advanceEpoch_NoRewards()"); _withdrawExcess(); _advanceEpoch(); } @@ -347,13 +347,13 @@ contract BeaconChainMock is Logger { /// - does NOT withdraw in excess of Max EB /// - does NOT withdraw if validator is exited function advanceEpoch_NoWithdraw() public { - print.method("advanceEpoch_NoWithdraw"); + console.log("BeaconChain.advanceEpoch_NoWithdraw()"); _generateRewards(); _advanceEpoch(); } function advanceEpoch_NoWithdrawNoRewards() public { - print.method("advanceEpoch_NoWithdrawNoRewards"); + console.log("BeaconChain.advanceEpoch_NoWithdrawNoRewards()"); _advanceEpoch(); } @@ -412,7 +412,7 @@ contract BeaconChainMock is Logger { _setCurrentBalance(uint40(i), newBalanceGwei); } - if (totalExcessWei != 0) console.log("- Withdrew excess balance:", totalExcessWei.asGwei()); + if (totalExcessWei != 0) console.log("- Withdrew excess balance:", totalExcessWei); } function _advanceEpoch() public virtual { @@ -794,7 +794,7 @@ contract BeaconChainMock is Logger { return leaves; } - function _getBeaconBlockLeaves(bytes32 beaconStateRoot) internal pure returns (bytes32[] memory) { + function _getBeaconBlockLeaves(bytes32 beaconStateRoot) internal view returns (bytes32[] memory) { bytes32[] memory leaves = new bytes32[](BEACON_BLOCK_FIELDS); // Pre-populate leaves with dummy values so sibling/parent tracking is correct diff --git a/src/test/integration/mocks/BeaconChainMock_Deneb.t.sol b/src/test/mocks/BeaconChainMock_Deneb.t.sol similarity index 90% rename from src/test/integration/mocks/BeaconChainMock_Deneb.t.sol rename to src/test/mocks/BeaconChainMock_Deneb.t.sol index aeb47f6e03..4f4717939d 100644 --- a/src/test/integration/mocks/BeaconChainMock_Deneb.t.sol +++ b/src/test/mocks/BeaconChainMock_Deneb.t.sol @@ -1,37 +1,45 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; +import "src/test/mocks/BeaconChainMock.t.sol"; /// @notice A backwards-compatible BeaconChain Mock that updates containers & proofs from Deneb to Pectra contract BeaconChainMock_DenebForkable is BeaconChainMock { using StdStyle for *; - using print for *; // Denotes whether the beacon chain has been forked to Pectra - bool isPectra; + bool public isPectra; // The timestamp of the Pectra hard fork uint64 public pectraForkTimestamp; - constructor(EigenPodManager _eigenPodManager, uint64 _genesisTime) BeaconChainMock(_eigenPodManager, _genesisTime) { + function initialize(EigenPodManager _eigenPodManager, uint64 _genesisTime) external virtual override { + genesisTime = _genesisTime; + eigenPodManager = _eigenPodManager; + + // Create mock 4788 oracle + cheats.etch(address(DEPOSIT_CONTRACT), type(ETHPOSDepositMock).runtimeCode); + cheats.etch(address(EIP_4788_ORACLE), type(EIP_4788_Oracle_Mock).runtimeCode); + + // Calculate nodes of empty merkle tree + bytes32 curNode = Merkle.merkleizeSha256(new bytes32[](8)); + zeroNodes = new bytes32[](ZERO_NODES_LENGTH); + zeroNodes[0] = curNode; + + for (uint i = 1; i < zeroNodes.length; i++) { + zeroNodes[i] = sha256(abi.encodePacked(curNode, curNode)); + curNode = zeroNodes[i]; + } + /// DENEB SPECIFIC CONSTANTS (PROOF LENGTHS, FIELD SIZES): - // see https://eth2book.info/capella/part3/containers/state/#beaconstate BEACON_STATE_FIELDS = 32; - VAL_FIELDS_PROOF_LEN = 32 * ((BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT); - BALANCE_CONTAINER_PROOF_LEN = 32 * (BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT + BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT); - MAX_EFFECTIVE_BALANCE_GWEI = 32 gwei; MAX_EFFECTIVE_BALANCE_WEI = 32 ether; } - function NAME() public pure override returns (string memory) { - return "BeaconChain_PectraForkable"; - } - /** * * INTERNAL FUNCTIONS diff --git a/src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol b/src/test/mocks/EIP_4788_Oracle_Mock.t.sol similarity index 100% rename from src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol rename to src/test/mocks/EIP_4788_Oracle_Mock.t.sol diff --git a/src/test/unit/DeployFromScratch.t.sol b/src/test/unit/DeployFromScratch.t.sol deleted file mode 100644 index df76a24906..0000000000 --- a/src/test/unit/DeployFromScratch.t.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Test, console2} from "forge-std/Test.sol"; -import {DeployFromScratch} from "script/deploy/local/deploy_from_scratch.slashing.s.sol"; - -// NOTE: Run the following command to deploy from scratch in an anvil instance: -// RUST_LOG=forge,foundry=trace forge script script/deploy/local/Deploy_From_Scratch.s.sol --slow \ -// --rpc-url http://127.0.0.1:8545 \ -// --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ -// --broadcast \ -// --sig "run(string memory configFile)" \ -// -- local/deploy_from_scratch.slashing.anvil.config.json -contract DeployTest is Test { - DeployFromScratch public deployer; - - function setUp() public { - deployer = new DeployFromScratch(); - } - - function test_DeployFromScratch() public { - // Deploy, expecting no revert. - deployer.run("local/deploy_from_scratch.slashing.anvil.config.json"); - } -} diff --git a/src/test/unit/EigenPodUnit.t.sol b/src/test/unit/EigenPodUnit.t.sol index cec4b9cabc..1c43a5f5d0 100644 --- a/src/test/unit/EigenPodUnit.t.sol +++ b/src/test/unit/EigenPodUnit.t.sol @@ -13,9 +13,9 @@ import "src/test/harnesses/EigenPodHarness.sol"; import "src/test/utils/ProofParsing.sol"; import "src/test/utils/EigenLayerUnitTestSetup.sol"; -import "src/test/integration/mocks/BeaconChainMock.t.sol"; -import "src/test/integration/mocks/BeaconChainMock_Deneb.t.sol"; -import "src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol"; +import "src/test/mocks/BeaconChainMock.t.sol"; +import "src/test/mocks/BeaconChainMock_Deneb.t.sol"; +import "src/test/mocks/EIP_4788_Oracle_Mock.t.sol"; import "src/test/utils/EigenPodUser.t.sol"; import "src/test/utils/BytesLib.sol"; @@ -29,9 +29,7 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, IBeacon public eigenPodBeacon; // BeaconChain Mock Setup - TimeMachine public timeMachine; ETHPOSDepositMock ethPOSDepositMock; - BeaconChainMock public beaconChain; EIP_4788_Oracle_Mock constant EIP_4788_ORACLE = EIP_4788_Oracle_Mock(0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02); uint public numStakers; @@ -54,8 +52,10 @@ contract EigenPodUnitTests is EigenLayerUnitTestSetup, EigenPodPausingConstants, // beaconChainMock will also etch 4788 precompile ethPOSDepositMock = new ETHPOSDepositMock(); cheats.warp(GENESIS_TIME_LOCAL); - timeMachine = new TimeMachine(); - beaconChain = new BeaconChainMock(EigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); + + cheats.etch(address(timeMachine), type(TimeMachine).runtimeCode); + cheats.etch(address(beaconChain), type(BeaconChainMock).runtimeCode); + beaconChain.initialize(EigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); // Deploy EigenPod podImplementation = new EigenPod(ethPOSDepositMock, IEigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL, "v9.9.9"); @@ -1656,7 +1656,9 @@ contract EigenPodUnitTests_DenebProofsAgainstPectra is EigenPodUnitTests { EigenPodUnitTests.setUp(); // Set beaconChainMock to Deneb Forkable - beaconChain = BeaconChainMock(new BeaconChainMock_DenebForkable(EigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL)); + cheats.etch(address(beaconChain), type(BeaconChainMock_DenebForkable).runtimeCode); + beaconChain.initialize(EigenPodManager(address(eigenPodManagerMock)), GENESIS_TIME_LOCAL); + eigenPodManagerMock.setPectraForkTimestamp(1 hours * 12); } function testFuzz_revert_verifyWC_DenebAgainstPectra(uint24 rand) public { diff --git a/src/test/utils/ArrayLib.sol b/src/test/utils/ArrayLib.sol index 4e203ce7aa..92c19a97b0 100644 --- a/src/test/utils/ArrayLib.sol +++ b/src/test/utils/ArrayLib.sol @@ -151,6 +151,13 @@ library ArrayLib { return array; } + function setLength(uint40[] memory array, uint len) internal pure returns (uint40[] memory) { + assembly { + mstore(array, len) + } + return array; + } + function setLength(uint64[] memory array, uint len) internal pure returns (uint64[] memory) { assembly { mstore(array, len) @@ -373,4 +380,20 @@ library ArrayLib { return array; } + + /// ----------------------------------------------------------------------- + /// Typecasting + /// ----------------------------------------------------------------------- + + function toAddressArray(IStrategy[] memory array) internal pure returns (address[] memory r) { + assembly { + r := array + } + } + + function toUintArray(uint64[] memory array) internal pure returns (uint[] memory r) { + assembly { + r := array + } + } } diff --git a/src/test/utils/Constants.t.sol b/src/test/utils/Constants.t.sol new file mode 100644 index 0000000000..ce2d6c6e2b --- /dev/null +++ b/src/test/utils/Constants.t.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/contracts/interfaces/IETHPOSDeposit.sol"; +import "src/contracts/interfaces/IStrategy.sol"; + +import "src/test/mocks/BeaconChainMock.t.sol"; +import "src/test/mocks/EIP_4788_Oracle_Mock.t.sol"; +import "src/test/utils/TimeMachine.t.sol"; + +/// ----------------------------------------------------------------------- +/// General Constants +/// ----------------------------------------------------------------------- + +/// @dev Returns the address of the Foundry Hevm cheatcodes. +Vm constant cheats = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); // Vm(address(uint160(uint256(keccak256("hevm cheat code"))))) +/// @dev Returns the address that has pauser privileges. +address constant PAUSER = address(0x0000000000000000000000000000706175736572); // bytes32("pauser") +/// @dev Returns the address that has unpauser privileges. +address constant UNPAUSER = address(0x000000000000000000000000756E706175736572); // bytes32("unpauser") + +/// ----------------------------------------------------------------------- +/// Beacon Chain Constants +/// ----------------------------------------------------------------------- + +/// @dev Returns the address of the mock implementation of the Ethereum beacon chain. +BeaconChainMock constant beaconChain = BeaconChainMock(address(0x0000000000000000626561636f6e636861696e6D6f636b)); // bytes32("beacon chain") +/// @dev Returns the address of the mock beacon chain ETH strategy. +IStrategy constant BEACONCHAIN_ETH_STRAT = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); +/// @dev Returns the address of the mock beacon chain ETH token. +IERC20 constant NATIVE_ETH = IERC20(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0); +/// @dev Returns the address of the mock beacon chain POS deposit contract. +IETHPOSDeposit constant DEPOSIT_CONTRACT = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); +/// @dev Returns the address of the mock beacon chain EIP-4788 oracle. +EIP_4788_Oracle_Mock constant EIP_4788_ORACLE = EIP_4788_Oracle_Mock(0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02); + +/// ----------------------------------------------------------------------- +/// Integration Test Constants +/// ----------------------------------------------------------------------- + +/// @dev Returns you to 1985 if you reach 88mph, but we just use it for fetching previous state. +TimeMachine constant timeMachine = TimeMachine(address(0x000000000000000074696D65206D616368696e65)); // bytes32("time machine") +/// @dev Returns the genesis time for the beacon chain when running locally. +uint64 constant GENESIS_TIME_LOCAL = 1 hours * 12; +/// @dev Returns the genesis time for the beacon chain when forking mainnet. +uint64 constant GENESIS_TIME_MAINNET = 1_606_824_023; +/// @dev Returns the block number to fork from mainnet. +/// @dev Current value is post "Protocol Council" upgrade queued in timelock. +uint constant MAINNET_FORK_BLOCK = 22_225_622; +/// @dev Returns the number of LST strategies to deploy. +uint8 constant NUM_LST_STRATS = 8; + +/// @dev Returns the minimum balance a user can hold. +uint constant MIN_BALANCE = 1e6; +/// @dev Returns the maximum balance a user can hold. +uint constant MAX_BALANCE = 5e6; +/// @dev Returns the conversion factor from Gwei to Wei. +uint constant GWEI_TO_WEI = 1e9; + +/// @dev Types representing the different types of assets a ranomized users can hold. +uint constant NO_ASSETS = (1 << 0); // will have no assets +uint constant HOLDS_LST = (1 << 1); // will hold some random amount of LSTs +uint constant HOLDS_ETH = (1 << 2); // will hold some random amount of ETH +uint constant HOLDS_ALL = (1 << 3); // will always hold ETH, and some LSTs +uint constant HOLDS_MAX = (1 << 4); // will hold every LST and ETH (used for testing max strategies) + +/// @dev Types representing the different types of users that can be created. +uint constant DEFAULT = (1 << 0); +uint constant ALT_METHODS = (1 << 1); + +/// @dev Types representing the different types of forks that can be simulated. +uint constant LOCAL = (1 << 0); +uint constant MAINNET = (1 << 1); diff --git a/src/test/utils/EigenPodUser.t.sol b/src/test/utils/EigenPodUser.t.sol index 089ff3ac67..0273ea5b87 100644 --- a/src/test/utils/EigenPodUser.t.sol +++ b/src/test/utils/EigenPodUser.t.sol @@ -8,9 +8,11 @@ import "src/contracts/pods/EigenPod.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/mocks/BeaconChainMock.t.sol"; + +import "src/test/utils/Constants.t.sol"; import "src/test/utils/Logger.t.sol"; +import "src/test/utils/TimeMachine.t.sol"; struct Validator { uint40 index; @@ -23,8 +25,6 @@ interface IUserDeployer { } contract EigenPodUser is Logger { - TimeMachine timeMachine; - BeaconChainMock beaconChain; IBeacon public eigenPodBeacon; string _NAME; @@ -38,10 +38,8 @@ contract EigenPodUser is Logger { constructor(string memory name) { IUserDeployer deployer = IUserDeployer(msg.sender); - - timeMachine = deployer.timeMachine(); - beaconChain = deployer.beaconChain(); eigenPodBeacon = deployer.eigenPodBeacon(); + pod = EigenPod( payable( Create2.deploy( diff --git a/src/test/utils/Logger.t.sol b/src/test/utils/Logger.t.sol index 9d86400f21..b96cf8e7c9 100644 --- a/src/test/utils/Logger.t.sol +++ b/src/test/utils/Logger.t.sol @@ -2,36 +2,17 @@ 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(uint(keccak256("hevm cheat code"))))); - -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; -uint constant FLAG = 1; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -/// @dev Types representing the different types of assets a ranomized users can hold. -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 always hold ETH, and some LSTs -uint constant HOLDS_MAX = (FLAG << 4); // will hold every LST and ETH (used for testing max strategies) +import {IAllocationManagerTypes} from "src/contracts/interfaces/IAllocationManager.sol"; +import "src/contracts/interfaces/IStrategy.sol"; +import "src/contracts/interfaces/IStrategy.sol"; -/// @dev Types representing the different types of users that can be created. -uint constant DEFAULT = (FLAG << 0); -uint constant ALT_METHODS = (FLAG << 1); +import "src/test/mocks/BeaconChainMock.t.sol"; +import "src/test/utils/TimeMachine.t.sol"; -/// @dev Types representing the different types of forks that can be simulated. -uint constant LOCAL = (FLAG << 0); -uint constant MAINNET = (FLAG << 1); -uint constant HOLESKY = (FLAG << 2); +import "src/test/utils/Constants.t.sol"; abstract contract Logger is Test { using StdStyle for *; @@ -46,25 +27,10 @@ abstract contract Logger is Test { /// Modifiers /// ----------------------------------------------------------------------- - // Address used to store a trace counter to allow us to use noTracing - // across any contract that inherits Logger - address constant LOG_STATE_ADDR = address(0xDEADBEEF); - bytes32 constant LOG_STATE_SLOT = bytes32(0); - modifier noTracing() { - uint traceCounter = _getTraceCounter(); - if (traceCounter == 0) cheats.pauseTracing(); - - traceCounter++; - _setTraceCounter(traceCounter); - + cheats.pauseTracing(); _; - - traceCounter = _getTraceCounter(); - traceCounter--; - _setTraceCounter(traceCounter); - - if (traceCounter == 0) cheats.resumeTracing(); + cheats.resumeTracing(); } modifier noLogging() { @@ -128,18 +94,6 @@ abstract contract Logger is Test { logging = !logging; console.log("\n%s logging %s...", NAME_COLORED(), logging ? "enabled" : "disabled"); } - - /// ----------------------------------------------------------------------- - /// Trace Counter get/set - /// ----------------------------------------------------------------------- - - function _getTraceCounter() internal view returns (uint) { - return uint(cheats.load(LOG_STATE_ADDR, LOG_STATE_SLOT)); - } - - function _setTraceCounter(uint _newValue) internal { - cheats.store(LOG_STATE_ADDR, LOG_STATE_SLOT, bytes32(_newValue)); - } } /// @dev Assumes the user is a `Logger`. @@ -147,6 +101,8 @@ library print { using print for *; using StdStyle for *; + Vm constant vm = Vm(address(uint160(uint(keccak256("hevm cheat code"))))); + /// ----------------------------------------------------------------------- /// Logging /// ----------------------------------------------------------------------- @@ -172,20 +128,14 @@ library print { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; if (strat == BEACONCHAIN_ETH_STRAT) { - console.log(" Native ETH: %s", print.asWad(tokenBalances[i])); + console.log(" Native ETH: %s", tokenBalances[i]); } else { IERC20 underlyingToken = strat.underlyingToken(); - console.log(" %s: %s", IERC20Metadata(address(underlyingToken)).name(), print.asGwei(tokenBalances[i])); + console.log(" %s: %s", IERC20Metadata(address(underlyingToken)).name(), tokenBalances[i]); } } } - function gasUsed() internal { - uint used = cheats.snapshotGasLastCall("gasUsed"); - if (!_logging()) return; - console.log(" Gas used: %d".dim().bold(), used); - } - /// ----------------------------------------------------------------------- /// Logging /// ----------------------------------------------------------------------- @@ -224,43 +174,6 @@ library print { else if (t == ALT_METHODS) s = "ALT_METHODS"; } - function asForkType(uint 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(uint x) internal pure returns (string memory) { - return x.asDecimal(9, " gwei"); - } - - function asWad(uint x) internal pure returns (string memory) { - return x.asDecimal(18, " wad"); - } - - function asDecimal(uint 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); - - uint 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 (uint i; i < left.length; ++i) { - left[i] = b[i]; - } - - for (uint i; i < decimals; ++i) { - right[i] = b[len - decimals + i]; - } - - return string.concat(left.length > 0 ? string(left) : "0", ".", string(right), denomination); - } - /// ----------------------------------------------------------------------- /// Helpers /// ----------------------------------------------------------------------- diff --git a/src/test/integration/TimeMachine.t.sol b/src/test/utils/TimeMachine.t.sol similarity index 69% rename from src/test/integration/TimeMachine.t.sol rename to src/test/utils/TimeMachine.t.sol index 3b2b793fc7..b73a48661a 100644 --- a/src/test/integration/TimeMachine.t.sol +++ b/src/test/utils/TimeMachine.t.sol @@ -2,22 +2,16 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; -import "src/test/utils/Logger.t.sol"; -contract TimeMachine is Test, Logger { +contract TimeMachine is Test { uint[] public snapshots; - function NAME() public view virtual override returns (string memory) { - return "TimeMachine"; - } - /// ----------------------------------------------------------------------- /// Setters /// ----------------------------------------------------------------------- function createSnapshot() public returns (uint snapshot) { - snapshots.push(snapshot = cheats.snapshotState()); - print.method("createSnapshot", cheats.toString(snapshot)); + snapshots.push(snapshot = vm.snapshotState()); } function travelToLast() public returns (uint currentSnapshot) { @@ -25,14 +19,12 @@ contract TimeMachine is Test, Logger { // to warp so we don't accidentally prevent our own births. assertTrue(pastExists(), "Global.warpToPast: invalid usage, past does not exist"); uint last = lastSnapshot(); - // print.method("travelToLast", cheats.toString(last)); currentSnapshot = createSnapshot(); - cheats.revertToState(last); + vm.revertToState(last); } function travel(uint snapshot) public { - // print.method("travel", cheats.toString(snapshot)); - cheats.revertToState(snapshot); + vm.revertToState(snapshot); } /// -----------------------------------------------------------------------