├── .devcontainer ├── Dockerfile ├── devcontainer.json └── install.sh ├── .dockerignore ├── .env.example ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── design.md │ ├── feature_request.md │ ├── implement.md │ ├── research.md │ ├── task.md │ └── test_implementation.md ├── configs │ ├── solhint.json │ ├── storage-diff.json │ └── typos-cli.toml ├── labeler.yml ├── pull_request_template.md └── workflows │ ├── automation.yml │ ├── certora-prover.yml │ ├── certora.yml │ ├── checks.yml │ ├── foundry-post-merge.yml │ ├── foundry.yml │ ├── remove-stale-branches.yml │ └── validate-deployment-scripts.yml ├── .gitignore ├── .gitmodules ├── .vscode └── tasks.json ├── .zeus ├── CHANGELOG ├── CHANGELOG-1.5.0.md ├── CHANGELOG-1.6.0.md ├── CHANGELOG-1.7.0.md └── CHANGELOG-template.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── MAINTENANCE.md ├── Makefile ├── README.md ├── audits ├── M1 Mainnet - Diligence - Mar 2023.pdf ├── M1 Mainnet - Sigma Prime - May 2023.pdf ├── M2 Mainnet - Cantina - Apr 2024.pdf ├── M2 Mainnet - Sigma Prime - Feb 2024.pdf ├── M4 Mainnet (PEPE) - Certora - Aug 2024.pdf ├── M4 Mainnet (PEPE) - Sigma Prime - Jul 2024.pdf ├── Permissionless Strategies - Sigma Prime - Aug 2024.pdf ├── Rewards v2 - SigmaPrime - Dec 2024.pdf ├── RewardsCoordinator - Sigma Prime - May 2024.pdf ├── Token + Programmatic Incentives - Sigma Prime - Sep 2024.pdf ├── V1.0.0 (Slashing) - Certora - Feb 2025.pdf └── V1.0.0 (Slashing) - Sigma Prime - Feb 2025.pdf ├── bin ├── compile-bindings.sh ├── install-deps.sh ├── pre-commit.sh ├── source-env.sh ├── storage-diff.sh └── storage-report.sh ├── certora ├── .bin │ └── verify.sh ├── confs │ ├── core │ │ ├── AllocationManager.conf │ │ ├── AllocationManagerSanity.conf │ │ ├── DelegationManager.conf │ │ ├── DelegationManagerValidState.conf │ │ └── StrategyManager.conf │ ├── permissions │ │ └── Pausable.conf │ ├── pods │ │ └── EigenPodManagerRules.conf │ └── strategies │ │ └── StrategyBase.conf ├── harnesses │ ├── DelegationManagerHarness.sol │ ├── EigenPodHarness.sol │ ├── EigenPodManagerHarness.sol │ ├── PausableHarness.sol │ ├── ShortStringsUpgradeableHarness.sol │ ├── StrategyManagerHarness.sol │ └── StructuredLinkedListHarness.sol ├── mocks │ └── CertoraAVSRegistrar.sol ├── scripts │ ├── core │ │ ├── verifyAllocationManager.sh │ │ ├── verifyAllocationManagerSanity.sh │ │ ├── verifyDelegationManager.sh │ │ ├── verifyDelegationManagerValidState.sh │ │ └── verifyStrategyManager.sh │ ├── permissions │ │ └── verifyPausable.sh │ ├── pods │ │ ├── verifyEigenPod.sh │ │ ├── verifyEigenPodManager.sh │ │ ├── verifyEigenPodManagerRules.sh │ │ └── verifyEigenPodManagerSanity.sh │ └── strategies │ │ └── verifyStrategyBase.sh └── specs │ ├── core │ ├── AllocationManagerRules.spec │ ├── AllocationManagerSanity.spec │ ├── AllocationManagerValidState.spec │ ├── DelegationManager.spec │ ├── DelegationManagerValidState.spec │ ├── Slasher.spec │ └── StrategyManager.spec │ ├── erc20cvl.spec │ ├── libraries │ └── StructuredLinkedList.spec │ ├── optimizations.spec │ ├── permissions │ └── Pausable.spec │ ├── pods │ ├── EigenPod.spec │ ├── EigenPodManager.spec │ └── EigenPodManagerRules.spec │ ├── ptaHelpers.spec │ └── strategies │ └── StrategyBase.spec ├── docs ├── README.md ├── core │ ├── AVSDirectory.md │ ├── AllocationManager.md │ ├── DelegationManager.md │ ├── EigenPod.md │ ├── EigenPodManager.md │ ├── RewardsCoordinator.md │ ├── SlashEscrowFactory.md │ ├── StrategyManager.md │ └── accounting │ │ ├── DualSlashingEdgeCase.md │ │ ├── SharesAccounting.md │ │ ├── SharesAccountingEdgeCases.md │ │ └── StrategyBaseAccounting.md ├── experimental │ └── AVS-Guide.md ├── images │ ├── RewardsCoordinator_Merkle_Tree.png │ ├── Staker Flow Diagrams │ │ ├── Complete Withdrawal as Shares.png │ │ ├── Complete Withdrawal as Tokens.png │ │ ├── Delegating.png │ │ ├── Depositing.png │ │ ├── Queue Withdrawal.png │ │ ├── Validator Exits.png │ │ ├── Validator Yield.png │ │ └── diagrams.excalidraw │ ├── avs-bc-slash.png │ └── slashing-model.png └── permissions │ └── PermissionController.md ├── foundry.toml ├── go.mod ├── go.sum ├── mythril.config.json ├── package-lock.json ├── package.json ├── pkg └── bindings │ ├── AVSDirectory │ └── binding.go │ ├── AVSDirectoryStorage │ └── binding.go │ ├── AllocationManager │ └── binding.go │ ├── AllocationManagerStorage │ └── binding.go │ ├── BackingEigen │ └── binding.go │ ├── BeaconChainProofs │ └── binding.go │ ├── BytesLib │ └── binding.go │ ├── DelegationManager │ └── binding.go │ ├── DelegationManagerStorage │ └── binding.go │ ├── Deprecated_OwnableUpgradeable │ └── binding.go │ ├── Eigen │ └── binding.go │ ├── EigenPod │ └── binding.go │ ├── EigenPodManager │ └── binding.go │ ├── EigenPodManagerStorage │ └── binding.go │ ├── EigenPodPausingConstants │ └── binding.go │ ├── EigenPodStorage │ └── binding.go │ ├── EigenStrategy │ └── binding.go │ ├── Endian │ └── binding.go │ ├── IAVSDirectory │ └── binding.go │ ├── IAVSRegistrar │ └── binding.go │ ├── IAllocationManager │ └── binding.go │ ├── IBackingEigen │ └── binding.go │ ├── IDelegationManager │ └── binding.go │ ├── IETHPOSDeposit │ └── binding.go │ ├── IEigen │ └── binding.go │ ├── IEigenPod │ └── binding.go │ ├── IEigenPodManager │ └── binding.go │ ├── IPausable │ └── binding.go │ ├── IPauserRegistry │ └── binding.go │ ├── IPermissionController │ └── binding.go │ ├── IRewardsCoordinator │ └── binding.go │ ├── ISemVerMixin │ └── binding.go │ ├── IShareManager │ └── binding.go │ ├── ISignatureUtils │ └── binding.go │ ├── ISignatureUtilsMixin │ └── binding.go │ ├── ISlashEscrow │ └── binding.go │ ├── ISlashEscrowFactory │ └── binding.go │ ├── IStrategy │ └── binding.go │ ├── IStrategyFactory │ └── binding.go │ ├── IStrategyManager │ └── binding.go │ ├── Merkle │ └── binding.go │ ├── OperatorSetLib │ └── binding.go │ ├── Pausable │ └── binding.go │ ├── PauserRegistry │ └── binding.go │ ├── PermissionController │ └── binding.go │ ├── PermissionControllerMixin │ └── binding.go │ ├── PermissionControllerStorage │ └── binding.go │ ├── RewardsCoordinator │ └── binding.go │ ├── RewardsCoordinatorStorage │ └── binding.go │ ├── SemVerMixin │ └── binding.go │ ├── SignatureUtils │ └── binding.go │ ├── SignatureUtilsMixin │ └── binding.go │ ├── SlashEscrow │ └── binding.go │ ├── SlashEscrowFactory │ └── binding.go │ ├── SlashEscrowFactoryStorage │ └── binding.go │ ├── SlashingLib │ └── binding.go │ ├── Snapshots │ └── binding.go │ ├── StrategyBase │ └── binding.go │ ├── StrategyBaseTVLLimits │ └── binding.go │ ├── StrategyFactory │ └── binding.go │ ├── StrategyFactoryStorage │ └── binding.go │ ├── StrategyManager │ └── binding.go │ └── StrategyManagerStorage │ └── binding.go ├── script ├── .gitignore ├── configs │ ├── devnet │ │ ├── deploy_from_scratch.anvil.config.json │ │ ├── deploy_from_scratch.holesky.config.json │ │ └── deploy_from_scratch.holesky.slashing.config.json │ ├── holesky.json │ ├── local │ │ └── deploy_from_scratch.slashing.anvil.config.json │ ├── mainnet.json │ ├── mainnet │ │ └── mainnet-addresses.config.json │ ├── preprod.json │ └── zipzoop.json ├── deploy │ ├── devnet │ │ └── deploy_from_scratch.s.sol │ └── local │ │ └── deploy_from_scratch.slashing.s.sol ├── interfaces │ └── IUpgradeableBeacon.sol ├── output │ └── devnet │ │ ├── M1_MOCK_deployment_data.json │ │ └── M2_from_scratch_deployment_data.json ├── releases │ ├── Env.sol │ ├── README.md │ └── v1.6.0-moocow-and-elip5 │ │ ├── 1-deployContracts.s.sol │ │ ├── 2-queueUpgrade.s.sol │ │ ├── 3-executeUpgrade.s.sol │ │ └── upgrade.json ├── tasks │ ├── README.md │ ├── allocate_operatorSet.s.sol │ ├── complete_withdrawal_from_strategy.s.sol │ ├── deposit_into_strategy.s.sol │ ├── register_as_operator.s.sol │ ├── register_operator_to_operatorSet.s.sol │ ├── run.sh │ ├── slash_operatorSet.s.sol │ ├── unpause_avsDirectory.s.sol │ └── withdraw_from_strategy.s.sol └── utils │ ├── ExistingDeploymentParser.sol │ └── validateStorage │ ├── README.md │ ├── validateStorage.ts │ └── validateUpgrade.sh ├── slither.config.json ├── snapshots └── Integration_ALM_Multi.json └── src ├── contracts ├── core │ ├── AVSDirectory.sol │ ├── AVSDirectoryStorage.sol │ ├── AllocationManager.sol │ ├── AllocationManagerStorage.sol │ ├── DelegationManager.sol │ ├── DelegationManagerStorage.sol │ ├── RewardsCoordinator.sol │ ├── RewardsCoordinatorStorage.sol │ ├── SlashEscrow.sol │ ├── SlashEscrowFactory.sol │ ├── SlashEscrowFactoryStorage.sol │ ├── StrategyManager.sol │ └── StrategyManagerStorage.sol ├── interfaces │ ├── IAVSDirectory.sol │ ├── IAVSRegistrar.sol │ ├── IAllocationManager.sol │ ├── IBackingEigen.sol │ ├── IDelegationManager.sol │ ├── IETHPOSDeposit.sol │ ├── IEigen.sol │ ├── IEigenPod.sol │ ├── IEigenPodManager.sol │ ├── IPausable.sol │ ├── IPauserRegistry.sol │ ├── IPermissionController.sol │ ├── IRewardsCoordinator.sol │ ├── ISemVerMixin.sol │ ├── IShareManager.sol │ ├── ISignatureUtilsMixin.sol │ ├── ISlashEscrow.sol │ ├── ISlashEscrowFactory.sol │ ├── IStrategy.sol │ ├── IStrategyFactory.sol │ └── IStrategyManager.sol ├── libraries │ ├── BeaconChainProofs.sol │ ├── Endian.sol │ ├── Merkle.sol │ ├── OperatorSetLib.sol │ ├── SlashingLib.sol │ └── Snapshots.sol ├── mixins │ ├── Deprecated_OwnableUpgradeable.sol │ ├── PermissionControllerMixin.sol │ ├── SemVerMixin.sol │ └── SignatureUtilsMixin.sol ├── permissions │ ├── Pausable.sol │ ├── PauserRegistry.sol │ ├── PermissionController.sol │ └── PermissionControllerStorage.sol ├── pods │ ├── EigenPod.sol │ ├── EigenPodManager.sol │ ├── EigenPodManagerStorage.sol │ ├── EigenPodPausingConstants.sol │ └── EigenPodStorage.sol ├── strategies │ ├── EigenStrategy.sol │ ├── StrategyBase.sol │ ├── StrategyBaseTVLLimits.sol │ ├── StrategyFactory.sol │ └── StrategyFactoryStorage.sol └── token │ ├── BackingEigen.sol │ └── Eigen.sol └── test ├── DevnetLifecycle.t.sol ├── TestConstants.sol ├── harnesses ├── AllocationManagerHarness.sol ├── DelegationManagerHarness.sol ├── EigenHarness.sol ├── EigenPodHarness.sol ├── EigenPodManagerWrapper.sol └── PausableHarness.sol ├── integration ├── IntegrationBase.t.sol ├── IntegrationChecks.t.sol ├── IntegrationDeployer.t.sol ├── README.md ├── TimeMachine.t.sol ├── TypeImporter.t.sol ├── UpgradeTest.t.sol ├── deprecatedInterfaces │ └── mainnet │ │ ├── BeaconChainProofs.sol │ │ ├── IAllocationManager.sol │ │ ├── IBeaconChainOracle.sol │ │ ├── IDelayedWithdrawalRouter.sol │ │ ├── IDelegationManager.sol │ │ ├── IEigenPod.sol │ │ ├── IEigenPodManager.sol │ │ └── IStrategyManager.sol ├── mocks │ ├── BeaconChainMock.t.sol │ ├── BeaconChainMock_Deneb.t.sol │ ├── EIP_4788_Oracle_Mock.t.sol │ ├── EIP_7002_Mock.t.sol │ ├── EIP_7251_Mock.t.sol │ ├── LibProofGen.t.sol │ └── LibValidator.t.sol ├── tests │ ├── ALM_Multi.t.sol │ ├── ALM_RegisterAndModify.t.sol │ ├── Delegate_Deposit_Queue_Complete.t.sol │ ├── Deposit_Delegate_Allocate_Slash_Escrow.t.sol │ ├── Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol │ ├── Deposit_Delegate_Queue_Complete.t.sol │ ├── Deposit_Delegate_Redelegate_Complete.t.sol │ ├── Deposit_Delegate_Undelegate_Complete.t.sol │ ├── Deposit_Delegate_UpdateBalance.t.sol │ ├── Deposit_Queue_Complete.t.sol │ ├── Deposit_Register_QueueWithdrawal_Complete.t.sol │ ├── DualSlashing.t.sol │ ├── FullySlashed_Operator.t.sol │ ├── HighDSF_Multiple_Deposits.t.sol │ ├── Slashed_Eigenpod_AVS.t.sol │ ├── SlashingWithdrawals.t.sol │ ├── Timing.t.sol │ ├── Upgrade_Setup.t.sol │ ├── eigenpod │ │ ├── FullySlashed_EigenPod.t.sol │ │ ├── Pectra_Features.t.sol │ │ ├── Register_Allocate_Slash_VerifyWC_.t.sol │ │ ├── SlashBC_OneBCSF.t.sol │ │ ├── Slashed_Eigenpod_BC.t.sol │ │ └── VerifyWC_StartCP_CompleteCP.t.sol │ └── upgrade │ │ ├── README.md │ │ └── Redistribution.t.sol └── users │ ├── AVS.t.sol │ └── User.t.sol ├── mocks ├── AVSDirectoryMock.sol ├── AllocationManagerMock.sol ├── DelegationManagerMock.sol ├── Dummy.sol ├── ERC20Mock.sol ├── ERC20_OneWeiFeeOnTransfer.sol ├── ERC20_SetTransferReverting_Mock.sol ├── ETHDepositMock.sol ├── EigenPodManagerMock.sol ├── EigenPodMock.sol ├── EmptyContract.sol ├── LiquidStakingToken.sol ├── MockAVSRegistrar.sol ├── MockDecimals.sol ├── MockERC20.sol ├── OwnableMock.sol ├── Reenterer.sol ├── Reverter.sol ├── SlashEscrowFactoryMock.sol └── StrategyManagerMock.sol ├── test-data ├── balanceUpdateProof_balance28ETH_302913.json ├── balanceUpdateProof_notOverCommitted_302913.json ├── balanceUpdateProof_notOverCommitted_302913_incrementedBlockBy100.json ├── balanceUpdateProof_updated_to_0ETH_302913.json ├── balanceUpdateProof_updated_to_30ETH_302913.json ├── fullWithdrawalCapellaAgainstDenebRoot.json ├── fullWithdrawalDeneb.json ├── fullWithdrawalProof_Latest.json ├── fullWithdrawalProof_Latest_1SlotAdvanced.json ├── fullWithdrawalProof_Latest_28ETH.json ├── operators.json ├── owners.json ├── partialWithdrawalProof_Latest.json ├── reputedOwners.json ├── rewardsCoordinator │ ├── processClaimProofs_MaxEarnerAndLeafIndices.json │ ├── processClaimProofs_Root1.json │ ├── processClaimProofs_Root2.json │ ├── processClaimProofs_Root3.json │ ├── processClaimProofs_SingleEarnerLeaf.json │ ├── processClaimProofs_SingleTokenLeaf.json │ └── processClaim_Preprod_Test.json ├── slashedProofs │ ├── balanceUpdateProof_Overcommitted_61511.json │ ├── balanceUpdateProof_notOvercommitted_61511.json │ └── balanceUpdateProof_notOvercommitted_61511_incrementedBlockBy100.json ├── withdrawalCredentialAndBalanceProof_61068.json ├── withdrawalCredentialAndBalanceProof_61336.json ├── withdrawal_credential_proof_302913.json ├── withdrawal_credential_proof_302913_30ETHBalance.json ├── withdrawal_credential_proof_302913_exited.json └── withdrawal_credential_proof_510257.json ├── token ├── EigenTransferRestrictions.t.sol ├── EigenWrapping.t.sol └── bEIGEN.t.sol ├── tree ├── AllocationManagerUnit.tree ├── DelegationManagerUnit.tree ├── EigenPodManagerUnit.tree ├── EigenPodUnit.tree ├── PermissionControllerUnit.tree └── StrategyManagerUnit.tree ├── unit ├── AVSDirectoryUnit.t.sol ├── AllocationManagerUnit.t.sol ├── DelegationUnit.t.sol ├── DeployFromScratch.t.sol ├── EigenPodManagerUnit.t.sol ├── EigenPodUnit.t.sol ├── PausableUnit.t.sol ├── PauserRegistryUnit.t.sol ├── PermissionControllerUnit.t.sol ├── RewardsCoordinatorUnit.t.sol ├── SlashEscrowFactoryUnit.t.sol ├── StrategyBaseTVLLimitsUnit.sol ├── StrategyBaseUnit.t.sol ├── StrategyFactoryUnit.t.sol ├── StrategyManagerUnit.t.sol ├── libraries │ ├── BytesLibUnit.t.sol │ └── SnapshotsUnit.t.sol └── mixins │ ├── SemVerMixin.t.sol │ └── SignatureUtilsUnit.t.sol └── utils ├── ArrayLib.sol ├── BytesLib.sol ├── EigenLayerUnitTestSetup.sol ├── EigenPodUser.t.sol ├── Logger.t.sol ├── ProofParsing.sol └── Random.sol /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Ubuntu version (use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon): ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 2 | ARG VARIANT=ubuntu-22.04 3 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 4 | 5 | # [Optional] Uncomment this section to install additional OS packages. 6 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 7 | && apt-get -y install --no-install-recommends libssl-dev \ 8 | ripgrep python3-pip python3-venv python3 9 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/go 3 | { 4 | "name": "Ubuntu", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | }, 8 | // Configure tool-specific properties. 9 | "customizations": { 10 | // Configure access control to other repositories 11 | "codespaces": { 12 | "repositories": { 13 | "Layr-Labs/*": { 14 | "permissions": "write-all" 15 | } 16 | } 17 | }, 18 | // Configure properties specific to VS Code. 19 | "vscode": { 20 | // Add the IDs of extensions you want installed when the container is created. 21 | "extensions": [ 22 | "NomicFoundation.hardhat-solidity", 23 | "GitHub.copilot" 24 | ] 25 | } 26 | }, 27 | "containerEnv": { 28 | "PRIVATE_KEY": "${localEnv:PRIVATE_KEY}", 29 | "PUBLIC_KEY": "${localEnv:PUBLIC_KEY}", 30 | "RPC_MAINNET": "${localEnv:RPC_MAINNET}", 31 | "RPC_HOLESKY": "${localEnv:RPC_HOLESKY}" 32 | }, 33 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 34 | // "forwardPorts": [], 35 | // Use 'postCreateCommand' to run commands after the container is created. 36 | "postCreateCommand": "chmod +x ./.devcontainer/install.sh && bash ./.devcontainer/install.sh", 37 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 38 | "remoteUser": "vscode" 39 | } -------------------------------------------------------------------------------- /.devcontainer/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | NVM_DIR=${HOME}/.nvm 6 | NODE_VERSION=v22.3.0 7 | 8 | # Install node 9 | function npm_install { 10 | mkdir -p ${NVM_DIR}/etc 11 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash 12 | bash -c ". ${NVM_DIR}/nvm.sh && nvm install ${NODE_VERSION} && nvm alias default ${NODE_VERSION} && nvm use default" 13 | 14 | NVM_NODE_PATH=${NVM_DIR}/versions/node/${NODE_VERSION} 15 | NODE_PATH=${NVM_NODE_PATH}/lib/node_modules 16 | PATH=${NVM_NODE_PATH}/bin:$PATH 17 | 18 | npm install npm -g 19 | npm install yarn -g 20 | } 21 | 22 | # Install foundry 23 | function foundry_install { 24 | curl -L https://foundry.paradigm.xyz | bash 25 | ~/.foundry/bin/foundryup 26 | } 27 | 28 | npm_install 29 | foundry_install 30 | 31 | export NVM_NODE_PATH=${NVM_DIR}/versions/node/${NODE_VERSION} 32 | export NODE_PATH=${NVM_NODE_PATH}/lib/node_modules 33 | export PATH=${PATH}:${NVM_NODE_PATH}/bin: -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /cache 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | RPC_MAINNET="https://eth.llamarpc.com" 2 | RPC_HOLESKY="" 3 | ETHERSCAN_API_KEY="API-KEY" 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | pkg/**/*.go linguist-generated=true 2 | 3 | # Certora formatting settings 4 | *.spec linguist-language=Solidity 5 | *.conf linguist-detectable 6 | *.conf linguist-language=JSON5 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 3 | about: Create a report to help us improve 4 | title: 'Bug: Title' 5 | labels: bug 6 | 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Environment** 26 | Enter important environment info needed to reproduce the bug. 27 | - [e.g. chrome, safari] 28 | - [e.g. version] 29 | 30 | **Don't Forget To** 31 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 32 | * Add priority + size estimate 33 | * Set status to New 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/design.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Design 3 | about: Design 4 | title: 'Design: Title' 5 | labels: design 6 | 7 | --- 8 | 9 | ## Description 10 | Add a summary and description. What are we trying to do and why? 11 | 12 | ### Action Items 13 | - [ ] Come up with scheme for... 14 | - [ ] Spec it in a HackMD or Google Doc that is linked here 15 | - [ ] Get @ to review design 16 | - [ ] Discuss design and tradeoffs with @ 17 | - [ ] Finalize the doc, and come to consensus 18 | - [ ] Create ticket for implementation and link the doc to it 19 | 20 | ### Blocking Issues 21 | Is anything blocking for this? (Does this depend on other unfinished designs or pending changes?) 22 | Please link blocking issues here. If something is blocking and doesn't have an issue yet, create it! 23 | 24 | ### Don't Forget To 25 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 26 | * Add priority + size estimate 27 | * Set status to New 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: Suggest an idea for this project 4 | title: 'Feature: Title' 5 | labels: feature 6 | 7 | --- 8 | 9 | **User story** 10 | User stories are often expressed in a simple sentence, structured as follows: 'As a PERSONA, I want to GOAL_DESCRIPTION, so that CUSTOMER_VALUE_DESCRIPTION.' Alternatively for 11 | 12 | **Actions** 13 | - [ ] An action item list describing the work to be done 14 | - [ ] Link to all of the related tasks needed to complete the feature. See the [tasks](https://github.com/Layr-Labs/eigenlayer-contracts/tree/master/.github/ISSUE_TEMPLATE/task.md) template. 15 | - [ ] Include everything in the definition of done e.g. unit tests and documentation 16 | 17 | **Acceptance criteria** 18 | Acceptance criteria are the requirements that need to be met in order to mark a user story as complete. For example, if your user story is, "As a New Relic customer, I want to know how to interpret AI anomalies in order to monitor my site and protect myself against incidents," then the acceptance criteria would be: "A complete and published doc describing AI anomalies," and all related quality checks. 19 | 20 | **Don't Forget To** 21 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 22 | * Add priority + size estimate 23 | * Set status to New 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/implement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Implementation 3 | about: Implementation 4 | title: 'Implement: Title' 5 | labels: implement 6 | 7 | --- 8 | 9 | ## Description 10 | If we already have a design doc then link it [here](). 11 | Otherwise at least add a summary and description. 12 | 13 | ### Action Items 14 | - [ ] Implement changes to the contracts on a separate branch 15 | - [ ] Update tests and scripts as necessary 16 | - [ ] Update documentation to reflect changes 17 | - [ ] Get PR reviewed 18 | - [ ] Respond to review / make any further changes 19 | - [ ] Create ticket for tests 20 | - [ ] Merge PR 21 | 22 | ### Blocking Issues 23 | Is anything blocking for this? (Do we need to design and/or build something first?) 24 | Please link blocking issues here. If something is blocking and doesn't have an issue yet, create it! 25 | 26 | ### Don't Forget To 27 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 28 | * Add priority + size estimate 29 | * Set status to New 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/research.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Research 3 | about: Research 4 | title: 'Research: Title' 5 | labels: research 6 | 7 | --- 8 | 9 | ## Description 10 | Add a summary and description. What do we need any why? Any preliminary notion of options + what we want out of them? 11 | 12 | ### Action Items 13 | - [ ] Create a list of options to evaluate 14 | - [ ] Do research, summarize findings into a doc or here 15 | - [ ] Present research, discuss next steps 16 | - [ ] Write up next steps + create new issue(s) for them 17 | 18 | ### Blocking Issues 19 | Is anything blocking for this? (Should we make another decision or scope something first?) 20 | Please link blocking issues here. If something is blocking and doesn't have an issue yet, create it! 21 | 22 | ### Don't Forget To 23 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 24 | * Add priority + size estimate 25 | * Set status to New 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Task 4 | title: 'Task: Title' 5 | labels: task 6 | 7 | --- 8 | 9 | ## Description 10 | Add a summary and description. Link to any parent [feature requests](https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) or [bug reports](https://github.com/Layr-Labs/eigenlayer-contracts/blob/master/.github/ISSUE_TEMPLATE/bug_report.md). 11 | 12 | ### Action Items 13 | - [ ] An action item list describing the work to be done 14 | - [ ] Include everything in the definition of done e.g. unit tests and documentation 15 | 16 | ### Blocking Issues 17 | Is anything else clearly blocking for this? (Do we need to fix something else first?) 18 | Please link blocking issues here. If something is blocking and doesn't have an issue yet, create it! 19 | 20 | ### Don't Forget To 21 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 22 | * Add priority + size estimate 23 | * Set status to New 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/test_implementation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test 3 | about: Test 4 | title: 'Test: Title' 5 | labels: test 6 | 7 | --- 8 | 9 | ## Description 10 | Add a summary and description. What are we trying to do and why? 11 | 12 | ### Action Items 13 | - [ ] Discuss scoping for tests with the team 14 | - [ ] List possible test cases in this issue 15 | - [ ] Get @ to review design 16 | - [ ] Implement tests 17 | 18 | ### Blocking Issues 19 | Is anything blocking for this? (Does this depend on other unfinished designs or pending changes?) 20 | Please link blocking issues here. If something is blocking and doesn't have an issue yet, create it! 21 | 22 | ### Don't Forget To 23 | * Assign this to a project (our default is [eigenlayer](https://github.com/orgs/Layr-Labs/projects/3/)) 24 | * Add priority + size estimate 25 | * Set status to New -------------------------------------------------------------------------------- /.github/configs/solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "max-line-length": "off", 5 | "no-inline-assembly": "off", 6 | "reason-string": ["warn",{"maxLength":160}], 7 | "func-visibility": ["warn",{"ignoreConstructors":true}], 8 | "explicit-types": ["warn","explicit"], 9 | "quotes": ["warn","double"], 10 | "const-name-snakecase": "off", 11 | "not-rely-on-time": "off", 12 | "avoid-low-level-calls": "off", 13 | "contract-name-camelcase": "off", 14 | "func-name-mixedcase": "off", 15 | "var-name-mixedcase": "off", 16 | "compiler-version": "off", 17 | "custom-errors": "off", 18 | "no-global-import": "off", 19 | "immutable-vars-naming": "off", 20 | "no-console": "off" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/configs/storage-diff.json: -------------------------------------------------------------------------------- 1 | { 2 | "contracts": [ 3 | { 4 | "name": "AllocationManager", 5 | "address": "0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39" 6 | }, 7 | { 8 | "name": "AVSDirectory", 9 | "address": "0x135dda560e946695d6f155dacafc6f1f25c1f5af" 10 | }, 11 | { 12 | "name": "DelegationManager", 13 | "address": "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A" 14 | }, 15 | { 16 | "name": "RewardsCoordinator", 17 | "address": "0x7750d328b314EfFa365A0402CcfD489B80B0adda" 18 | }, 19 | { 20 | "name": "StrategyManager", 21 | "address": "0x858646372CC42E1A627fcE94aa7A7033e7CF075A" 22 | }, 23 | { 24 | "name": "StrategyFactory", 25 | "address": "0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647" 26 | }, 27 | { 28 | "name": "EigenPodManager", 29 | "address": "0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338" 30 | }, 31 | { 32 | "name": "EigenPod", 33 | "address": "0xd4018Ce9A041a9c110A9d0383d2b5E1c66Ae1513" 34 | }, 35 | { 36 | "name": "stETH Strategy", 37 | "address": "0x93c4b944D05dfe6df7645A86cd2206016c51564D" 38 | }, 39 | { 40 | "name": "EigenStrategy", 41 | "address": "0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7" 42 | }, 43 | { 44 | "name": "StrategyBase", 45 | "address": "0x6c6E8aF98a49bBaBCc17ca1dbA6b95c5D58A2ccb" 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /.github/configs/typos-cli.toml: -------------------------------------------------------------------------------- 1 | [files] 2 | extend-exclude = [ 3 | "**/lib/**", 4 | "**/docs/images/**", 5 | # Not present locally, but is in remote (github). 6 | "**/doc/**" 7 | ] 8 | ignore-hidden = true 9 | ignore-files = true 10 | ignore-dot = true 11 | ignore-vcs = true 12 | ignore-global = true 13 | ignore-parent = true 14 | 15 | [default] 16 | binary = false 17 | check-filename = true 18 | check-file = true 19 | unicode = true 20 | ignore-hex = true 21 | identifier-leading-digits = false 22 | locale = "en" 23 | extend-ignore-identifiers-re = [] 24 | extend-ignore-words-re = [] 25 | extend-ignore-re = [] 26 | 27 | [default.extend-identifiers] 28 | 29 | # Weird syntax, but this how you ignore corrections for certain words. 30 | [default.extend-words] 31 | strat = "strat" 32 | froms = "froms" 33 | 34 | [type.go] 35 | extend-glob = [] 36 | extend-ignore-identifiers-re = [] 37 | extend-ignore-words-re = [] 38 | extend-ignore-re = [] 39 | 40 | [type.go.extend-identifiers] 41 | flate = "flate" 42 | 43 | [type.go.extend-words] 44 | 45 | [type.sh] 46 | extend-glob = [] 47 | extend-ignore-identifiers-re = [] 48 | extend-ignore-words-re = [] 49 | extend-ignore-re = [] 50 | 51 | [type.sh.extend-identifiers] 52 | ot = "ot" 53 | stap = "stap" 54 | 55 | [type.sh.extend-words] 56 | 57 | [type.py] 58 | extend-glob = [] 59 | extend-ignore-identifiers-re = [] 60 | extend-ignore-words-re = [] 61 | extend-ignore-re = [] 62 | 63 | [type.py.extend-identifiers] 64 | NDArray = "NDArray" 65 | arange = "arange" 66 | EOFError = "EOFError" 67 | 68 | [type.py.extend-words] 69 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # Cannot move to .github/configs/ for some reason... this should do for now. 2 | 3 | # Applies when PR branch name contains "bug" or "fix" 4 | '🐞 Bug': 5 | - head-branch: ['bug'] 6 | 7 | # Applies when PR branch name contains "chore" 8 | '📜 Chore': 9 | - head-branch: ['chore'] 10 | - changed-files: 11 | - any-glob-to-any-file: ['.github/**/*', '.vscode/**/*', '.devcontainer/**/*', '.*', '.*rc', '.*ignore', '.env*'] 12 | 13 | # Applies when PR branch name contains "docs" or "documentation" or changes markdown files 14 | '📖 Documentation': 15 | - head-branch: ['docs', 'documentation'] 16 | - changed-files: 17 | - any-glob-to-any-file: ['**/*.md'] 18 | 19 | # Applies when PR branch name contains "feat", "feature", or "enhance" or changes contract files 20 | '✨ Enhancement': 21 | - head-branch: ['feat', 'feature', 'enhance'] 22 | - changed-files: 23 | - any-glob-to-any-file: ['src/contracts/**/*'] 24 | 25 | # Applies when PR branch name contains "fix", "bug", or "patch" 26 | '🔧 Fix': 27 | - head-branch: ['fix', 'patch'] 28 | 29 | # Applies when PR branch name contains "optimize" or "perf" 30 | '⚡ Optimization': 31 | - head-branch: ['optimize', 'perf'] 32 | 33 | # Applies when PR branch name contains "refactor" 34 | '♻️ Refactor': 35 | - head-branch: ['refactor'] 36 | 37 | # Applies when PR changes script files 38 | '📜 Script': 39 | - changed-files: 40 | - any-glob-to-any-file: ['script/**/*', 'bin/**/*'] 41 | 42 | # Applies when PR targets the slashing integration testing branch 43 | '🗡️ Slashing Release': 44 | - base-branch: ['slashing','test/slashing-integration-testing'] 45 | 46 | # Applies when PR changes test files 47 | '🧪 Test': 48 | - changed-files: 49 | - any-glob-to-any-file: ['src/test/**/*'] -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | **Motivation:** 13 | 14 | *Explain here the context, and why you're making that change. What is the problem you're trying to solve.* 15 | 16 | **Modifications:** 17 | 18 | *Describe the modifications you've done.* 19 | 20 | **Result:** 21 | 22 | *After your change, what will change.* 23 | -------------------------------------------------------------------------------- /.github/workflows/automation.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | 3 | on: 4 | pull_request: 5 | types: [opened, edited, synchronize] 6 | 7 | permissions: 8 | contents: read 9 | pull-requests: read 10 | 11 | jobs: 12 | # triage: 13 | # runs-on: protocol-x64-16core 14 | # name: Labels 15 | # permissions: 16 | # contents: read 17 | # pull-requests: write 18 | 19 | # steps: 20 | # - name: Checkout code 21 | # uses: actions/checkout@v4 22 | 23 | # - uses: actions/labeler@v5 24 | # with: 25 | # repo-token: "${{ secrets.GITHUB_TOKEN }}" 26 | # sync-labels: true 27 | 28 | lint-pr-title: 29 | runs-on: ubuntu-latest 30 | name: Title 31 | steps: 32 | - name: Fetch PR Title 33 | run: | 34 | PR_TITLE=$(jq -r '.pull_request.title' "$GITHUB_EVENT_PATH") 35 | echo "PR title: $PR_TITLE" 36 | 37 | # Define the valid pattern (supports conventional commit format) 38 | if [[ ! "$PR_TITLE" =~ ^(release|feat|fix|chore|docs|refactor|test|style|ci|perf)(\(.*?\))?:\ .* ]]; then 39 | echo "❌ Invalid PR title: '$PR_TITLE'" 40 | echo "Expected format: 'type: description' or 'type(scope): description'" 41 | echo "Allowed types: release, feat, fix, chore, docs, refactor, test, style, ci, perf." 42 | exit 1 43 | fi 44 | 45 | echo "✅ PR title is valid" 46 | -------------------------------------------------------------------------------- /.github/workflows/certora.yml: -------------------------------------------------------------------------------- 1 | # name: Certora 2 | 3 | # on: 4 | # workflow_dispatch: 5 | # pull_request: 6 | # branches: 7 | # - dev 8 | # push: 9 | # branches: 10 | # - dev 11 | # - master 12 | # - release-v* 13 | # - formal-verification 14 | # - m2-mainnet 15 | # - testnet-holesky 16 | 17 | # jobs: 18 | # certora: 19 | # name: Test 20 | 21 | # runs-on: ubuntu-latest 22 | # steps: 23 | 24 | # - uses: actions/checkout@v3 25 | # with: 26 | # submodules: recursive 27 | 28 | # - name: Install Foundry 29 | # uses: foundry-rs/foundry-toolchain@v1 30 | # with: 31 | # version: stable 32 | 33 | # - name: Install forge dependencies 34 | # run: forge install 35 | 36 | # - name: Install Python 37 | # uses: actions/setup-python@v2 38 | # with: 39 | # python-version: '3.10' 40 | # cache: 'pip' 41 | 42 | # - name: Install Java 43 | # uses: actions/setup-java@v2 44 | # with: 45 | # distribution: temurin 46 | # java-version: '17' 47 | 48 | # - name: Install Certora CLI 49 | # run: pip install certora-cli 50 | 51 | # - name: Install Solidity Compiler 52 | # run: | 53 | # pip install solc-select 54 | # solc-select use 0.8.27 --always-install 55 | 56 | # - name: Run Certora Verification 57 | # run: | 58 | # for script in $(ls certora/scripts/{,**}/*.sh | grep -v '\WnoCI\W'); do 59 | # bash "$script" 60 | # done 61 | # env: 62 | # CERTORAKEY: ${{ secrets.CERTORAKEY }} 63 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: 4 | push: 5 | workflow_dispatch: {} 6 | 7 | permissions: 8 | contents: read 9 | pull-requests: read 10 | 11 | env: 12 | CLICOLOR: 1 13 | 14 | jobs: 15 | typos: 16 | name: Typo Linting 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: crate-ci/typos@v1.29.7 21 | with: 22 | config: .github/configs/typos-cli.toml 23 | 24 | go-bindings: 25 | name: Bindings 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 31 | - name: Build and validate 32 | if: github.event_name == 'push' 33 | run: | 34 | make docker 35 | docker run -v `pwd`:/build -w /build --rm -i eigenlayer-contracts:latest bash -c "make gha" 36 | if [ ! -z "$(git status --porcelain)" ]; then git diff; git status; exit 1; fi -------------------------------------------------------------------------------- /.github/workflows/foundry-post-merge.yml: -------------------------------------------------------------------------------- 1 | name: Foundry Post Merge 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - '.github/workflows/foundry-post-merge.yml' 10 | - 'src/**' 11 | - 'lib/**' 12 | - 'foundry.toml' 13 | - '**/*.sol' 14 | 15 | permissions: 16 | contents: read 17 | pull-requests: read 18 | 19 | env: 20 | FOUNDRY_PROFILE: medium 21 | 22 | jobs: 23 | # ----------------------------------------------------------------------- 24 | # Forge Test (Intense) 25 | # ----------------------------------------------------------------------- 26 | 27 | continuous-fuzzing: 28 | name: Test (Intense) 29 | runs-on: protocol-x64-16core 30 | strategy: 31 | fail-fast: true 32 | steps: 33 | # Check out repository with all submodules for complete codebase access. 34 | - uses: actions/checkout@v4 35 | with: 36 | submodules: recursive 37 | 38 | # Restore Forge cache 39 | - name: Cache Forge Build 40 | uses: actions/cache@v3 41 | with: 42 | path: | 43 | cache/ 44 | out/ 45 | key: ${{ runner.os }}-forge-${{ hashFiles('**/foundry.toml', '**/remappings.txt', 'src/**/*.sol', 'lib/**/*.sol') }} 46 | restore-keys: | 47 | ${{ runner.os }}-forge- 48 | 49 | # Install the Foundry toolchain. 50 | - name: "Install Foundry" 51 | uses: foundry-rs/foundry-toolchain@v1 52 | with: 53 | version: stable 54 | 55 | # Build the project and display contract sizes. 56 | - name: "Forge Build" 57 | run: | 58 | forge --version 59 | forge build --sizes 60 | id: build 61 | 62 | # Run Forge Test (Intense) 63 | - name: Forge Test (Intense) 64 | run: | 65 | echo -e "\033[1;33mWarning: This workflow may take several hours to complete.\033[0m" 66 | echo -e "\033[1;33mThis intense fuzzing workflow is optional but helps catch edge cases through extended testing.\033[0m" 67 | FOUNDRY_PROFILE=intense forge test -vvv 68 | -------------------------------------------------------------------------------- /.github/workflows/remove-stale-branches.yml: -------------------------------------------------------------------------------- 1 | name: Remove Stale Branches 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" # Everday at midnight 6 | workflow_dispatch: # Allows manual trigger from GitHub UI 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | remove-stale-branches: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: fpicalausa/remove-stale-branches@v1.6.0 16 | with: 17 | dry-run: false # Check out the console output before setting this to false 18 | exempt-authors-regex: "^dependabot" 19 | days-before-branch-stale: 90 20 | days-before-branch-delete: 7 21 | operations-per-run: 100 22 | exempt-branches-regex: "^(main|release-dev/.*|v[0-9]+\\.[0-9]+\\.[0-9]+)$" 23 | ignore-unknown-authors: true 24 | default-recipient: "bowenli86" 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */node_modules 2 | *node_modules 3 | .env 4 | coverage 5 | coverage.json 6 | typechain 7 | config.json 8 | contract.addresses 9 | deployedAddresses 10 | 11 | script/output/eigenpods.json 12 | 13 | #Hardhat files 14 | cache_hardhat 15 | artifacts 16 | *.lock 17 | #Foundry files 18 | out 19 | cache 20 | 21 | *.DS_Store 22 | 23 | broadcast 24 | 25 | # Deployment tools 26 | /data 27 | .idea/ 28 | 29 | # Certora Outputs 30 | .certora_internal/ 31 | .certora_recent_jobs.json 32 | 33 | #script config file 34 | # script/M1_deploy.config.json 35 | script/output/M1_deployment_data.json 36 | /script/output/M2_deployment_data.json 37 | 38 | # autogenerated docs (you can generate these locally) 39 | /docs/docgen/ 40 | 41 | script/misc 42 | 43 | test.sh 44 | 45 | # Surya outputs 46 | InheritanceGraph.png 47 | surya_report.md 48 | 49 | .idea 50 | 51 | *state.json 52 | deployed_strategies.json 53 | populate_src* 54 | 55 | # cerota 56 | .certora_internal/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | [submodule "lib/openzeppelin-contracts-v4.9.0"] 5 | path = lib/openzeppelin-contracts-v4.9.0 6 | url = https://github.com/OpenZeppelin/openzeppelin-contracts 7 | [submodule "lib/openzeppelin-contracts-upgradeable-v4.9.0"] 8 | path = lib/openzeppelin-contracts-upgradeable-v4.9.0 9 | url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable 10 | [submodule "lib/zeus-templates"] 11 | path = lib/zeus-templates 12 | url = https://github.com/Layr-Labs/zeus-templates 13 | [submodule "lib/forge-std"] 14 | path = lib/forge-std 15 | url = https://github.com/foundry-rs/forge-std 16 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "install", 8 | "type": "shell", 9 | "command": "npm install --include=dev", 10 | "options": { 11 | "cwd": "${workspaceFolder}", 12 | }, 13 | "group": { 14 | "kind": "build" 15 | } 16 | }, 17 | { 18 | "label": "fmt", 19 | "type": "shell", 20 | "command": "forge fmt --check src/contracts", 21 | "options": { 22 | "cwd": "${workspaceFolder}" 23 | }, 24 | "dependsOn": "install", 25 | "group": { 26 | "kind": "build" 27 | } 28 | }, 29 | { 30 | "label": "hint", 31 | "type": "shell", 32 | "command": "npm run hint", 33 | "options": { 34 | "cwd": "${workspaceFolder}" 35 | }, 36 | "dependsOn": "fmt", 37 | "group": { 38 | "kind": "build" 39 | } 40 | }, 41 | { 42 | "label": "build", 43 | "type": "shell", 44 | "command": "forge build --sizes", 45 | "options": { 46 | "cwd": "${workspaceFolder}" 47 | }, 48 | "dependsOn": "hint", 49 | "group": { 50 | "kind": "build", 51 | "isDefault": true 52 | } 53 | }, 54 | { 55 | "label": "clean", 56 | "type": "shell", 57 | "command": "forge clean && forge cache clean", 58 | "options": { 59 | "cwd": "${workspaceFolder}" 60 | }, 61 | "dependsOn": "build", 62 | "group": { 63 | "kind": "build", 64 | "isDefault": false 65 | } 66 | }, 67 | { 68 | "label": "test", 69 | "type": "shell", 70 | "command": "forge test -vvv", 71 | "options": { 72 | "cwd": "${workspaceFolder}" 73 | }, 74 | "dependsOn": "hint", 75 | "group": { 76 | "kind": "test", 77 | "isDefault": true 78 | } 79 | }, 80 | ] 81 | } -------------------------------------------------------------------------------- /.zeus: -------------------------------------------------------------------------------- 1 | { 2 | "zeusHost": "https://github.com/Layr-Labs/eigenlayer-contracts-zeus-metadata", 3 | "migrationDirectory": "script/releases" 4 | } -------------------------------------------------------------------------------- /CHANGELOG/CHANGELOG-1.6.0.md: -------------------------------------------------------------------------------- 1 | # v1.6.0 Moocow and ELIP5 2 | 3 | ## Release Manager 4 | 5 | @wadealexc @bowenli86 6 | 7 | ## Highlights 8 | 9 | 🚀 **New Features** 10 | - New APIs supporting Pectra's validator consolidation and withdrawal features: `EigenPod.requestConsolidation(...)` and `EigenPod.requestWithdrawal(...)` 11 | - New getters to support Pectra APIs: `EigenPod.getConsolidationRequestFee()` and `EigenPod.getWithdrawalRequestFee()` 12 | - Added 4 new events to `EigenPod.sol` to track consolidation and withdrawal requests 13 | - Added 2 new events to `Eigen.sol` to track token wraps/unwraps with `BackingEigen` 14 | 15 | 📌 **Deprecations** 16 | - Removed `EigenPod.GENESIS_TIME()` getter. This method, though public, has been unused for over a year. 17 | 18 | 🔧 **Improvements** 19 | - When finalizing an `EigenPod` checkpoint (`proofsRemaining == 0`), the contract will store the finalized checkpoint in storage. This can be queried via `EigenPod.currentCheckpoint()`. Starting a new checkpoint will overwrite this previously-finalized checkpoint. 20 | - Added semver to `Eigen` 21 | - Signatures of a few `EigenPod` events are changed to match the rest events and take validator pubkey hash instead of validator index, which standardized `EigenPod` events signature 22 | 23 | 🐛 Bug Fixes 24 | - For Hoodi, updates fixes ethPOS deposit contract to point to `0x00000000219ab540356cBB839Cbe05303d7705Fa` 25 | 26 | ## Changelog 27 | 28 | - feat: merge Moocow and ELIP5 into main [PR #1425](https://github.com/layr-labs/eigenlayer-contracts/pull/1425) 29 | - docs: proper markdown [PR #1435](https://github.com/layr-labs/eigenlayer-contracts/pull/1435) 30 | - docs: update readme 31 | - chore: update testnet addresses for redistribution [PR #1428](https://github.com/layr-labs/eigenlayer-contracts/pull/1428) 32 | - chore: remove User_M2.t.sol 33 | - feat: update EIGEN binding 34 | - chore: resolve conflicts in upgrade.json 35 | - chore: update harness class formatting 36 | - chore: complete v1.6.0 changelog 37 | - chore: changelog and bindings 38 | - test: add more script tests for Eigen and standardize semver 39 | - feat: add semver to eigen [PR #1371](https://github.com/layr-labs/eigenlayer-contracts/pull/1371) 40 | - feat: add TokenWrapped and TokenUnwrapped events in Eigen for observability [PR #1356](https://github.com/layr-labs/eigenlayer-contracts/pull/1356) 41 | - feat: change eigenpod events to use pubkeyHash over index 42 | - feat: release scripts for moocow and elip5 43 | - feat: currentCheckpoint now returns finalized checkpoint 44 | - feat: implement consolidation and withdrawal requests 45 | -------------------------------------------------------------------------------- /CHANGELOG/CHANGELOG-1.7.0.md: -------------------------------------------------------------------------------- 1 | # v1.7.0 Multi Chain 2 | 3 | **Use this template to draft changelog and submit PR to review by the team** 4 | 5 | 6 | ## Release Manager 7 | 8 | @ypatil12 9 | 10 | 11 | ## Highlights 12 | 13 | 🚀 New Features – Highlight major new functionality 14 | - ... 15 | - ... 16 | 17 | ⛔ Breaking Changes – Call out backward-incompatible changes. 18 | - ... 19 | - ... 20 | 21 | 📌 Deprecations – Mention features that are being phased out. 22 | - ... 23 | - ... 24 | 25 | 🛠️ Security Fixes – Specify patched vulnerabilities. 26 | - ... 27 | - ... 28 | 29 | 🔧 Improvements – Enhancements to existing features. 30 | - ... 31 | - ... 32 | 33 | 🐛 Bug Fixes – List resolved issues. 34 | - ... 35 | - ... 36 | 37 | 38 | ## Changelog 39 | 40 | Copy the one that's auto generated from github by default to here, and submit PR for review 41 | 42 | 43 | - merged PRs in diff from last release 44 | - contributors 45 | - etc 46 | -------------------------------------------------------------------------------- /CHANGELOG/CHANGELOG-template.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | **Use this template to draft changelog and submit PR to review by the team** 4 | 5 | ## Release Manager 6 | 7 | github handle of release manager 8 | 9 | ## Highlights 10 | 11 | 🚀 New Features – Highlight major new functionality 12 | - ... 13 | - ... 14 | 15 | ⛔ Breaking Changes – Call out backward-incompatible changes. 16 | - ... 17 | - ... 18 | 19 | 📌 Deprecations – Mention features that are being phased out. 20 | - ... 21 | - ... 22 | 23 | 🛠️ Security Fixes – Specify patched vulnerabilities. 24 | - ... 25 | - ... 26 | 27 | 🔧 Improvements – Enhancements to existing features. 28 | - ... 29 | - ... 30 | 31 | 🐛 Bug Fixes – List resolved issues. 32 | - ... 33 | - ... 34 | 35 | 36 | ## Changelog 37 | 38 | To generate a changelog of commits added since the last release using Git on 39 | the command line, follow these steps: 40 | 41 | 1. Identify the last release tag 42 | 43 | First, list your tags (assuming you use Git tags for releases): 44 | 45 | ``` 46 | git tag --sort=-creatordate 47 | ``` 48 | 49 | This shows your most recent tags at the top. Let's say the last release tag is `v1.4.2` 50 | 51 | 52 | 2. Generate the changelog 53 | 54 | Now, use the following command to list the commits since that tag, and auto generate github PR link if there's any 55 | 56 | ``` 57 | git log v1.4.2..HEAD --pretty=format:"%s" --no-merges | \ 58 | sed -E 's/^(.*)\(#([0-9]+)\)$/- \1[PR #\2](https:\/\/github.com\/layr-labs\/eigenlayer-contracts\/pull\/\2)/' | \ 59 | sed -E '/\[PR #[0-9]+\]/! s/^(.*)$/- \1/' 60 | ``` 61 | 62 | This will show: 63 | 64 | - Only commits since v1.4.2 up to the current HEAD 65 | - One-line commit messages (%s) with the author name (%an) 66 | 67 | 68 | An example output is: 69 | 70 | ``` 71 | - ci: add explicit permissions to workflows to mitigate security concerns [PR #1392](https://github.com/layr-labs/eigenlayer-contracts/pull/1392) 72 | - ci: remove branch constraint for foundry coverage job 73 | - docs: add release managers to changelogs 74 | - docs: add templates for changelog and release notes [PR #1382](https://github.com/layr-labs/eigenlayer-contracts/pull/1382) 75 | - docs: add doc for steps to write deploy scripts [PR #1380](https://github.com/layr-labs/eigenlayer-contracts/pull/1380) 76 | - ci: add testnet envs sepolia and hoodi to validate-deployment-scripts [PR #1378](https://github.com/layr-labs/eigenlayer-contracts/pull/1378) 77 | - docs: update MAINTENANCE to include practices of merging multiple release-dev branches 78 | - docs: updating readme for dead links, readability, new language, and more [PR #1377](https://github.com/layr-labs/eigenlayer-contracts/pull/1377) 79 | ... 80 | ``` 81 | 82 | 3. Commit the Changelog 83 | 84 | Copy the output and add here with a commit, then proceed to cut the release from the commit. 85 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | COPY bin /build-bin 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y \ 7 | make curl git \ 8 | software-properties-common \ 9 | jq sudo 10 | RUN /build-bin/install-deps.sh 11 | RUN apt-get clean && \ 12 | rm -rf /var/lib/apt/lists/* 13 | 14 | WORKDIR /workspaces/eigenlayer-contracts 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CONTAINER_NAME = eigenlayer-contracts 3 | 4 | .PHONY: install-hooks 5 | install-hooks: 6 | cp bin/pre-commit.sh .git/hooks/pre-commit 7 | 8 | .PHONY: install-deps 9 | install-deps: 10 | ./bin/install-deps.sh 11 | 12 | .PHONY: deps 13 | deps: install-hooks install-deps 14 | 15 | .PHONY: compile 16 | compile: 17 | forge b 18 | 19 | .PHONY: bindings 20 | bindings: compile 21 | ./bin/compile-bindings.sh 22 | 23 | .PHONY: all 24 | all: compile bindings 25 | 26 | gha: 27 | git config --global --add safe.directory "*" 28 | forge install 29 | forge b 30 | ./bin/compile-bindings.sh 31 | 32 | docker: 33 | docker build --progress=plain -t ${CONTAINER_NAME}:latest . 34 | 35 | compile-in-docker: 36 | docker run -v $(PWD):/build -w /build --rm -it ${CONTAINER_NAME}:latest bash -c "make compile" 37 | 38 | bindings-in-docker: 39 | docker run -v $(PWD):/build -w /build --rm -it ${CONTAINER_NAME}:latest bash -c "make bindings" 40 | 41 | all-in-docker: 42 | docker run -v $(PWD):/build -w /build --rm -it ${CONTAINER_NAME}:latest bash -c "make all" 43 | 44 | gha-docker: 45 | docker run -v $(PWD):/build -w /build --rm -i ${CONTAINER_NAME}:latest bash -c "make gha" 46 | 47 | storage-report: 48 | bash "bin/storage-report.sh" "docs/storage-report/" 49 | 50 | fix-typos: 51 | typos --config .github/configs/typos-cli.toml --write-changes 52 | 53 | fmt: 54 | forge fmt; FOUNDRY_PROFILE=test forge fmt -------------------------------------------------------------------------------- /audits/M1 Mainnet - Diligence - Mar 2023.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M1 Mainnet - Diligence - Mar 2023.pdf -------------------------------------------------------------------------------- /audits/M1 Mainnet - Sigma Prime - May 2023.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M1 Mainnet - Sigma Prime - May 2023.pdf -------------------------------------------------------------------------------- /audits/M2 Mainnet - Cantina - Apr 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M2 Mainnet - Cantina - Apr 2024.pdf -------------------------------------------------------------------------------- /audits/M2 Mainnet - Sigma Prime - Feb 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M2 Mainnet - Sigma Prime - Feb 2024.pdf -------------------------------------------------------------------------------- /audits/M4 Mainnet (PEPE) - Certora - Aug 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M4 Mainnet (PEPE) - Certora - Aug 2024.pdf -------------------------------------------------------------------------------- /audits/M4 Mainnet (PEPE) - Sigma Prime - Jul 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/M4 Mainnet (PEPE) - Sigma Prime - Jul 2024.pdf -------------------------------------------------------------------------------- /audits/Permissionless Strategies - Sigma Prime - Aug 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/Permissionless Strategies - Sigma Prime - Aug 2024.pdf -------------------------------------------------------------------------------- /audits/Rewards v2 - SigmaPrime - Dec 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/Rewards v2 - SigmaPrime - Dec 2024.pdf -------------------------------------------------------------------------------- /audits/RewardsCoordinator - Sigma Prime - May 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/RewardsCoordinator - Sigma Prime - May 2024.pdf -------------------------------------------------------------------------------- /audits/Token + Programmatic Incentives - Sigma Prime - Sep 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/Token + Programmatic Incentives - Sigma Prime - Sep 2024.pdf -------------------------------------------------------------------------------- /audits/V1.0.0 (Slashing) - Certora - Feb 2025.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/V1.0.0 (Slashing) - Certora - Feb 2025.pdf -------------------------------------------------------------------------------- /audits/V1.0.0 (Slashing) - Sigma Prime - Feb 2025.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/audits/V1.0.0 (Slashing) - Sigma Prime - Feb 2025.pdf -------------------------------------------------------------------------------- /bin/compile-bindings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BINDING_DIR=./pkg/bindings 4 | JSON_DIR=./out 5 | 6 | function create_binding { 7 | contract_name=$1 8 | 9 | mkdir -p $BINDING_DIR/${contract_name} 10 | 11 | contract_json_path="${JSON_DIR}/${contract_name}.sol/${contract_name}.json" 12 | 13 | binding_out_dir="${BINDING_DIR}/${contract_name}" 14 | mkdir -p $binding_out_dir || true 15 | 16 | cat $contract_json_path | jq -r '.abi' > $binding_out_dir/tmp.abi 17 | cat $contract_json_path | jq -r '.bytecode.object' > $binding_out_dir/tmp.bin 18 | 19 | abigen \ 20 | --bin=$binding_out_dir/tmp.bin \ 21 | --abi=$binding_out_dir/tmp.abi \ 22 | --pkg="${contract_name}" \ 23 | --out=$BINDING_DIR/$contract_name/binding.go \ 24 | > /dev/null 2>&1 25 | 26 | if [[ $? == "1" ]]; 27 | then 28 | echo "Failed to generate binding for $contract_json_path" 29 | fi 30 | rm $binding_out_dir/tmp.abi 31 | rm $binding_out_dir/tmp.bin 32 | } 33 | 34 | contracts=$(find src/contracts -type f -name "*.sol" ) 35 | IFS=$'\n' 36 | 37 | for contract_name in $contracts; do 38 | contract_name=$(basename $contract_name .sol) 39 | create_binding $contract_name 40 | done 41 | -------------------------------------------------------------------------------- /bin/install-deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | OS=$(uname -s | tr '[:upper:]' '[:lower:]') 4 | ARCH=$(uname -a | tr '[:upper:]' '[:lower:]') 5 | 6 | linuxAmd64="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.14.6-aadddf3a.tar.gz" 7 | linuxArm64="https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-arm64-1.14.5-0dd173a7.tar.gz" 8 | 9 | 10 | if [[ "$OS" == "linux" ]]; then 11 | sudo apt-get update 12 | sudo apt-get install -y make curl git software-properties-common jq 13 | 14 | if [[ $ARCH == *"x86_64"* ]]; then 15 | curl -L $linuxAmd64 | tar -xz 16 | elif [[ $ARCH == *"aarch64"* ]]; then 17 | curl -L $linuxArm64 | tar -xz 18 | else 19 | echo "Unsupported architecture: $ARCH" 20 | exit 1 21 | fi 22 | elif [[ "$OS" == "darwin" ]]; then 23 | brew tap ethereum/ethereum 24 | brew install libusb ethereum@1.14.5 25 | else 26 | echo "Unsupported OS: $OS" 27 | exit 1 28 | fi 29 | 30 | curl -L https://foundry.paradigm.xyz | bash 31 | 32 | cp -R /root/.foundry/bin/* /usr/local/bin/ 33 | 34 | foundryup 35 | 36 | cp -R /root/.foundry/bin/* /usr/local/bin/ 37 | -------------------------------------------------------------------------------- /bin/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make bindings 4 | -------------------------------------------------------------------------------- /bin/source-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check for arguments 4 | if [ "$#" -ne 1 ]; then 5 | echo "Usage: $0 [local]" 6 | return 1 7 | fi 8 | 9 | case $1 in 10 | local) 11 | CHAIN_ID=31337 12 | FOUNDRY_FUZZ_RUNS=256 13 | ;; 14 | *) 15 | echo "Invalid argument. Usage: $0 [local]" 16 | return 1 17 | ;; 18 | esac 19 | 20 | # Export environment variables 21 | export CHAIN_ID=$CHAIN_ID 22 | export EXECUTOR_MULTISIG=$EXECUTOR_MULTISIG 23 | export FOUNDRY_FUZZ_RUNS=$FOUNDRY_FUZZ_RUNS 24 | 25 | # Print environment variables 26 | echo "Environment variables set:" 27 | echo "CHAIN_ID: $CHAIN_ID" 28 | echo "EXECUTOR_MULTISIG: $EXECUTOR_MULTISIG" 29 | echo "FOUNDRY_FUZZ_RUNS: $FOUNDRY_FUZZ_RUNS" -------------------------------------------------------------------------------- /bin/storage-report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Default output directory 4 | OUTPUT_DIR=${1:-docs/storage-report} 5 | 6 | # Function to print messages 7 | log() { 8 | echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" 9 | } 10 | 11 | # Function to print error messages 12 | error() { 13 | echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >&2 14 | } 15 | 16 | log "Starting the storage report generation." 17 | 18 | # Create the output directory if it doesn't exist 19 | if ! mkdir -p "$OUTPUT_DIR"; then 20 | error "Failed to create output directory: $OUTPUT_DIR" 21 | exit 1 22 | fi 23 | 24 | log "Output directory is set to: $OUTPUT_DIR" 25 | 26 | # Loop through Solidity files and generate storage report 27 | # NOTE: Ignores `src/contracts/interfaces` & `src/contracts/libraries` since they "should" not contain storage logic. 28 | for file in $(find src/contracts -name "*.sol" ! -path "src/contracts/interfaces/*" ! -path "src/contracts/libraries/*"); do 29 | contract_name=$(basename "$file" .sol) 30 | 31 | # Check if the file exists and is readable 32 | if [ ! -r "$file" ]; then 33 | error "Cannot read file: $file" 34 | continue 35 | fi 36 | 37 | log "Processing contract: $contract_name" 38 | 39 | # Run forge inspect and capture errors 40 | if ! forge inspect "$contract_name" storage --pretty > "$OUTPUT_DIR/$contract_name.md"; then 41 | error "Failed to generate storage report for contract: $contract_name" 42 | else 43 | log "Storage report generated for contract: $contract_name" 44 | fi 45 | done -------------------------------------------------------------------------------- /certora/.bin/verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script should not be run directly but instead through a link 4 | # 5 | 6 | usage="$0 [-hd] [-f ' ...'] [-l ] [] []" 7 | 8 | usage_long="\ 9 | Script for verifying contracts.\n\ 10 | \n\ 11 | -h|--help Print this message and exit\n\ 12 | -d|--dev Use dev mode: send to staging and run on master using 13 | certoraRun.py\n\ 14 | -f|--functions Verify the listed functions only (for parametric rules)\n\ 15 | -l|--hash-length hash bound length in bytes\n\ 16 | " 17 | 18 | script=$0 19 | 20 | scriptDir=$(cd $(dirname $script); pwd) 21 | scriptName=$(basename $0 .sh) 22 | contractName=$(echo $scriptName |sed 's/^verify//g') 23 | module=$(basename $scriptDir) 24 | projectBase=$scriptDir/../../.. 25 | confDir=$projectBase/certora/confs/$module 26 | 27 | devFlags="" 28 | certoraRun="certoraRun" 29 | 30 | while [ $# -gt 0 ]; do 31 | case $1 in 32 | -h|--help) 33 | printf -- "${usage_long}\nIn summary:\n\n $usage\n\n" 34 | exit 1 35 | ;; 36 | -d|--dev) 37 | devFlags="--server staging --commit_sha1 d6b1d13a2e01dda0b070d7c12a94f3d4bf27885c" # 7.25.2 38 | certoraRun=certoraRun.py 39 | ;; 40 | -f|--functions) 41 | methods=$2; 42 | shift 43 | ;; 44 | -l|--hash-length) 45 | hashLength=$2; 46 | shift 47 | ;; 48 | -*) 49 | echo "Error: invalid option '$1'" 50 | exit 1 51 | ;; 52 | *) 53 | break 54 | esac 55 | shift; 56 | done 57 | 58 | ARGS= 59 | 60 | if [[ "$2" ]]; then 61 | ARGS+="--rule $2" 62 | fi 63 | 64 | if [[ $methods ]]; then 65 | ARGS+=" --method $methods" 66 | fi 67 | 68 | if [[ $hashLength ]]; then 69 | ARGS+=" --hashing_length_bound $hashLength" 70 | fi 71 | 72 | ( 73 | cd $projectBase 74 | $certoraRun $confDir/$contractName.conf $ARGS --msg "$contractName $1 $2" $devFlags 75 | ) 76 | -------------------------------------------------------------------------------- /certora/confs/core/AllocationManager.conf: -------------------------------------------------------------------------------- 1 | { 2 | "assert_autofinder_success": true, 3 | "files": [ 4 | "src/contracts/core/AllocationManager.sol", 5 | "src/contracts/permissions/PauserRegistry.sol", 6 | "src/contracts/permissions/PermissionController.sol", 7 | "src/contracts/core/DelegationManager.sol", 8 | "src/contracts/pods/EigenPodManager.sol", 9 | "src/contracts/core/StrategyManager.sol", 10 | "src/contracts/strategies/StrategyBase.sol", 11 | "certora/mocks/CertoraAVSRegistrar.sol", 12 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 13 | "src/contracts/libraries/OperatorSetLib.sol" 14 | ], 15 | "java_args": [ 16 | ], 17 | "link": [ 18 | "AllocationManager:pauserRegistry=PauserRegistry", 19 | "DelegationManager:permissionController=PermissionController", 20 | "DelegationManager:allocationManager=AllocationManager", 21 | "AllocationManager:permissionController=PermissionController", 22 | "DelegationManager:strategyManager=StrategyManager", 23 | "AllocationManager:delegation=DelegationManager", 24 | "EigenPodManager:delegationManager=DelegationManager", 25 | "DelegationManager:eigenPodManager=EigenPodManager" 26 | ], 27 | "loop_iter": "1", 28 | "optimistic_fallback": true, 29 | "optimistic_loop": true, 30 | "packages": [ 31 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 32 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 33 | ], 34 | "parametric_contracts": [ 35 | "AllocationManager" 36 | ], 37 | "process": "emv", 38 | "prover_args": [ 39 | " -recursionErrorAsAssert false -recursionEntryLimit 3" 40 | ], 41 | "solc": "solc8.27", 42 | "solc_optimize": "1", 43 | "verify": "AllocationManager:certora/specs/core/AllocationManagerRules.spec", 44 | "server": "production", 45 | } 46 | -------------------------------------------------------------------------------- /certora/confs/core/AllocationManagerSanity.conf: -------------------------------------------------------------------------------- 1 | { 2 | "assert_autofinder_success": true, 3 | "files": [ 4 | "src/contracts/core/AllocationManager.sol", 5 | "src/contracts/permissions/PauserRegistry.sol", 6 | "src/contracts/permissions/PermissionController.sol", 7 | "src/contracts/core/DelegationManager.sol", 8 | "src/contracts/pods/EigenPodManager.sol", 9 | "src/contracts/core/StrategyManager.sol", 10 | "src/contracts/strategies/StrategyBase.sol", 11 | "certora/mocks/CertoraAVSRegistrar.sol", 12 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 13 | "src/contracts/libraries/OperatorSetLib.sol" 14 | ], 15 | "java_args": [ 16 | ], 17 | "link": [ 18 | "AllocationManager:pauserRegistry=PauserRegistry", 19 | "DelegationManager:permissionController=PermissionController", 20 | "DelegationManager:allocationManager=AllocationManager", 21 | "AllocationManager:permissionController=PermissionController", 22 | "DelegationManager:strategyManager=StrategyManager", 23 | "AllocationManager:delegation=DelegationManager", 24 | "EigenPodManager:delegationManager=DelegationManager", 25 | "DelegationManager:eigenPodManager=EigenPodManager" 26 | ], 27 | "loop_iter": "2", 28 | "optimistic_fallback": true, 29 | "optimistic_loop": true, 30 | "packages": [ 31 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 32 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 33 | ], 34 | "parametric_contracts": [ 35 | "AllocationManager" 36 | ], 37 | "process": "emv", 38 | "prover_args": [ 39 | " -recursionErrorAsAssert false -recursionEntryLimit 3" 40 | ], 41 | "solc": "solc8.27", 42 | "solc_optimize": "1", 43 | "solc_via_ir": true, 44 | "verify": "AllocationManager:certora/specs/core/AllocationManagerSanity.spec" 45 | } 46 | -------------------------------------------------------------------------------- /certora/confs/core/DelegationManager.conf: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "certora/harnesses/DelegationManagerHarness.sol", 4 | "certora/harnesses/ShortStringsUpgradeableHarness.sol", 5 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 6 | "lib/openzeppelin-contracts-v4.9.0/contracts/mocks/ERC1271WalletMock.sol", 7 | "src/contracts/pods/EigenPodManager.sol", 8 | "src/contracts/pods/EigenPod.sol", 9 | "src/contracts/strategies/StrategyBase.sol", 10 | "src/contracts/core/StrategyManager.sol", 11 | "src/contracts/permissions/PauserRegistry.sol", 12 | "src/contracts/core/DelegationManager.sol", 13 | "src/contracts/permissions/PermissionController.sol", 14 | "src/contracts/core/AllocationManager.sol" 15 | ], 16 | "link": [ 17 | "AllocationManager:delegation=DelegationManagerHarness", 18 | "DelegationManagerHarness:permissionController=PermissionController", 19 | "DelegationManagerHarness:allocationManager=AllocationManager", 20 | "AllocationManager:permissionController=PermissionController", 21 | "DelegationManagerHarness:strategyManager=StrategyManager", 22 | "EigenPodManager:delegationManager=DelegationManagerHarness", 23 | "DelegationManagerHarness:eigenPodManager=EigenPodManager" 24 | ], 25 | "loop_iter": "2", 26 | "optimistic_fallback": true, 27 | "optimistic_hashing": true, 28 | "hashing_length_bound": "320", 29 | "optimistic_loop": true, 30 | "prover_args": [ 31 | "-destructiveOptimizations twostage", 32 | "-mediumTimeout 20", 33 | "-lowTimeout 20", 34 | "-tinyTimeout 20", 35 | "-depth 20" 36 | ], 37 | "packages": [ 38 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 39 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 40 | ], 41 | "parametric_contracts": [ 42 | "DelegationManagerHarness" 43 | ], 44 | "rule_sanity": "basic", 45 | "process": "emv", 46 | "solc": "solc8.27", 47 | "solc_optimize": "1", 48 | "solc_via_ir": true, 49 | "verify": "DelegationManagerHarness:certora/specs/core/DelegationManager.spec" 50 | } 51 | -------------------------------------------------------------------------------- /certora/confs/core/DelegationManagerValidState.conf: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "certora/harnesses/DelegationManagerHarness.sol", 4 | "certora/harnesses/ShortStringsUpgradeableHarness.sol", 5 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 6 | "lib/openzeppelin-contracts-v4.9.0/contracts/mocks/ERC1271WalletMock.sol", 7 | "src/contracts/pods/EigenPodManager.sol", 8 | "src/contracts/pods/EigenPod.sol", 9 | "src/contracts/strategies/StrategyBase.sol", 10 | "src/contracts/core/StrategyManager.sol", 11 | "src/contracts/permissions/PauserRegistry.sol", 12 | "src/contracts/core/DelegationManager.sol", 13 | "src/contracts/permissions/PermissionController.sol", 14 | "src/contracts/core/AllocationManager.sol" 15 | ], 16 | "link": [ 17 | "AllocationManager:delegation=DelegationManagerHarness", 18 | "DelegationManagerHarness:permissionController=PermissionController", 19 | "DelegationManagerHarness:allocationManager=AllocationManager", 20 | "AllocationManager:permissionController=PermissionController", 21 | "DelegationManagerHarness:strategyManager=StrategyManager", 22 | "EigenPodManager:delegationManager=DelegationManagerHarness", 23 | "DelegationManagerHarness:eigenPodManager=EigenPodManager" 24 | ], 25 | "loop_iter": "1", 26 | "optimistic_fallback": true, 27 | "optimistic_hashing": true, 28 | "hashing_length_bound": "320", 29 | "optimistic_loop": true, 30 | "packages": [ 31 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 32 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 33 | ], 34 | "parametric_contracts": [ 35 | "DelegationManagerHarness" 36 | ], 37 | "rule_sanity": "basic", 38 | "process": "emv", 39 | "solc": "solc8.27", 40 | "solc_optimize": "1", 41 | "solc_via_ir": true, 42 | "verify": "DelegationManagerHarness:certora/specs/core/DelegationManagerValidState.spec" 43 | } 44 | -------------------------------------------------------------------------------- /certora/confs/core/StrategyManager.conf: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "certora/harnesses/ShortStringsUpgradeableHarness.sol", 4 | "certora/harnesses/StrategyManagerHarness.sol", 5 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 6 | "lib/openzeppelin-contracts-v4.9.0/contracts/mocks/ERC1271WalletMock.sol", 7 | "src/contracts/pods/EigenPodManager.sol", 8 | "src/contracts/pods/EigenPod.sol", 9 | "src/contracts/strategies/StrategyBase.sol", 10 | "src/contracts/core/DelegationManager.sol", 11 | "src/contracts/permissions/PauserRegistry.sol", 12 | "src/contracts/core/AllocationManager.sol" 13 | ], 14 | "link": [ 15 | "DelegationManager:allocationManager=AllocationManager", 16 | "DelegationManager:eigenPodManager=EigenPodManager", 17 | "StrategyManagerHarness:delegation=DelegationManager" 18 | ], 19 | "loop_iter": "2", 20 | "optimistic_fallback": true, 21 | "optimistic_hashing": true, 22 | "hashing_length_bound": "320", 23 | "optimistic_loop": true, 24 | "packages": [ 25 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 26 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 27 | ], 28 | "parametric_contracts": [ 29 | "StrategyManagerHarness" 30 | ], 31 | "process": "emv", 32 | "solc": "solc8.27", 33 | "solc_optimize": "1", 34 | "solc_via_ir": true, 35 | "verify": "StrategyManagerHarness:certora/specs/core/StrategyManager.spec", 36 | "rule_sanity": "basic" 37 | } 38 | -------------------------------------------------------------------------------- /certora/confs/permissions/Pausable.conf: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "certora/harnesses/PausableHarness.sol", 4 | "src/contracts/permissions/PauserRegistry.sol" 5 | ], 6 | "link": [ 7 | "PausableHarness:pauserRegistry=PauserRegistry" 8 | ], 9 | "loop_iter": "3", 10 | "optimistic_fallback": true, 11 | "optimistic_loop": true, 12 | "process": "emv", 13 | "prover_args": [ 14 | " -recursionErrorAsAssert false -recursionEntryLimit 3" 15 | ], 16 | "solc": "solc8.27", 17 | "solc_optimize": "1", 18 | "solc_via_ir": true, 19 | "verify": "PausableHarness:certora/specs/permissions/Pausable.spec" 20 | } 21 | -------------------------------------------------------------------------------- /certora/confs/pods/EigenPodManagerRules.conf: -------------------------------------------------------------------------------- 1 | { 2 | "assert_autofinder_success": true, 3 | "auto_dispatcher": true, 4 | "optimistic_summary_recursion": true, 5 | "summary_recursion_limit": "1", 6 | "optimistic_contract_recursion": true, 7 | "contract_recursion_limit": "1", 8 | // "optimistic_hashing": true, 9 | // "hashing_length_bound": "4700", 10 | "files": [ 11 | "src/contracts/pods/EigenPodManager.sol", 12 | "src/contracts/core/DelegationManager.sol", 13 | "src/contracts/permissions/PermissionController.sol", 14 | "src/contracts/core/AllocationManager.sol", 15 | "src/contracts/core/StrategyManager.sol", 16 | "src/contracts/permissions/PauserRegistry.sol", 17 | "src/contracts/pods/EigenPod.sol", 18 | "src/test/mocks/ETHDepositMock.sol:ETHPOSDepositMock", 19 | "lib/openzeppelin-contracts-v4.9.0/contracts/utils/Create2.sol", 20 | // 21 | // "src/contracts/strategies/StrategyBase.sol", 22 | // "certora/mocks/CertoraAVSRegistrar.sol", 23 | // "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol" 24 | ], 25 | "java_args": [ 26 | ], 27 | "link": [ 28 | "EigenPodManager:delegationManager=DelegationManager", 29 | "AllocationManager:pauserRegistry=PauserRegistry", 30 | "DelegationManager:permissionController=PermissionController", 31 | "DelegationManager:allocationManager=AllocationManager", 32 | "AllocationManager:permissionController=PermissionController", 33 | "DelegationManager:strategyManager=StrategyManager", 34 | "AllocationManager:delegation=DelegationManager", 35 | "DelegationManager:eigenPodManager=EigenPodManager" 36 | ], 37 | "loop_iter": "3", 38 | "optimistic_fallback": true, 39 | "optimistic_loop": true, 40 | "packages": [ 41 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 42 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 43 | ], 44 | "parametric_contracts": [ 45 | "EigenPodManager" 46 | ], 47 | "process": "emv", 48 | "prover_args": [ 49 | " -recursionErrorAsAssert false -recursionEntryLimit 3" 50 | ], 51 | "solc": "solc8.27", 52 | "solc_optimize": "1", 53 | "solc_via_ir": true, 54 | "verify": "EigenPodManager:certora/specs/pods/EigenPodManagerRules.spec", 55 | "server": "production", 56 | "rule_sanity": "basic" 57 | } 58 | -------------------------------------------------------------------------------- /certora/confs/strategies/StrategyBase.conf: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "src/contracts/strategies/StrategyBase.sol", 4 | "lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol", 5 | "src/contracts/core/StrategyManager.sol", 6 | "src/contracts/permissions/PauserRegistry.sol" 7 | ], 8 | "link": [ 9 | "StrategyBase:strategyManager=StrategyManager" 10 | ], 11 | "loop_iter": "3", 12 | "optimistic_fallback": true, 13 | "optimistic_loop": true, 14 | "packages": [ 15 | "@openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0", 16 | "@openzeppelin=lib/openzeppelin-contracts-v4.9.0" 17 | ], 18 | "parametric_contracts": [ 19 | "StrategyBase" 20 | ], 21 | "process": "emv", 22 | "prover_args": [ 23 | ], 24 | "solc": "solc8.27", 25 | "solc_optimize": "1", 26 | "solc_via_ir": true, 27 | "verify": "StrategyBase:certora/specs/strategies/StrategyBase.spec" 28 | } 29 | -------------------------------------------------------------------------------- /certora/harnesses/DelegationManagerHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/DelegationManager.sol"; 5 | 6 | contract DelegationManagerHarness is DelegationManager { 7 | 8 | constructor( 9 | IStrategyManager _strategyManager, 10 | IEigenPodManager _eigenPodManager, 11 | IAllocationManager _allocationManager, 12 | IPauserRegistry _pauserRegistry, 13 | IPermissionController _permissionController, 14 | uint32 _MIN_WITHDRAWAL_DELAY, 15 | string memory _version 16 | ) 17 | DelegationManager( 18 | _strategyManager, 19 | _eigenPodManager, 20 | _allocationManager, 21 | _pauserRegistry, 22 | _permissionController, 23 | _MIN_WITHDRAWAL_DELAY, 24 | _version 25 | ) {} 26 | 27 | function get_operatorShares(address operator, IStrategy strategy) public view returns (uint256) { 28 | return operatorShares[operator][strategy]; 29 | } 30 | 31 | function get_stakerDelegateableShares(address staker, IStrategy strategy) public view returns (uint256) { 32 | // this is the address of the virtual 'beaconChainETH' strategy 33 | if (address(strategy) == 0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0) { 34 | int256 beaconChainETHShares = eigenPodManager.podOwnerDepositShares(staker); 35 | if (beaconChainETHShares <= 0) { 36 | return 0; 37 | } else { 38 | return uint256(beaconChainETHShares); 39 | } 40 | } else { 41 | return strategyManager.stakerDepositShares(staker, strategy); 42 | } 43 | } 44 | 45 | function get_min_withdrawal_delay_blocks() public view returns (uint32) { 46 | return MIN_WITHDRAWAL_DELAY_BLOCKS; 47 | } 48 | 49 | function canCall(address account, address caller, address target, uint32 selector) external returns (bool) { 50 | return permissionController.canCall(account, caller, target, bytes4(selector)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /certora/harnesses/EigenPodHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/pods/EigenPod.sol"; 5 | 6 | contract EigenPodHarness is EigenPod { 7 | 8 | constructor( 9 | IETHPOSDeposit _ethPOS, 10 | IEigenPodManager _eigenPodManager, 11 | string memory _version 12 | ) 13 | EigenPod(_ethPOS, _eigenPodManager, _version) {} 14 | 15 | function get_validatorIndex(bytes32 pubkeyHash) public view returns (uint64) { 16 | return _validatorPubkeyHashToInfo[pubkeyHash].validatorIndex; 17 | } 18 | 19 | function get_restakedBalanceGwei(bytes32 pubkeyHash) public view returns (uint64) { 20 | return _validatorPubkeyHashToInfo[pubkeyHash].restakedBalanceGwei; 21 | } 22 | 23 | function get_mostRecentBalanceUpdateTimestamp(bytes32 pubkeyHash) public view returns (uint64) { 24 | return _validatorPubkeyHashToInfo[pubkeyHash].mostRecentBalanceUpdateTimestamp; 25 | } 26 | 27 | function get_podOwnerShares() public view returns (int256) { 28 | return eigenPodManager.podOwnerShares(podOwner); 29 | } 30 | 31 | function get_withdrawableRestakedExecutionLayerGwei() public view returns (uint256) { 32 | return withdrawableRestakedExecutionLayerGwei; 33 | } 34 | 35 | function get_ETH_Balance() public view returns (uint256) { 36 | return address(this).balance; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /certora/harnesses/EigenPodManagerHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/pods/EigenPodManager.sol"; 5 | 6 | contract EigenPodManagerHarness is EigenPodManager { 7 | 8 | constructor( 9 | IETHPOSDeposit _ethPOS, 10 | IBeacon _eigenPodBeacon, 11 | IStrategyManager _strategyManager, 12 | ISlasher _slasher, 13 | IDelegationManager _delegationManager 14 | ) 15 | EigenPodManager(_ethPOS, _eigenPodBeacon, _strategyManager, _slasher, _delegationManager) {} 16 | 17 | function get_podOwnerShares(address podOwner) public view returns (int256) { 18 | return podOwnerShares[podOwner]; 19 | } 20 | 21 | function get_podByOwner(address podOwner) public view returns (IEigenPod) { 22 | return ownerToPod[podOwner]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /certora/harnesses/PausableHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/permissions/Pausable.sol"; 5 | 6 | contract PausableHarness is Pausable { 7 | constructor( 8 | IPauserRegistry _pauserRegistry 9 | ) Pausable(_pauserRegistry) 10 | {} 11 | 12 | // getters 13 | function isPauser(address pauser) external view returns (bool) { 14 | return pauserRegistry.isPauser(pauser); 15 | } 16 | 17 | function unpauser() external view returns (address) { 18 | return pauserRegistry.unpauser(); 19 | } 20 | 21 | // bitwise operations 22 | function bitwise_not(uint256 input) external pure returns (uint256) { 23 | return (~input); 24 | } 25 | 26 | function bitwise_and(uint256 input_1, uint256 input_2) external pure returns (uint256) { 27 | return (input_1 & input_2); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /certora/harnesses/ShortStringsUpgradeableHarness.sol: -------------------------------------------------------------------------------- 1 | import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol"; 2 | 3 | contract ShortStringsUpgradeableHarness { 4 | using ShortStringsUpgradeable for ShortString; 5 | function toStringHarness(ShortString sstr) external pure returns (string memory) { 6 | // Get the length of the string 7 | uint256 len = sstr.byteLength(); 8 | 9 | // Create a bytes array of the correct length 10 | bytes memory bytesArray = new bytes(len); 11 | 12 | // Copy each byte directly from the ShortString to bytesArray 13 | bytes32 raw = ShortString.unwrap(sstr); 14 | for (uint256 i = 0; i < len; i++) { 15 | bytesArray[i] = raw[i]; 16 | } 17 | 18 | // Convert bytes to string 19 | return string(bytesArray); 20 | } 21 | } -------------------------------------------------------------------------------- /certora/harnesses/StrategyManagerHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/StrategyManager.sol"; 5 | 6 | contract StrategyManagerHarness is StrategyManager { 7 | constructor( 8 | IDelegationManager _delegation, 9 | IPauserRegistry _pauseRegistry, 10 | string memory _version 11 | ) StrategyManager(_delegation, _pauseRegistry, _version) 12 | {} 13 | 14 | function strategy_is_in_stakers_array(address staker, IStrategy strategy) public view returns (bool) { 15 | uint256 length = stakerStrategyList[staker].length; 16 | for (uint256 i = 0; i < length; ++i) { 17 | if (stakerStrategyList[staker][i] == strategy) { 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | 24 | function num_times_strategy_is_in_stakers_array(address staker, IStrategy strategy) public view returns (uint256) { 25 | uint256 length = stakerStrategyList[staker].length; 26 | uint256 res = 0; 27 | for (uint256 i = 0; i < length; ++i) { 28 | if (stakerStrategyList[staker][i] == strategy) { 29 | res += 1; 30 | } 31 | } 32 | return res; 33 | } 34 | 35 | // checks that stakerStrategyList[staker] contains no duplicates and that all strategies in array have nonzero shares 36 | function array_exhibits_properties(address staker) public view returns (bool) { 37 | uint256 length = stakerStrategyList[staker].length; 38 | uint256 res = 0; 39 | // loop for each strategy in array 40 | for (uint256 i = 0; i < length; ++i) { 41 | IStrategy strategy = stakerStrategyList[staker][i]; 42 | // check that staker's shares in strategy are nonzero 43 | if (stakerDepositShares[staker][strategy] == 0) { 44 | return false; 45 | } 46 | // check that strategy is not duplicated in array 47 | if (num_times_strategy_is_in_stakers_array(staker, strategy) != 1) { 48 | return false; 49 | } 50 | } 51 | return true; 52 | } 53 | 54 | function totalShares(address strategy) public view returns (uint256) { 55 | return IStrategy(strategy).totalShares(); 56 | } 57 | 58 | function get_stakerDepositShares(address staker, IStrategy strategy) public view returns (uint256) { 59 | return stakerDepositShares[staker][strategy]; 60 | } 61 | 62 | function sharesToUnderlyingView(address strategy, uint256 shares) public returns (uint256) { 63 | return IStrategy(strategy).sharesToUnderlyingView(shares); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /certora/mocks/CertoraAVSRegistrar.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/contracts/interfaces/IAVSRegistrar.sol"; 5 | 6 | contract CertoraAVSRegistrar is IAVSRegistrar { 7 | function registerOperator(address, address, uint32[] calldata, bytes calldata) external {} 8 | function deregisterOperator(address, address, uint32[] calldata) external {} 9 | 10 | function supportsAVS( 11 | address 12 | ) external view returns (bool) { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /certora/scripts/core/verifyAllocationManager.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/core/verifyAllocationManagerSanity.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/core/verifyDelegationManager.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/core/verifyDelegationManagerValidState.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/core/verifyStrategyManager.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/permissions/verifyPausable.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/pods/verifyEigenPod.sh: -------------------------------------------------------------------------------- 1 | if [[ "$2" ]] 2 | then 3 | RULE="--rule $2" 4 | fi 5 | 6 | # solc-select use 0.8.27 7 | 8 | # certoraRun certora/harnesses/EigenPodHarness.sol \ 9 | # src/contracts/core/DelegationManager.sol src/contracts/pods/EigenPodManager.sol \ 10 | # src/contracts/permissions/PauserRegistry.sol \ 11 | # src/contracts/core/StrategyManager.sol \ 12 | # src/contracts/strategies/StrategyBase.sol \ 13 | # lib/openzeppelin-contracts-v4.9.0/contracts/token/ERC20/ERC20.sol \ 14 | # lib/openzeppelin-contracts-v4.9.0/contracts/mocks/ERC1271WalletMock.sol \ 15 | # --verify EigenPodHarness:certora/specs/pods/EigenPod.spec \ 16 | # --optimistic_loop \ 17 | # --prover_args '-recursionEntryLimit 3' \ 18 | # --optimistic_hashing \ 19 | # --parametric_contracts EigenPodHarness \ 20 | # $RULE \ 21 | # --loop_iter 1 \ 22 | # --packages @openzeppelin=lib/openzeppelin-contracts-v4.9.0 @openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0 \ 23 | # --msg "EigenPod $1 $2" \ 24 | -------------------------------------------------------------------------------- /certora/scripts/pods/verifyEigenPodManager.sh: -------------------------------------------------------------------------------- 1 | if [[ "$2" ]] 2 | then 3 | RULE="--rule $2" 4 | fi 5 | 6 | # solc-select use 0.8.27 7 | 8 | # certoraRun certora/harnesses/EigenPodManagerHarness.sol \ 9 | # src/contracts/core/DelegationManager.sol src/contracts/pods/EigenPod.sol src/contracts/strategies/StrategyBase.sol src/contracts/core/StrategyManager.sol \ 10 | # src/contracts/permissions/PauserRegistry.sol \ 11 | # --verify EigenPodManagerHarness:certora/specs/pods/EigenPodManager.spec \ 12 | # --optimistic_loop \ 13 | # --optimistic_fallback \ 14 | # --optimistic_hashing \ 15 | # --parametric_contracts EigenPodManagerHarness \ 16 | # $RULE \ 17 | # --loop_iter 3 \ 18 | # --packages @openzeppelin=lib/openzeppelin-contracts-v4.9.0 @openzeppelin-upgrades=lib/openzeppelin-contracts-upgradeable-v4.9.0 \ 19 | # --msg "EigenPodManager $1 $2" \ 20 | -------------------------------------------------------------------------------- /certora/scripts/pods/verifyEigenPodManagerRules.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/pods/verifyEigenPodManagerSanity.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/scripts/strategies/verifyStrategyBase.sh: -------------------------------------------------------------------------------- 1 | ../../.bin/verify.sh -------------------------------------------------------------------------------- /certora/specs/core/AllocationManagerRules.spec: -------------------------------------------------------------------------------- 1 | import "./AllocationManagerValidState.spec"; 2 | 3 | use invariant maxMagnitudeHistoryKeysMonotonicInc; 4 | use invariant maxMagnitudeHistoryKeysLessThanCurrentBlock; 5 | use invariant maxMagnitudeMonotonicallyDecreasing; 6 | use invariant SetInRegisteredIFFStatusIsTrue; 7 | use invariant encumberedMagnitudeEqSumOfCurrentMagnitudesAndPositivePending; 8 | use invariant negativePendingDiffAtMostCurrentMagnitude; 9 | use invariant deallocationQueueDataUniqueness; 10 | use invariant noZeroKeyInDealocationQ; 11 | use invariant deallocationQueueEffectBlocLessThanCurrBlockNumberPlushDelayPlusOne; 12 | use invariant deallocationQueueEffectBlockAscesndingOrder; 13 | use invariant noPositivePendingDiffInDeallocationQ; 14 | use invariant effectBlockZeroHasNoPendingDiff; 15 | 16 | /* 17 | This rule applies to all methods except modifyAllocation because this function makes valid transitions, 18 | but only at the memory level. first, it loads allocation from memory, makes several valid transitions, 19 | and then stores it in the storage again, which can lead to an overall violation. 20 | */ 21 | /// @title pendingDiff can transition from 0 to negative or positive, from positive zero only, from negative to negative or to zero. 22 | /// @property pendingDiffs state transitions 23 | rule pendingDiffStateTransitions(method f, address operator, bytes32 setKey, address strategy) 24 | filtered {f -> f.selector != sig:modifyAllocations(address,IAllocationManagerTypes.AllocateParams[]).selector} { 25 | env e; 26 | calldataarg args; 27 | requireValidState(); 28 | 29 | require didMakeInvalidPendingDiffTransition == false; 30 | 31 | f(e, args); 32 | 33 | assert didMakeInvalidPendingDiffTransition == false; 34 | } 35 | 36 | // this rule is for modifyAllocations where when all the effectblock are in the future, this function cannot make more than one transition at a time. 37 | rule pendingDiffStateTransitionModifyAllocations(method f) 38 | filtered {f -> f.selector == sig:modifyAllocations(address,IAllocationManagerTypes.AllocateParams[]).selector} { 39 | env e; 40 | calldataarg args; 41 | requireValidState(); 42 | require forall address operator . forall bytes32 setKey . forall address strategy . allocationsEffectBlock[operator][setKey][strategy] > e.block.number; 43 | 44 | require didMakeInvalidPendingDiffTransition == false; 45 | 46 | f(e, args); 47 | 48 | assert didMakeInvalidPendingDiffTransition == false; 49 | } 50 | -------------------------------------------------------------------------------- /certora/specs/core/AllocationManagerSanity.spec: -------------------------------------------------------------------------------- 1 | import "../optimizations.spec"; 2 | 3 | using AllocationManager as AllocationManager; 4 | methods { 5 | function AllocationManager.DEALLOCATION_DELAY() external returns(uint32) envfree; 6 | 7 | // external calls to AVSRegistrar. Note that the source does not have a proper implementation, the one available always reverts 8 | function _.registerOperator(address,address,uint32[],bytes) external => DISPATCHER(true); 9 | function _.deregisterOperator(address,address,uint32[]) external => DISPATCHER(true); 10 | function _.supportsAVS(address) external => DISPATCHER(true); 11 | 12 | // external calls to Strategy contracts 13 | function _.underlyingToken() external => DISPATCHER(true); 14 | function _.withdraw(address,address,uint256) external => DISPATCHER(true); 15 | 16 | // external calls to ERC20 17 | function _.balanceOf(address) external => DISPATCHER(true); 18 | function _.transfer(address,uint256) external => DISPATCHER(true); 19 | 20 | function OperatorSetLib.key(OperatorSetLib.OperatorSet memory os) internal returns (bytes32) => returnOperatorSetKey(os); // expect (bytes32); // return unique bytes32 that is not zero. 21 | 22 | // internal math summary to avoid overflows from the tool; 23 | // function AllocationManager._addInt128(uint64 a, int128 b) internal returns (uint64) => cvlAddInt128(a, b); 24 | } 25 | 26 | function cvlAddInt128(uint64 a, int128 b) returns uint64 { 27 | require(b >= 0 || to_mathint(a) > to_mathint(-b)); // Prevent underflow 28 | require(b <= 0 || a < to_mathint(max_uint64) -to_mathint(b)); // Prevent overflow 29 | return require_uint64(to_mathint(a) + to_mathint(b)); 30 | } 31 | 32 | function returnOperatorSetKey(OperatorSetLib.OperatorSet os) returns bytes32 { 33 | return idToKey[os.id]; 34 | } 35 | 36 | ghost mapping(uint32 => bytes32) idToKey { 37 | axiom forall uint32 id1 . forall uint32 id2 . (idToKey[id1] != to_bytes32(0) && idToKey[id2] != to_bytes32(0)) && 38 | (id1 != id2 => idToKey[id1] != idToKey[id2]); 39 | } 40 | 41 | use builtin rule sanity; 42 | -------------------------------------------------------------------------------- /certora/specs/optimizations.spec: -------------------------------------------------------------------------------- 1 | // optimizing summaries 2 | 3 | methods { 4 | function Math.mulDiv(uint256 x, uint256 y, uint256 denominator) internal returns (uint256) => cvlMulDiv(x, y, denominator); 5 | function Math.mulDiv(uint256 x, uint256 y, uint256 denominator, Math.Rounding rounding) internal returns (uint256) => cvlMulDivDirectional(x, y, denominator, rounding); 6 | function MathUpgradeable.average(uint256 a, uint256 b) internal returns (uint256) => cvlAverage(a, b); 7 | } 8 | 9 | function cvlMulDiv(uint256 x, uint256 y, uint256 denominator) returns uint256 { 10 | require denominator != 0; 11 | return require_uint256(x*y/denominator); 12 | } 13 | 14 | function cvlMulDivUp(uint256 x, uint256 y, uint256 denominator) returns uint256 { 15 | require denominator != 0; 16 | return require_uint256((x*y + denominator - 1)/denominator); 17 | } 18 | 19 | function cvlMulDivDirectional(uint256 x, uint256 y, uint256 denominator, Math.Rounding rounding) returns uint256 { 20 | if (rounding == Math.Rounding.Up) { 21 | return cvlMulDivUp(x, y, denominator); 22 | } else { 23 | return cvlMulDiv(x, y, denominator); 24 | } 25 | } 26 | 27 | function cvlAverage(uint256 a, uint256 b) returns uint256 { 28 | return require_uint256((a+b)/2); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /certora/specs/permissions/Pausable.spec: -------------------------------------------------------------------------------- 1 | 2 | methods { 3 | // envfree functions 4 | function paused() external returns (uint256) envfree; 5 | function paused(uint8 index) external returns (bool) envfree; 6 | function pauserRegistry() external returns (address) envfree; 7 | 8 | // harnessed functions 9 | function isPauser(address) external returns (bool) envfree; 10 | function unpauser() external returns (address) envfree; 11 | function bitwise_not(uint256) external returns (uint256) envfree; 12 | function bitwise_and(uint256, uint256) external returns (uint256) envfree; 13 | } 14 | 15 | rule onlyPauserCanPauseAndOnlyUnpauserCanUnpause() { 16 | method f; 17 | env e; 18 | uint256 pausedStatusBefore = paused(); 19 | address unpauser = unpauser(); 20 | if (f.selector == sig:pause(uint256).selector) { 21 | uint256 newPausedStatus; 22 | pause(e, newPausedStatus); 23 | uint256 pausedStatusAfter = paused(); 24 | if (isPauser(e.msg.sender) && bitwise_and(pausedStatusBefore, newPausedStatus) == pausedStatusBefore) { 25 | assert(pausedStatusAfter == newPausedStatus, "pausedStatusAfter != newPausedStatus"); 26 | } else { 27 | assert(pausedStatusAfter == pausedStatusBefore, "pausedStatusAfter != pausedStatusBefore"); 28 | } 29 | } else if (f.selector == sig:pauseAll().selector) { 30 | pauseAll(e); 31 | uint256 pausedStatusAfter = paused(); 32 | if (isPauser(e.msg.sender)) { 33 | // assert(pausedStatusAfter == type(uint256).max, "pausedStatusAfter != newPausedStatus"); 34 | assert(pausedStatusAfter == 115792089237316195423570985008687907853269984665640564039457584007913129639935, 35 | "pausedStatusAfter != newPausedStatus"); 36 | } else { 37 | assert(pausedStatusAfter == pausedStatusBefore, "pausedStatusAfter != pausedStatusBefore"); 38 | } 39 | } else if (f.selector == sig:unpause(uint256).selector) { 40 | uint256 newPausedStatus; 41 | unpause(e, newPausedStatus); 42 | uint256 pausedStatusAfter = paused(); 43 | if (e.msg.sender == unpauser && bitwise_and(bitwise_not(pausedStatusBefore), bitwise_not(newPausedStatus)) == bitwise_not(pausedStatusBefore)) { 44 | assert(pausedStatusAfter == newPausedStatus, "pausedStatusAfter != newPausedStatus"); 45 | } else { 46 | assert(pausedStatusAfter == pausedStatusBefore, "pausedStatusAfter != pausedStatusBefore"); 47 | } 48 | } else { 49 | calldataarg arg; 50 | f(e,arg); 51 | uint256 pausedStatusAfter = paused(); 52 | assert(pausedStatusAfter == pausedStatusBefore, "pausedStatusAfter != pausedStatusBefore"); 53 | } 54 | } -------------------------------------------------------------------------------- /certora/specs/ptaHelpers.spec: -------------------------------------------------------------------------------- 1 | // Helpers to make Points-to-analysis work 2 | using ShortStringsUpgradeableHarness as ShortStringsUpgradeableHarness; 3 | 4 | methods { 5 | function ShortStringsUpgradeable.toString(ShortStringsUpgradeableHarness.ShortString sstr) internal returns (string memory) => cvlToString(sstr); 6 | function ShortStringsUpgradeableHarness.toStringHarness(ShortStringsUpgradeableHarness.ShortString sstr) external returns (string memory) envfree; 7 | } 8 | 9 | function cvlToString(ShortStringsUpgradeableHarness.ShortString sstr) returns string { 10 | return ShortStringsUpgradeableHarness.toStringHarness(sstr); 11 | } 12 | -------------------------------------------------------------------------------- /certora/specs/strategies/StrategyBase.spec: -------------------------------------------------------------------------------- 1 | using StrategyManager as strategyManager; 2 | methods { 3 | // external calls to PauserRegistry 4 | function _.isPauser(address) external => DISPATCHER(true); 5 | function _.unpauser() external => DISPATCHER(true); 6 | 7 | // external calls to ERC20 8 | function _.balanceOf(address) external => DISPATCHER(true); 9 | function _.transfer(address, uint256) external => DISPATCHER(true); 10 | function _.decimals() external => DISPATCHER(true); 11 | 12 | // envfree functions 13 | function totalShares() external returns (uint256) envfree; 14 | function underlyingToken() external returns (address) envfree; 15 | function sharesToUnderlyingView(uint256) external returns (uint256) envfree; 16 | function sharesToUnderlying(uint256) external returns (uint256) envfree; 17 | function underlyingToSharesView(uint256) external returns (uint256) envfree; 18 | function underlyingToShares(uint256) external returns (uint256) envfree; 19 | function shares(address) external returns (uint256) envfree; 20 | } 21 | 22 | // // idea based on OpenZeppelin invariant -- see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/formal-verification/certora/specs/ERC20.spec#L8-L22 23 | // ghost sumOfShares() returns uint256 { 24 | // init_state axiom sumOfShares() == 0; 25 | // } 26 | 27 | // hook Sstore currentContract.strategyManager.stakerStrategyShares[KEY address staker][KEY address strategy] uint256 newValue (uint256 oldValue) STORAGE { 28 | // havoc sumOfShares assuming sumOfShares@new() == sumOfShares@old() + newValue - oldValue; 29 | // } 30 | 31 | // invariant totalSharesIsSumOfShares() 32 | // totalShares() == sumOfShares() 33 | 34 | use builtin rule sanity; -------------------------------------------------------------------------------- /docs/images/RewardsCoordinator_Merkle_Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/RewardsCoordinator_Merkle_Tree.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Complete Withdrawal as Shares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Complete Withdrawal as Shares.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Complete Withdrawal as Tokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Complete Withdrawal as Tokens.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Delegating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Delegating.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Depositing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Depositing.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Queue Withdrawal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Queue Withdrawal.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Validator Exits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Validator Exits.png -------------------------------------------------------------------------------- /docs/images/Staker Flow Diagrams/Validator Yield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/Staker Flow Diagrams/Validator Yield.png -------------------------------------------------------------------------------- /docs/images/avs-bc-slash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/avs-bc-slash.png -------------------------------------------------------------------------------- /docs/images/slashing-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Layr-Labs/eigenlayer-contracts/ecc3fdffe71815f6dc3a414aa0a89807dc79625b/docs/images/slashing-model.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Layr-Labs/eigenlayer-contracts 2 | 3 | go 1.21 4 | 5 | require github.com/ethereum/go-ethereum v1.14.0 6 | 7 | require ( 8 | github.com/Microsoft/go-winio v0.6.1 // indirect 9 | github.com/StackExchange/wmi v1.2.1 // indirect 10 | github.com/bits-and-blooms/bitset v1.10.0 // indirect 11 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect 12 | github.com/consensys/bavard v0.1.13 // indirect 13 | github.com/consensys/gnark-crypto v0.12.1 // indirect 14 | github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect 15 | github.com/deckarep/golang-set/v2 v2.1.0 // indirect 16 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 17 | github.com/ethereum/c-kzg-4844 v1.0.0 // indirect 18 | github.com/fsnotify/fsnotify v1.6.0 // indirect 19 | github.com/go-ole/go-ole v1.3.0 // indirect 20 | github.com/google/uuid v1.3.0 // indirect 21 | github.com/gorilla/websocket v1.4.2 // indirect 22 | github.com/holiman/uint256 v1.2.4 // indirect 23 | github.com/mmcloughlin/addchain v0.4.0 // indirect 24 | github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect 25 | github.com/supranational/blst v0.3.11 // indirect 26 | github.com/tklauser/go-sysconf v0.3.12 // indirect 27 | github.com/tklauser/numcpus v0.6.1 // indirect 28 | golang.org/x/crypto v0.22.0 // indirect 29 | golang.org/x/mod v0.17.0 // indirect 30 | golang.org/x/sync v0.7.0 // indirect 31 | golang.org/x/sys v0.19.0 // indirect 32 | golang.org/x/tools v0.20.0 // indirect 33 | rsc.io/tmplfunc v0.0.3 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /mythril.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "remappings": [ 3 | "forge-std/=lib/forge-std/src/", 4 | "@openzeppelin/=lib/openzeppelin-contracts-v4.9.0/", 5 | "@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable-v4.9.0/" 6 | ], 7 | "optimizer": { 8 | "enabled": true, 9 | "runs": 200 10 | } 11 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eigenlayer-contracts", 3 | "version": "1.0.0", 4 | "description": " # EigenLayer EigenLayer (formerly 'EigenLayr') is a set of smart contracts deployed on Ethereum that enable restaking of assets to secure new services. At present, this repository contains *both* the contracts for EigenLayer *and* a set of general \"middleware\" contracts, designed to be reusable across different applications built on top of EigenLayer.", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs", 8 | "lib": "lib" 9 | }, 10 | "scripts": { 11 | "test": "forge test -v", 12 | "fmt:check": "forge fmt --check", 13 | "fmt:fix": "forge fmt", 14 | "hint": "solhint -c .github/configs/solhint.json 'contracts/**/*.sol' 'script/**/*.sol'" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/Layr-Labs/eigenlayer-contracts.git" 19 | }, 20 | "author": "", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/Layr-Labs/eigenlayer-contracts/issues" 24 | }, 25 | "homepage": "https://github.com/Layr-Labs/eigenlayer-contracts#readme", 26 | "devDependencies": { 27 | "@commitlint/cli": "^18.2.0", 28 | "@commitlint/config-conventional": "^18.1.0", 29 | "@types/yargs": "^17.0.28", 30 | "dotenv": "^16.3.1", 31 | "fs": "^0.0.1-security", 32 | "husky": "^8.0.3", 33 | "ts-node": "^10.9.1", 34 | "typescript": "^4.9.4", 35 | "yargs": "^17.7.2", 36 | "solhint": "5.0.1" 37 | }, 38 | "dependencies": { 39 | "solidity-docgen": "^0.6.0-beta.32" 40 | } 41 | } -------------------------------------------------------------------------------- /script/.gitignore: -------------------------------------------------------------------------------- 1 | output/* -------------------------------------------------------------------------------- /script/configs/devnet/deploy_from_scratch.anvil.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maintainer": "samlaf@eigenlabs.org", 3 | "multisig_addresses": { 4 | "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 6 | "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 7 | "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 8 | "timelock": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 9 | }, 10 | "strategies": [ 11 | { 12 | "token_address": "0x0000000000000000000000000000000000000000", 13 | "token_symbol": "WETH", 14 | "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, 15 | "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 16 | } 17 | ], 18 | "strategyManager": { 19 | "init_paused_status": 0, 20 | "init_withdrawal_delay_blocks": 1 21 | }, 22 | "eigenPod": { 23 | "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, 24 | "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" 25 | }, 26 | "eigenPodManager": { 27 | "init_paused_status": 30 28 | }, 29 | "delayedWithdrawalRouter": { 30 | "init_paused_status": 0, 31 | "init_withdrawal_delay_blocks": 1 32 | }, 33 | "slasher": { 34 | "init_paused_status": 0 35 | }, 36 | "delegation": { 37 | "init_paused_status": 0, 38 | "init_withdrawal_delay_blocks": 1 39 | }, 40 | "rewardsCoordinator": { 41 | "init_paused_status": 0, 42 | "CALCULATION_INTERVAL_SECONDS": 604800, 43 | "MAX_REWARDS_DURATION": 6048000, 44 | "MAX_RETROACTIVE_LENGTH": 7776000, 45 | "MAX_FUTURE_LENGTH": 2592000, 46 | "GENESIS_REWARDS_TIMESTAMP": 1710979200, 47 | "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", 48 | "activation_delay": 7200, 49 | "calculation_interval_seconds": 604800, 50 | "global_operator_commission_bips": 1000, 51 | "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, 52 | "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 53 | }, 54 | "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", 55 | "semver": "v1.0.3" 56 | } -------------------------------------------------------------------------------- /script/configs/devnet/deploy_from_scratch.holesky.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maintainer": "samlaf@eigenlabs.org", 3 | "multisig_addresses": { 4 | "operationsMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", 5 | "communityMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", 6 | "pauserMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", 7 | "executorMultisig": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", 8 | "timelock": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479" 9 | }, 10 | "strategies": [ 11 | { 12 | "token_address": "0x0000000000000000000000000000000000000000", 13 | "token_symbol": "WETH", 14 | "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, 15 | "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 16 | } 17 | ], 18 | "strategyManager": { 19 | "init_paused_status": 0, 20 | "init_withdrawal_delay_blocks": 1 21 | }, 22 | "eigenPod": { 23 | "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, 24 | "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" 25 | }, 26 | "eigenPodManager": { 27 | "init_paused_status": 30 28 | }, 29 | "delayedWithdrawalRouter": { 30 | "init_paused_status": 0, 31 | "init_withdrawal_delay_blocks": 1 32 | }, 33 | "slasher": { 34 | "init_paused_status": 0 35 | }, 36 | "delegation": { 37 | "init_paused_status": 0, 38 | "init_withdrawal_delay_blocks": 1 39 | }, 40 | "rewardsCoordinator": { 41 | "init_paused_status": 0, 42 | "CALCULATION_INTERVAL_SECONDS": 604800, 43 | "MAX_REWARDS_DURATION": 6048000, 44 | "MAX_RETROACTIVE_LENGTH": 7776000, 45 | "MAX_FUTURE_LENGTH": 2592000, 46 | "GENESIS_REWARDS_TIMESTAMP": 1710979200, 47 | "rewards_updater_address": "0xDA29BB71669f46F2a779b4b62f03644A84eE3479", 48 | "activation_delay": 7200, 49 | "calculation_interval_seconds": 604800, 50 | "global_operator_commission_bips": 1000, 51 | "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, 52 | "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 53 | }, 54 | "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", 55 | "semver": "v0.0.0" 56 | } 57 | -------------------------------------------------------------------------------- /script/configs/devnet/deploy_from_scratch.holesky.slashing.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "multisig_addresses": { 3 | "operationsMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", 4 | "communityMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", 5 | "pauserMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", 6 | "executorMultisig": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", 7 | "timelock": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07" 8 | }, 9 | "strategyManager": { 10 | "init_paused_status": 0, 11 | "init_withdrawal_delay_blocks": 1 12 | }, 13 | "eigenPod": { 14 | "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, 15 | "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" 16 | }, 17 | "eigenPodManager": { 18 | "init_paused_status": 115792089237316195423570985008687907853269984665640564039457584007913129639935 19 | }, 20 | "slasher": { 21 | "init_paused_status": 0 22 | }, 23 | "delegation": { 24 | "init_paused_status": 0, 25 | "init_withdrawal_delay_blocks": 1 26 | }, 27 | "rewardsCoordinator": { 28 | "init_paused_status": 115792089237316195423570985008687907853269984665640564039457584007913129639935, 29 | "CALCULATION_INTERVAL_SECONDS": 604800, 30 | "MAX_REWARDS_DURATION": 6048000, 31 | "MAX_RETROACTIVE_LENGTH": 7776000, 32 | "MAX_FUTURE_LENGTH": 2592000, 33 | "GENESIS_REWARDS_TIMESTAMP": 1710979200, 34 | "rewards_updater_address": "0xBB37b72F67A410B76Ce9b9aF9e37aa561B1C5B07", 35 | "activation_delay": 7200, 36 | "calculation_interval_seconds": 604800, 37 | "global_operator_commission_bips": 1000, 38 | "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, 39 | "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 40 | }, 41 | "allocationManager": { 42 | "init_paused_status": 0, 43 | "DEALLOCATION_DELAY": 86400, 44 | "ALLOCATION_CONFIGURATION_DELAY": 600 45 | }, 46 | "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", 47 | "semver": "v0.0.0" 48 | } -------------------------------------------------------------------------------- /script/configs/local/deploy_from_scratch.slashing.anvil.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maintainer": "samlaf@eigenlabs.org", 3 | "multisig_addresses": { 4 | "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 6 | "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 7 | "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 8 | "timelock": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 9 | }, 10 | "strategies": [ 11 | { 12 | "token_address": "0x0000000000000000000000000000000000000000", 13 | "token_symbol": "WETH", 14 | "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, 15 | "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 16 | } 17 | ], 18 | "allocationManager": { 19 | "init_paused_status": 0, 20 | "DEALLOCATION_DELAY": 900, 21 | "ALLOCATION_CONFIGURATION_DELAY": 1200 22 | }, 23 | "strategyManager": { 24 | "init_paused_status": 0, 25 | "init_withdrawal_delay_blocks": 1 26 | }, 27 | "eigenPod": { 28 | "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, 29 | "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" 30 | }, 31 | "eigenPodManager": { 32 | "init_paused_status": 30 33 | }, 34 | "delayedWithdrawalRouter": { 35 | "init_paused_status": 0, 36 | "init_withdrawal_delay_blocks": 1 37 | }, 38 | "slasher": { 39 | "init_paused_status": 0 40 | }, 41 | "delegation": { 42 | "withdrawal_delay_blocks": 900, 43 | "init_paused_status": 0, 44 | "init_withdrawal_delay_blocks": 1 45 | }, 46 | "rewardsCoordinator": { 47 | "init_paused_status": 0, 48 | "CALCULATION_INTERVAL_SECONDS": 604800, 49 | "MAX_REWARDS_DURATION": 6048000, 50 | "MAX_RETROACTIVE_LENGTH": 7776000, 51 | "MAX_FUTURE_LENGTH": 2592000, 52 | "GENESIS_REWARDS_TIMESTAMP": 1710979200, 53 | "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", 54 | "activation_delay": 7200, 55 | "calculation_interval_seconds": 604800, 56 | "global_operator_commission_bips": 1000, 57 | "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, 58 | "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 59 | }, 60 | "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa", 61 | "semver": "v0.0.0" 62 | } -------------------------------------------------------------------------------- /script/interfaces/IUpgradeableBeacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.12; 3 | 4 | interface IUpgradeableBeacon { 5 | function upgradeTo( 6 | address newImplementation 7 | ) external; 8 | function implementation() external returns (address); 9 | } 10 | -------------------------------------------------------------------------------- /script/output/devnet/M1_MOCK_deployment_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "baseStrategyImplementation": "0x5207CfA0166E8de0FCdFd78B4d17b68587bE306d", 4 | "delayedWithdrawalRouter": "0xD718d5A27a29FF1cD22403426084bA0d479869a0", 5 | "delayedWithdrawalRouterImplementation": "0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4", 6 | "delegation": "0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76", 7 | "delegationImplementation": "0xd21060559c9beb54fC07aFd6151aDf6cFCDDCAeB", 8 | "eigenLayerPauserReg": "0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496", 9 | "eigenLayerProxyAdmin": "0x90193C961A926261B756D1E5bb255e67ff9498A1", 10 | "eigenPodBeacon": "0x416C42991d05b31E9A6dC209e91AD22b79D87Ae6", 11 | "eigenPodImplementation": "0x4f559F30f5eB88D635FDe1548C4267DB8FaB0351", 12 | "eigenPodManager": "0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809", 13 | "eigenPodManagerImplementation": "0x8B71b41D4dBEb2b6821d44692d3fACAAf77480Bb", 14 | "emptyContract": "0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3", 15 | "slasher": "0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1", 16 | "slasherImplementation": "0x978e3286EB805934215a88694d80b09aDed68D90", 17 | "strategies": { 18 | "WETH": "0x39Af23E00F1e662025aA01b0cEdA19542B78DF99", 19 | "rETH": "0xd6EAF4c146261653EE059077B78ED088Add54309", 20 | "tsETH": "0x970670459734a83899773A0fd45941B5afC1200e", 21 | "wstETH": "0xEF179756ea6525AFade217cA5aB0b1b5CfE0fd92" 22 | }, 23 | "strategyManager": "0x50EEf481cae4250d252Ae577A09bF514f224C6C4", 24 | "strategyManagerImplementation": "0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1" 25 | }, 26 | "chainInfo": { 27 | "chainId": 31337, 28 | "deploymentBlock": 1 29 | }, 30 | "parameters": { 31 | "communityMultisig": "0x37bAFb55BC02056c5fD891DFa503ee84a97d89bF", 32 | "operationsMultisig": "0x040353E9d057689b77DF275c07FFe1A46b98a4a6", 33 | "executorMultisig": "0x3d9C2c2B40d890ad53E27947402e977155CD2808", 34 | "timelock": "0xA7e72a0564ebf25Fa082Fc27020225edeAF1796E" 35 | } 36 | } -------------------------------------------------------------------------------- /script/output/devnet/M2_from_scratch_deployment_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "allocationManager": "0xD718d5A27a29FF1cD22403426084bA0d479869a0", 4 | "allocationManagerImplementation": "0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D", 5 | "avsDirectory": "0x50EEf481cae4250d252Ae577A09bF514f224C6C4", 6 | "avsDirectoryImplementation": "0x8B71b41D4dBEb2b6821d44692d3fACAAf77480Bb", 7 | "baseStrategyImplementation": "0x29C66C9208f106f34754814f488FA80b6d566790", 8 | "delegationManager": "0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3", 9 | "delegationManagerImplementation": "0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1", 10 | "eigenLayerPauserReg": "0x90193C961A926261B756D1E5bb255e67ff9498A1", 11 | "eigenLayerProxyAdmin": "0x34A1D3fff3958843C43aD80F30b94c510645C316", 12 | "eigenPodBeacon": "0xd21060559c9beb54fC07aFd6151aDf6cFCDDCAeB", 13 | "eigenPodImplementation": "0x416C42991d05b31E9A6dC209e91AD22b79D87Ae6", 14 | "eigenPodManager": "0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1", 15 | "eigenPodManagerImplementation": "0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4", 16 | "emptyContract": "0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496", 17 | "numStrategiesDeployed": 0, 18 | "permissionController": "0x4f559F30f5eB88D635FDe1548C4267DB8FaB0351", 19 | "permissionControllerImplementation": "0xDeF3bca8c80064589E6787477FFa7Dd616B5574F", 20 | "rewardsCoordinator": "0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809", 21 | "rewardsCoordinatorImplementation": "0x0c8b5822b6e02CDa722174F19A1439A7495a3fA6", 22 | "strategies": { 23 | "WETH": "0xC92B57772d68b7445F19ef9f08226f4C8C74E499" 24 | }, 25 | "strategyManager": "0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76", 26 | "strategyManagerImplementation": "0x978e3286EB805934215a88694d80b09aDed68D90", 27 | "token": { 28 | "tokenProxyAdmin": "0x0000000000000000000000000000000000000000", 29 | "EIGEN": "0x0000000000000000000000000000000000000000", 30 | "bEIGEN": "0x0000000000000000000000000000000000000000", 31 | "EIGENImpl": "0x0000000000000000000000000000000000000000", 32 | "bEIGENImpl": "0x0000000000000000000000000000000000000000", 33 | "eigenStrategy": "0x0000000000000000000000000000000000000000", 34 | "eigenStrategyImpl": "0x0000000000000000000000000000000000000000" 35 | } 36 | }, 37 | "chainInfo": { 38 | "chainId": 31337, 39 | "deploymentBlock": 1 40 | }, 41 | "parameters": { 42 | "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 43 | "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 44 | "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 45 | "pauserMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 46 | "timelock": "0x0000000000000000000000000000000000000000" 47 | } 48 | } -------------------------------------------------------------------------------- /script/releases/v1.6.0-moocow-and-elip5/upgrade.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moocow-and-elip5", 3 | "from": "1.5.0", 4 | "to": "1.6.0", 5 | "phases": [ 6 | { 7 | "type": "eoa", 8 | "filename": "1-deployContracts.s.sol" 9 | }, 10 | { 11 | "type": "multisig", 12 | "filename": "2-queueUpgrade.s.sol" 13 | }, 14 | { 15 | "type": "multisig", 16 | "filename": "3-executeUpgrade.s.sol" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /script/tasks/allocate_operatorSet.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/AVSDirectory.sol"; 5 | import "../../src/contracts/core/AllocationManager.sol"; 6 | 7 | import "forge-std/Script.sol"; 8 | import "forge-std/Test.sol"; 9 | 10 | // use forge: 11 | // RUST_LOG=forge,foundry=trace forge script script/tasks/allocate_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" -- 12 | // RUST_LOG=forge,foundry=trace forge script script/tasks/allocate_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address avs,uint32 operatorSetId,uint64 magnitude)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 00000001 0500000000000000000 13 | contract AllocateOperatorSet is Script, Test { 14 | Vm cheats = Vm(VM_ADDRESS); 15 | 16 | function run( 17 | string memory configFile, 18 | address strategy, 19 | address avs, 20 | uint32 operatorSetId, 21 | uint64 magnitude 22 | ) public { 23 | // Load config 24 | string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); 25 | string memory config_data = vm.readFile(deployConfigPath); 26 | 27 | // Pull allocationManager address 28 | address allocationManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); 29 | 30 | // START RECORDING TRANSACTIONS FOR DEPLOYMENT 31 | vm.startBroadcast(); 32 | 33 | // Attach to the AllocationManager 34 | AllocationManager am = AllocationManager(allocationManager); 35 | 36 | // Correct array initialization 37 | IStrategy[] memory strategies = new IStrategy[](1); 38 | strategies[0] = IStrategy(strategy); 39 | 40 | // Set OperatorSets 41 | OperatorSet[] memory sets = new OperatorSet[](1); 42 | sets[0] = OperatorSet({avs: avs, id: operatorSetId}); 43 | 44 | // Set new mangitudes 45 | uint64[] memory magnitudes = new uint64[](1); 46 | magnitudes[0] = magnitude; 47 | 48 | // Define a single MagnitudeAllocation and wrap it in an array 49 | IAllocationManagerTypes.AllocateParams[] memory allocations = new IAllocationManagerTypes.AllocateParams[](1); 50 | allocations[0] = IAllocationManagerTypes.AllocateParams({ 51 | operatorSet: sets[0], 52 | strategies: strategies, 53 | newMagnitudes: magnitudes 54 | }); 55 | 56 | // Perform allocation 57 | am.modifyAllocations(msg.sender, allocations); 58 | 59 | // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT 60 | vm.stopBroadcast(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /script/tasks/deposit_into_strategy.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/StrategyManager.sol"; 5 | 6 | import "forge-std/Script.sol"; 7 | import "forge-std/Test.sol"; 8 | 9 | // use cast: 10 | // 11 | // cast send "approve(address,uint256)" \ 12 | // \ 13 | // \ 14 | // --private-key 15 | // 16 | // cast send "depositIntoStrategy(address,address,uint256)" \ 17 | // \ 18 | // \ 19 | // \ 20 | // --private-key 21 | 22 | // use forge: 23 | // RUST_LOG=forge,foundry=trace forge script script/tasks/deposit_into_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- 24 | // RUST_LOG=forge,foundry=trace forge script script/tasks/deposit_into_strategy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address strategy,address token,uint256 amount)" -- local/slashing_output.json 0x8aCd85898458400f7Db866d53FCFF6f0D49741FF 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 $DEPOSIT_SHARES 25 | contract DepositIntoStrategy is Script, Test { 26 | Vm cheats = Vm(VM_ADDRESS); 27 | 28 | function run(string memory configFile, address strategy, address token, uint256 amount) public { 29 | // Load config 30 | string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); 31 | string memory config_data = vm.readFile(deployConfigPath); 32 | 33 | // Pull strategy manager address 34 | address strategyManager = stdJson.readAddress(config_data, ".addresses.strategyManager"); 35 | 36 | // START RECORDING TRANSACTIONS FOR DEPLOYMENT 37 | vm.startBroadcast(); 38 | 39 | IERC20 tkn = IERC20(token); 40 | StrategyManager sm = StrategyManager(strategyManager); 41 | 42 | // approve spend 43 | tkn.approve(strategyManager, amount); 44 | 45 | // do deposit 46 | sm.depositIntoStrategy(IStrategy(strategy), IERC20(token), amount); 47 | 48 | vm.stopBroadcast(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /script/tasks/register_as_operator.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/DelegationManager.sol"; 5 | 6 | import "forge-std/Script.sol"; 7 | import "forge-std/Test.sol"; 8 | 9 | // use cast: 10 | // cast send "registerAsOperator((address,address,uint32),uint256,string)" \ 11 | // "(address(0), , 0)" \ 12 | // 0 \ 13 | // "" \ 14 | // --private-key 15 | 16 | // use forge: 17 | // RUST_LOG=forge,foundry=trace forge script script/tasks/register_as_operator.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,string memory metadataURI)" -- 18 | // RUST_LOG=forge,foundry=trace forge script script/tasks/register_as_operator.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,string metadataURI)" -- local/slashing_output.json 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 "test" 19 | contract RegisterAsOperator is Script, Test { 20 | Vm cheats = Vm(VM_ADDRESS); 21 | 22 | function run(string memory configFile, address operator, string memory metadataURI) public { 23 | // Load config 24 | string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); 25 | string memory config_data = vm.readFile(deployConfigPath); 26 | 27 | // Pull delegation manager address 28 | address delegationManager = stdJson.readAddress(config_data, ".addresses.delegationManager"); 29 | 30 | // START RECORDING TRANSACTIONS FOR DEPLOYMENT 31 | vm.startBroadcast(); 32 | 33 | // Attach the delegationManager 34 | DelegationManager delegation = DelegationManager(delegationManager); 35 | 36 | // Register the sender as an Operator 37 | delegation.registerAsOperator(operator, 0, metadataURI); 38 | 39 | // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT 40 | vm.stopBroadcast(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /script/tasks/slash_operatorSet.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/AllocationManager.sol"; 5 | 6 | import "forge-std/Script.sol"; 7 | import "forge-std/Test.sol"; 8 | 9 | // use forge: 10 | // RUST_LOG=forge,foundry=trace forge script script/tasks/slash_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" -- 11 | // RUST_LOG=forge,foundry=trace forge script script/tasks/slash_operatorSet.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile,address operator,uint32 operatorSetId,uint256 wadToSlash)" -- local/slashing_output.json 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 00000001 05000000 12 | contract SlashOperatorSet is Script, Test, IAllocationManagerTypes { 13 | Vm cheats = Vm(VM_ADDRESS); 14 | 15 | function run( 16 | string memory configFile, 17 | address operator, 18 | uint32 operatorSetId, 19 | IStrategy[] memory strategies, 20 | uint256[] memory wadsToSlash 21 | ) public { 22 | // Load config 23 | string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); 24 | string memory config_data = vm.readFile(deployConfigPath); 25 | 26 | // Pull allocationManager address 27 | address allocationManager = stdJson.readAddress(config_data, ".addresses.allocationManager"); 28 | 29 | // START RECORDING TRANSACTIONS FOR DEPLOYMENT 30 | vm.startBroadcast(); 31 | 32 | // Attach to the AllocationManager 33 | AllocationManager am = AllocationManager(allocationManager); 34 | 35 | // Define SlashingParams struct instance with correct array initialization 36 | SlashingParams memory slashing = SlashingParams({ 37 | operator: operator, 38 | operatorSetId: operatorSetId, 39 | strategies: strategies, 40 | wadsToSlash: wadsToSlash, 41 | description: "slashed" 42 | }); 43 | 44 | // Perform slashing 45 | am.slashOperator(operator, slashing); 46 | 47 | // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT 48 | vm.stopBroadcast(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /script/tasks/unpause_avsDirectory.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../src/contracts/core/AVSDirectory.sol"; 5 | 6 | import "forge-std/Script.sol"; 7 | import "forge-std/Test.sol"; 8 | 9 | // use cast: 10 | // 11 | // cast send "approve(address,uint256)" \ 12 | // \ 13 | // \ 14 | // --private-key 15 | // 16 | // cast send "depositIntoStrategy(address,address,uint256)" \ 17 | // \ 18 | // \ 19 | // \ 20 | // --private-key 21 | 22 | // use forge: 23 | // RUST_LOG=forge,foundry=trace forge script script/tasks/unpause_avsDirectory.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- 24 | // RUST_LOG=forge,foundry=trace forge script script/tasks/unpause_avsDirectory.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- local/slashing_output.json 25 | contract UnpauseAVSDirectory is Script, Test { 26 | Vm cheats = Vm(VM_ADDRESS); 27 | 28 | function run( 29 | string memory configFile 30 | ) public { 31 | // Load config 32 | string memory deployConfigPath = string(bytes(string.concat("script/output/", configFile))); 33 | string memory config_data = vm.readFile(deployConfigPath); 34 | 35 | // Pull avs directory address 36 | address avsDir = stdJson.readAddress(config_data, ".addresses.avsDirectory"); 37 | 38 | // START RECORDING TRANSACTIONS FOR DEPLOYMENT 39 | vm.startBroadcast(); 40 | 41 | // Attach to the AVSDirectory 42 | AVSDirectory avsDirectory = AVSDirectory(avsDir); 43 | 44 | // Unpause the AVSDirectory 45 | avsDirectory.unpause(0); 46 | 47 | // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT 48 | vm.stopBroadcast(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /script/utils/validateStorage/README.md: -------------------------------------------------------------------------------- 1 | # Storage Validation Scripts 2 | This script uses cast and forge inspect to get the layouts of the local and on-chain contract. Your `ETHERSCAN_API_KEY` must be set as an environment variable. The storage layouts are saved into csv files and passed into the typescript helper validateStorage.ts, which takes paths to two csv layouts and validates the storage slots. 3 | 4 | ## Run validation 5 | To validate the storage of an upgradeable deployed contract against a local one, run the script: 6 | ```bash 7 | bash script/upgrade/validateUpgrade.sh -n -c -a 8 | ``` 9 | 10 | The supported networks are `mainnet`. The supported contracts are `strategyManager`, `delegation`, `eigenPod`, `eigenPodManager`, and `slasher`. 11 | 12 | The above script generates two csv files, `localLayout.csv` and `onChainLayout.csv`. To keep these csv files after validating storage, add a `-k` flag to the above command 13 | 14 | Additionally, one can validate the storage of two csv files outputted by the `forge inspect` command by running 15 | 16 | ```js 17 | npx ts-node script/upgrade/validateStorage.ts --old --new --keep 18 | ``` 19 | 20 | ## Limitations 21 | Storage slot validation is NOT comprehensive, and errs on the side of caution. We recommend using this script as a tool along with manual storage slot verification. The validation is opinionated on storage for each contract consuming 50 slots and gaps being sized accordingly. 22 | 23 | The script does not validate legal type changes (ie. from bool to uint8) and errors out if the types of slots have updated, including having different struct names. A manual check will need to be done to validate this conversion. In addition, the script does not support non-contiguous gaps. -------------------------------------------------------------------------------- /script/utils/validateStorage/validateUpgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source .env 4 | 5 | # Parse command-line arguments using getopt 6 | while getopts ":n:c:a:k:" opt; do 7 | case $opt in 8 | n) NETWORK="$OPTARG";; 9 | c) CONTRACT="$OPTARG";; 10 | a) ADDRESS="$OPTARG";; 11 | \?) echo "Invalid option -$OPTARG" >&2; exit 1;; 12 | esac 13 | done 14 | 15 | # Validate that network and contract inputs are provided 16 | if [ -z "$NETWORK" ] || [ -z "$CONTRACT" ] || [ -z "$ADDRESS" ]; then 17 | echo "Usage: $0 -n -c -a
-k" 18 | exit 1 19 | fi 20 | 21 | # Validate the network input 22 | if [ "$NETWORK" != "mainnet" ] ; then 23 | echo "Invalid network. Use 'mainnet'." 24 | exit 1 25 | fi 26 | 27 | # Get local path for contract & validate contract input 28 | case $CONTRACT in 29 | "strategyManager") CONTRACT_PATH="src/contracts/core/StrategyManager.sol:StrategyManager";; 30 | "delegation") CONTRACT_PATH="src/contracts/core/DelegationManager.sol:DelegationManager";; 31 | "eigenPodManager") CONTRACT_PATH="src/contracts/pods/EigenPodManager.sol:EigenPodManager";; 32 | "eigenPod") CONTRACT_PATH="src/contracts/pods/EigenPod.sol:EigenPod";; 33 | "slasher") CONTRACT_PATH="src/contracts/core/Slasher.sol:Slasher";; 34 | *) 35 | echo "Invalid contract name." 36 | exit 1 37 | ;; 38 | esac 39 | 40 | # Set RPC 41 | if [ "$NETWORK" == "mainnet" ]; then 42 | RPC_URL="$RPC_MAINNET" 43 | fi 44 | 45 | # Print the selected network and contract 46 | echo "Checking storage layouts for contract on: $NETWORK" 47 | echo "Contract to validate upgrade: $CONTRACT" 48 | 49 | # Get storage layout for on-chain contract 50 | echo "Retrieving on-chain storage layout for $ADDRESS" 51 | command="cast storage $ADDRESS --rpc-url $RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY" 52 | eval "$command > /dev/null 2>&1" # precompile contracts so onChainLayout.csv isn't filled with warnings 53 | output=$(eval $command) 54 | echo "$output" | tail -n +2 > onChainLayout.csv 55 | echo "On-chain storage saved to onChainLayout.csv" 56 | 57 | # Get storage layout for local contract 58 | echo "Retrieving local storage layout for $CONTRACT at $CONTRACT_PATH" 59 | command="forge inspect $CONTRACT_PATH storage --pretty" 60 | output=$(eval $command) 61 | echo "$output" | tail -n +1 > localLayout.csv 62 | echo "Local storage saved to localLayout.csv" 63 | 64 | # Compare the two storage layouts via typescript script 65 | echo "Comparing storage layouts..." 66 | 67 | # Add -k operator if present 68 | if [ ! -k "$1" ]; then 69 | echo "Keeping old storage layout files" 70 | eval "npx ts-node script/utils/validateStorage/validateStorage.ts --old onChainLayout.csv --new localLayout.csv --keep" 71 | else 72 | eval "npx ts-node script/utils/validateStorage/validateStorage.ts --old onChainLayout.csv --new localLayout.csv" 73 | fi -------------------------------------------------------------------------------- /slither.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "detectors_to_exclude": "assembly,solc-version,naming-convention,incorrect-equality,uninitialized-local,timestamp,low-level-calls,unimplemented-functions,too-many-digits,similar-names,calls-loop,arbitrary-send-eth,reentrancy-no-eth,reentrancy-benign,reentrancy-events,unused-state,incorrect-shift-in-assembly,dead-code", 3 | "filter_paths": "lib/|test/|mocks/|BytesLib|script/", 4 | "solc_remaps": [ 5 | "forge-std/=lib/forge-std/src/", 6 | "@openzeppelin/=lib/openzeppelin-contracts-v4.9.0/", 7 | "@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable-v4.9.0/", 8 | "ds-test/=lib/ds-test/src/" 9 | ], 10 | "compile_force_framework": "foundry" 11 | } -------------------------------------------------------------------------------- /snapshots/Integration_ALM_Multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "gasUsed": "47579" 3 | } -------------------------------------------------------------------------------- /src/contracts/core/AVSDirectoryStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../interfaces/IAVSDirectory.sol"; 5 | import "../interfaces/IDelegationManager.sol"; 6 | 7 | abstract contract AVSDirectoryStorage is IAVSDirectory { 8 | // Constants 9 | 10 | /// @notice The EIP-712 typehash for the `Registration` struct used by the contract 11 | bytes32 public constant OPERATOR_AVS_REGISTRATION_TYPEHASH = 12 | keccak256("OperatorAVSRegistration(address operator,address avs,bytes32 salt,uint256 expiry)"); 13 | 14 | /// @notice The EIP-712 typehash for the `OperatorSetRegistration` struct used by the contract 15 | bytes32 public constant OPERATOR_SET_REGISTRATION_TYPEHASH = 16 | keccak256("OperatorSetRegistration(address avs,uint32[] operatorSetIds,bytes32 salt,uint256 expiry)"); 17 | 18 | /// @notice The EIP-712 typehash for the `OperatorSetMembership` struct used by the contract 19 | bytes32 public constant OPERATOR_SET_FORCE_DEREGISTRATION_TYPEHASH = 20 | keccak256("OperatorSetForceDeregistration(address avs,uint32[] operatorSetIds,bytes32 salt,uint256 expiry)"); 21 | 22 | /// @dev Index for flag that pauses operator register/deregister to avs when set. 23 | uint8 internal constant PAUSED_OPERATOR_REGISTER_DEREGISTER_TO_AVS = 0; 24 | 25 | /// @dev Index for flag that pauses operator register/deregister to operator sets when set. 26 | uint8 internal constant PAUSED_OPERATOR_SET_REGISTRATION_AND_DEREGISTRATION = 1; 27 | 28 | // Immutables 29 | 30 | /// @notice The DelegationManager contract for EigenLayer 31 | IDelegationManager public immutable delegation; 32 | 33 | // Mutatables 34 | 35 | /// @dev Do not remove, deprecated storage. 36 | bytes32 internal __deprecated_DOMAIN_SEPARATOR; 37 | 38 | /// @notice Returns the registration status of each `operator` for a given `avs`. 39 | /// @dev This storage will be deprecated once M2-based deregistration is removed. 40 | mapping(address avs => mapping(address operator => OperatorAVSRegistrationStatus)) public avsOperatorStatus; 41 | 42 | /// @notice Returns whether a `salt` has been used by a given `operator`. 43 | mapping(address operator => mapping(bytes32 salt => bool isSpent)) public operatorSaltIsSpent; 44 | 45 | // Construction 46 | 47 | constructor( 48 | IDelegationManager _delegation 49 | ) { 50 | delegation = _delegation; 51 | } 52 | 53 | /** 54 | * @dev This empty reserved space is put in place to allow future versions to add new 55 | * variables without shifting down storage in the inheritance chain. 56 | * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps 57 | */ 58 | uint256[47] private __gap; 59 | } 60 | -------------------------------------------------------------------------------- /src/contracts/core/SlashEscrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import "@openzeppelin-upgrades/contracts/proxy/ClonesUpgradeable.sol"; 6 | import "../interfaces/ISlashEscrow.sol"; 7 | import "../interfaces/ISlashEscrowFactory.sol"; 8 | 9 | contract SlashEscrow is ISlashEscrow { 10 | using OperatorSetLib for *; 11 | using SafeERC20 for IERC20; 12 | 13 | /// @inheritdoc ISlashEscrow 14 | function releaseTokens( 15 | ISlashEscrowFactory slashEscrowFactory, 16 | ISlashEscrow slashEscrowImplementation, 17 | OperatorSet calldata operatorSet, 18 | uint256 slashId, 19 | address recipient, 20 | IStrategy strategy 21 | ) external { 22 | // Assert that the deployment parameters are valid by validating against the address of this proxy. 23 | require( 24 | verifyDeploymentParameters(slashEscrowFactory, slashEscrowImplementation, operatorSet, slashId), 25 | InvalidDeploymentParameters() 26 | ); 27 | 28 | // Assert that the caller is the slash escrow factory. 29 | require(msg.sender == address(slashEscrowFactory), OnlySlashEscrowFactory()); 30 | 31 | // Burn or redistribute the underlying tokens. 32 | IERC20 underlyingToken = strategy.underlyingToken(); 33 | underlyingToken.safeTransfer(recipient, underlyingToken.balanceOf(address(this))); 34 | } 35 | 36 | /// @inheritdoc ISlashEscrow 37 | function verifyDeploymentParameters( 38 | ISlashEscrowFactory slashEscrowFactory, 39 | ISlashEscrow slashEscrowImplementation, 40 | OperatorSet calldata operatorSet, 41 | uint256 slashId 42 | ) public view returns (bool) { 43 | return ClonesUpgradeable.predictDeterministicAddress( 44 | address(slashEscrowImplementation), 45 | keccak256(abi.encodePacked(operatorSet.key(), slashId)), 46 | address(slashEscrowFactory) 47 | ) == address(this); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IAVSRegistrar.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity >=0.5.0; 3 | 4 | interface IAVSRegistrar { 5 | /** 6 | * @notice Called by the AllocationManager when an operator wants to register 7 | * for one or more operator sets. This method should revert if registration 8 | * is unsuccessful. 9 | * @param operator the registering operator 10 | * @param avs the AVS the operator is registering for. This should be the same as IAVSRegistrar.avs() 11 | * @param operatorSetIds the list of operator set ids being registered for 12 | * @param data arbitrary data the operator can provide as part of registration 13 | */ 14 | function registerOperator( 15 | address operator, 16 | address avs, 17 | uint32[] calldata operatorSetIds, 18 | bytes calldata data 19 | ) external; 20 | 21 | /** 22 | * @notice Called by the AllocationManager when an operator is deregistered from 23 | * one or more operator sets. If this method reverts, it is ignored. 24 | * @param operator the deregistering operator 25 | * @param avs the AVS the operator is deregistering from. This should be the same as IAVSRegistrar.avs() 26 | * @param operatorSetIds the list of operator set ids being deregistered from 27 | */ 28 | function deregisterOperator(address operator, address avs, uint32[] calldata operatorSetIds) external; 29 | 30 | /** 31 | * @notice Returns true if the AVS is supported by the registrar 32 | * @param avs the AVS to check 33 | * @return true if the AVS is supported, false otherwise 34 | */ 35 | function supportsAVS( 36 | address avs 37 | ) external view returns (bool); 38 | } 39 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IBackingEigen.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity >=0.5.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IBackingEigen is IERC20 { 7 | /** 8 | * @notice This function allows the owner to set the allowedFrom status of an address 9 | * @param from the address whose allowedFrom status is being set 10 | * @param isAllowedFrom the new allowedFrom status 11 | */ 12 | function setAllowedFrom(address from, bool isAllowedFrom) external; 13 | 14 | /** 15 | * @notice This function allows the owner to set the allowedTo status of an address 16 | * @param to the address whose allowedTo status is being set 17 | * @param isAllowedTo the new allowedTo status 18 | */ 19 | function setAllowedTo(address to, bool isAllowedTo) external; 20 | 21 | /** 22 | * @notice Allows the owner to disable transfer restrictions 23 | */ 24 | function disableTransferRestrictions() external; 25 | 26 | /** 27 | * @notice An initializer function that sets initial values for the contract's state variables. 28 | */ 29 | function initialize( 30 | address initialOwner 31 | ) external; 32 | 33 | // @notice Allows the contract owner to modify an entry in the `isMinter` mapping. 34 | function setIsMinter(address minterAddress, bool newStatus) external; 35 | 36 | /** 37 | * @notice Allows any privileged address to mint `amount` new tokens to the address `to`. 38 | * @dev Callable only by an address that has `isMinter` set to true. 39 | */ 40 | function mint(address to, uint256 amount) external; 41 | 42 | /** 43 | * @dev Destroys `amount` tokens from the caller. 44 | * 45 | * See {ERC20-_burn}. 46 | */ 47 | function burn( 48 | uint256 amount 49 | ) external; 50 | 51 | /// @notice the address of the wrapped Eigen token EIGEN 52 | function EIGEN() external view returns (IERC20); 53 | 54 | /// @notice the timestamp after which transfer restrictions are disabled 55 | function transferRestrictionsDisabledAfter() external view returns (uint256); 56 | 57 | /** 58 | * @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based 59 | * checkpoints (and voting). 60 | */ 61 | function clock() external view returns (uint48); 62 | 63 | /** 64 | * @dev Machine-readable description of the clock as specified in EIP-6372. 65 | * Has been overridden to inform callers that this contract uses timestamps instead of block numbers, to match `clock()` 66 | */ 67 | // solhint-disable-next-line func-name-mixedcase 68 | function CLOCK_MODE() external pure returns (string memory); 69 | } 70 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IETHPOSDeposit.sol: -------------------------------------------------------------------------------- 1 | // ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━ 2 | // ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓ 3 | // ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛ 4 | // ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━ 5 | // ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓ 6 | // ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛ 7 | // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8 | // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9 | 10 | // SPDX-License-Identifier: CC0-1.0 11 | 12 | pragma solidity >=0.5.0; 13 | 14 | // This interface is designed to be compatible with the Vyper version. 15 | /// @notice This is the Ethereum 2.0 deposit contract interface. 16 | /// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs 17 | interface IETHPOSDeposit { 18 | /// @notice A processed deposit event. 19 | event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index); 20 | 21 | /// @notice Submit a Phase 0 DepositData object. 22 | /// @param pubkey A BLS12-381 public key. 23 | /// @param withdrawal_credentials Commitment to a public key for withdrawals. 24 | /// @param signature A BLS12-381 signature. 25 | /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. 26 | /// Used as a protection against malformed input. 27 | function deposit( 28 | bytes calldata pubkey, 29 | bytes calldata withdrawal_credentials, 30 | bytes calldata signature, 31 | bytes32 deposit_data_root 32 | ) external payable; 33 | 34 | /// @notice Query the current deposit root hash. 35 | /// @return The deposit root hash. 36 | function get_deposit_root() external view returns (bytes32); 37 | 38 | /// @notice Query the current deposit count. 39 | /// @return The deposit count encoded as a little endian 64-bit number. 40 | function get_deposit_count() external view returns (bytes memory); 41 | } 42 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IEigen.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity >=0.5.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IEigen is IERC20 { 7 | /** 8 | * @notice This function allows the owner to set the allowedFrom status of an address 9 | * @param from the address whose allowedFrom status is being set 10 | * @param isAllowedFrom the new allowedFrom status 11 | */ 12 | function setAllowedFrom(address from, bool isAllowedFrom) external; 13 | 14 | /** 15 | * @notice This function allows the owner to set the allowedTo status of an address 16 | * @param to the address whose allowedTo status is being set 17 | * @param isAllowedTo the new allowedTo status 18 | */ 19 | function setAllowedTo(address to, bool isAllowedTo) external; 20 | 21 | /** 22 | * @notice Allows the owner to disable transfer restrictions 23 | */ 24 | function disableTransferRestrictions() external; 25 | 26 | /** 27 | * @notice This function allows minter to mint tokens 28 | */ 29 | function mint() external; 30 | 31 | /** 32 | * @notice This function allows bEIGEN holders to wrap their tokens into Eigen 33 | */ 34 | function wrap( 35 | uint256 amount 36 | ) external; 37 | 38 | /** 39 | * @notice This function allows Eigen holders to unwrap their tokens into bEIGEN 40 | */ 41 | function unwrap( 42 | uint256 amount 43 | ) external; 44 | 45 | /** 46 | * @dev Clock used for flagging checkpoints. Has been overridden to implement timestamp based 47 | * checkpoints (and voting). 48 | */ 49 | function clock() external view returns (uint48); 50 | 51 | /** 52 | * @dev Machine-readable description of the clock as specified in EIP-6372. 53 | * Has been overridden to inform callers that this contract uses timestamps instead of block numbers, to match `clock()` 54 | */ 55 | // solhint-disable-next-line func-name-mixedcase 56 | function CLOCK_MODE() external pure returns (string memory); 57 | } 58 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IPauserRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity >=0.5.0; 3 | 4 | /** 5 | * @title Interface for the `PauserRegistry` contract. 6 | * @author Layr Labs, Inc. 7 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 8 | */ 9 | interface IPauserRegistry { 10 | error OnlyUnpauser(); 11 | error InputAddressZero(); 12 | 13 | event PauserStatusChanged(address pauser, bool canPause); 14 | 15 | event UnpauserChanged(address previousUnpauser, address newUnpauser); 16 | 17 | /// @notice Mapping of addresses to whether they hold the pauser role. 18 | function isPauser( 19 | address pauser 20 | ) external view returns (bool); 21 | 22 | /// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses. 23 | function unpauser() external view returns (address); 24 | } 25 | -------------------------------------------------------------------------------- /src/contracts/interfaces/ISemVerMixin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | /// @title ISemVerMixin 5 | /// @notice A mixin interface that provides semantic versioning functionality. 6 | /// @dev Follows SemVer 2.0.0 specification (https://semver.org/) 7 | interface ISemVerMixin { 8 | /// @notice Returns the semantic version string of the contract. 9 | /// @return The version string in SemVer format (e.g., "1.1.1") 10 | function version() external view returns (string memory); 11 | } 12 | -------------------------------------------------------------------------------- /src/contracts/interfaces/IShareManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../libraries/SlashingLib.sol"; 5 | import "./IStrategy.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import "../libraries/OperatorSetLib.sol"; 8 | /** 9 | * @title Interface for a `IShareManager` contract. 10 | * @author Layr Labs, Inc. 11 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 12 | * @notice This contract is used by the DelegationManager as a unified interface to interact with the EigenPodManager and StrategyManager 13 | */ 14 | 15 | interface IShareManager { 16 | /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue 17 | /// @dev strategy must be beaconChainETH when talking to the EigenPodManager 18 | /// @return updatedShares the staker's deposit shares after decrement 19 | function removeDepositShares( 20 | address staker, 21 | IStrategy strategy, 22 | uint256 depositSharesToRemove 23 | ) external returns (uint256); 24 | 25 | /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue 26 | /// @dev strategy must be beaconChainETH when talking to the EigenPodManager 27 | /// @return existingDepositShares the shares the staker had before any were added 28 | /// @return addedShares the new shares added to the staker's balance 29 | function addShares(address staker, IStrategy strategy, uint256 shares) external returns (uint256, uint256); 30 | 31 | /// @notice Used by the DelegationManager to convert deposit shares to tokens and send them to a staker 32 | /// @dev strategy must be beaconChainETH when talking to the EigenPodManager 33 | /// @dev token is not validated when talking to the EigenPodManager 34 | function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external; 35 | 36 | /// @notice Returns the current shares of `user` in `strategy` 37 | /// @dev strategy must be beaconChainETH when talking to the EigenPodManager 38 | /// @dev returns 0 if the user has negative shares 39 | function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares); 40 | 41 | /** 42 | * @notice Increase the amount of burnable/redistributable shares for a given Strategy. This is called by the DelegationManager 43 | * when an operator is slashed in EigenLayer. 44 | * @param operatorSet The operator set to burn shares in. 45 | * @param slashId The slash id to burn shares in. 46 | * @param strategy The strategy to burn shares in. 47 | * @param addedSharesToBurn The amount of added shares to burn. 48 | * @dev This function is only called by the DelegationManager when an operator is slashed. 49 | */ 50 | function increaseBurnOrRedistributableShares( 51 | OperatorSet calldata operatorSet, 52 | uint256 slashId, 53 | IStrategy strategy, 54 | uint256 addedSharesToBurn 55 | ) external; 56 | } 57 | -------------------------------------------------------------------------------- /src/contracts/interfaces/ISignatureUtilsMixin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity >=0.5.0; 3 | 4 | import "./ISemVerMixin.sol"; 5 | 6 | interface ISignatureUtilsMixinErrors { 7 | /// @notice Thrown when a signature is invalid. 8 | error InvalidSignature(); 9 | /// @notice Thrown when a signature has expired. 10 | error SignatureExpired(); 11 | } 12 | 13 | interface ISignatureUtilsMixinTypes { 14 | /// @notice Struct that bundles together a signature and an expiration time for the signature. 15 | /// @dev Used primarily for stack management. 16 | struct SignatureWithExpiry { 17 | // the signature itself, formatted as a single bytes object 18 | bytes signature; 19 | // the expiration timestamp (UTC) of the signature 20 | uint256 expiry; 21 | } 22 | 23 | /// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. 24 | /// @dev Used primarily for stack management. 25 | struct SignatureWithSaltAndExpiry { 26 | // the signature itself, formatted as a single bytes object 27 | bytes signature; 28 | // the salt used to generate the signature 29 | bytes32 salt; 30 | // the expiration timestamp (UTC) of the signature 31 | uint256 expiry; 32 | } 33 | } 34 | 35 | /** 36 | * @title The interface for common signature utilities. 37 | * @author Layr Labs, Inc. 38 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 39 | */ 40 | interface ISignatureUtilsMixin is ISignatureUtilsMixinErrors, ISignatureUtilsMixinTypes, ISemVerMixin { 41 | /// @notice Computes the EIP-712 domain separator used for signature validation. 42 | /// @dev The domain separator is computed according to EIP-712 specification, using: 43 | /// - The hardcoded name "EigenLayer" 44 | /// - The contract's version string 45 | /// - The current chain ID 46 | /// - This contract's address 47 | /// @return The 32-byte domain separator hash used in EIP-712 structured data signing. 48 | /// @dev See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator. 49 | function domainSeparator() external view returns (bytes32); 50 | } 51 | -------------------------------------------------------------------------------- /src/contracts/interfaces/ISlashEscrow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../interfaces/ISlashEscrowFactory.sol"; 5 | import "../libraries/OperatorSetLib.sol"; 6 | import "../interfaces/IStrategy.sol"; 7 | 8 | interface ISlashEscrow { 9 | /// @notice Thrown when the provided deployment parameters do not create this contract's address. 10 | error InvalidDeploymentParameters(); 11 | 12 | /// @notice Thrown when the caller is not the slash escrow factory. 13 | error OnlySlashEscrowFactory(); 14 | 15 | /** 16 | * @notice Burns or redistributes the underlying tokens of the strategies. 17 | * @param slashEscrowFactory The factory contract that created the slash escrow. 18 | * @param slashEscrowImplementation The implementation contract that was used to create the slash escrow. 19 | * @param operatorSet The operator set that was used to create the slash escrow. 20 | * @param slashId The slash ID that was used to create the slash escrow. 21 | * @param recipient The recipient of the underlying tokens. 22 | * @param strategy The strategy that was used to create the slash escrow. 23 | */ 24 | function releaseTokens( 25 | ISlashEscrowFactory slashEscrowFactory, 26 | ISlashEscrow slashEscrowImplementation, 27 | OperatorSet calldata operatorSet, 28 | uint256 slashId, 29 | address recipient, 30 | IStrategy strategy 31 | ) external; 32 | 33 | /** 34 | * @notice Verifies the deployment parameters of the slash escrow. 35 | * @param slashEscrowFactory The factory contract that created the slash escrow. 36 | * @param slashEscrowImplementation The implementation contract that was used to create the slash escrow. 37 | * @param operatorSet The operator set that was used to create the slash escrow. 38 | * @param slashId The slash ID that was used to create the slash escrow. 39 | * @return True if the provided parameters create this contract's address, false otherwise. 40 | * @dev Uses ClonesUpgradeable.predictDeterministicAddress() to compute the expected address from the parameters. 41 | * - Compares the computed address against this contract's address to validate parameter integrity. 42 | * - Provides a stateless validation mechanism for releaseTokens() inputs. 43 | * - Security relies on the cryptographic properties of CREATE2 address derivation. 44 | * - Attack vector would require finding a hash collision in the CREATE2 address computation. 45 | */ 46 | function verifyDeploymentParameters( 47 | ISlashEscrowFactory slashEscrowFactory, 48 | ISlashEscrow slashEscrowImplementation, 49 | OperatorSet calldata operatorSet, 50 | uint256 slashId 51 | ) external view returns (bool); 52 | } 53 | -------------------------------------------------------------------------------- /src/contracts/libraries/Endian.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | library Endian { 5 | /** 6 | * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64 7 | * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type 8 | * @return n The big endian-formatted uint64 9 | * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits) 10 | * through a right-shift/shr operation. 11 | */ 12 | function fromLittleEndianUint64( 13 | bytes32 lenum 14 | ) internal pure returns (uint64 n) { 15 | // the number needs to be stored in little-endian encoding (ie in bytes 0-8) 16 | n = uint64(uint256(lenum >> 192)); 17 | // forgefmt: disable-next-item 18 | return (n >> 56) | 19 | ((0x00FF000000000000 & n) >> 40) | 20 | ((0x0000FF0000000000 & n) >> 24) | 21 | ((0x000000FF00000000 & n) >> 8) | 22 | ((0x00000000FF000000 & n) << 8) | 23 | ((0x0000000000FF0000 & n) << 24) | 24 | ((0x000000000000FF00 & n) << 40) | 25 | ((0x00000000000000FF & n) << 56); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/contracts/libraries/OperatorSetLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | using OperatorSetLib for OperatorSet global; 5 | 6 | /** 7 | * @notice An operator set identified by the AVS address and an identifier 8 | * @param avs The address of the AVS this operator set belongs to 9 | * @param id The unique identifier for the operator set 10 | */ 11 | struct OperatorSet { 12 | address avs; 13 | uint32 id; 14 | } 15 | 16 | library OperatorSetLib { 17 | function key( 18 | OperatorSet memory os 19 | ) internal pure returns (bytes32) { 20 | return bytes32(abi.encodePacked(os.avs, uint96(os.id))); 21 | } 22 | 23 | function decode( 24 | bytes32 _key 25 | ) internal pure returns (OperatorSet memory) { 26 | /// forgefmt: disable-next-item 27 | return OperatorSet({ 28 | avs: address(uint160(uint256(_key) >> 96)), 29 | id: uint32(uint256(_key) & type(uint96).max) 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/contracts/mixins/Deprecated_OwnableUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; 5 | import "@openzeppelin-upgrades/contracts/utils/ContextUpgradeable.sol"; 6 | 7 | /** 8 | * @title Deprecated_OwnableUpgradeable 9 | * @dev This contract can be inherited in place of OpenZeppelin's OwnableUpgradeable 10 | * to maintain the same storage layout while effectively removing the Ownable functionality. 11 | * 12 | * This is useful in cases where a contract previously used OwnableUpgradeable but no longer 13 | * needs ownership functionality, yet must maintain the same storage slots to ensure 14 | * compatibility with existing deployed proxies. 15 | * 16 | * The contract preserves the same storage layout as OwnableUpgradeable: 17 | * - It keeps the `_owner` storage variable in the same slot 18 | * - It maintains the same storage gap for future upgrades 19 | */ 20 | abstract contract Deprecated_OwnableUpgradeable is Initializable, ContextUpgradeable { 21 | address private _owner; 22 | 23 | /** 24 | * @dev This empty reserved space is put in place to allow future versions to add new 25 | * variables without shifting down storage in the inheritance chain. 26 | * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps 27 | */ 28 | uint256[49] private __gap; 29 | } 30 | -------------------------------------------------------------------------------- /src/contracts/mixins/PermissionControllerMixin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | import "../interfaces/IPermissionController.sol"; 5 | 6 | abstract contract PermissionControllerMixin { 7 | /// @dev Thrown when the caller is not allowed to call a function on behalf of an account. 8 | error InvalidPermissions(); 9 | 10 | /// @notice Pointer to the permission controller contract. 11 | IPermissionController public immutable permissionController; 12 | 13 | constructor( 14 | IPermissionController _permissionController 15 | ) { 16 | permissionController = _permissionController; 17 | } 18 | 19 | /// @notice Checks if the caller (msg.sender) can call on behalf of an account. 20 | modifier checkCanCall( 21 | address account 22 | ) { 23 | require(_checkCanCall(account), InvalidPermissions()); 24 | _; 25 | } 26 | 27 | /** 28 | * @notice Checks if the caller is allowed to call a function on behalf of an account. 29 | * @param account the account to check 30 | * @dev `msg.sender` is the caller to check that can call the function on behalf of `account`. 31 | * @dev Returns a bool, instead of reverting 32 | */ 33 | function _checkCanCall( 34 | address account 35 | ) internal returns (bool) { 36 | return permissionController.canCall(account, msg.sender, address(this), msg.sig); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/contracts/mixins/SemVerMixin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | import "../interfaces/ISemVerMixin.sol"; 5 | import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol"; 6 | 7 | /// @title SemVerMixin 8 | /// @notice A mixin contract that provides semantic versioning functionality. 9 | /// @dev Follows SemVer 2.0.0 specification (https://semver.org/). 10 | abstract contract SemVerMixin is ISemVerMixin { 11 | using ShortStringsUpgradeable for *; 12 | 13 | /// @notice The semantic version string for this contract, stored as a ShortString for gas efficiency. 14 | /// @dev Follows SemVer 2.0.0 specification (https://semver.org/). 15 | ShortString internal immutable _VERSION; 16 | 17 | /// @notice Initializes the contract with a semantic version string. 18 | /// @param _version The SemVer-formatted version string (e.g., "1.2.3") 19 | /// @dev Version should follow SemVer 2.0.0 format: MAJOR.MINOR.PATCH 20 | constructor( 21 | string memory _version 22 | ) { 23 | _VERSION = _version.toShortString(); 24 | } 25 | 26 | /// @inheritdoc ISemVerMixin 27 | function version() public view virtual returns (string memory) { 28 | return _VERSION.toString(); 29 | } 30 | 31 | /// @notice Returns the major version of the contract. 32 | /// @dev Supports single digit major versions (e.g., "1" for version "1.2.3") 33 | /// @return The major version string (e.g., "1" for version "1.2.3") 34 | function _majorVersion() internal view returns (string memory) { 35 | bytes memory v = bytes(_VERSION.toString()); 36 | return string(abi.encodePacked(v[0])); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/contracts/permissions/PauserRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../interfaces/IPauserRegistry.sol"; 5 | 6 | /** 7 | * @title Defines pauser & unpauser roles + modifiers to be used elsewhere. 8 | * @author Layr Labs, Inc. 9 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 10 | */ 11 | contract PauserRegistry is IPauserRegistry { 12 | /// @notice Mapping of addresses to whether they hold the pauser role. 13 | mapping(address => bool) public isPauser; 14 | 15 | /// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses. 16 | address public unpauser; 17 | 18 | modifier onlyUnpauser() { 19 | require(msg.sender == unpauser, OnlyUnpauser()); 20 | _; 21 | } 22 | 23 | constructor(address[] memory _pausers, address _unpauser) { 24 | for (uint256 i = 0; i < _pausers.length; i++) { 25 | _setIsPauser(_pausers[i], true); 26 | } 27 | _setUnpauser(_unpauser); 28 | } 29 | 30 | /// @notice Sets new pauser - only callable by unpauser, as the unpauser is expected to be kept more secure, e.g. being a multisig with a higher threshold 31 | /// @param newPauser Address to be added/removed as pauser 32 | /// @param canPause Whether the address should be added or removed as pauser 33 | function setIsPauser(address newPauser, bool canPause) external onlyUnpauser { 34 | _setIsPauser(newPauser, canPause); 35 | } 36 | 37 | /// @notice Sets new unpauser - only callable by unpauser, as the unpauser is expected to be kept more secure, e.g. being a multisig with a higher threshold 38 | function setUnpauser( 39 | address newUnpauser 40 | ) external onlyUnpauser { 41 | _setUnpauser(newUnpauser); 42 | } 43 | 44 | function _setIsPauser(address pauser, bool canPause) internal { 45 | require(pauser != address(0), InputAddressZero()); 46 | isPauser[pauser] = canPause; 47 | emit PauserStatusChanged(pauser, canPause); 48 | } 49 | 50 | function _setUnpauser( 51 | address newUnpauser 52 | ) internal { 53 | require(newUnpauser != address(0), InputAddressZero()); 54 | emit UnpauserChanged(unpauser, newUnpauser); 55 | unpauser = newUnpauser; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/contracts/permissions/PermissionControllerStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | 6 | import "../interfaces/IPermissionController.sol"; 7 | 8 | abstract contract PermissionControllerStorage is IPermissionController { 9 | using EnumerableSet for EnumerableSet.Bytes32Set; 10 | using EnumerableSet for EnumerableSet.AddressSet; 11 | 12 | struct AccountPermissions { 13 | /// @notice The pending admins of the account 14 | EnumerableSet.AddressSet pendingAdmins; 15 | /// @notice The admins of the account 16 | EnumerableSet.AddressSet admins; 17 | /// @notice Mapping from an appointee to the list of encoded target & selectors 18 | mapping(address appointee => EnumerableSet.Bytes32Set) appointeePermissions; 19 | /// @notice Mapping from encoded target & selector to the list of appointees 20 | mapping(bytes32 targetSelector => EnumerableSet.AddressSet) permissionAppointees; 21 | } 22 | 23 | /// @notice Mapping from an account to its permission 24 | mapping(address account => AccountPermissions) internal _permissions; 25 | 26 | /** 27 | * @dev This empty reserved space is put in place to allow future versions to add new 28 | * variables without shifting down storage in the inheritance chain. 29 | * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps 30 | */ 31 | uint256[49] private __gap; 32 | } 33 | -------------------------------------------------------------------------------- /src/contracts/pods/EigenPodPausingConstants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | /** 5 | * @title Constants shared between 'EigenPod' and 'EigenPodManager' contracts. 6 | * @author Layr Labs, Inc. 7 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 8 | */ 9 | abstract contract EigenPodPausingConstants { 10 | /// @notice Index for flag that pauses creation of new EigenPods when set. See EigenPodManager code for details. 11 | uint8 internal constant PAUSED_NEW_EIGENPODS = 0; 12 | 13 | // Deprecated 14 | // uint8 internal constant PAUSED_WITHDRAW_RESTAKED_ETH = 1; 15 | 16 | /// @notice Index for flag that pauses the deposit related functions *of the EigenPods* when set. see EigenPod code for details. 17 | uint8 internal constant PAUSED_EIGENPODS_VERIFY_CREDENTIALS = 2; 18 | 19 | // Deprecated 20 | // uint8 internal constant PAUSED_EIGENPODS_VERIFY_BALANCE_UPDATE = 3; 21 | 22 | // Deprecated 23 | // uint8 internal constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4; 24 | 25 | /// @notice Pausability for EigenPod's "accidental transfer" withdrawal methods 26 | uint8 internal constant PAUSED_NON_PROOF_WITHDRAWALS = 5; 27 | 28 | uint8 internal constant PAUSED_START_CHECKPOINT = 6; 29 | 30 | /// @notice Index for flag that pauses the `verifyCheckpointProofs` function *of the EigenPods* when set. see EigenPod code for details. 31 | uint8 internal constant PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS = 7; 32 | 33 | uint8 internal constant PAUSED_VERIFY_STALE_BALANCE = 8; 34 | 35 | uint8 internal constant PAUSED_CONSOLIDATIONS = 9; 36 | 37 | uint8 internal constant PAUSED_WITHDRAWAL_REQUESTS = 10; 38 | } 39 | -------------------------------------------------------------------------------- /src/contracts/strategies/StrategyFactoryStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../interfaces/IStrategyFactory.sol"; 5 | 6 | /** 7 | * @title Storage for the StrategyFactory contract. 8 | * @author Layr Labs, Inc. 9 | * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service 10 | */ 11 | abstract contract StrategyFactoryStorage is IStrategyFactory { 12 | /// @notice Upgradeable beacon which new Strategies deployed by this contract point to 13 | IBeacon public strategyBeacon; 14 | 15 | /// @notice Mapping token => Strategy contract for the token 16 | /// The strategies in this mapping are deployed by the StrategyFactory. 17 | /// The factory can only deploy a single strategy per token address 18 | /// These strategies MIGHT not be whitelisted in the StrategyManager, 19 | /// though deployNewStrategy does whitelist by default. 20 | /// These strategies MIGHT not be the only strategy for the underlying token 21 | /// as additional strategies can be whitelisted by the owner of the factory. 22 | mapping(IERC20 => IStrategy) public deployedStrategies; 23 | 24 | /// @notice Mapping token => Whether or not a strategy can be deployed for the token 25 | mapping(IERC20 => bool) public isBlacklisted; 26 | 27 | /** 28 | * @dev This empty reserved space is put in place to allow future versions to add new 29 | * variables without shifting down storage in the inheritance chain. 30 | * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps 31 | */ 32 | uint256[48] private __gap; 33 | } 34 | -------------------------------------------------------------------------------- /src/test/TestConstants.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | library TestConstants { 5 | string constant TEST_VERSION = "9.9.9"; 6 | } 7 | -------------------------------------------------------------------------------- /src/test/harnesses/AllocationManagerHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/core/AllocationManager.sol"; 5 | import "forge-std/Test.sol"; 6 | import "../TestConstants.sol"; 7 | 8 | contract AllocationManagerHarness is AllocationManager { 9 | using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; 10 | 11 | constructor( 12 | IDelegationManager _delegation, 13 | IPauserRegistry _pauserRegistry, 14 | IPermissionController _permissionController, 15 | uint32 _DEALLOCATION_DELAY, 16 | uint32 _ALLOCATION_CONFIGURATION_DELAY 17 | ) 18 | AllocationManager( 19 | _delegation, 20 | _pauserRegistry, 21 | _permissionController, 22 | _DEALLOCATION_DELAY, 23 | _ALLOCATION_CONFIGURATION_DELAY, 24 | TestConstants.TEST_VERSION 25 | ) 26 | {} 27 | 28 | function deallocationQueueAtIndex(address operator, IStrategy strategy, uint index) external view returns (bytes32) { 29 | return deallocationQueue[operator][strategy].at(index); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/harnesses/DelegationManagerHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/core/DelegationManager.sol"; 5 | import "forge-std/Test.sol"; 6 | import "../TestConstants.sol"; 7 | 8 | contract DelegationManagerHarness is DelegationManager { 9 | constructor( 10 | IStrategyManager _strategyManager, 11 | IEigenPodManager _eigenPodManager, 12 | IAllocationManager _allocationManager, 13 | IPauserRegistry _pauserRegistry, 14 | IPermissionController _permissionController, 15 | uint32 _MIN_WITHDRAWAL_DELAY 16 | ) 17 | DelegationManager( 18 | _strategyManager, 19 | _eigenPodManager, 20 | _allocationManager, 21 | _pauserRegistry, 22 | _permissionController, 23 | _MIN_WITHDRAWAL_DELAY, 24 | TestConstants.TEST_VERSION 25 | ) 26 | {} 27 | 28 | function getSlashingFactor(address staker, IStrategy strategy, uint64 operatorMaxMagnitude) external view returns (uint) { 29 | return _getSlashingFactor(staker, strategy, operatorMaxMagnitude); 30 | } 31 | 32 | function getSlashingFactors(address staker, address operator, IStrategy[] memory strategies) external view returns (uint[] memory) { 33 | return _getSlashingFactors(staker, operator, strategies); 34 | } 35 | 36 | function getSlashingFactorsAtBlock(address staker, address operator, IStrategy[] memory strategies, uint32 blockNumber) 37 | external 38 | view 39 | returns (uint[] memory) 40 | { 41 | return _getSlashingFactorsAtBlock(staker, operator, strategies, blockNumber); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/harnesses/EigenHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/token/Eigen.sol"; 5 | import "../TestConstants.sol"; 6 | 7 | contract EigenHarness is Eigen { 8 | constructor(IERC20 _bEIGEN) Eigen(_bEIGEN, TestConstants.TEST_VERSION) {} 9 | 10 | /// expose internal mint function 11 | function mint(address to, uint amount) public { 12 | _mint(to, amount); 13 | } 14 | 15 | /** 16 | * @notice This function allows the owner to set the allowedFrom status of an address 17 | * @param from the address whose allowedFrom status is being set 18 | * @param isAllowedFrom the new allowedFrom status 19 | * @dev this function is callable by anoyone in the harness 20 | */ 21 | function setAllowedFromPermissionless(address from, bool isAllowedFrom) external { 22 | allowedFrom[from] = isAllowedFrom; 23 | emit SetAllowedFrom(from, isAllowedFrom); 24 | } 25 | 26 | function setTransferRestrictionsDisabledAfterToMax() external { 27 | transferRestrictionsDisabledAfter = type(uint).max; 28 | } 29 | 30 | function transferOwnershipPermissionless(address newOwner) external { 31 | _transferOwnership(newOwner); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/harnesses/EigenPodHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/pods/EigenPod.sol"; 5 | import "forge-std/Test.sol"; 6 | 7 | contract EigenPodHarness is EigenPod { 8 | constructor(IETHPOSDeposit _ethPOS, IEigenPodManager _eigenPodManager, string memory _version) 9 | EigenPod(_ethPOS, _eigenPodManager, _version) 10 | {} 11 | 12 | function getActiveValidatorCount() public view returns (uint) { 13 | return activeValidatorCount; 14 | } 15 | 16 | function setActiveValidatorCount(uint _count) public { 17 | activeValidatorCount = _count; 18 | } 19 | 20 | function verifyWithdrawalCredentials( 21 | uint64 beaconTimestamp, 22 | bytes32 beaconStateRoot, 23 | uint40 validatorIndex, 24 | bytes calldata validatorFieldsProof, 25 | bytes32[] calldata validatorFields 26 | ) public returns (uint) { 27 | return _verifyWithdrawalCredentials(beaconTimestamp, beaconStateRoot, validatorIndex, validatorFieldsProof, validatorFields); 28 | } 29 | 30 | function setValidatorStatus(bytes32 pkhash, VALIDATOR_STATUS status) public { 31 | _validatorPubkeyHashToInfo[pkhash].status = status; 32 | } 33 | 34 | function setValidatorRestakedBalance(bytes32 pkhash, uint64 restakedBalanceGwei) public { 35 | _validatorPubkeyHashToInfo[pkhash].restakedBalanceGwei = restakedBalanceGwei; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/harnesses/EigenPodManagerWrapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/pods/EigenPodManager.sol"; 5 | 6 | ///@notice This contract exposes a manual setter for podShares in order to initialize podShares as negative 7 | contract EigenPodManagerWrapper is EigenPodManager { 8 | constructor( 9 | IETHPOSDeposit _ethPOS, 10 | IBeacon _eigenPodBeacon, 11 | IDelegationManager _delegationManager, 12 | IPauserRegistry _pauserRegistry, 13 | string memory _version 14 | ) EigenPodManager(_ethPOS, _eigenPodBeacon, _delegationManager, _pauserRegistry, _version) {} 15 | 16 | function setPodOwnerShares(address owner, IEigenPod pod) external { 17 | ownerToPod[owner] = pod; 18 | } 19 | 20 | function setPodOwnerShares(address owner, int shares) external { 21 | podOwnerDepositShares[owner] = shares; 22 | } 23 | 24 | function setBeaconChainSlashingFactor(address podOwner, uint64 slashingFactor) external { 25 | _beaconChainSlashingFactor[podOwner] = BeaconChainSlashingFactor({slashingFactor: slashingFactor, isSet: true}); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/harnesses/PausableHarness.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/permissions/Pausable.sol"; 5 | 6 | // wrapper around the Pausable contract that exposes the internal `_setPausedStatus` function. 7 | contract PausableHarness is Pausable { 8 | constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) {} 9 | 10 | function initializePauser(uint initPausedStatus) external { 11 | _setPausedStatus(initPausedStatus); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/integration/TimeMachine.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/test/utils/Logger.t.sol"; 6 | 7 | contract TimeMachine is Test, Logger { 8 | uint[] public snapshots; 9 | 10 | function NAME() public view virtual override returns (string memory) { 11 | return "TimeMachine"; 12 | } 13 | 14 | /// ----------------------------------------------------------------------- 15 | /// Setters 16 | /// ----------------------------------------------------------------------- 17 | 18 | function createSnapshot() public returns (uint snapshot) { 19 | snapshots.push(snapshot = cheats.snapshotState()); 20 | print.method("createSnapshot", cheats.toString(snapshot)); 21 | } 22 | 23 | function travelToLast() public returns (uint currentSnapshot) { 24 | // Safety check to make sure createSnapshot is called before attempting 25 | // to warp so we don't accidentally prevent our own births. 26 | assertTrue(pastExists(), "Global.warpToPast: invalid usage, past does not exist"); 27 | uint last = lastSnapshot(); 28 | // print.method("travelToLast", cheats.toString(last)); 29 | currentSnapshot = createSnapshot(); 30 | cheats.revertToState(last); 31 | } 32 | 33 | function travel(uint snapshot) public { 34 | // print.method("travel", cheats.toString(snapshot)); 35 | cheats.revertToState(snapshot); 36 | } 37 | 38 | /// ----------------------------------------------------------------------- 39 | /// Getters 40 | /// ----------------------------------------------------------------------- 41 | 42 | function lastSnapshot() public view returns (uint) { 43 | return snapshots[snapshots.length - 1]; 44 | } 45 | 46 | function pastExists() public view returns (bool) { 47 | return snapshots.length != 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/integration/TypeImporter.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/contracts/interfaces/IAllocationManager.sol"; 5 | import "src/contracts/interfaces/IAVSDirectory.sol"; 6 | import "src/contracts/interfaces/IDelegationManager.sol"; 7 | import "src/contracts/interfaces/IEigenPod.sol"; 8 | import "src/contracts/interfaces/IEigenPodManager.sol"; 9 | import "src/contracts/interfaces/IStrategyManager.sol"; 10 | 11 | /// @dev A master interface contract that imports types defined in our 12 | /// contract interfaces so they can be used without needing to refer to 13 | /// the interface, e.g: 14 | /// 15 | /// `AllocateParams memory params;` 16 | /// vs 17 | /// `IAllocationManagerTypes.AllocateParams memory params;` 18 | interface TypeImporter is IAllocationManagerTypes, IAVSDirectoryTypes, IDelegationManagerTypes, IEigenPodManagerTypes, IEigenPodTypes {} 19 | -------------------------------------------------------------------------------- /src/test/integration/UpgradeTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/test/integration/IntegrationDeployer.t.sol"; 5 | import "src/test/integration/IntegrationChecks.t.sol"; 6 | 7 | abstract contract UpgradeTest is IntegrationCheckUtils { 8 | /// Only run upgrade tests on mainnet forks 9 | function setUp() public virtual override { 10 | if (!isForktest()) { 11 | cheats.skip(true); 12 | } else { 13 | isUpgraded = false; 14 | super.setUp(); 15 | } 16 | } 17 | 18 | /// Deploy current implementation contracts and upgrade existing proxies 19 | function _upgradeEigenLayerContracts() public virtual { 20 | require(forkType == MAINNET, "_upgradeEigenLayerContracts: somehow running upgrade test locally"); 21 | require(!isUpgraded, "_upgradeEigenLayerContracts: already performed upgrade"); 22 | 23 | emit log("_upgradeEigenLayerContracts: upgrading mainnet to redistribution"); 24 | 25 | _upgradeMainnetContracts(); 26 | 27 | emit log("======"); 28 | 29 | isUpgraded = true; 30 | emit log("_upgradeEigenLayerContracts: redistribution upgrade complete"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/integration/deprecatedInterfaces/mainnet/IAllocationManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/contracts/interfaces/IStrategy.sol"; 5 | 6 | /** 7 | * @notice Interface of the allocationManager prior to redistribution. 8 | * @dev The interface remains the exact same, except `SlashOperator` does not return the slashID or shares 9 | * @dev This interface is the minimal possibl interface needed for the redistribution upgrade test 10 | */ 11 | interface IAllocationManager_PreRedistribution { 12 | /** 13 | * @notice Struct containing parameters to slashing 14 | * @param operator the address to slash 15 | * @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of 16 | * @param strategies the set of strategies to slash 17 | * @param wadsToSlash the parts in 1e18 to slash, this will be proportional to the operator's 18 | * slashable stake allocation for the operatorSet 19 | * @param description the description of the slashing provided by the AVS for legibility 20 | */ 21 | struct SlashingParams { 22 | address operator; 23 | uint32 operatorSetId; 24 | IStrategy[] strategies; 25 | uint[] wadsToSlash; 26 | string description; 27 | } 28 | 29 | /** 30 | * @notice Called by an AVS to slash an operator in a given operator set. The operator must be registered 31 | * and have slashable stake allocated to the operator set. 32 | * 33 | * @param avs The AVS address initiating the slash. 34 | * @param params The slashing parameters, containing: 35 | * - operator: The operator to slash. 36 | * - operatorSetId: The ID of the operator set the operator is being slashed from. 37 | * - strategies: Array of strategies to slash allocations from (must be in ascending order). 38 | * - wadsToSlash: Array of proportions to slash from each strategy (must be between 0 and 1e18). 39 | * - description: Description of why the operator was slashed. 40 | * 41 | * @dev For each strategy: 42 | * 1. Reduces the operator's current allocation magnitude by wadToSlash proportion. 43 | * 2. Reduces the strategy's max and encumbered magnitudes proportionally. 44 | * 3. If there is a pending deallocation, reduces it proportionally. 45 | * 4. Updates the operator's shares in the DelegationManager. 46 | * 47 | * @dev Small slashing amounts may not result in actual token burns due to 48 | * rounding, which will result in small amounts of tokens locked in the contract 49 | * rather than fully burning through the burn mechanism. 50 | */ 51 | function slashOperator(address avs, SlashingParams calldata params) external; 52 | } 53 | -------------------------------------------------------------------------------- /src/test/integration/mocks/BeaconChainMock_Deneb.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/test/integration/mocks/BeaconChainMock.t.sol"; 5 | import "src/test/integration/mocks/LibProofGen.t.sol"; 6 | 7 | /// @notice A backwards-compatible BeaconChain Mock that updates containers & proofs from Deneb to Pectra 8 | contract BeaconChainMock_DenebForkable is BeaconChainMock { 9 | using StdStyle for *; 10 | using print for *; 11 | using LibValidator for *; 12 | using LibProofGen for *; 13 | 14 | // Denotes whether the beacon chain has been forked to Pectra 15 | bool isPectra; 16 | 17 | // The timestamp of the Pectra hard fork 18 | uint64 public pectraForkTimestamp; 19 | 20 | constructor(EigenPodManager _eigenPodManager, uint64 _genesisTime) BeaconChainMock(_eigenPodManager, _genesisTime) { 21 | LibProofGen.useDencun(); 22 | } 23 | 24 | function NAME() public pure override returns (string memory) { 25 | return "BeaconChain_PectraForkable"; 26 | } 27 | 28 | /// @dev Always return 32 ETH in gwei 29 | function _getMaxEffectiveBalanceGwei(Validator storage v) internal view override returns (uint64) { 30 | return isPectra ? super._getMaxEffectiveBalanceGwei(v) : MIN_ACTIVATION_BALANCE_GWEI; 31 | } 32 | 33 | /// @notice Forks the beacon chain to Pectra 34 | /// @dev Test battery should warp to the fork timestamp after calling this method 35 | function forkToPectra(uint64 _pectraForkTimestamp) public { 36 | isPectra = true; 37 | LibProofGen.usePectra(); 38 | 39 | cheats.warp(_pectraForkTimestamp); 40 | pectraForkTimestamp = _pectraForkTimestamp; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/integration/mocks/EIP_4788_Oracle_Mock.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | contract EIP_4788_Oracle_Mock { 5 | mapping(uint => bytes32) blockRoots; 6 | 7 | uint constant HISTORY_BUFFER_LENGTH = 8191; 8 | 9 | fallback() external { 10 | require(msg.data.length == 32, "4788OracleMock.fallback: malformed msg.data"); 11 | 12 | uint timestamp = abi.decode(msg.data, (uint)); 13 | require(timestamp != 0, "4788OracleMock.fallback: timestamp is 0"); 14 | 15 | bytes32 blockRoot = blockRoots[timestamp]; 16 | require(blockRoot != 0, "4788OracleMock.fallback: no block root found. DID YOU USE CHEATS.WARP?"); 17 | 18 | assembly { 19 | mstore(0, blockRoot) 20 | return(0, 32) 21 | } 22 | } 23 | 24 | function timestampToBlockRoot(uint timestamp) public view returns (bytes32) { 25 | return blockRoots[uint64(timestamp)]; 26 | } 27 | 28 | function setBlockRoot(uint64 timestamp, bytes32 blockRoot) public { 29 | blockRoots[timestamp] = blockRoot; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/integration/tests/eigenpod/Pectra_Features.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "src/test/integration/IntegrationChecks.t.sol"; 5 | 6 | contract Integration_Pectra_Features_Base is IntegrationCheckUtils { 7 | using ArrayLib for *; 8 | 9 | function _init() internal virtual override { 10 | _configAssetTypes(HOLDS_ETH); 11 | } 12 | 13 | function testFuzz_consolidate(uint24 _r) public rand(_r) { 14 | User staker = _newEmptyStaker(); 15 | 16 | // Deal ETH and start 0x01 validators 17 | (uint40[] memory validators, uint64 totalBalanceGwei) = staker.startETH1Validators(uint8(_randUint({min: 2, max: 65}))); 18 | 19 | staker.verifyWithdrawalCredentials(validators); 20 | check_Deposit_State(staker, beaconChainETHStrategy.toArray(), (totalBalanceGwei * GWEI_TO_WEI).toArrayU256()); 21 | 22 | (uint40[] memory newValidators, uint40[] memory consolidated) = staker.maxConsolidation(validators); 23 | 24 | staker.startCheckpoint(); 25 | check_StartCheckpoint_State(staker); 26 | 27 | staker.completeCheckpoint(); 28 | check_CompleteCheckpoint_WithConsolidations_State(staker, consolidated); 29 | 30 | beaconChain.advanceEpoch_NoWithdraw(); 31 | 32 | staker.startCheckpoint(); 33 | check_StartCheckpoint_State(staker); 34 | 35 | staker.completeCheckpoint(); 36 | check_CompleteCheckpoint_EarnOnBeacon_State(staker, uint64(newValidators.length) * beaconChain.CONSENSUS_REWARD_AMOUNT_GWEI()); 37 | } 38 | 39 | function testFuzz_partialWithdrawals(uint24 _r) public rand(_r) { 40 | User staker = _newEmptyStaker(); 41 | 42 | // Deal ETH and start 0x02 validators 43 | (uint40[] memory validators, uint64 totalBalanceGwei) = staker.startCompoundingValidators(uint8(_randUint({min: 2, max: 10}))); 44 | 45 | staker.verifyWithdrawalCredentials(validators); 46 | check_Deposit_State(staker, beaconChainETHStrategy.toArray(), (totalBalanceGwei * GWEI_TO_WEI).toArrayU256()); 47 | 48 | // Create partial withdrawal requests for each validator, down to 32 ETH 49 | uint64 amountWithdrawnGwei = staker.withdrawExcess(validators); 50 | 51 | staker.startCheckpoint(); 52 | check_StartCheckpoint_WithPodBalance_State(staker, amountWithdrawnGwei); 53 | 54 | staker.completeCheckpoint(); 55 | check_CompleteCheckpoint_WithPodBalance_State(staker, amountWithdrawnGwei); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/integration/tests/upgrade/README.md: -------------------------------------------------------------------------------- 1 | ## Upgrade Tests 2 | 3 | This folder contains specific tests we want to conduct to determine upgrade compatibility. Tests in this folder are only run if the `forktest` profile is selected, e.g: 4 | 5 | `env FOUNDRY_PROFILE=forktest forge t --mc Upgrade` 6 | 7 | #### How to Write 8 | 9 | Upgrade tests inherit from the `UpgradeTest` mixin, which imports everything you need for a standard integration test. A standard integration test automatically upgrades all contracts to the latest repo contracts, even when forking from mainnet. 10 | 11 | In contrast, the `UpgradeTest` mixin ensures that (when a test begins) the contracts we're working with are _not upgraded_. This allows the test writer to perform some initial setup actions before calling `_upgradeEigenLayerContracts()`, after which we can check that the upgrade correctly handles pre-upgrade state. 12 | 13 | #### Example 14 | 15 | Say we want to check that withdrawals initiated before the slashing upgrade are completable after the slashing upgrade. This example test shows how: 16 | 17 | ```solidity 18 | contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { 19 | 20 | function testFuzz_deposit_queue_upgrade_completeAsShares(uint24 _random) public rand(_random) { 21 | /// Pre-upgrade: 22 | /// 1. Create staker with some assets 23 | /// 2. Staker deposits into EigenLayer 24 | /// 3. Staker queues a withdrawal 25 | (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); 26 | User operator = User(payable(0)); 27 | 28 | staker.depositIntoEigenlayer(strategies, tokenBalances); 29 | uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); 30 | IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); 31 | 32 | /// Upgrade to slashing contracts 33 | _upgradeEigenLayerContracts(); 34 | 35 | // Complete pre-slashing withdrawals as shares 36 | _rollBlocksForCompleteWithdrawals(withdrawals); 37 | for (uint i = 0; i < withdrawals.length; i++) { 38 | staker.completeWithdrawalAsShares(withdrawals[i]); 39 | check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], strategies, shares); 40 | } 41 | } 42 | } 43 | ``` 44 | 45 | **Note** how the initial staker actions are NOT followed by `check_X_State` methods. This is because, before calling `_upgradeEigenLayerContracts`, the test is being run on old contracts. Adding invariant checks to old state transitions is not the point of this test and would add a lot of maintenance overhead. 46 | 47 | **Note** that tests for previous upgrades should be removed if you need to write an upgrade for a new fork block. -------------------------------------------------------------------------------- /src/test/mocks/AVSDirectoryMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.9; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/contracts/interfaces/IAVSDirectory.sol"; 6 | import "src/contracts/libraries/OperatorSetLib.sol"; 7 | 8 | contract AVSDirectoryMock is Test { 9 | receive() external payable {} 10 | fallback() external payable {} 11 | } 12 | -------------------------------------------------------------------------------- /src/test/mocks/Dummy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | contract EmptyContract { 5 | function foo() public pure returns (uint) { 6 | return 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/mocks/ERC20_SetTransferReverting_Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; 5 | 6 | contract ERC20_SetTransferReverting_Mock is ERC20PresetFixedSupply { 7 | bool public transfersRevert; 8 | 9 | constructor(uint initSupply, address initOwner) 10 | ERC20PresetFixedSupply("ERC20_SetTransferReverting_Mock", "ERC20_SetTransferReverting_Mock", initSupply, initOwner) 11 | {} 12 | 13 | function setTransfersRevert(bool _transfersRevert) public { 14 | transfersRevert = _transfersRevert; 15 | } 16 | 17 | function _beforeTokenTransfer(address, address, uint) internal view override { 18 | if (transfersRevert) { 19 | // revert without message 20 | revert(); 21 | // revert("ERC20_SetTransferReverting_Mock._beforeTokenTransfer: transfersRevert set"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/mocks/ETHDepositMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "../../contracts/interfaces/IETHPOSDeposit.sol"; 5 | 6 | contract ETHPOSDepositMock is IETHPOSDeposit { 7 | function deposit(bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature, bytes32 deposit_data_root) 8 | external 9 | payable 10 | {} 11 | 12 | function get_deposit_root() external pure returns (bytes32) { 13 | bytes32 root; 14 | return root; 15 | } 16 | 17 | /// @notice Query the current deposit count. 18 | /// @return The deposit count encoded as a little endian 64-bit number. 19 | function get_deposit_count() external pure returns (bytes memory) { 20 | bytes memory root; 21 | return root; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/mocks/EigenPodManagerMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.9; 3 | 4 | import "forge-std/Test.sol"; 5 | import "../../contracts/interfaces/IStrategy.sol"; 6 | import "../../contracts/permissions/Pausable.sol"; 7 | 8 | contract EigenPodManagerMock is Test, Pausable { 9 | receive() external payable {} 10 | fallback() external payable {} 11 | 12 | mapping(address => int) public podOwnerDepositShares; 13 | 14 | mapping(address => uint) public podOwnerSharesWithdrawn; 15 | 16 | uint64 public pectraForkTimestamp; 17 | 18 | struct BeaconChainSlashingFactor { 19 | bool isSet; 20 | uint64 slashingFactor; 21 | } 22 | 23 | mapping(address => BeaconChainSlashingFactor) _beaconChainSlashingFactor; 24 | 25 | constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) { 26 | _setPausedStatus(0); 27 | pectraForkTimestamp = 1 hours * 12; 28 | } 29 | 30 | function podOwnerShares(address podOwner) external view returns (int) { 31 | return podOwnerDepositShares[podOwner]; 32 | } 33 | 34 | function stakerDepositShares(address user, address) public view returns (uint depositShares) { 35 | return podOwnerDepositShares[user] < 0 ? 0 : uint(podOwnerDepositShares[user]); 36 | } 37 | 38 | function setPodOwnerShares(address podOwner, int shares) external { 39 | podOwnerDepositShares[podOwner] = shares; 40 | } 41 | 42 | function addShares(address podOwner, IStrategy, uint shares) external returns (uint, uint) { 43 | uint existingDepositShares = uint(podOwnerDepositShares[podOwner]); 44 | podOwnerDepositShares[podOwner] += int(shares); 45 | return (existingDepositShares, shares); 46 | } 47 | 48 | function removeDepositShares( 49 | address podOwner, 50 | IStrategy, // strategy 51 | uint shares 52 | ) external returns (uint) { 53 | int updatedShares = podOwnerDepositShares[podOwner] - int(shares); 54 | podOwnerDepositShares[podOwner] = updatedShares; 55 | return uint(updatedShares); 56 | } 57 | 58 | function denebForkTimestamp() external pure returns (uint64) { 59 | return type(uint64).max; 60 | } 61 | 62 | function withdrawSharesAsTokens( 63 | address podOwner, 64 | address, 65 | /** 66 | * strategy 67 | */ 68 | address, 69 | /** 70 | * token 71 | */ 72 | uint shares 73 | ) external { 74 | podOwnerSharesWithdrawn[podOwner] += shares; 75 | } 76 | 77 | function setBeaconChainSlashingFactor(address staker, uint64 bcsf) external { 78 | _beaconChainSlashingFactor[staker] = BeaconChainSlashingFactor({isSet: true, slashingFactor: bcsf}); 79 | } 80 | 81 | function beaconChainSlashingFactor(address staker) external view returns (uint64) { 82 | BeaconChainSlashingFactor memory bsf = _beaconChainSlashingFactor[staker]; 83 | return bsf.isSet ? bsf.slashingFactor : WAD; 84 | } 85 | 86 | function setPectraForkTimestamp(uint64 _pectraForkTimestamp) external { 87 | pectraForkTimestamp = _pectraForkTimestamp; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/mocks/EmptyContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | contract EmptyContract { 5 | function foo() public pure returns (uint) { 6 | return 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/mocks/LiquidStakingToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | // modified version of https://github.com/itstargetconfirmed/wrapped-ether/blob/master/contracts/WETH.sol 3 | pragma solidity >=0.4.22 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | /// @notice An implementation of Wrapped Ether. 8 | /// @author Anderson Singh. 9 | 10 | contract WETH is ERC20 { 11 | constructor() ERC20("Wrapped Ether", "WETH") {} 12 | 13 | /// @dev mint tokens for sender based on amount of ether sent. 14 | function deposit() public payable { 15 | _mint(msg.sender, msg.value); 16 | } 17 | 18 | /// @dev withdraw ether based on requested amount and user balance. 19 | function withdraw(uint _amount) external { 20 | require(balanceOf(msg.sender) >= _amount, "insufficient balance."); 21 | _burn(msg.sender, _amount); 22 | payable(msg.sender).transfer(_amount); 23 | } 24 | 25 | fallback() external payable { 26 | deposit(); 27 | } 28 | 29 | receive() external payable { 30 | deposit(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/mocks/MockAVSRegistrar.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | contract MockAVSRegistrar { 5 | function supportsAVS(address /*avs*/ ) external pure returns (bool) { 6 | return true; 7 | } 8 | 9 | fallback() external {} 10 | } 11 | -------------------------------------------------------------------------------- /src/test/mocks/MockDecimals.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | contract MockDecimals { 5 | function decimals() public pure returns (uint8) { 6 | return 18; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/mocks/OwnableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract OwnableMock is Ownable {} 7 | -------------------------------------------------------------------------------- /src/test/mocks/Reverter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.9; 3 | 4 | contract Reverter { 5 | fallback() external { 6 | revert("Reverter: I am a contract that always reverts"); 7 | } 8 | } 9 | 10 | contract ReverterWithDecimals is Reverter { 11 | function decimals() external pure returns (uint8) { 12 | return 18; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/mocks/SlashEscrowFactoryMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.9; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/contracts/interfaces/IStrategy.sol"; 6 | import "src/contracts/libraries/OperatorSetLib.sol"; 7 | 8 | contract SlashEscrowFactoryMock is Test { 9 | receive() external payable {} 10 | fallback() external payable {} 11 | 12 | function getSlashEscrow(OperatorSet calldata operatorSet, uint slashId) public view returns (address) { 13 | // Hash the operatorSet and slashId to get a random address 14 | return address(uint160(uint(keccak256(abi.encode(operatorSet, slashId))))); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/test-data/owners.json: -------------------------------------------------------------------------------- 1 | { 2 | "numOwners": 10, 3 | "owners": [ 4 | { 5 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e399c2" 6 | }, 7 | { 8 | "Address": "0x164dfa4241059a1880a289ccf6f3e730371e399c2" 9 | }, 10 | { 11 | "Address": "0x264ea4241059a1880a289ccf6f3e730371e399c4" 12 | }, 13 | { 14 | "Address": "0x464ea4241059a1880a289ccf6f3e730371e399c5" 15 | }, 16 | { 17 | "Address": "0x564ea4241059a1880a289ccf6f3e730371e399c6" 18 | }, 19 | { 20 | "Address": "0x864ea4241059a1880a289ccf6f3e730371e399c7" 21 | }, 22 | { 23 | "Address": "0x344ea4241059a1880a289ccf6f3e730371e399c8" 24 | }, 25 | { 26 | "Address": "0x304ea4241059a1880a289ccf6f3e730371e399c9" 27 | }, 28 | { 29 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e399d4" 30 | }, 31 | { 32 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e39955" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /src/test/test-data/reputedOwners.json: -------------------------------------------------------------------------------- 1 | { 2 | "numOwners": 10, 3 | "owners": [ 4 | { 5 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e399c2" 6 | }, 7 | { 8 | "Address": "0x164dfa4241059a1880a289ccf6f3e730371e399c2" 9 | }, 10 | { 11 | "Address": "0x264ea4241059a1880a289ccf6f3e730371e399c4" 12 | }, 13 | { 14 | "Address": "0x464ea4241059a1880a289ccf6f3e730371e399c5" 15 | }, 16 | { 17 | "Address": "0x564ea4241059a1880a289ccf6f3e730371e399c6" 18 | }, 19 | { 20 | "Address": "0x864ea4241059a1880a289ccf6f3e730371e399c7" 21 | }, 22 | { 23 | "Address": "0x344ea4241059a1880a289ccf6f3e730371e399c8" 24 | }, 25 | { 26 | "Address": "0x304ea4241059a1880a289ccf6f3e730371e399c9" 27 | }, 28 | { 29 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e399d4" 30 | }, 31 | { 32 | "Address": "0x364ea4241059a1880a289ccf6f3e730371e39955" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_MaxEarnerAndLeafIndices.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0x37550707c80f3d8907c467999730e52127ab89be3f17a5017a3f1ffb73a1445f", 3 | "RootIndex": 0, 4 | "EarnerIndex": 7, 5 | "EarnerTreeProof": "0x4bf5e16eaabbc36964f1e1639808669420f55d60e51adb7e9695b77145c479fd6777be59643947bb24d78e69d6605bf369c515b479f3a8967dd68a97c5bb4a4a262b28002eeb6cbbffb7e79e5741bf2be189a6073440a62fabcd8af4dbda94e3", 6 | "EarnerLeaf": { 7 | "Earner": "0x25a1b7322f9796b26a4bec125913b34c292b28d6", 8 | "EarnerTokenRoot": "0xf8e7e20b32aae1d818dcb593b98982841e9a0ed12c161ad603e3ee3948746cba" 9 | }, 10 | "LeafIndices": [ 11 | 7 12 | ], 13 | "TokenTreeProofs": [ 14 | "0x3cd04e8fc6f23812c570fe12292a30bb9e105e00f5913ac4b4938f23e65d8d10e6b1403d58c9d5450952e7d96c81305dad9fb966e8a27d3a42058e3958a0d30033148e91b455542d05deb81b8305b672e742cd3145f7022a0089bad2e6af9173" 15 | ], 16 | "TokenLeaves": [ 17 | { 18 | "Token": "0x7fbfdd1dfd80730385aee232cc9f79b8ae12a654", 19 | "CumulativeEarnings": 3000000000000000000 20 | } 21 | ], 22 | "TokenTreeProofsNum": 1, 23 | "TokenLeavesNum": 1 24 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_Root1.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0xc5d6bb1073f9040366851b5971493165893558f1cdc0b0046b6703baa85cddfc", 3 | "RootIndex": 0, 4 | "EarnerIndex": 3, 5 | "EarnerTreeProof": "0x04da796e892869089dfdaae7269c8eb12548f6aa3774a747322b65c42d1ca0050d38d6d5e7e9e65ba24c275fcc0f0c377d8fb6ed089770d849c39a1829d1edf27e78a529aa8f867a3777f97541a23fb1844d6ae24c3b8ca1cc981510e5d08bda", 6 | "EarnerLeaf": { 7 | "Earner": "0xf2288d736d27c1584ebf7be5f52f9e4d47251aee", 8 | "EarnerTokenRoot": "0xa81e82a39e6da197c3c83b8b1343eb7e8a969db52d4bfc424fd04d60350d76e3" 9 | }, 10 | "LeafIndices": [ 11 | 0, 12 | 1, 13 | 2, 14 | 3, 15 | 4, 16 | 5 17 | ], 18 | "TokenTreeProofs": [ 19 | "0x6166682a9a29283a51a1c1575de82334227cc45b1ce686973039a44eb9a6b008e3e64bd80597510ac0b737fc645f15801cc3835b279412e1a09ba66d50c2aa82e3f64b05b0f9ee23e853d9c134984c27b5b58d14b70c4dacea9a5e40600e17a3", 20 | "0x167f18d55815451f979244946b7eb2ce019c323a9e02fba1b2e05e19a27b91b5e3e64bd80597510ac0b737fc645f15801cc3835b279412e1a09ba66d50c2aa82e3f64b05b0f9ee23e853d9c134984c27b5b58d14b70c4dacea9a5e40600e17a3", 21 | "0x2faa07574e263370227b938c72ca18ae40edf215067ce325ebfc36f11b1f19484923b477146618e0f36993536e7bbec8ef5346613df2fb9d53caf8d9365b4c68e3f64b05b0f9ee23e853d9c134984c27b5b58d14b70c4dacea9a5e40600e17a3", 22 | "0x4dccc729db7b3ad40fc9acfe257d45196427285382332a4bc6704e1ae42785474923b477146618e0f36993536e7bbec8ef5346613df2fb9d53caf8d9365b4c68e3f64b05b0f9ee23e853d9c134984c27b5b58d14b70c4dacea9a5e40600e17a3", 23 | "0x1e9348730aee854752d72b32f4eed96ad80093807b53f3a07068536ce96d0e9aad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb51ab784a49394ced1b194ec2cac2163a6a5a0108e31a2510f82162f3d41b79962", 24 | "0x7a570fedf4656f3240f44fb4771c946ea688c554f82e204778b792013b29ded3ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb51ab784a49394ced1b194ec2cac2163a6a5a0108e31a2510f82162f3d41b79962" 25 | ], 26 | "TokenLeaves": [ 27 | { 28 | "Token": "0x1006dd1b8c3d0ef53489bed27577c75299f71473", 29 | "CumulativeEarnings": 1000000000000000000 30 | }, 31 | { 32 | "Token": "0x11a4b85eab283c98d27c8ae64469224d55ed1894", 33 | "CumulativeEarnings": 400000000000000000 34 | }, 35 | { 36 | "Token": "0x43afffbe0afacdabe9ce7dbc4f07407a2b788a84", 37 | "CumulativeEarnings": 30000000000000000000 38 | }, 39 | { 40 | "Token": "0x748a3ed7e6b04239150d7ebe12d7aef3e3994a23", 41 | "CumulativeEarnings": 250000000000 42 | }, 43 | { 44 | "Token": "0xd275b23e0a5b68ae251b0dc4c81104cba36e7cd6", 45 | "CumulativeEarnings": 884300000000000000 46 | }, 47 | { 48 | "Token": "0xec562acb9e470de27dca2495950660fa9fbd85f8", 49 | "CumulativeEarnings": 42000000000000 50 | } 51 | ], 52 | "TokenTreeProofsNum": 6, 53 | "TokenLeavesNum": 6 54 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_Root2.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0x4d58d15093f392176c29504b94be56fb4969cf100083b6e8d3c79373f2d25974", 3 | "RootIndex": 0, 4 | "EarnerIndex": 3, 5 | "EarnerTreeProof": "0xa9ed93ecba6058bc5cfab91319b40d344e7c829fb40eb26208e2898cb90071ed3bcd0aa5a1fbb1782053d35aaec2c6203ff53f6d6493100bafbf9506c7a3edf2bbcc90923e3f236d88ec22330aa91f3f50c425bc56ad3ff9707c72dcf853e206", 6 | "EarnerLeaf": { 7 | "Earner": "0xf2288d736d27c1584ebf7be5f52f9e4d47251aee", 8 | "EarnerTokenRoot": "0x6eeac100b8cd705b92cda3015844005d918e118a3c7ba20046b6523cdc203d48" 9 | }, 10 | "LeafIndices": [ 11 | 0, 12 | 1, 13 | 2, 14 | 3, 15 | 4, 16 | 5 17 | ], 18 | "TokenTreeProofs": [ 19 | "0x57898ab69c4024d674e8c18eea33fef5cd76c5b01e0f93ef168c602298f7b27ee2b46f44bc74268bc383609078e0217a0ea21d6a658975171f5233c1cd3133c0797252a751b45d9f15ef34a230f200a1c8bb69cdbbfb1fead4a3fd0f792fda58", 20 | "0x97a04c80233ddc54eccd67a57f442c63c8f741079f41d95dd6242e275dcbe871e2b46f44bc74268bc383609078e0217a0ea21d6a658975171f5233c1cd3133c0797252a751b45d9f15ef34a230f200a1c8bb69cdbbfb1fead4a3fd0f792fda58", 21 | "0xb0f239391b892c4b6f4ce0fea0a15de171f977f6798713e540b3493b93b557ffb9cf5ff8530c7a7932e4349c3c4d0172466b77e791a4e8bb1523fdb57c1fe96a797252a751b45d9f15ef34a230f200a1c8bb69cdbbfb1fead4a3fd0f792fda58", 22 | "0x71a2384092132151928d8a13f599e52ad0aebe5587aa1cac9199d782c08847e2b9cf5ff8530c7a7932e4349c3c4d0172466b77e791a4e8bb1523fdb57c1fe96a797252a751b45d9f15ef34a230f200a1c8bb69cdbbfb1fead4a3fd0f792fda58", 23 | "0xf8b6a59d2da40bb3c9a9fed1f77336c45e3550f34b8bcb76fa64adcf6d9a409dad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb508231e83c23fa7d9b9a2820a400601f21f946161a3817010724592cf53cf4ad9", 24 | "0x87fa7a4daeedebd0069679c39d095a21293b412f6f9fdae3398b454160703e3bad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb508231e83c23fa7d9b9a2820a400601f21f946161a3817010724592cf53cf4ad9" 25 | ], 26 | "TokenLeaves": [ 27 | { 28 | "Token": "0x1006dd1b8c3d0ef53489bed27577c75299f71473", 29 | "CumulativeEarnings": 1630000000000000000 30 | }, 31 | { 32 | "Token": "0x11a4b85eab283c98d27c8ae64469224d55ed1894", 33 | "CumulativeEarnings": 780000000000000000 34 | }, 35 | { 36 | "Token": "0x43afffbe0afacdabe9ce7dbc4f07407a2b788a84", 37 | "CumulativeEarnings": 37800000000000000000 38 | }, 39 | { 40 | "Token": "0x748a3ed7e6b04239150d7ebe12d7aef3e3994a23", 41 | "CumulativeEarnings": 5050000000000 42 | }, 43 | { 44 | "Token": "0xd275b23e0a5b68ae251b0dc4c81104cba36e7cd6", 45 | "CumulativeEarnings": 2284300000000000000 46 | }, 47 | { 48 | "Token": "0xec562acb9e470de27dca2495950660fa9fbd85f8", 49 | "CumulativeEarnings": 886400000000000 50 | } 51 | ], 52 | "TokenTreeProofsNum": 6, 53 | "TokenLeavesNum": 6 54 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_Root3.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0x53d76498642862250c1caa8b14df55642d977200467a3dfce62e6da30b4820c6", 3 | "RootIndex": 0, 4 | "EarnerIndex": 3, 5 | "EarnerTreeProof": "0xecd8c0e6d2d221742f8025acd6f1f0a5ff8482fe8f1cb135439e346df6fd56acce4f8a04a8bcb37dcbc11cb6984ba73cfa4da51dd037f7be27c257cf0605673b38d2f9a729da60cd7c3c2b7ff53bebfdef61de0871518eb36654368ac584b6b8", 6 | "EarnerLeaf": { 7 | "Earner": "0xf2288d736d27c1584ebf7be5f52f9e4d47251aee", 8 | "EarnerTokenRoot": "0x36c11c299ad4a8b95a795d6afc1f5f958b9d1a1ea5cc13ea2fc59b6ccd4b6ee4" 9 | }, 10 | "LeafIndices": [ 11 | 0, 12 | 1, 13 | 2, 14 | 3, 15 | 4, 16 | 5 17 | ], 18 | "TokenTreeProofs": [ 19 | "0xfcf8546a323ba4d4bcfbdb5930b3bede1e93ec4bdd8d1372ed84db3126df143fb306484eeaece55c5cd8db0ce3f3a77f4aa6fa5150b95db06b9c1cec4825aae157a8dfba810f55acf97f229426649e26f6fe58886e1edcb404535334da43d92d", 20 | "0xde4e83fd8b6b5e44f72fd511cd1a9ce6704f16378e5ca20c15f4d52efe27aa57b306484eeaece55c5cd8db0ce3f3a77f4aa6fa5150b95db06b9c1cec4825aae157a8dfba810f55acf97f229426649e26f6fe58886e1edcb404535334da43d92d", 21 | "0x67f846894f21973d7db36e6b363141b291b2f0f57bfc4b9a74b4f5335c0d068a17aac423247fab5821f643830b49570dfdecd0f30a9ae24ff5fd59bd4e9e8a4e57a8dfba810f55acf97f229426649e26f6fe58886e1edcb404535334da43d92d", 22 | "0xc27217da67ce7b0418f5c8bef4ceeefe04c5561ddd73ab9750798d8f981d981d17aac423247fab5821f643830b49570dfdecd0f30a9ae24ff5fd59bd4e9e8a4e57a8dfba810f55acf97f229426649e26f6fe58886e1edcb404535334da43d92d", 23 | "0xd084816ad70c189dbfa8be4e6b1f912edb6fe3b39ba1c19c4ed16d91b84f903dad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb550d72c280c9bd978b5ef45c3647daa2ab564342c473cb977f35b053706ed19d1", 24 | "0x2bec75e7737677b586943a2292393137cad6617ac248d249d220afb3bf31f4dcad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb550d72c280c9bd978b5ef45c3647daa2ab564342c473cb977f35b053706ed19d1" 25 | ], 26 | "TokenLeaves": [ 27 | { 28 | "Token": "0x1006dd1b8c3d0ef53489bed27577c75299f71473", 29 | "CumulativeEarnings": 3500000000000000000 30 | }, 31 | { 32 | "Token": "0x11a4b85eab283c98d27c8ae64469224d55ed1894", 33 | "CumulativeEarnings": 1240000000000000000 34 | }, 35 | { 36 | "Token": "0x43afffbe0afacdabe9ce7dbc4f07407a2b788a84", 37 | "CumulativeEarnings": 56800000000000000000 38 | }, 39 | { 40 | "Token": "0x748a3ed7e6b04239150d7ebe12d7aef3e3994a23", 41 | "CumulativeEarnings": 8900000000000 42 | }, 43 | { 44 | "Token": "0xd275b23e0a5b68ae251b0dc4c81104cba36e7cd6", 45 | "CumulativeEarnings": 4343000000000000000 46 | }, 47 | { 48 | "Token": "0xec562acb9e470de27dca2495950660fa9fbd85f8", 49 | "CumulativeEarnings": 1064000000000000 50 | } 51 | ], 52 | "TokenTreeProofsNum": 6, 53 | "TokenLeavesNum": 6 54 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_SingleEarnerLeaf.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0xd4aa4d1bdb95eb78f061238d587609407301a05bd952334ad6b5e8ca60bb347e", 3 | "RootIndex": 0, 4 | "EarnerIndex": 0, 5 | "EarnerTreeProof": "0x", 6 | "EarnerLeaf": { 7 | "Earner": "0x0d6ba28b9919cfcdb6b233469cc5ce30b979e08e", 8 | "EarnerTokenRoot": "0x12104ce9deb6e62ef479656476be1da6d71905234252cf9a5c9733e6cb115d77" 9 | }, 10 | "LeafIndices": [ 11 | 0, 12 | 2, 13 | 3 14 | ], 15 | "TokenTreeProofs": [ 16 | "0xf027f6a1f6522a5ede64f16448001378272bcc3b4d9b2660f241ea87d4cafc880d5fa8201813790dcfddb37966811813117ab78db2cce941c8b1d1f3888cccca6271c73f26f5e492cc990b25f85410beaf6f04958410162dc16eb5e3ce4791ce", 17 | "0x9ae7a20b0f244cb25a1c18339432139587ecc0058130e9ebb10a98049981395d5bef23d3c6b22f7b1265e30a68e83b675394ea57b7fa150f5ecc07bae7e3b88d6271c73f26f5e492cc990b25f85410beaf6f04958410162dc16eb5e3ce4791ce", 18 | "0x31335a07ff9047e08d712967b2ef1720f8682cb696d9df15902602b0c5eebdde5bef23d3c6b22f7b1265e30a68e83b675394ea57b7fa150f5ecc07bae7e3b88d6271c73f26f5e492cc990b25f85410beaf6f04958410162dc16eb5e3ce4791ce" 19 | ], 20 | "TokenLeaves": [ 21 | { 22 | "Token": "0x1006dd1b8c3d0ef53489bed27577c75299f71473", 23 | "CumulativeEarnings": 1000000000000000000 24 | }, 25 | { 26 | "Token": "0x43afffbe0afacdabe9ce7dbc4f07407a2b788a84", 27 | "CumulativeEarnings": 3000000000000000000 28 | }, 29 | { 30 | "Token": "0x748a3ed7e6b04239150d7ebe12d7aef3e3994a23", 31 | "CumulativeEarnings": 1000000000000000000 32 | } 33 | ], 34 | "TokenTreeProofsNum": 3, 35 | "TokenLeavesNum": 3 36 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaimProofs_SingleTokenLeaf.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0x86867b737e68a56280554c0447ac6b43ba1cb68f4a46d1d9a0ecb919f912959b", 3 | "RootIndex": 0, 4 | "EarnerIndex": 3, 5 | "EarnerTreeProof": "0x04da796e892869089dfdaae7269c8eb12548f6aa3774a747322b65c42d1ca0050d38d6d5e7e9e65ba24c275fcc0f0c377d8fb6ed089770d849c39a1829d1edf27e78a529aa8f867a3777f97541a23fb1844d6ae24c3b8ca1cc981510e5d08bda", 6 | "EarnerLeaf": { 7 | "Earner": "0xf2288d736d27c1584ebf7be5f52f9e4d47251aee", 8 | "EarnerTokenRoot": "0x167f18d55815451f979244946b7eb2ce019c323a9e02fba1b2e05e19a27b91b5" 9 | }, 10 | "LeafIndices": [ 11 | 0 12 | ], 13 | "TokenTreeProofs": [ 14 | "0x" 15 | ], 16 | "TokenLeaves": [ 17 | { 18 | "Token": "0x1006dd1b8c3d0ef53489bed27577c75299f71473", 19 | "CumulativeEarnings": 1000000000000000000 20 | } 21 | ], 22 | "TokenTreeProofsNum": 1, 23 | "TokenLeavesNum": 1 24 | } -------------------------------------------------------------------------------- /src/test/test-data/rewardsCoordinator/processClaim_Preprod_Test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Root": "0x5e3227269ddcd5ddc7bc76ef42243a16166e86f9adab6183ee49b9875f2c7002", 3 | "RootIndex": 0, 4 | "EarnerIndex": 1, 5 | "EarnerTreeProof": "0x468cfb9f23175803c35daccc788454e82e192aa69bd770b26861dbe1fb42336d44b3fc6ad9da7ba33382006677e1808659ccd50c35705233f0fedca7b34c0e07d8894c83317a23b1f54108d86045843d34a127d92fb262452a636d0d40b577e1", 6 | "EarnerLeaf": { 7 | "Earner": "0x2222aac0c980cc029624b7ff55b88bc6f63c538f", 8 | "EarnerTokenRoot": "0x987aa019b1caf3fb0eaf02ebc1b8ce46840aee48d94ee21a2753045805ae38a8" 9 | }, 10 | "LeafIndices": [ 11 | 0 12 | ], 13 | "TokenTreeProofs": [ 14 | "0x" 15 | ], 16 | "TokenLeaves": [ 17 | { 18 | "Token": "0x94373a4919b3240d86ea41593d5eba789fef3848", 19 | "CumulativeEarnings": 1003827094673442500 20 | } 21 | ], 22 | "TokenTreeProofsNum": 1, 23 | "TokenLeavesNum": 1 24 | } -------------------------------------------------------------------------------- /src/test/tree/PermissionControllerUnit.tree: -------------------------------------------------------------------------------- 1 | . 2 | └── PermissionController (**** denotes that integration tests are needed to fully validate path) 3 | ├── when setAdmin is called 4 | │ ├── given that the current admin it not set 5 | │ │ └── given that the caller is not the account 6 | │ │ └── it should revert 7 | │ ├── given that the current admin is set 8 | │ │ └── given that the msg.sender is not the current admin 9 | │ │ └── it should revert 10 | │ ├── given that the new admin is the zero address 11 | │ │ └── it should revert 12 | │ └── given that a valid caller sets a valid admin 13 | │ └── it should update the permissions of the account & emit an AdminSet event 14 | ├── when setAppointee is called 15 | │ ├── given that the caller is not the admin 16 | │ │ └── it should revert 17 | │ ├── given that the appointee already has permissions 18 | │ │ └── it should revert 19 | │ └── given that proper permissions are set 20 | │ └── it should emit a DelegateSet event, and update the `appointeePermissions` and `permissionAppointee` mappings for the account 21 | └── when removeAppointee is called 22 | ├── given that the caller is not the admin 23 | │ └── it should revert 24 | ├── given that the appointee does not have permissions 25 | │ └── it should revert 26 | └── given that proper permissions are set 27 | └── it should emit a DelegateRemoved event, and update the `appointeePermissions` and `permissionAppointee` mappings for the account -------------------------------------------------------------------------------- /src/test/unit/DeployFromScratch.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console2} from "forge-std/Test.sol"; 5 | import {DeployFromScratch} from "script/deploy/local/deploy_from_scratch.slashing.s.sol"; 6 | 7 | // NOTE: Run the following command to deploy from scratch in an anvil instance: 8 | // RUST_LOG=forge,foundry=trace forge script script/deploy/local/Deploy_From_Scratch.s.sol --slow \ 9 | // --rpc-url http://127.0.0.1:8545 \ 10 | // --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ 11 | // --broadcast \ 12 | // --sig "run(string memory configFile)" \ 13 | // -- local/deploy_from_scratch.slashing.anvil.config.json 14 | contract DeployTest is Test { 15 | DeployFromScratch public deployer; 16 | 17 | function setUp() public { 18 | deployer = new DeployFromScratch(); 19 | } 20 | 21 | function test_DeployFromScratch() public { 22 | // Deploy, expecting no revert. 23 | deployer.run("local/deploy_from_scratch.slashing.anvil.config.json"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/unit/mixins/SemVerMixin.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | import {SemVerMixin} from "src/contracts/mixins/SemVerMixin.sol"; 6 | 7 | // Helper contract to test the abstract SemVerMixin 8 | contract SemVerMixinMock is SemVerMixin { 9 | constructor(string memory version) SemVerMixin(version) {} 10 | 11 | // Expose internal function for testing 12 | function majorVersion() public view returns (string memory) { 13 | return _majorVersion(); 14 | } 15 | } 16 | 17 | contract SemVerMixinTest is Test { 18 | SemVerMixinMock public semVer; 19 | 20 | function test_version_returnsCorrectVersion() public { 21 | semVer = new SemVerMixinMock("1.2.3"); 22 | assertEq(semVer.version(), "1.2.3"); 23 | } 24 | 25 | function test_majorVersion_returnsCorrectMajorVersion() public { 26 | semVer = new SemVerMixinMock("1.2.3"); 27 | assertEq(semVer.majorVersion(), "1"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/unit/mixins/SignatureUtilsUnit.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.27; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/contracts/mixins/SignatureUtilsMixin.sol"; 6 | 7 | contract MockSigner { 8 | mapping(bytes32 => mapping(bytes => bool)) public validSignatures; 9 | 10 | function setValidSignature(bytes32 digest, bytes memory signature, bool valid) public { 11 | validSignatures[digest][signature] = valid; 12 | } 13 | 14 | function isValidSignatureNow(bytes32 digest, bytes memory signature) public view returns (bool) { 15 | return validSignatures[digest][signature]; 16 | } 17 | } 18 | 19 | contract SignatureUtilsMixinUnit is Test, SignatureUtilsMixin("9.9.9") { 20 | uint signerPk; 21 | address signer; 22 | bytes32 hash; 23 | bytes32 digest; 24 | bytes32 expectedDomainSeparator; 25 | 26 | function setUp() public { 27 | vm.chainId(1); 28 | 29 | signerPk = 1; 30 | signer = vm.addr(signerPk); 31 | 32 | hash = keccak256(""); 33 | digest = _calculateSignableDigest(hash); 34 | 35 | expectedDomainSeparator = keccak256( 36 | abi.encode( 37 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), 38 | keccak256(bytes("EigenLayer")), 39 | keccak256(bytes(_majorVersion())), 40 | block.chainid, 41 | address(this) 42 | ) 43 | ); 44 | } 45 | 46 | function test_domainSeparator_NonZero() public view { 47 | assertTrue(domainSeparator() != 0, "The domain separator should be non-zero"); 48 | assertTrue(domainSeparator() == expectedDomainSeparator, "The domain separator should be as expected"); 49 | } 50 | 51 | function test_domainSeparator_NewChainId() public { 52 | bytes32 initialDomainSeparator = domainSeparator(); 53 | 54 | // Change the chain ID 55 | vm.chainId(9999); 56 | 57 | bytes32 newDomainSeparator = domainSeparator(); 58 | 59 | assertTrue(newDomainSeparator != 0, "The new domain separator should be non-zero"); 60 | assertTrue(initialDomainSeparator != newDomainSeparator, "The domain separator should change when the chain ID changes"); 61 | } 62 | 63 | /// forge-config: default.allow_internal_expect_revert = true 64 | function test_checkIsValidSignatureNow_Expired() public { 65 | (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPk, digest); 66 | 67 | vm.expectRevert(ISignatureUtilsMixinErrors.SignatureExpired.selector); 68 | _checkIsValidSignatureNow(signer, digest, abi.encode(r, s, v), block.timestamp - 1); 69 | } 70 | 71 | // function testFail_checkIsValidSignatureNow_InvalidSignature() public { 72 | // _checkIsValidSignatureNow(signer, digest, "", block.timestamp); 73 | // } 74 | } 75 | --------------------------------------------------------------------------------