├── .cargo └── config.toml ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── release.yml └── workflows │ ├── bindings.yml │ ├── changelog.yml │ ├── check-anvil-dump.yml │ ├── foundry.yml │ ├── integration.yml │ ├── release-plz.yml │ └── stale.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── book.toml ├── book └── src │ ├── SUMMARY.md │ └── chapter_1.md ├── clippy.toml ├── crates ├── chainio │ ├── README.md │ └── clients │ │ ├── avsregistry │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── error.rs │ │ │ ├── fake_reader.rs │ │ │ ├── lib.rs │ │ │ ├── reader.rs │ │ │ └── writer.rs │ │ ├── elcontracts │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── error.rs │ │ │ ├── lib.rs │ │ │ ├── reader.rs │ │ │ └── writer.rs │ │ ├── eth │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── client.rs │ │ │ ├── instrumented_client.rs │ │ │ └── lib.rs │ │ └── fireblocks │ │ ├── Cargo.toml │ │ └── src │ │ ├── client.rs │ │ ├── contract_call.rs │ │ ├── error.rs │ │ ├── get_asset_addresses.rs │ │ ├── get_transaction.rs │ │ ├── lib.rs │ │ ├── list_contracts.rs │ │ ├── list_external_accounts.rs │ │ ├── list_vault_accounts.rs │ │ ├── status.rs │ │ └── transaction.rs ├── common │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── crypto │ ├── bls │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── error.rs │ │ │ └── lib.rs │ ├── bn254 │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── error.rs │ │ │ ├── lib.rs │ │ │ └── utils.rs │ └── ecdsa │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── eigen-cli │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── args.rs │ │ ├── bls.rs │ │ ├── convert.rs │ │ ├── eigen_address.rs │ │ ├── generate.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ └── operator_id.rs ├── eigensdk │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs ├── logging │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── log_level.rs │ │ ├── logger.rs │ │ ├── noop_logger.rs │ │ └── tracing_logger.rs ├── m2_contracts │ ├── .env.example │ ├── .gitignore │ ├── anvil │ │ ├── deploy-avs.sh │ │ ├── deploy-eigenlayer.sh │ │ ├── dump-state.sh │ │ ├── m2_contracts_deployed_anvil_state │ │ │ └── state.json │ │ ├── start-anvil-chain-with-el-and-avs-deployed.sh │ │ └── utils.sh │ ├── foundry.toml │ ├── mock_avs_config.json │ ├── remappings.txt │ ├── script │ │ ├── ContractsRegistry.s.sol │ │ ├── DeployEigenLayerCore.s.sol │ │ ├── DeployMockAvs.s.sol │ │ ├── deployments │ │ │ ├── core │ │ │ │ ├── 31337.json │ │ │ │ └── m2 │ │ │ │ │ └── 31337.json │ │ │ └── mock-avs │ │ │ │ └── 31337.json │ │ ├── input │ │ │ └── 31337 │ │ │ │ └── ops_addresses.json │ │ ├── output │ │ │ └── 31337 │ │ │ │ ├── eigenlayer_deployment_output.json │ │ │ │ ├── mockAvs_deployment_output.json │ │ │ │ └── token_and_strategy_deployment_output.json │ │ └── utils │ │ │ ├── CoreDeploymentLib.sol │ │ │ ├── FundOperator.sol │ │ │ ├── MockAvsDeploymentLib.sol │ │ │ ├── UpgradeableProxyLib.sol │ │ │ └── WriteToContractsRegistryLib.sol │ └── src │ │ ├── ContractsRegistry.sol │ │ ├── MockAvsServiceManager.sol │ │ └── MockERC20.sol ├── metrics │ ├── Cargo.toml │ ├── README.md │ ├── collectors │ │ ├── economic │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── error.rs │ │ │ │ ├── fake_collector.rs │ │ │ │ └── lib.rs │ │ └── rpc_calls │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── src │ │ ├── eigenmetrics.rs │ │ ├── lib.rs │ │ └── prometheus.rs ├── nodeapi │ ├── Cargo.toml │ └── src │ │ ├── error.rs │ │ └── lib.rs ├── operator_sets_contracts │ ├── .env.example │ ├── .gitignore │ ├── anvil │ │ ├── deploy-avs.sh │ │ ├── deploy-eigenlayer.sh │ │ ├── dump-state.sh │ │ ├── operatorset_contracts_deployed_anvil_state │ │ │ └── state.json │ │ ├── start-anvil-chain-with-el-and-avs-deployed.sh │ │ └── utils.sh │ ├── foundry.toml │ ├── mock_avs_config.json │ ├── remappings.txt │ ├── script │ │ ├── ContractsRegistry.s.sol │ │ ├── DeployEigenLayerCore.s.sol │ │ ├── DeployMockAvs.s.sol │ │ ├── deployments │ │ │ ├── core │ │ │ │ ├── 31337.json │ │ │ │ └── m2 │ │ │ │ │ └── 31337.json │ │ │ └── mock-avs │ │ │ │ └── 31337.json │ │ ├── input │ │ │ └── 31337 │ │ │ │ └── ops_addresses.json │ │ ├── output │ │ │ └── 31337 │ │ │ │ ├── eigenlayer_deployment_output.json │ │ │ │ ├── mockAvs_deployment_output.json │ │ │ │ └── token_and_strategy_deployment_output.json │ │ └── utils │ │ │ ├── CoreDeploymentLib.sol │ │ │ ├── FundOperator.sol │ │ │ ├── MockAvsDeploymentLib.sol │ │ │ ├── UpgradeableProxyLib.sol │ │ │ └── WriteToContractsRegistryLib.sol │ └── src │ │ ├── ContractsRegistry.sol │ │ ├── MockAvsServiceManager.sol │ │ └── MockERC20.sol ├── services │ ├── README.md │ ├── avsregistry │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── chaincaller.rs │ │ │ ├── fake_avs_registry_service.rs │ │ │ └── lib.rs │ ├── bls_aggregation │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── diagram │ │ │ └── sequence-bls.mmd │ │ └── src │ │ │ ├── bls_agg.rs │ │ │ ├── bls_agg_test.rs │ │ │ ├── bls_aggregation_service_error.rs │ │ │ ├── bls_aggregation_service_response.rs │ │ │ └── lib.rs │ └── operatorsinfo │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ ├── fake_operator_info.rs │ │ ├── lib.rs │ │ ├── operator_info.rs │ │ ├── operatorsinfo_inmemory.rs │ │ └── operatorsinfo_onchain.rs ├── signer │ ├── Cargo.toml │ ├── README.md │ ├── mockdata │ │ └── dummy.key.json │ └── src │ │ ├── lib.rs │ │ ├── signer.rs │ │ └── web3_signer.rs ├── types │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── avs.rs │ │ ├── avs_state.rs │ │ ├── lib.rs │ │ ├── operator.rs │ │ ├── operator_metadata.rs │ │ ├── operator_pubkeys.rs │ │ └── test.rs └── utils │ ├── Cargo.toml │ └── src │ ├── common.rs │ ├── lib.rs │ ├── rewardsv2 │ ├── core │ │ ├── avsdirectory.rs │ │ ├── delegationmanager.rs │ │ ├── eigenpod.rs │ │ ├── eigenpodmanager.rs │ │ ├── erc20.rs │ │ ├── ieigenpod.rs │ │ ├── ieigenpodmanager.rs │ │ ├── irewardscoordinator.rs │ │ ├── islasher.rs │ │ ├── istrategy.rs │ │ ├── mod.rs │ │ ├── rewardscoordinator.rs │ │ ├── slasher.rs │ │ └── strategymanager.rs │ ├── middleware │ │ ├── blsapkregistry.rs │ │ ├── ecdsaservicemanagerbase.rs │ │ ├── ecdsastakeregistry.rs │ │ ├── iblssignaturechecker.rs │ │ ├── ierc20.rs │ │ ├── indexregistry.rs │ │ ├── mod.rs │ │ ├── operatorstateretriever.rs │ │ ├── registrycoordinator.rs │ │ ├── servicemanagerbase.rs │ │ └── stakeregistry.rs │ ├── mod.rs │ └── sdk │ │ ├── contractsregistry.rs │ │ ├── mockavsservicemanager.rs │ │ ├── mockerc20.rs │ │ └── mod.rs │ └── slashing │ ├── core │ ├── allocationmanager.rs │ ├── avsdirectory.rs │ ├── delegationmanager.rs │ ├── eigenpod.rs │ ├── eigenpodmanager.rs │ ├── ieigenpod.rs │ ├── ieigenpodmanager.rs │ ├── irewardscoordinator.rs │ ├── istrategy.rs │ ├── mod.rs │ ├── permissioncontroller.rs │ └── strategymanager.rs │ ├── middleware │ ├── blsapkregistry.rs │ ├── iblssignaturechecker.rs │ ├── ierc20.rs │ ├── indexregistry.rs │ ├── islashingregistrycoordinator.rs │ ├── mod.rs │ ├── operatorstateretriever.rs │ ├── registrycoordinator.rs │ ├── servicemanagerbase.rs │ ├── slashingregistrycoordinator.rs │ ├── socketregistry.rs │ └── stakeregistry.rs │ ├── mod.rs │ └── sdk │ ├── contractsregistry.rs │ ├── mockavsservicemanager.rs │ ├── mockerc20.rs │ └── mod.rs ├── examples ├── README.md ├── anvil-utils │ ├── Cargo.toml │ └── examples │ │ └── get_contracts_from_registry.rs ├── avsregistry-read │ ├── Cargo.toml │ └── examples │ │ ├── get_operator_from_id.rs │ │ ├── get_operator_id.rs │ │ ├── get_operator_stake_in_quorums_of_operator_at_current_block.rs │ │ ├── get_operators_stake_in_quorums_at_block.rs │ │ ├── get_quorum_count.rs │ │ └── query_existing_registered_operator_pub_keys.rs ├── avsregistry-write │ ├── Cargo.toml │ └── examples │ │ └── register_operator_in_quorum_with_avs_registry_coordinator.rs └── info-operator-service │ ├── Cargo.toml │ └── examples │ └── get_operator_info.rs ├── release-plz.toml ├── scripts ├── bindings.patch ├── generate_rewardsv2_bindings.sh └── generate_slashing_bindings.sh └── tests ├── integration ├── Cargo.toml └── src │ └── lib.rs └── testing-utils ├── Cargo.toml ├── README.md └── src ├── anvil.rs ├── anvil_constants.rs ├── chain_clients.rs ├── lib.rs ├── m2_holesky_constants.rs ├── mainnet_constants.rs ├── test_data.rs └── transaction.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-pc-windows-msvc] 2 | rustflags = [ 3 | # Increases the stack size to 10MB, which is 4 | # in line with Linux (whereas default for Windows is 1MB) 5 | "-Clink-arg=/STACK:10000000", 6 | ] 7 | 8 | [target.i686-pc-windows-msvc] 9 | rustflags = [ 10 | # Increases the stack size to 10MB, which is 11 | # in line with Linux (whereas default for Windows is 1MB) 12 | "-Clink-arg=/STACK:10000000", 13 | ] 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes # 2 | 3 | ### What Changed? 4 | 5 | 6 | ### Reviewer Checklist 7 | 8 | - [ ] New features are tested and documented 9 | - [ ] PR updates the changelog with a description of changes 10 | - [ ] PR has one of the `changelog-X` labels (if applies) 11 | - [ ] Code deprecates any old functionality before removing it 12 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | categories: 6 | # vulnerabilities 7 | - title: Security 🔒 8 | labels: 9 | - changelog-security 10 | # new features 11 | - title: Added 🎉 12 | labels: 13 | - changelog-added 14 | # changes in existing functionality 15 | - title: Breaking Changes 🛠 16 | labels: 17 | - changelog-breaking 18 | # soon-to-be removed features 19 | - title: Deprecated ⚠️ 20 | labels: 21 | - changelog-deprecated 22 | # now removed features 23 | - title: Removed 🗑 24 | labels: 25 | - changelog-removed 26 | # documentation was added or changed 27 | - title: Documentation 📚 28 | labels: 29 | - changelog-documentation 30 | 31 | - title: Other Changes 32 | labels: 33 | - "*" 34 | -------------------------------------------------------------------------------- /.github/workflows/bindings.yml: -------------------------------------------------------------------------------- 1 | name: Bindings 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [ '**' ] 8 | 9 | env: 10 | FOUNDRY_PROFILE: ci 11 | 12 | jobs: 13 | check: 14 | strategy: 15 | fail-fast: true 16 | 17 | name: Check bindings are up to date 18 | runs-on: ubuntu-22.04 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | submodules: recursive 24 | 25 | - name: Install Foundry 26 | uses: foundry-rs/foundry-toolchain@v1 27 | with: 28 | version: stable 29 | 30 | - name: Show Forge version 31 | run: forge --version 32 | 33 | - name: Generate new bindings 34 | run: make bindings_host 35 | 36 | - name: Compare existing and new bindings 37 | working-directory: crates/utils/src/ 38 | run: git diff --exit-code 39 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Workflow" 2 | on: 3 | merge_group: 4 | pull_request: 5 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] 6 | 7 | env: 8 | PR_URL: https://github.com/Layr-Labs/eigensdk-rs/pull/${{ github.event.number }} 9 | 10 | jobs: 11 | # Enforces the update of a changelog file on every pull request 12 | # The update in the changelog can be skipped if the pull request 13 | # includes the `changelog-ignore` label. 14 | changelog: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - uses: dangoslen/changelog-enforcer@v3 22 | with: 23 | skipLabels: changelog-ignore 24 | 25 | - name: Enforce PR URL in CHANGELOG.md 26 | if: contains(github.event.pull_request.labels.*.name, 'changelog-ignore') == false 27 | run: git diff CHANGELOG.md | grep $PR_URL CHANGELOG.md 28 | -------------------------------------------------------------------------------- /.github/workflows/check-anvil-dump.yml: -------------------------------------------------------------------------------- 1 | name: Check anvil dump is up-to-date 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | pull_request: 8 | branches: [ '**' ] 9 | 10 | jobs: 11 | rewardsv2: 12 | name: Check rewardsv2 anvil dump state is up to date 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | 20 | # This step is needed to know if the contracts were changed. 21 | - uses: dorny/paths-filter@v3 22 | id: filter 23 | with: 24 | filters: | 25 | contracts: 26 | - 'crates/m2_contracts/lib/**' 27 | - 'crates/m2_contracts/script/**' 28 | - 'crates/m2_contracts/src/**' 29 | 30 | # This step runs only if some contract changed. 31 | # It checks the diff in the anvil state file. 32 | # If the diff is null, that means the anvil state has not changed, 33 | # i.e. the anvil state outdated and therefore this step will fail. 34 | # Note: if the git diff fails to fetch the changes, then the step will also fail. 35 | - name: Check the anvil dump has changed 36 | if: steps.filter.outputs.contracts == 'true' 37 | working-directory: crates/m2_contracts/anvil/m2_contracts_deployed_anvil_state 38 | run: | 39 | if [ -z "$(git diff origin/${{ github.event.pull_request.base.ref }} -- state.json)" ]; then 40 | echo "The anvil dump is outdated"; 41 | exit 1 42 | fi 43 | 44 | slashing: 45 | name: Check slashing anvil dump state is up to date 46 | runs-on: ubuntu-latest 47 | 48 | steps: 49 | - uses: actions/checkout@v4 50 | with: 51 | fetch-depth: 0 52 | 53 | # This step is needed to know if the contracts were changed. 54 | - uses: dorny/paths-filter@v3 55 | id: filter 56 | with: 57 | filters: | 58 | contracts: 59 | - 'crates/operator_sets_contracts/lib/**' 60 | - 'crates/operator_sets_contracts/script/**' 61 | - 'crates/operator_sets_contracts/src/**' 62 | 63 | # This step runs only if some contract changed. 64 | # It checks the diff in the anvil state file. 65 | # If the diff is null, that means the anvil state has not changed, 66 | # i.e. the anvil state outdated and therefore this step will fail. 67 | # Note: if the git diff fails to fetch the changes, then the step will also fail. 68 | - name: Check the anvil dump has changed 69 | if: steps.filter.outputs.contracts == 'true' 70 | working-directory: crates/operator_sets_contracts/anvil/operatorset_contracts_deployed_anvil_state 71 | run: | 72 | if [ -z "$(git diff origin/${{ github.event.pull_request.base.ref }} -- state.json)" ]; then 73 | echo "The anvil dump is outdated"; 74 | exit 1 75 | fi 76 | 77 | -------------------------------------------------------------------------------- /.github/workflows/foundry.yml: -------------------------------------------------------------------------------- 1 | name: Foundry CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [ '**' ] 8 | 9 | env: 10 | FOUNDRY_PROFILE: ci 11 | 12 | jobs: 13 | m2: 14 | strategy: 15 | fail-fast: true 16 | 17 | name: Foundry project 18 | runs-on: ubuntu-latest 19 | defaults: 20 | run: 21 | working-directory: ./crates/m2_contracts 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | 27 | - name: Install Foundry 28 | uses: foundry-rs/foundry-toolchain@v1 29 | with: 30 | version: stable 31 | 32 | - name: Show Forge version 33 | run: forge --version 34 | 35 | - name: Run Forge fmt 36 | run: forge fmt --check 37 | 38 | - name: Run Forge build 39 | run: forge build --sizes 40 | 41 | slashing: 42 | strategy: 43 | fail-fast: true 44 | 45 | name: Foundry project 46 | runs-on: ubuntu-latest 47 | defaults: 48 | run: 49 | working-directory: ./crates/operator_sets_contracts 50 | steps: 51 | - uses: actions/checkout@v4 52 | with: 53 | submodules: recursive 54 | 55 | - name: Install Foundry 56 | uses: foundry-rs/foundry-toolchain@v1 57 | with: 58 | version: stable 59 | 60 | - name: Show Forge version 61 | run: forge --version 62 | 63 | - name: Run Forge fmt 64 | run: forge fmt --check 65 | 66 | - name: Run Forge build 67 | run: forge build --sizes 68 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | branches: [ '**' ] 10 | 11 | jobs: 12 | build: 13 | name: Build 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Install Rust 17 | uses: dtolnay/rust-toolchain@stable 18 | 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Set up cargo cache 23 | uses: Swatinem/rust-cache@v2 24 | 25 | - name: Run cargo check 26 | run: cargo check --workspace --all-features --all-targets 27 | 28 | lint: 29 | name: Run Lints 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Install Rust 33 | uses: dtolnay/rust-toolchain@stable 34 | with: 35 | components: rustfmt, clippy 36 | 37 | - name: Checkout repository 38 | uses: actions/checkout@v4 39 | 40 | - name: Set up cargo cache 41 | uses: Swatinem/rust-cache@v2 42 | 43 | - name: Run cargo fmt 44 | run: cargo fmt --all -- --check 45 | 46 | - name: Run clippy 47 | run: cargo clippy --workspace --all-features --benches --examples --tests -- -D warnings 48 | 49 | test: 50 | name: Run Tests 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Checkout repository 54 | uses: actions/checkout@v4 55 | 56 | - name: Install Rust 57 | uses: dtolnay/rust-toolchain@stable 58 | 59 | - name: Cache Rust dependencies 60 | uses: Swatinem/rust-cache@v2 61 | with: 62 | cache-on-failure: true 63 | 64 | - name: docker 65 | uses: docker/setup-docker-action@v4 66 | 67 | - name: Run tests 68 | run: cargo test --workspace 69 | 70 | coverage: 71 | name: Generate Coverage 72 | runs-on: ubuntu-latest 73 | env: 74 | HOLESKY_WS_URL: ${{ secrets.HOLESKY_WS_URL }} 75 | HOLESKY_HTTP_URL: ${{ secrets.HOLESKY_HTTP_URL }} 76 | FIREBLOCKS_API_KEY: ${{ secrets.FIREBLOCKS_API_KEY }} 77 | FIREBLOCKS_API_URL: ${{ secrets.FIREBLOCKS_API_URL }} 78 | FIREBLOCKS_PRIVATE_KEY: ${{ secrets.FIREBLOCKS_PRIVATE_KEY }} 79 | steps: 80 | - name: Checkout repository 81 | uses: actions/checkout@v4 82 | 83 | - name: Install Rust 84 | uses: dtolnay/rust-toolchain@stable 85 | 86 | - name: Create private key file 87 | run: printf "%b" "$FIREBLOCKS_PRIVATE_KEY" > fireblocks_secret.key 88 | 89 | - name: Set environment variable for private key path 90 | run: echo "FIREBLOCKS_PRIVATE_KEY_PATH=$(pwd)/fireblocks_secret.key" >> $GITHUB_ENV 91 | 92 | - name: Cache Rust dependencies 93 | uses: Swatinem/rust-cache@v2 94 | with: 95 | cache-on-failure: true 96 | 97 | - name: Install llvm-cov 98 | uses: taiki-e/install-action@v2 99 | with: 100 | tool: cargo-llvm-cov 101 | 102 | - name: docker 103 | uses: docker/setup-docker-action@v4 104 | 105 | - name: Run tests and generate code coverage 106 | run: make coverage 107 | 108 | - name: Zip coverage html report 109 | run: zip -r coverage.zip lcov.info target/llvm-cov/html 110 | 111 | - name: Upload coverage report 112 | uses: actions/upload-artifact@v4 113 | with: 114 | name: coverage-summary 115 | path: coverage.zip 116 | 117 | generate_anvil_dump: 118 | strategy: 119 | fail-fast: true 120 | 121 | name: Generate anvil state 122 | runs-on: ubuntu-latest 123 | steps: 124 | - uses: actions/checkout@v4 125 | with: 126 | submodules: recursive 127 | 128 | - name: Install Foundry 129 | uses: foundry-rs/foundry-toolchain@v1 130 | with: 131 | version: stable 132 | 133 | - name: Generate anvil state 134 | run: make dump-state 135 | -------------------------------------------------------------------------------- /.github/workflows/release-plz.yml: -------------------------------------------------------------------------------- 1 | name: Release-plz 2 | 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | 7 | on: 8 | workflow_dispatch: 9 | push: 10 | branches: 11 | - main 12 | - dev 13 | 14 | jobs: 15 | # Release unpublished packages. 16 | release-plz-release: 17 | name: Release-plz release 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: write 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | - name: Install Rust toolchain 27 | uses: dtolnay/rust-toolchain@stable 28 | - name: Run release-plz 29 | uses: release-plz/action@v0.5 30 | with: 31 | command: release 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # Marks issues as stale. 2 | 3 | name: stale issues 4 | 5 | on: 6 | workflow_dispatch: {} 7 | schedule: 8 | - cron: "30 1 * * *" 9 | 10 | jobs: 11 | close-issues: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | issues: write 15 | pull-requests: write 16 | steps: 17 | - uses: actions/stale@v9 18 | with: 19 | days-before-stale: 21 20 | days-before-close: 7 21 | stale-issue-label: "S-stale" 22 | stale-pr-label: "S-stale" 23 | exempt-issue-labels: "M-prevent-stale" 24 | exempt-pr-labels: "M-prevent-stale" 25 | stale-issue-message: "This issue is stale because it has been open for 21 days with no activity." 26 | close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale." 27 | exempt-all-milestones: true 28 | exempt-all-assignees: true 29 | repo-token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debug/ 2 | target/ 3 | coverage 4 | 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "crates/m2_contracts/lib/forge-std"] 2 | path = crates/m2_contracts/lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "crates/m2_contracts/lib/eigenlayer-middleware"] 5 | path = crates/m2_contracts/lib/eigenlayer-middleware 6 | url = https://github.com/layr-labs/eigenlayer-middleware 7 | [submodule "crates/operator_sets_contracts/lib/forge-std"] 8 | path = crates/operator_sets_contracts/lib/forge-std 9 | url = https://github.com/foundry-rs/forge-std 10 | [submodule "crates/operator_sets_contracts/lib/eigenlayer-middleware"] 11 | path = crates/operator_sets_contracts/lib/eigenlayer-middleware 12 | url = https://github.com/layr-labs/eigenlayer-middleware 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.linkedProjects": [ 3 | ] 4 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | __CONTRACTS__: ## 2 | 3 | .PHONY: deploy-eigenlayer 4 | deploy-eigenlayer: 5 | ./crates/operator_sets_contracts/anvil/deploy-eigenlayer.sh 6 | 7 | .PHONY: deploy-avs 8 | deploy-avs: 9 | ./crates/operator_sets_contracts/anvil/deploy-avs.sh 10 | 11 | deploy-m2-eigenlayer: 12 | ./crates/m2_contracts/anvil/deploy-eigenlayer.sh 13 | 14 | deploy-m2-avs: 15 | ./crates/m2_contracts/anvil/deploy-avs.sh 16 | 17 | .PHONY: dump-m2-state 18 | dump-m2-state: 19 | ./crates/m2_contracts/anvil/dump-state.sh 20 | 21 | .PHONY: dump-slashing-state 22 | dump-slashing-state: 23 | ./crates/operator_sets_contracts/anvil/dump-state.sh 24 | 25 | .PHONY: dump-state 26 | dump-state: copy-env dump-m2-state dump-slashing-state 27 | 28 | __TESTING__: ## 29 | 30 | .PHONY: start-anvil 31 | start-anvil: reset-anvil ## 32 | ./crates/operator_sets_contracts/anvil/start-anvil-chain-with-el-and-avs-deployed.sh 33 | 34 | .PHONY: reset-anvil 35 | reset-anvil: 36 | -docker stop anvil 37 | -docker rm anvil 38 | 39 | .PHONY: coverage 40 | coverage: 41 | cargo llvm-cov --lcov --output-path lcov.info --workspace --features fireblock-tests 42 | cargo llvm-cov report --html 43 | 44 | .PHONY: deps 45 | deps: 46 | @if ! command -v cargo-llvm-cov &> /dev/null; then \ 47 | cargo install cargo-llvm-cov; \ 48 | fi 49 | 50 | .PHONY: fireblocks-tests 51 | fireblocks-tests: 52 | cargo test --package eigen-client-fireblocks --features fireblock-tests 53 | 54 | .PHONY: lint 55 | lint: 56 | cargo fmt --all -- --check \ 57 | && cargo clippy --workspace --all-features --benches --examples --tests -- -D warnings 58 | 59 | .PHONY: docs 60 | docs: 61 | cargo doc --workspace --all-features --no-deps --open 62 | 63 | .PHONY: copy-env 64 | copy-env: 65 | @echo "Copying .env.example to .env..." 66 | cp ./crates/m2_contracts/.env.example ./crates/m2_contracts/.env 67 | cp ./crates/operator_sets_contracts/.env.example ./crates/operator_sets_contracts/.env 68 | 69 | __BINDINGS__: ## 70 | 71 | .PHONY: bindings_rewardsv2_host 72 | bindings_rewardsv2_host: 73 | @echo "Generating bindings..." 74 | ./scripts/generate_rewardsv2_bindings.sh 75 | cargo fmt --all 76 | @echo "Bindings generated" 77 | 78 | .PHONY: bindings_slashing_host 79 | bindings_slashing_host: 80 | @echo "Generating bindings..." 81 | ./scripts/generate_slashing_bindings.sh 82 | cargo fmt --all 83 | # Apply a fix for any compile issues 84 | git apply --allow-empty scripts/bindings.patch 85 | @echo "Bindings generated" 86 | 87 | .PHONY: bindings_host 88 | bindings_host: bindings_rewardsv2_host bindings_slashing_host 89 | .PHONY: rewardsv2-bindings 90 | rewardsv2-bindings: 91 | @echo "Starting Docker container..." 92 | @docker run --rm -v "$(PWD):/sdk" -w "/sdk" \ 93 | ghcr.io/foundry-rs/foundry:stable \ 94 | -c scripts/generate_rewardsv2_bindings.sh 95 | cargo fmt --all 96 | 97 | .PHONY: slashing-bindings 98 | slashing-bindings: 99 | @echo "Starting Docker container..." 100 | @docker run --rm -v "$(PWD):/sdk" -w "/sdk" \ 101 | ghcr.io/foundry-rs/foundry:stable \ 102 | -c scripts/generate_slashing_bindings.sh 103 | cargo fmt --all 104 | # Apply a fix for any compile issues 105 | git apply --allow-empty scripts/bindings.patch 106 | 107 | .PHONY: bindings 108 | bindings: rewardsv2-bindings slashing-bindings 109 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | The following checklist has all the steps needed to publish a new release in both GitHub and crates.io using `release-plz` and the GitHub UI. 4 | 5 | - [ ] Check the last CI run on the release branch succeeded. 6 | 7 | - [ ] Checkout the branch to release from and pull the latest changes: 8 | 9 | ```sh 10 | git checkout BRANCH && git pull origin BRANCH 11 | ``` 12 | 13 | - [ ] In your local clone, create a new branch: 14 | 15 | ```sh 16 | git checkout -b release-vX.X.X 17 | ``` 18 | 19 | - [ ] Bump the version in `Cargo.toml` (both `workspace` and `workspace.dependencies` fields). 20 | The new version number must follow [Semantic Versioning](https://semver.org/). 21 | You can use [`release-plz update`](https://release-plz.dev/docs/usage/update) to automatically do this while checking for semver violations. 22 | There's also [`cargo-semver-checks`](https://github.com/obi1kenobi/cargo-semver-checks) to validate the chosen version. 23 | 24 | - [ ] Verify the workspace compiles. 25 | This will also update the `Cargo.lock` with the new version 26 | 27 | ```sh 28 | cargo check --workspace --all-targets 29 | ``` 30 | 31 | - [ ] Cut the changelog. 32 | 33 | - [ ] Commit and push all changes and open a new PR. 34 | 35 | - [ ] Once it's reviewed and merged, wait for the [Release-plz workflow](./.github/workflows/release-plz.yml) to finish. 36 | Look into [the "Releasing from non-default branches" section](#releasing-from-non-default-branches-ie-not-dev-nor-main) if releasing from a branch that's not `main` or `dev`. 37 | 38 | - [ ] Check on crates.io that [the new version of the `eigensdk` crate](https://crates.io/crates/eigensdk/versions) was published. 39 | The other crates are required by this one, so if this one was published, the rest were too. 40 | 41 | - [ ] Go to [the releases page](https://github.com/Layr-Labs/eigensdk-rs/releases). A draft release should have been created by `release-plz`. 42 | 43 | - [ ] Adjust the release target or previous tag if needed. 44 | The release title can also be updated. 45 | 46 | - [ ] Merge the autogenerated changelog with the new version's section of the `CHANGELOG.md`. 47 | 48 | - [ ] Add any missing descriptions to the changelog items. It's recommended that every item that's not in "Documentation" or "Other Changes" has a description of what changed and instructions on how to migrate. You can encounter examples in previous changelog entries. 49 | 50 | - [ ] Commit the updated changelog and submit a PR. 51 | 52 | - [ ] Sync the release draft description with the changelog and save the draft. 53 | 54 | - [ ] Once the draft is reviewed and the PR merged, publish the release. 55 | 56 | ## Releasing from non-default branches (i.e. not `dev` nor `main`) 57 | 58 | > [!CAUTION] 59 | > Keep in mind commits will be lost once those branches are deleted, which reduces the auditability of the release. 60 | > 61 | > Because of this, we don't recommend releasing from non-default branches unless we expect them to be permanent, or the release is temporary, like for release candidates. 62 | 63 | The [Release-plz workflow](./.github/workflows/release-plz.yml) runs on each new commit on the `main` and `dev` branches. 64 | Pushing a commit with a new version on a branch not including those won't trigger it. 65 | 66 | For those cases, the workflow includes a `workflow_dispatch` trigger. 67 | This can be used to run it manually on any branch by going to the runs history for the workflow ([link](https://github.com/Layr-Labs/eigensdk-rs/actions/workflows/release-plz.yml)). 68 | There should be a "Run workflow" button which expands to a pop-up to specify the branch or tag to run the workflow on. 69 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | language = "en" 3 | multilingual = false 4 | src = "src" 5 | title = "eigenlayer book" 6 | description = "A book on eigen rust developer tooling" 7 | 8 | 9 | [build] 10 | build-dir = "target/book" 11 | 12 | -------------------------------------------------------------------------------- /book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Chapter 1](./chapter_1.md) 4 | -------------------------------------------------------------------------------- /book/src/chapter_1.md: -------------------------------------------------------------------------------- 1 | # Chapter 1 2 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.82" 2 | allow-unwrap-in-tests = true 3 | allow-expect-in-tests = true 4 | -------------------------------------------------------------------------------- /crates/chainio/README.md: -------------------------------------------------------------------------------- 1 | # ChainIo 2 | 3 | Read / write / subscribe to eigen core contract and avs contract. 4 | -------------------------------------------------------------------------------- /crates/chainio/clients/avsregistry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-client-avsregistry" 3 | description = "Eigen Layer AvsRegistry Sdk" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | async-trait.workspace = true 20 | num-bigint = "0.4.4" 21 | eigen-types.workspace = true 22 | eigen-crypto-bls.workspace = true 23 | ark-ff.workspace = true 24 | eigen-client-elcontracts.workspace = true 25 | eigen-common.workspace = true 26 | eigen-utils.workspace = true 27 | eigen-logging.workspace = true 28 | thiserror.workspace = true 29 | tracing.workspace = true 30 | 31 | [lints] 32 | workspace = true 33 | 34 | [dev-dependencies] 35 | # We don't use workspace due to: 36 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 37 | eigen-testing-utils = { path = "../../../../tests/testing-utils" } 38 | 39 | hex = "0.4.3" 40 | once_cell.workspace = true 41 | tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } 42 | futures-util.workspace = true 43 | -------------------------------------------------------------------------------- /crates/chainio/clients/avsregistry/README.md: -------------------------------------------------------------------------------- 1 | # AvsRegistry 2 | 3 | Reader , writer and subscribing methods to interact with avs registry contracts 4 | 5 | ## Example 6 | 7 | - [get_operator_from_id](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/get_operator_from_id.rs) 8 | - [get_operator_id](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/get_operator_id.rs) 9 | - [get_operator_stake_in_quorums_of_operator_at_current_block](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/get_operator_stake_in_quorums_of_operator_at_current_block.rs) 10 | - [get_operators_stake_in_quorums_at_block](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/get_operators_stake_in_quorums_at_block.rs) 11 | - [get_quorum_count](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/get_quorum_count.rs) 12 | - [query_existing_registered_operator_pub_keys](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-read/examples/query_existing_registered_operator_pub_keys.rs) 13 | -------------------------------------------------------------------------------- /crates/chainio/clients/avsregistry/src/fake_reader.rs: -------------------------------------------------------------------------------- 1 | use crate::{error::AvsRegistryError, reader::AvsRegistryReader}; 2 | use alloy::primitives::{aliases::U96, Address, Bytes, FixedBytes}; 3 | use async_trait::async_trait; 4 | use eigen_types::test::TestOperator; 5 | use eigen_utils::slashing::middleware::operatorstateretriever::OperatorStateRetriever; 6 | 7 | /// This struct is used to test AvsRegistryServiceChainCaller methods. 8 | #[derive(Debug)] 9 | pub struct FakeAvsRegistryReader { 10 | operator_address: Address, 11 | operator_id: FixedBytes<32>, 12 | } 13 | 14 | impl FakeAvsRegistryReader { 15 | /// Creates a FakeAvsRegistryReader 16 | /// 17 | /// # Arguments 18 | /// 19 | /// * `operator` - A TestOperator. 20 | /// * `operator_address` - The operator address. 21 | /// 22 | /// # Returns 23 | /// 24 | /// A FakeAvsRegistryReader 25 | pub fn new(operator: TestOperator, operator_address: Address) -> Self { 26 | Self { 27 | operator_address, 28 | operator_id: operator.operator_id, 29 | } 30 | } 31 | } 32 | 33 | #[async_trait] 34 | impl AvsRegistryReader for FakeAvsRegistryReader { 35 | async fn get_operators_stake_in_quorums_at_block( 36 | &self, 37 | _block_number: u64, 38 | _quorum_numbers: Bytes, 39 | ) -> Result>, AvsRegistryError> { 40 | Ok(vec![vec![OperatorStateRetriever::Operator { 41 | operator: self.operator_address, 42 | operatorId: self.operator_id, 43 | stake: U96::from(123), 44 | }]]) 45 | } 46 | 47 | async fn get_check_signatures_indices( 48 | &self, 49 | _reference_block_number: u64, 50 | _quorum_numbers: Vec, 51 | _non_signer_operator_ids: Vec>, 52 | ) -> Result { 53 | unimplemented!() 54 | } 55 | 56 | async fn get_operator_from_id( 57 | &self, 58 | _operator_id: [u8; 32], 59 | ) -> Result { 60 | Ok(self.operator_address) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/chainio/clients/avsregistry/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! AvsRegistry methods for reading, writing and subscribing purposes. 2 | 3 | #![doc( 4 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 5 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 6 | )] 7 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 8 | 9 | /// Reader module 10 | pub mod reader; 11 | 12 | /// Writer module 13 | pub mod writer; 14 | 15 | /// Avs registry error message 16 | pub mod error; 17 | 18 | /// Fake avs registry module 19 | pub mod fake_reader; 20 | -------------------------------------------------------------------------------- /crates/chainio/clients/elcontracts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-client-elcontracts" 3 | description = "Eigen Layer core contracts sdk" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | eigen-crypto-bls.workspace = true 20 | eigen-common.workspace = true 21 | eigen-logging.workspace = true 22 | eigen-types.workspace = true 23 | eigen-utils.workspace = true 24 | thiserror.workspace = true 25 | tracing.workspace = true 26 | 27 | [dev-dependencies] 28 | # We don't use workspace due to: 29 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 30 | eigen-testing-utils = { path = "../../../../tests/testing-utils" } 31 | 32 | once_cell.workspace = true 33 | tokio.workspace = true 34 | -------------------------------------------------------------------------------- /crates/chainio/clients/elcontracts/README.md: -------------------------------------------------------------------------------- 1 | # ElContracts 2 | 3 | Methods for core Eigen layer contracts 4 | 5 | ## Example -------------------------------------------------------------------------------- /crates/chainio/clients/elcontracts/src/error.rs: -------------------------------------------------------------------------------- 1 | use alloy::contract::Error as AlloyError; 2 | use alloy::providers::PendingTransactionError; 3 | use thiserror::Error; 4 | #[derive(Debug, Error)] 5 | pub enum ElContractsError { 6 | /// Get slasher address 7 | #[error("failed to get slasher address")] 8 | GetSlasher, 9 | 10 | /// Get strategy manager 11 | #[error("Failed to get strategy manager address")] 12 | GetStrategyManager, 13 | 14 | /// Get delegation approval digest hash 15 | #[error("Failed to get delegation approval digest hash")] 16 | GetDelegationApprovalDigestHash, 17 | 18 | /// Get Operator avs registration digest hash 19 | #[error("Failed to get operator avs registration digest hash")] 20 | GetOperatorAvsRegistrationDigestHash, 21 | 22 | /// Get Operator shares 23 | #[error("Failed to get oeprator shares")] 24 | GetOperatorShares, 25 | 26 | /// Is frozen 27 | #[error("failed to get operator frozen status ")] 28 | IsFrozen, 29 | 30 | /// service_manager_can_slash_operator_until_block 31 | #[error("Failed to get service manager slashing expiry")] 32 | ServiceManagerCanSlashOperatorExpiry, 33 | 34 | /// Get underlying token 35 | #[error("Failed to get underlying token")] 36 | GetUnderlyingToken, 37 | 38 | /// is operator or not 39 | #[error("Is operator or not ")] 40 | IsOperator, 41 | 42 | /// registering as operator 43 | #[error("Failed to register as a operator")] 44 | RegisterAsOperator, 45 | 46 | /// modify operator details 47 | #[error("modify operator details")] 48 | ModifyOperatorDetails, 49 | 50 | /// get strategy and underlying erc20 token 51 | #[error("get strategy and underlying erc20 token")] 52 | GetStrategyAndUnderlyingERC20Token, 53 | 54 | /// approve to underlying token 55 | #[error("Failed to call approve in underlying token contract")] 56 | ApproveCallToUnderlyingToken, 57 | 58 | /// deposit into strategy call 59 | #[error("Failed to deposit into strategy")] 60 | DepositIntoStrategy, 61 | 62 | /// update metadata uri 63 | #[error("Failed to update metadata uri")] 64 | UpdateMetadataUri, 65 | 66 | #[error("Alloy contract error: {0}")] 67 | AlloyContractError(#[from] AlloyError), 68 | 69 | #[error("Alloy pending Transaction error {0}")] 70 | AlloyPendingTransactionError(#[from] PendingTransactionError), 71 | 72 | #[error("Allocation delay not set for operator")] 73 | AllocationDelayNotSet, 74 | 75 | #[error("No slashable shares found for operator")] 76 | NoSlashableSharesFound, 77 | 78 | #[error("BLS key pair invalid")] 79 | BLSKeyPairInvalid, 80 | 81 | #[error("Permission Controller is not set")] 82 | MissingParameter, 83 | 84 | #[error("StakerOptOutWindowBlocks is not set")] 85 | StakerOptOutWindowBlocksNotSet, 86 | 87 | #[error("Invalid signature")] 88 | InvalidSignature, 89 | } 90 | -------------------------------------------------------------------------------- /crates/chainio/clients/elcontracts/src/lib.rs: -------------------------------------------------------------------------------- 1 | //!Convenience methods for AVSs developers to call Eigen layer contract methods 2 | 3 | #![doc( 4 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 5 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 6 | )] 7 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 8 | 9 | pub mod error; 10 | pub mod reader; 11 | pub mod writer; 12 | -------------------------------------------------------------------------------- /crates/chainio/clients/eth/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-client-eth" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "eigen layer instrumented client " 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | alloy.workspace = true 18 | async-trait.workspace = true 19 | eigen-logging.workspace = true 20 | eigen-metrics-collectors-rpc-calls.workspace = true 21 | hex.workspace = true 22 | thiserror.workspace = true 23 | url.workspace = true 24 | 25 | [dev-dependencies] 26 | # We don't use workspace due to: 27 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 28 | eigen-testing-utils = { path = "../../../../tests/testing-utils" } 29 | eigen-common = { path = "../../../common" } 30 | 31 | once_cell.workspace = true 32 | serial_test.workspace = true 33 | tokio.workspace = true 34 | -------------------------------------------------------------------------------- /crates/chainio/clients/eth/src/client.rs: -------------------------------------------------------------------------------- 1 | use alloy::eips::BlockNumberOrTag; 2 | use alloy::primitives::BlockNumber; 3 | use alloy::rpc::types::eth::Block; 4 | 5 | #[async_trait::async_trait] 6 | pub trait BackendClient { 7 | type Error; 8 | 9 | /// Get the latest block number. 10 | /// 11 | /// # Returns 12 | /// 13 | /// The latest block number. 14 | async fn block_number(&self) -> Result; 15 | 16 | /// Get the block hash given its block number. 17 | /// 18 | /// # Arguments 19 | /// 20 | /// * `number` - The block number. 21 | /// 22 | /// # Returns 23 | /// 24 | /// The block having that number. 25 | async fn block_by_number(&self, number: BlockNumberOrTag) 26 | -> Result, Self::Error>; 27 | } 28 | -------------------------------------------------------------------------------- /crates/chainio/clients/eth/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | pub mod client; 7 | pub mod instrumented_client; 8 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-client-fireblocks" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "fireblocks support for eigenlayer" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | #alloy 18 | alloy.workspace = true 19 | chrono = "0.4" 20 | 21 | #eigen 22 | eigen-common.workspace = true 23 | hex = "0.4" 24 | jsonwebtoken = "7" 25 | mime = "0.3.17" 26 | once_cell.workspace = true 27 | reqwest = "0.11" 28 | serde.workspace = true 29 | serde_json = "1.0.120" 30 | sha2 = "0.10" 31 | 32 | #error 33 | thiserror.workspace = true 34 | uuid = { version = "1", features = ["v4"] } 35 | 36 | [dev-dependencies] 37 | tokio.workspace = true 38 | 39 | [features] 40 | fireblock-tests = [] 41 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/error.rs: -------------------------------------------------------------------------------- 1 | use alloy::contract::Error as AlloyError; 2 | use jsonwebtoken::errors::Error; 3 | use reqwest::header::InvalidHeaderValue; 4 | use reqwest::Error as ReqwestError; 5 | use serde_json::Error as SerdeErr; 6 | use std::fmt; 7 | use thiserror::Error; 8 | 9 | /// Error returned by AvsRegistry 10 | #[derive(Debug, Error)] 11 | pub enum FireBlockError { 12 | /// Could not sign the jwt payload 13 | #[error("Failed to sign the jwt payload")] 14 | JsonWebTokenError(Error), 15 | 16 | /// Alloy Contract error 17 | #[error("Alloy error{0}")] 18 | AlloyContractError(#[from] AlloyError), 19 | 20 | #[error("Other Error {0}")] 21 | OtherError(String), 22 | 23 | /// Reqwest error 24 | #[error("Reqwest error {0}")] 25 | ReqwestError(#[from] ReqwestError), 26 | 27 | /// Invalid header value error 28 | #[error("Invalid header value error {0}")] 29 | InvalidHeaderValueError(#[from] InvalidHeaderValue), 30 | 31 | /// Serde error 32 | #[error("Serde json error {0}")] 33 | SerdeError(#[from] SerdeErr), 34 | 35 | /// Serde error 36 | #[error("Chain Id not supported{0} . Create an issue at https://github.com/Layr-Labs/eigensdk-rs/issues/new")] 37 | AssetIDError(String), 38 | 39 | /// Account not found in whitelisted accounts 40 | #[error("Account not found in whitelisted accounts {0}")] 41 | AccountNotFoundError(String), 42 | 43 | /// Contract not found in whitelisted contract 44 | #[error("Contract {0} not found in whitelisted contract")] 45 | ContractNotFound(String), 46 | 47 | /// Transaction failed or rejected or Cancelled or Blocked 48 | #[error("Transaction Failed with Status {0} , tx_id {1}")] 49 | TransactionFailed(String, String), 50 | 51 | /// To be broadcasted transactions 52 | #[error("Transaction to be broadcasted with Status {0} , tx_id {1}")] 53 | NotBroadcasted(String, String), 54 | 55 | /// Receipt not available yet 56 | #[error("Transaction not available yet with Status {0} , tx_id {1} ")] 57 | ReceiptNotYetAvailable(String, String), 58 | 59 | /// Transaction receipt not found 60 | #[error("Transactin receipt not found with tx_id {0}")] 61 | TransactionReceiptNotFound(String), 62 | } 63 | 64 | impl FireBlockError { 65 | pub fn from(error: E) -> FireBlockError { 66 | FireBlockError::OtherError(error.to_string()) 67 | } 68 | } 69 | 70 | impl From<&str> for FireBlockError { 71 | fn from(err: &str) -> FireBlockError { 72 | FireBlockError::OtherError(err.to_string()) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/get_asset_addresses.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | client::{AssetID, Client}, 3 | error::FireBlockError, 4 | }; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | #[derive(Serialize, Deserialize, Debug)] 8 | #[serde(rename_all = "camelCase")] 9 | pub struct AssetAddress { 10 | asset_id: AssetID, 11 | address: String, 12 | tag: String, 13 | description: String, 14 | #[serde(rename = "type")] 15 | type_field: String, 16 | legacy_address: String, 17 | enterprise_address: String, 18 | user_defined: bool, 19 | bip_44_address_index: u32, 20 | } 21 | 22 | /// Addresses Response struct that contains an array of [`AssetAddress`] 23 | #[derive(Debug, Serialize, Deserialize)] 24 | pub struct AddressesResponse { 25 | addresses: Vec, 26 | } 27 | 28 | /// Get Asset Addresses trait for "/v1/vault/accounts/{vault_id}/{asset_id}/addresses_paginated" requests 29 | #[allow(async_fn_in_trait)] 30 | pub trait GetAssetAddresses { 31 | async fn get_asset_addresses( 32 | &self, 33 | vault_id: String, 34 | asset_id: AssetID, 35 | ) -> Result; 36 | } 37 | 38 | impl GetAssetAddresses for Client { 39 | async fn get_asset_addresses( 40 | &self, 41 | vault_id: String, 42 | asset_id: AssetID, 43 | ) -> Result { 44 | let asset_addresses = self 45 | .get_request(&format!( 46 | "/v1/vault/accounts/{}/{}/addresses_paginated", 47 | vault_id, asset_id 48 | )) 49 | .await?; 50 | 51 | serde_json::from_str(&asset_addresses).map_err(FireBlockError::SerdeError) 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | 58 | #[cfg(feature = "fireblock-tests")] 59 | use super::*; 60 | #[cfg(feature = "fireblock-tests")] 61 | use std::env; 62 | 63 | #[tokio::test] 64 | #[cfg(feature = "fireblock-tests")] 65 | async fn test_asset_addresses() { 66 | let api_key = env::var("FIREBLOCKS_API_KEY").expect("FIREBLOCKS_API_KEY not set"); 67 | let private_key_path = 68 | env::var("FIREBLOCKS_PRIVATE_KEY_PATH").expect("FIREBLOCKS_PRIVATE_KEY_PATH not set"); 69 | let api_url = env::var("FIREBLOCKS_API_URL").expect("FIREBLOCKS_API_URL not set"); 70 | let private_key = 71 | std::fs::read_to_string(private_key_path).expect("Failed to read private key file"); 72 | let vault_id = "13"; 73 | let asset_id: AssetID = AssetID::EthTest5; 74 | let client = Client::new( 75 | api_key.to_string(), 76 | private_key.to_string(), 77 | api_url.clone(), 78 | ); 79 | 80 | let _ = client 81 | .get_asset_addresses(vault_id.to_string(), asset_id) 82 | .await 83 | .unwrap(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/get_transaction.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | client::{AssetID, Client}, 3 | contract_call::{Account, TransactionOperation}, 4 | error::FireBlockError, 5 | status::Status, 6 | }; 7 | use serde::{Deserialize, Serialize}; 8 | 9 | /// Amount Info 10 | #[allow(dead_code)] 11 | #[derive(Serialize, Deserialize, Debug)] 12 | struct AmountInfo { 13 | amount: String, 14 | #[serde(rename = "requestedAmount")] 15 | requested_amount: String, 16 | #[serde(rename = "netAmount")] 17 | net_amount: String, 18 | #[serde(rename = "amountUSD")] 19 | amount_usdc: String, 20 | } 21 | 22 | /// Fee Info 23 | #[allow(dead_code)] 24 | #[derive(Serialize, Deserialize, Debug)] 25 | #[serde(rename_all = "camelCase")] 26 | struct FeeInfo { 27 | network_fee: String, 28 | // Service_fee: String, 29 | gas_price: String, 30 | } 31 | 32 | /// Extra Parameters 33 | #[allow(dead_code)] 34 | #[derive(Serialize, Deserialize, Debug)] 35 | struct ExtraParameters { 36 | #[serde(rename = "contractCallData")] 37 | contract_calldata: String, 38 | } 39 | 40 | #[allow(dead_code)] 41 | #[derive(Serialize, Deserialize, Debug)] 42 | struct BlockInfo { 43 | #[serde(rename = "blockHeight")] 44 | block_height: String, 45 | #[serde(rename = "blockHash")] 46 | block_hash: String, 47 | } 48 | 49 | #[allow(dead_code)] 50 | #[derive(Serialize, Deserialize, Debug)] 51 | #[serde(rename_all = "camelCase")] 52 | pub struct Transaction { 53 | id: String, 54 | status: Status, 55 | sub_status: String, 56 | tx_hash: String, 57 | operation: TransactionOperation, 58 | created_at: i64, 59 | last_updated: i64, 60 | asset_id: AssetID, 61 | source: Account, 62 | source_address: String, 63 | destination: Account, 64 | destination_address: String, 65 | destination_address_description: String, 66 | destination_tag: String, 67 | amount_info: AmountInfo, 68 | fee_info: FeeInfo, 69 | fee_currency: String, 70 | extra_parameters: Option, 71 | num_of_confirmations: i64, 72 | block_info: BlockInfo, 73 | } 74 | 75 | impl Transaction { 76 | pub fn status(&self) -> Status { 77 | self.status.clone() 78 | } 79 | 80 | pub fn tx_hash(&self) -> String { 81 | self.tx_hash.clone() 82 | } 83 | } 84 | 85 | /// Get Transaction trait for "/v1/transactions/tx_id" get requests 86 | pub trait GetTransaction { 87 | async fn get_transaction(&self, tx_id: String) -> Result; 88 | } 89 | 90 | impl GetTransaction for Client { 91 | async fn get_transaction(&self, tx_id: String) -> Result { 92 | let transaction = self 93 | .get_request(&format!("/v1/transactions/{}", tx_id)) 94 | .await?; 95 | 96 | serde_json::from_str(&transaction).map_err(FireBlockError::SerdeError) 97 | } 98 | } 99 | 100 | #[cfg(test)] 101 | mod tests { 102 | 103 | #[cfg(feature = "fireblock-tests")] 104 | use super::*; 105 | #[cfg(feature = "fireblock-tests")] 106 | use std::env; 107 | 108 | #[tokio::test] 109 | #[cfg(feature = "fireblock-tests")] 110 | async fn test_get_transaction() { 111 | let api_key = env::var("FIREBLOCKS_API_KEY").expect("FIREBLOCKS_API_KEY not set"); 112 | let private_key_path = 113 | env::var("FIREBLOCKS_PRIVATE_KEY_PATH").expect("FIREBLOCKS_PRIVATE_KEY_PATH not set"); 114 | let api_url = env::var("FIREBLOCKS_API_URL").expect("FIREBLOCKS_API_URL not set"); 115 | let private_key = 116 | std::fs::read_to_string(private_key_path).expect("Failed to read private key file"); 117 | let tx_id = "4f182a65-07a0-46aa-b8aa-d047ab94f0aa"; 118 | 119 | let client = Client::new( 120 | api_key.to_string(), 121 | private_key.to_string(), 122 | api_url.clone(), 123 | ); 124 | 125 | let _ = client.get_transaction(tx_id.to_string()).await.unwrap(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/list_contracts.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | client::{AssetID, Client}, 3 | error::FireBlockError, 4 | status::Status, 5 | }; 6 | use serde::{Deserialize, Serialize}; 7 | 8 | #[derive(Debug, Serialize, Deserialize, Clone)] 9 | #[serde(rename_all = "camelCase")] 10 | pub struct Assets { 11 | pub id: Option, 12 | balance: Option, 13 | pub status: Option, 14 | pub address: Option, 15 | tag: Option, 16 | locked_amount: Option, 17 | activation_time: Option, 18 | } 19 | 20 | #[derive(Debug, Serialize, Deserialize, Clone, Default)] 21 | pub struct WhitelistedContract { 22 | id: String, 23 | name: String, 24 | #[serde(default)] 25 | assets: Vec, 26 | } 27 | 28 | impl WhitelistedContract { 29 | pub fn assets(&self) -> Vec { 30 | self.assets.clone() 31 | } 32 | 33 | pub fn id(&self) -> String { 34 | self.id.clone() 35 | } 36 | } 37 | 38 | #[derive(Debug, Serialize, Deserialize)] 39 | pub struct WhitelistedContractResponse { 40 | contracts: Vec, 41 | } 42 | 43 | impl WhitelistedContractResponse { 44 | pub fn contracts(&self) -> Vec { 45 | self.contracts.clone() 46 | } 47 | } 48 | 49 | /// Get List Contracts trait for "/v1/contracts" requests 50 | pub trait ListContracts { 51 | async fn list_contracts(&self) -> Result; 52 | } 53 | 54 | impl ListContracts for Client { 55 | async fn list_contracts(&self) -> Result { 56 | let list_contracts_object = self.get_request("/v1/contracts").await?; 57 | 58 | if list_contracts_object.trim() == "[]" { 59 | return Ok(WhitelistedContractResponse { 60 | contracts: Vec::new(), 61 | }); 62 | } 63 | 64 | let contracts: Vec = 65 | serde_json::from_str(&list_contracts_object).map_err(FireBlockError::SerdeError)?; 66 | 67 | Ok(WhitelistedContractResponse { contracts }) 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | 74 | #[cfg(feature = "fireblock-tests")] 75 | use super::*; 76 | #[cfg(feature = "fireblock-tests")] 77 | use std::env; 78 | 79 | #[tokio::test] 80 | #[cfg(feature = "fireblock-tests")] 81 | async fn test_list_contracts() { 82 | let api_key = env::var("FIREBLOCKS_API_KEY").expect("FIREBLOCKS_API_KEY not set"); 83 | let private_key_path = 84 | env::var("FIREBLOCKS_PRIVATE_KEY_PATH").expect("FIREBLOCKS_PRIVATE_KEY_PATH not set"); 85 | let api_url = env::var("FIREBLOCKS_API_URL").expect("FIREBLOCKS_API_URL not set"); 86 | let private_key = std::fs::read_to_string(private_key_path.clone()) 87 | .expect("Failed to read private key file"); 88 | let client = Client::new( 89 | api_key.to_string(), 90 | private_key.to_string(), 91 | api_url.clone(), 92 | ); 93 | 94 | let _ = client.list_contracts().await.unwrap(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/list_external_accounts.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::{client::Client, error::FireBlockError, list_contracts::Assets}; 4 | 5 | #[derive(Debug, Serialize, Deserialize, Default, Clone)] 6 | pub struct WhitelistedAccount { 7 | id: String, 8 | 9 | name: String, 10 | 11 | pub assets: Vec, 12 | } 13 | impl WhitelistedAccount { 14 | pub fn id(&self) -> String { 15 | self.id.clone() 16 | } 17 | } 18 | 19 | #[allow(async_fn_in_trait)] 20 | /// Get List External Accounts trait for "/v1/external_wallets" requests 21 | pub trait ListExternalAccounts { 22 | async fn list_external_accounts(&self) -> Result, FireBlockError>; 23 | } 24 | 25 | impl ListExternalAccounts for Client { 26 | async fn list_external_accounts(&self) -> Result, FireBlockError> { 27 | let list_external_accounts = self.get_request("/v1/external_wallets").await?; 28 | 29 | if list_external_accounts.trim() == "[]" { 30 | let default_accounts = vec![WhitelistedAccount::default()]; 31 | return Ok(default_accounts); 32 | } 33 | serde_json::from_str(&list_external_accounts).map_err(FireBlockError::SerdeError) 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | 40 | #[cfg(feature = "fireblock-tests")] 41 | use super::*; 42 | #[cfg(feature = "fireblock-tests")] 43 | use std::env; 44 | 45 | #[tokio::test] 46 | #[cfg(feature = "fireblock-tests")] 47 | async fn test_list_external_accounts() { 48 | let api_key = env::var("FIREBLOCKS_API_KEY").expect("FIREBLOCKS_API_KEY not set"); 49 | let private_key_path = 50 | env::var("FIREBLOCKS_PRIVATE_KEY_PATH").expect("FIREBLOCKS_PRIVATE_KEY_PATH not set"); 51 | let api_url = env::var("FIREBLOCKS_API_URL").expect("FIREBLOCKS_API_URL not set"); 52 | let private_key = 53 | std::fs::read_to_string(private_key_path).expect("Failed to read private key file"); 54 | let client = Client::new( 55 | api_key.to_string(), 56 | private_key.to_string(), 57 | api_url.clone(), 58 | ); 59 | 60 | let _ = client.list_external_accounts().await.unwrap(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/list_vault_accounts.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | client::{AssetID, Client}, 3 | error::FireBlockError, 4 | }; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | #[derive(Serialize, Deserialize, Debug, Clone)] 8 | #[serde(rename_all = "camelCase")] 9 | struct Asset { 10 | id: AssetID, 11 | total: String, 12 | balance: String, 13 | available: String, 14 | locked_amount: Option, 15 | pending: Option, 16 | frozen: Option, 17 | staked: Option, 18 | block_height: Option, 19 | #[serde(default)] 20 | block_hash: Option, 21 | } 22 | 23 | #[allow(unused)] 24 | #[derive(Debug, Serialize, Deserialize, Clone)] 25 | pub struct VaultAccount { 26 | id: String, 27 | name: String, 28 | #[serde(rename = "hiddenOnUI")] 29 | hidden_on_ui: bool, 30 | #[serde(rename = "autoFuel")] 31 | auto_fuel: bool, 32 | assets: Vec, 33 | } 34 | 35 | impl VaultAccount { 36 | pub fn name(&self) -> String { 37 | self.name.clone() 38 | } 39 | } 40 | 41 | #[derive(Debug, Serialize, Deserialize)] 42 | pub struct VaultAccountResponse { 43 | #[serde(rename = "accounts")] 44 | vault_accounts: Vec, 45 | paging: Paging, 46 | } 47 | 48 | impl VaultAccountResponse { 49 | pub fn vault_accounts(&self) -> Vec { 50 | self.vault_accounts.clone() 51 | } 52 | } 53 | 54 | #[derive(Debug, Serialize, Deserialize)] 55 | pub struct Paging {} 56 | 57 | /// Get List Vault Accounts trait for "/v1/vault/accounts_paged" get requests 58 | pub trait ListVaultAccounts { 59 | async fn list_vault_accounts(&self) -> Result; 60 | } 61 | 62 | impl ListVaultAccounts for Client { 63 | async fn list_vault_accounts(&self) -> Result { 64 | let list_vault_accounts = self.get_request("/v1/vault/accounts_paged").await?; 65 | serde_json::from_str(&list_vault_accounts).map_err(FireBlockError::SerdeError) 66 | } 67 | } 68 | 69 | #[cfg(test)] 70 | mod tests { 71 | 72 | #[cfg(feature = "fireblock-tests")] 73 | use super::*; 74 | #[cfg(feature = "fireblock-tests")] 75 | use std::env; 76 | 77 | #[tokio::test] 78 | #[cfg(feature = "fireblock-tests")] 79 | async fn test_list_vault_accounts() { 80 | let api_key = env::var("FIREBLOCKS_API_KEY").expect("FIREBLOCKS_API_KEY not set"); 81 | let private_key_path = 82 | env::var("FIREBLOCKS_PRIVATE_KEY_PATH").expect("FIREBLOCKS_PRIVATE_KEY_PATH not set"); 83 | let api_url = env::var("FIREBLOCKS_API_URL").expect("FIREBLOCKS_API_URL not set"); 84 | let private_key = 85 | std::fs::read_to_string(private_key_path).expect("Failed to read private key file"); 86 | let client = Client::new( 87 | api_key.to_string(), 88 | private_key.to_string(), 89 | api_url.clone(), 90 | ); 91 | 92 | let _ = client.list_vault_accounts().await.unwrap(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/status.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug, Clone)] 4 | pub enum Status { 5 | #[serde(rename = "APPROVED")] 6 | Approved, 7 | #[serde(rename = "SUBMITTED")] 8 | Submitted, 9 | #[serde(rename = "PENDING_AML_SCREENING")] 10 | PendingScreening, 11 | #[serde(rename = "PENDING_AUTHORIZATION")] 12 | PendingAuthorization, 13 | #[serde(rename = "QUEUED")] 14 | Queued, 15 | #[serde(rename = "PENDING_SIGNATURE")] 16 | PendingSignature, 17 | #[serde(rename = "PENDING_3RD_PARTY_MANUAL_APPROVAL")] 18 | PendingEmailApproval, 19 | #[serde(rename = "PENDING_3RD_PARTY")] 20 | Pending3rdParity, 21 | #[serde(rename = "BROADCASTING")] 22 | Broadcasting, 23 | #[serde(rename = "CONFIRMING")] 24 | Confirming, 25 | #[serde(rename = "COMPLETED")] 26 | Completed, 27 | #[serde(rename = "CANCELLING")] 28 | Cancelling, 29 | #[serde(rename = "CANCELLED")] 30 | Cancelled, 31 | #[serde(rename = "BLOCKED")] 32 | Blocked, 33 | #[serde(rename = "REJECTED")] 34 | Rejected, 35 | #[serde(rename = "FAILED")] 36 | Failed, 37 | } 38 | 39 | impl Status { 40 | pub fn as_str(&self) -> &'static str { 41 | match self { 42 | Status::Approved => "APPROVED", 43 | Status::Submitted => "SUBMITTED", 44 | Status::PendingScreening => "PENDING_AML_SCREENING", 45 | Status::PendingAuthorization => "PENDING_AUTHORIZATION", 46 | Status::Queued => "QUEUED", 47 | Status::PendingSignature => "PENDING_SIGNATURE", 48 | Status::PendingEmailApproval => "PENDING_3RD_PARTY_MANUAL_APPROVAL", 49 | Status::Pending3rdParity => "PENDING_3RD_PARTY", 50 | Status::Broadcasting => "BROADCASTING", 51 | Status::Confirming => "CONFIRMING", 52 | Status::Completed => "COMPLETED", 53 | Status::Cancelling => "CANCELLING", 54 | Status::Cancelled => "CANCELLED", 55 | Status::Blocked => "BLOCKED", 56 | Status::Rejected => "REJECTED", 57 | Status::Failed => "FAILED", 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crates/chainio/clients/fireblocks/src/transaction.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::contract_call::{ 4 | DestinationTransferPeerPath, ExtraParameters, TransactionOperation, TransferPeerPath, 5 | }; 6 | 7 | #[derive(Debug, Serialize, Deserialize, Clone)] 8 | #[serde(rename_all = "camelCase")] 9 | pub struct TransactionRequest { 10 | #[serde(rename = "assetId")] 11 | pub asset_id: String, 12 | pub operation: TransactionOperation, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub external_tx_id: Option, 15 | pub source: TransferPeerPath, 16 | #[serde(skip_serializing_if = "Option::is_none")] 17 | pub destination: Option, 18 | pub amount: String, 19 | pub extra_parameters: Option, 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub gas_price: Option, 22 | #[serde(skip_serializing_if = "Option::is_none")] 23 | pub gas_limit: Option, 24 | #[serde(skip_serializing_if = "Option::is_none")] 25 | replace_tx_by_hash: Option, 26 | #[serde(skip_serializing_if = "Option::is_none")] 27 | pub note: Option, 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | #[serde(rename = "maxFee")] 30 | pub max_fee: Option, 31 | #[serde(skip_serializing_if = "Option::is_none")] 32 | #[serde(rename = "priorityFee")] 33 | priority_fee: Option, 34 | } 35 | 36 | impl TransactionRequest { 37 | #[allow(clippy::too_many_arguments)] 38 | pub fn new( 39 | operation: TransactionOperation, 40 | external_tx_id: Option, 41 | asset_id: String, 42 | source: TransferPeerPath, 43 | destination: Option, 44 | amount: String, 45 | extra_parameters: Option, 46 | replace_tx_by_hash: Option, 47 | gas_price: Option, 48 | gas_limit: Option, 49 | note: Option, 50 | max_fee: Option, 51 | priority_fee: Option, 52 | ) -> Self { 53 | Self { 54 | operation, 55 | external_tx_id, 56 | asset_id, 57 | source, 58 | destination, 59 | amount, 60 | extra_parameters, 61 | replace_tx_by_hash, 62 | gas_price, 63 | gas_limit, 64 | note, 65 | max_fee, 66 | priority_fee, 67 | } 68 | } 69 | } 70 | 71 | #[derive(Debug, Serialize, Deserialize)] 72 | pub struct TransactionResponse { 73 | id: String, 74 | status: String, 75 | } 76 | -------------------------------------------------------------------------------- /crates/common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-common" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "Common functions for EigenLayer SDK" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | alloy.workspace = true 18 | url.workspace = true 19 | -------------------------------------------------------------------------------- /crates/common/src/lib.rs: -------------------------------------------------------------------------------- 1 | use alloy::providers::{ 2 | fillers::{ 3 | BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller, 4 | }, 5 | network::EthereumWallet, 6 | Identity, ProviderBuilder, RootProvider, WsConnect, 7 | }; 8 | use alloy::signers::local::PrivateKeySigner; 9 | use alloy::transports::{RpcError, TransportErrorKind}; 10 | use std::str::FromStr; 11 | use url::Url; 12 | 13 | pub type SdkProvider = FillProvider< 14 | JoinFill< 15 | Identity, 16 | JoinFill>>, 17 | >, 18 | RootProvider, 19 | >; 20 | 21 | pub type SdkSigner = FillProvider< 22 | JoinFill< 23 | JoinFill< 24 | Identity, 25 | JoinFill>>, 26 | >, 27 | WalletFiller, 28 | >, 29 | RootProvider, 30 | >; 31 | 32 | pub fn get_signer(key: &str, rpc_url: &str) -> SdkSigner { 33 | let signer = PrivateKeySigner::from_str(key).expect("wrong key "); 34 | let wallet = EthereumWallet::from(signer); 35 | let url = Url::parse(rpc_url).expect("Wrong rpc url"); 36 | ProviderBuilder::new().wallet(wallet.clone()).on_http(url) 37 | } 38 | 39 | pub fn get_provider(rpc_url: &str) -> SdkProvider { 40 | let url = Url::parse(rpc_url).expect("Wrong rpc url"); 41 | ProviderBuilder::new().on_http(url) 42 | } 43 | 44 | #[allow(clippy::type_complexity)] 45 | pub async fn get_ws_provider(rpc_url: &str) -> Result> { 46 | let ws = WsConnect::new(rpc_url); 47 | ProviderBuilder::new() 48 | .disable_recommended_fillers() 49 | .on_ws(ws) 50 | .await 51 | } 52 | 53 | /// Emitted when a new pubkey is registered 54 | pub const NEW_PUBKEY_REGISTRATION_EVENT: &str = 55 | "NewPubkeyRegistration(address,(uint256,uint256),(uint256[2],uint256[2]))"; 56 | 57 | pub const OPERATOR_SOCKET_UPDATE: &str = "OperatorSocketUpdate(bytes32,string)"; 58 | -------------------------------------------------------------------------------- /crates/crypto/bls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-crypto-bls" 3 | description = "Eigen layer bls utilities" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | ark-bn254.workspace = true 19 | ark-ff.workspace = true 20 | ark-serialize.workspace = true 21 | thiserror.workspace = true 22 | ark-ec.workspace = true 23 | alloy.workspace = true 24 | ark-std = { version = "0.4.0", default-features = false } 25 | serde.workspace = true 26 | eigen-crypto-bn254.workspace = true 27 | eigen-utils.workspace = true 28 | 29 | [dev-dependencies] 30 | # We don't use workspace due to: 31 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 32 | eigen-testing-utils = { path = "../../../tests/testing-utils" } 33 | 34 | rand = "0.8.4" 35 | tokio = { workspace = true, features = ["full"] } 36 | serde_json.workspace = true 37 | -------------------------------------------------------------------------------- /crates/crypto/bls/README.md: -------------------------------------------------------------------------------- 1 | # Eigen Layer Bls 2 | 3 | This crate contains the following utilities: 4 | 5 | - New bls key pair generation 6 | - Get Public Key on G1 and G2 7 | - Helper functions to convert Arkworks parameters to alloy compatible . Ex: 8 | - convert_to_g1_point : Converts G1Affine to Alloy compatible G1Point 9 | - convert_to_g2_point : Converts G2Affine to Alloy compatible G2Point 10 | - alloy_g1_point_to_g1_affine: Converts Alloy G1Point to G1Affine 11 | - Signing a message using the keypair 12 | 13 | ## Example 14 | 15 | - [Registering an operator](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/avsregistry-write/examples/register_operator_in_quorum_with_avs_registry_coordinator.rs) 16 | -------------------------------------------------------------------------------- /crates/crypto/bls/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum BlsError { 5 | /// Invalid Bls Public Key 6 | #[error("Invalid bls public key")] 7 | InvalidPublicKey, 8 | 9 | /// Invalid Bls Private Key 10 | #[error("Invalid bls private key")] 11 | InvalidBlsPrivateKey, 12 | 13 | /// Invalid G1Affine 14 | #[error("Points missing in G1Affine")] 15 | InvalidG1Affine, 16 | 17 | /// Invalid G2Affine 18 | #[error("Points missing in G2Affine")] 19 | InvalidG2Affine, 20 | } 21 | -------------------------------------------------------------------------------- /crates/crypto/bn254/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-crypto-bn254" 3 | description = "Eigen layer SDK bn254 utilities" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | ark-bn254.workspace = true 19 | ark-ec.workspace = true 20 | ark-ff.workspace = true 21 | rust-bls-bn254.workspace = true 22 | 23 | 24 | [dev-dependencies] 25 | rand.workspace = true 26 | tokio = { workspace = true, features = ["full"] } 27 | -------------------------------------------------------------------------------- /crates/crypto/bn254/README.md: -------------------------------------------------------------------------------- 1 | # Eigen SDk Bn254 utilities 2 | -------------------------------------------------------------------------------- /crates/crypto/bn254/src/error.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/crypto/bn254/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | pub mod error; 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /crates/crypto/bn254/src/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_bn254::{Fq, G1Affine, G1Projective, G2Affine}; 2 | use ark_ec::{AffineRepr, CurveGroup}; 3 | use ark_ff::{ 4 | fields::{Field, PrimeField}, 5 | One, 6 | }; 7 | use rust_bls_bn254::pairing; 8 | 9 | /// MapToCurve implements the simple hash-and-check (also sometimes try-and-increment) algorithm 10 | /// see 11 | /// Note that this function needs to be the same as the one used in the contract: 12 | /// 13 | /// we don't use the newer constant time hash-to-curve algorithms as they are gas-expensive to compute onchain 14 | pub fn map_to_curve(bytes: &[u8; 32]) -> G1Affine { 15 | let one = Fq::one(); 16 | let three = Fq::from(3u64); 17 | 18 | let mut x = Fq::from_be_bytes_mod_order(bytes); 19 | 20 | loop { 21 | // y = x^3 + 3 22 | let mut y = x; 23 | y.square_in_place(); 24 | y *= x; 25 | y += three; 26 | 27 | // Check if y is a quadratic residue (i.e., has a square root in the field) 28 | if let Some(y) = y.sqrt() { 29 | return G1Projective::new(x, y, Fq::one()).into_affine(); 30 | } else { 31 | // x = x + 1 32 | x += one; 33 | } 34 | } 35 | } 36 | 37 | /// Verifies message on G2 38 | pub fn verify_message(public_key: G2Affine, message: &[u8; 32], signature: G1Affine) -> bool { 39 | if !signature.is_in_correct_subgroup_assuming_on_curve() || !signature.is_on_curve() { 40 | return false; 41 | } 42 | 43 | let q = map_to_curve(message); 44 | let c1 = pairing(public_key, q); 45 | let c2 = pairing(G2Affine::generator(), signature); 46 | c1 == c2 47 | } 48 | -------------------------------------------------------------------------------- /crates/crypto/ecdsa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-crypto-ecdsa" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | 8 | # docs.rs-specific configuration 9 | # see https://docs.rs/about/metadata 10 | [package.metadata.docs.rs] 11 | all-features = true 12 | rustdoc-args = ["--cfg", "docsrs"] 13 | 14 | [dependencies] 15 | eth-keystore = "0.5.0" 16 | -------------------------------------------------------------------------------- /crates/crypto/ecdsa/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | -------------------------------------------------------------------------------- /crates/eigen-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-cli" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "eigen layer cli" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | alloy.workspace = true 18 | ark-ec.workspace = true 19 | ark-ff.workspace = true 20 | ark-serialize.workspace = true 21 | clap.workspace = true 22 | colored = "2.1.0" 23 | eigen-common.workspace = true 24 | eigen-crypto-bls.workspace = true 25 | eigen-utils.workspace = true 26 | eth-keystore.workspace = true 27 | hex.workspace = true 28 | k256.workspace = true 29 | num-bigint.workspace = true 30 | rand.workspace = true 31 | rand_core.workspace = true 32 | rust-bls-bn254.workspace = true 33 | serde.workspace = true 34 | serde_json.workspace = true 35 | thiserror.workspace = true 36 | tokio.workspace = true 37 | uuid.workspace = true 38 | 39 | 40 | [dev-dependencies] 41 | # We don't use workspace due to: 42 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 43 | eigen-testing-utils = { path = "../../tests/testing-utils" } 44 | 45 | rstest.workspace = true 46 | tempfile.workspace = true 47 | -------------------------------------------------------------------------------- /crates/eigen-cli/README.md: -------------------------------------------------------------------------------- 1 | # Eigen Cli 2 | 3 | The `eigen-cli` crate provides the following utilities. 4 | 5 | ## egnaddrs 6 | This tool is used to help debug and test eigenlayer/avs deployments and contract setups. 7 | 8 | ### Usage 9 | 10 | Currently egnaddrs only supports deriving contract addresses starting from a registry-coordinator or service-manager address. 11 | To test it using a local anvil instance, run: 12 | ```bash 13 | $ make start-anvil 14 | ``` 15 | 16 | Then run the eigen-cli: 17 | ```bash 18 | $ cargo run --package eigen-cli -- egnaddrs --registry-coordinator 0x9E545E3C0baAB3E08CdfD552C960A1050f373042 19 | ``` 20 | 21 | It then prints the following datastructure: 22 | ```json 23 | { 24 | "avs": { 25 | "bls-pubkey-compendium (shared)": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", 26 | "bls-pubkey-registry": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", 27 | "index-registry": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", 28 | "registry-coordinator": "0x9E545E3C0baAB3E08CdfD552C960A1050f373042", 29 | "service-manager": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", 30 | "stake-registry": "0x851356ae760d987E095750cCeb3bC6014560891C" 31 | }, 32 | "eigenlayer": { 33 | "delegation-manager": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 34 | "slasher": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", 35 | "strategy-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" 36 | }, 37 | "network": { 38 | "chain-id": "31337", 39 | "rpc-url": "http://localhost:8545" 40 | } 41 | } 42 | ``` 43 | 44 | ## egnkey 45 | This tool is used to manage keys for AVS development purpose 46 | 47 | Features: 48 | - [Generate ecdsa or bls key in batches](#generate-ecdsa-or-bls-key-in-batches) 49 | 50 | ### Generate ecdsa or bls key in batches 51 | 52 | To create in a random folder: 53 | ```bash 54 | cargo run --package eigen-cli -- egnkey generate --key-type ecdsa --num-keys 55 | ``` 56 | 57 | To create in specific folder: 58 | ```bash 59 | cargo run --package eigen-cli -- egnkey generate --key-type ecdsa --num-keys --output-dir 60 | ``` 61 | 62 | To create `ECDSA` and `BLS` keys in a random folder: 63 | ```bash 64 | cargo run --package eigen-cli -- egnkey generate --key-type ecdsa --num-keys 65 | ``` 66 | -------------------------------------------------------------------------------- /crates/eigen-cli/src/bls.rs: -------------------------------------------------------------------------------- 1 | use crate::args::BlsKeystoreType; 2 | use crate::EigenBlsKeyStoreError; 3 | use rust_bls_bn254::keystores::{pbkdf2_keystore::Pbkdf2Keystore, scrypt_keystore::ScryptKeystore}; 4 | 5 | /// BlsKeystore 6 | pub enum BlsKeystore { 7 | Pbkdf2, 8 | Scrypt, 9 | } 10 | 11 | impl BlsKeystore { 12 | /// Create a new [`BlsKeystore`] instance. 13 | /// [`BlsKeystore::Pbkdf2`] or [`BlsKeystore::Scrypt`] 14 | pub fn new_keystore( 15 | self, 16 | secret_key: String, 17 | output_path: String, 18 | password: Option<&str>, 19 | ) -> Result<(), EigenBlsKeyStoreError> { 20 | match self { 21 | BlsKeystore::Pbkdf2 => { 22 | let secret_in_bytes = secret_key.into_bytes(); 23 | let bls_key = secret_in_bytes.as_slice(); 24 | let mut keystore = Pbkdf2Keystore::new(); 25 | keystore.encrypt( 26 | bls_key, 27 | password.unwrap_or_default(), 28 | &output_path.to_string(), 29 | None, 30 | None, 31 | )?; 32 | keystore.to_keystore().save(&output_path.to_string())?; 33 | Ok(()) 34 | } 35 | BlsKeystore::Scrypt => { 36 | let secret_in_bytes = secret_key.into_bytes(); 37 | let bls_key = secret_in_bytes.as_slice(); 38 | let mut keystore = ScryptKeystore::new(); 39 | keystore.encrypt( 40 | bls_key, 41 | password.unwrap_or_default(), 42 | &output_path.to_string(), 43 | None, 44 | None, 45 | )?; 46 | keystore.to_keystore().save(&output_path.to_string())?; 47 | Ok(()) 48 | } 49 | } 50 | } 51 | } 52 | 53 | impl From for BlsKeystore { 54 | fn from(value: BlsKeystoreType) -> Self { 55 | match value { 56 | BlsKeystoreType::Pbkdf2 => BlsKeystore::Pbkdf2, 57 | BlsKeystoreType::Scrypt => BlsKeystore::Scrypt, 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crates/eigen-cli/src/convert.rs: -------------------------------------------------------------------------------- 1 | use eth_keystore::{encrypt_key, KeystoreError}; 2 | use rand_core::OsRng; 3 | use std::path::Path; 4 | 5 | const DEFAULT_KEYSTORE_NAME: &str = "key.json"; 6 | 7 | /// Stores an ecdsa key to a file, in web3 secret storage format. 8 | /// 9 | /// # Arguments 10 | /// 11 | /// * `private_key` - A private key to store. 12 | /// * `output_file` - The name of the file where the key is going to be stored. 13 | /// * `password` - The password used to encrypt the key. *Note:* If `password` is `None` then the empty string is used as password. 14 | /// 15 | /// # Errors 16 | /// 17 | /// - If the key encryption fails. 18 | pub fn store( 19 | private_key: Vec, 20 | output_file: Option, 21 | password: Option, 22 | ) -> Result<(), KeystoreError> { 23 | let dir = Path::new("."); 24 | 25 | encrypt_key( 26 | dir, 27 | &mut OsRng, 28 | private_key, 29 | password.unwrap_or_default(), 30 | Some(&output_file.unwrap_or(DEFAULT_KEYSTORE_NAME.into())), 31 | )?; 32 | 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /crates/eigen-cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use eigen_cli::{args::Args, execute_command}; 3 | 4 | fn main() { 5 | let args = Args::parse(); 6 | execute_command(args.command).unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /crates/eigen-cli/src/operator_id.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::keccak256; 2 | use eigen_crypto_bls::{error::BlsError, BlsKeyPair}; 3 | 4 | /// Derives an operator ID from a private key 5 | /// 6 | /// # Arguments 7 | /// 8 | /// * `private_key` - A private key used to derive the operator ID 9 | /// 10 | /// # Returns 11 | /// 12 | /// * The operator ID as `String` 13 | /// 14 | /// # Errors 15 | /// 16 | /// * If the private key is not valid 17 | pub fn derive_operator_id(private_key: String) -> Result { 18 | let key_pair = BlsKeyPair::new(private_key)?; 19 | let pub_key = key_pair.public_key(); 20 | let pub_key_affine = pub_key.g1(); 21 | 22 | let x_int: num_bigint::BigUint = pub_key_affine.x.into(); 23 | let y_int: num_bigint::BigUint = pub_key_affine.y.into(); 24 | 25 | let x_bytes = x_int.to_bytes_be(); 26 | let y_bytes = y_int.to_bytes_be(); 27 | 28 | let hash = keccak256([x_bytes, y_bytes].concat()); 29 | Ok(hex::encode(hash)) 30 | } 31 | -------------------------------------------------------------------------------- /crates/eigensdk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigensdk" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "SDK for eigenlayer" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | eigen-client-avsregistry = { workspace = true, optional = true } 18 | eigen-client-elcontracts = { workspace = true, optional = true } 19 | eigen-client-eth = { workspace = true, optional = true } 20 | eigen-client-fireblocks = { workspace = true, optional = true } 21 | eigen-crypto-bls = { workspace = true, optional = true } 22 | eigen-crypto-bn254 = { workspace = true, optional = true } 23 | eigen-logging = { workspace = true, optional = true } 24 | eigen-metrics = { workspace = true, optional = true } 25 | eigen-metrics-collectors-economic = { workspace = true, optional = true } 26 | eigen-metrics-collectors-rpc-calls = { workspace = true, optional = true } 27 | eigen-services-avsregistry = { workspace = true, optional = true } 28 | eigen-services-blsaggregation = { workspace = true, optional = true } 29 | eigen-services-operatorsinfo = { workspace = true, optional = true } 30 | eigen-signer = { workspace = true, optional = true } 31 | eigen-testing-utils = { workspace = true, optional = true } 32 | eigen-types = { workspace = true, optional = true } 33 | eigen-utils = { workspace = true, optional = true } 34 | eigen-nodeapi = { workspace = true, optional = true } 35 | eigen-common = { workspace = true, optional = true } 36 | 37 | 38 | # Feature configurations 39 | [features] 40 | default = [] 41 | 42 | 43 | # Full features set for full usage 44 | full = [ 45 | "client-avsregistry", 46 | "client-elcontracts", 47 | "client-eth", 48 | "client-fireblocks", 49 | "common", 50 | "crypto-bls", 51 | "crypto-bn254", 52 | "logging", 53 | "metrics", 54 | "services-avsregistry", 55 | "services-blsaggregation", 56 | "services-operatorsinfo", 57 | "signer", 58 | "testing-utils", 59 | "nodeapi", 60 | "metrics-collectors-economic", 61 | "metrics-collectors-rpc-calls", 62 | "types", 63 | "utils", 64 | ] 65 | 66 | # Client-related features 67 | client-avsregistry = ["dep:eigen-client-avsregistry"] 68 | client-elcontracts = ["dep:eigen-client-elcontracts"] 69 | client-eth = ["dep:eigen-client-eth"] 70 | client-fireblocks = ["dep:eigen-client-fireblocks"] 71 | 72 | 73 | # Crypto-related features 74 | crypto-bls = ["dep:eigen-crypto-bls"] 75 | crypto-bn254 = ["dep:eigen-crypto-bn254"] 76 | 77 | # Metrics and collectors 78 | metrics = ["dep:eigen-metrics"] 79 | metrics-collectors-economic = ["dep:eigen-metrics-collectors-economic"] 80 | metrics-collectors-rpc-calls = ["dep:eigen-metrics-collectors-rpc-calls"] 81 | 82 | # Service-related features 83 | services-avsregistry = ["dep:eigen-services-avsregistry"] 84 | services-blsaggregation = ["dep:eigen-services-blsaggregation"] 85 | services-operatorsinfo = ["dep:eigen-services-operatorsinfo"] 86 | 87 | # Node API related features 88 | nodeapi = ["dep:eigen-nodeapi"] 89 | 90 | # Logging and utilities 91 | logging = ["dep:eigen-logging"] 92 | utils = ["dep:eigen-utils"] 93 | 94 | # Testing utilities 95 | testing-utils = ["dep:eigen-testing-utils"] 96 | 97 | # Signer-related features 98 | signer = ["dep:eigen-signer"] 99 | 100 | # types 101 | types = ["dep:eigen-types"] 102 | 103 | #common utilities 104 | common = ["dep:eigen-common"] 105 | -------------------------------------------------------------------------------- /crates/eigensdk/README.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /crates/eigensdk/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 3 | #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] 4 | 5 | /* --------------------------------------- Core re-exports -------------------------------------- */ 6 | 7 | #[doc(inline)] 8 | #[cfg(feature = "types")] 9 | pub use eigen_types as types; 10 | 11 | #[doc(inline)] 12 | #[cfg(feature = "utils")] 13 | pub use eigen_utils as utils; 14 | 15 | #[doc(inline)] 16 | #[cfg(feature = "crypto-bls")] 17 | pub use eigen_crypto_bls as crypto_bls; 18 | 19 | #[doc(inline)] 20 | #[cfg(feature = "crypto-bn254")] 21 | pub use eigen_crypto_bn254 as crypto_bn254; 22 | 23 | #[doc(inline)] 24 | #[cfg(feature = "signer")] 25 | pub use eigen_signer as signer; 26 | 27 | #[doc(inline)] 28 | #[cfg(feature = "logging")] 29 | pub use eigen_logging as logging; 30 | 31 | #[doc(inline)] 32 | #[cfg(feature = "metrics")] 33 | pub use eigen_metrics as metrics; 34 | 35 | /* ------------------------------------- Client Re-exports ------------------------------------- */ 36 | 37 | #[doc(inline)] 38 | #[cfg(feature = "client-avsregistry")] 39 | pub use eigen_client_avsregistry as client_avsregistry; 40 | 41 | #[doc(inline)] 42 | #[cfg(feature = "client-elcontracts")] 43 | pub use eigen_client_elcontracts as client_elcontracts; 44 | 45 | #[doc(inline)] 46 | #[cfg(feature = "client-eth")] 47 | pub use eigen_client_eth as client_eth; 48 | 49 | #[doc(inline)] 50 | #[cfg(feature = "client-fireblocks")] 51 | pub use eigen_client_fireblocks as client_fireblocks; 52 | 53 | /* ------------------------------------- Services Re-exports ------------------------------------- */ 54 | 55 | #[doc(inline)] 56 | #[cfg(feature = "services-avsregistry")] 57 | pub use eigen_services_avsregistry as services_avsregistry; 58 | 59 | #[doc(inline)] 60 | #[cfg(feature = "services-blsaggregation")] 61 | pub use eigen_services_blsaggregation as services_blsaggregation; 62 | 63 | #[doc(inline)] 64 | #[cfg(feature = "services-operatorsinfo")] 65 | pub use eigen_services_operatorsinfo as services_operatorsinfo; 66 | 67 | /* ------------------------------------ Node API Re-export ------------------------------------ */ 68 | 69 | #[doc(inline)] 70 | #[cfg(feature = "nodeapi")] 71 | pub use eigen_nodeapi as nodeapi; 72 | 73 | /* ------------------------------------ Testing Utils Re-export -------------------------------- */ 74 | 75 | #[doc(inline)] 76 | #[cfg(feature = "testing-utils")] 77 | pub use eigen_testing_utils as testing_utils; 78 | 79 | /* ------------------------------------ Metrics Collectors Re-exports -------------------------- */ 80 | 81 | #[doc(inline)] 82 | #[cfg(feature = "metrics-collectors-economic")] 83 | pub use eigen_metrics_collectors_economic as metrics_collectors_economic; 84 | 85 | #[doc(inline)] 86 | #[cfg(feature = "metrics-collectors-rpc-calls")] 87 | pub use eigen_metrics_collectors_rpc_calls as metrics_collectors_rpc_calls; 88 | 89 | /* ------------------------------------ Common Utilities Re-exports -------------------------- */ 90 | 91 | #[doc(inline)] 92 | #[cfg(feature = "common")] 93 | pub use eigen_common as common; 94 | -------------------------------------------------------------------------------- /crates/logging/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-logging" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "logging utilities" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | ctor = "0.2.8" 18 | once_cell.workspace = true 19 | tracing.workspace = true 20 | tracing-subscriber.workspace = true 21 | -------------------------------------------------------------------------------- /crates/logging/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | 7 | pub mod log_level; 8 | pub mod logger; 9 | pub mod noop_logger; 10 | pub mod tracing_logger; 11 | pub static COMPONENT_KEY: &str = "component"; 12 | use ctor::ctor; 13 | use log_level::LogLevel; 14 | use logger::Logger; 15 | use noop_logger::NoopLogger; 16 | use once_cell::sync::OnceCell; 17 | use std::sync::Arc; 18 | use tracing_logger::TracingLogger; 19 | 20 | /// [`NoopLogger`](for testing) OnceCell instance that can be initialized once 21 | static TEST_LOGGER: OnceCell> = OnceCell::new(); 22 | 23 | /// [`TracingLogger`] OnceCell instance that can be initialized once 24 | static LOGGER: OnceCell> = OnceCell::new(); 25 | 26 | /// Initializes the test logger at the start using ctor. 27 | #[ctor] 28 | fn init_test_logger() { 29 | TEST_LOGGER.get_or_init(|| { 30 | NoopLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) 31 | }); 32 | } 33 | 34 | /// get the initialized test logger 35 | pub fn get_test_logger() -> Arc { 36 | TEST_LOGGER.get().expect("Logger not initialized").clone() 37 | } 38 | 39 | /// Use this to initialize the tracer. It can only be initialized once. 40 | /// Set the tracing level according to [`LogLevel`] 41 | pub fn init_logger(log_level: LogLevel) { 42 | LOGGER 43 | .get_or_init(|| TracingLogger::new_text_logger(false, String::from(""), log_level, false)); 44 | } 45 | 46 | /// get the initialized logger 47 | pub fn get_logger() -> Arc { 48 | LOGGER.get().expect("Logger not initialized").clone() 49 | } 50 | -------------------------------------------------------------------------------- /crates/logging/src/log_level.rs: -------------------------------------------------------------------------------- 1 | #[derive(Default, Debug, Clone)] 2 | pub enum LogLevel { 3 | Error, 4 | Warn, 5 | #[default] 6 | Info, 7 | Debug, 8 | Trace, 9 | Fatal, 10 | } 11 | -------------------------------------------------------------------------------- /crates/logging/src/logger.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::sync::Arc; 3 | 4 | pub type SharedLogger = Arc; 5 | 6 | pub fn tags_as_debug<'a>(tags: &'a [&'a str]) -> Vec<&'a dyn Debug> { 7 | tags.iter().map(|tag| tag as &dyn Debug).collect() 8 | } 9 | 10 | pub trait Logger: Debug + Send + Sync { 11 | fn debug(&self, msg: &str, args: &str); 12 | fn info(&self, msg: &str, args: &str); 13 | fn warn(&self, msg: &str, args: &str); 14 | fn error(&self, msg: &str, args: &str); 15 | fn fatal(&self, msg: &str, args: &str); 16 | fn log(&self, msg: &str, args: &str); 17 | } 18 | -------------------------------------------------------------------------------- /crates/logging/src/noop_logger.rs: -------------------------------------------------------------------------------- 1 | use super::log_level::LogLevel; 2 | use super::logger::Logger; 3 | use std::fmt::Debug; 4 | use std::sync::Arc; 5 | 6 | #[derive(Debug, Default, Clone)] 7 | pub struct NoopLogger {} 8 | 9 | impl NoopLogger { 10 | pub fn new_text_logger( 11 | _no_color: bool, 12 | _time_format: String, 13 | _level: LogLevel, 14 | _add_source: bool, 15 | ) -> Arc { 16 | Arc::new(NoopLogger {}) 17 | } 18 | 19 | pub fn new_json_logger( 20 | _no_color: bool, 21 | _time_format: String, 22 | _level: LogLevel, 23 | _add_source: bool, 24 | ) -> Self { 25 | NoopLogger {} 26 | } 27 | } 28 | 29 | impl Logger for NoopLogger { 30 | fn debug(&self, _msg: &str, _args: &str) {} 31 | fn info(&self, _msg: &str, _args: &str) {} 32 | fn warn(&self, _msg: &str, _args: &str) {} 33 | fn error(&self, _msg: &str, _args: &str) {} 34 | fn fatal(&self, _msg: &str, _args: &str) {} 35 | 36 | fn log(&self, _msg: &str, _args: &str) {} 37 | } 38 | -------------------------------------------------------------------------------- /crates/logging/src/tracing_logger.rs: -------------------------------------------------------------------------------- 1 | use super::log_level::LogLevel; 2 | use super::logger::Logger; 3 | use std::{fmt::Debug, sync::Arc}; 4 | use tracing::{debug, error, info, trace, warn}; 5 | 6 | // SLoggerOptions are options when creating a new SLogger. 7 | // A zero Options consists entirely of default values. 8 | // 9 | // SLoggerOptions are an extension of [slog.HandlerOptions]. 10 | #[derive(Default, Debug, Clone)] 11 | pub struct TracingLogger { 12 | // Enable source code location (Default: false) 13 | pub add_source: bool, 14 | 15 | // Minimum level to log (Default: slog.LevelInfo) 16 | pub level: LogLevel, 17 | 18 | // Time format (Default: time.StampMilli) 19 | // only supported with text handler 20 | pub time_format: String, 21 | } 22 | 23 | impl TracingLogger { 24 | pub fn new_text_logger( 25 | no_color: bool, 26 | time_format: String, 27 | level: LogLevel, 28 | add_source: bool, 29 | ) -> Arc { 30 | let tracing_level = match level { 31 | LogLevel::Fatal => tracing::Level::ERROR, 32 | LogLevel::Error => tracing::Level::ERROR, 33 | LogLevel::Warn => tracing::Level::WARN, 34 | LogLevel::Info => tracing::Level::INFO, 35 | LogLevel::Debug => tracing::Level::DEBUG, 36 | LogLevel::Trace => tracing::Level::TRACE, 37 | }; 38 | tracing::subscriber::set_global_default( 39 | tracing_subscriber::fmt::Subscriber::builder() 40 | .with_max_level(tracing_level) 41 | .with_ansi(no_color) 42 | .finish(), 43 | ) 44 | .expect("setting default subscriber failed"); 45 | 46 | Arc::new(TracingLogger { 47 | add_source, 48 | level, 49 | time_format, 50 | }) 51 | } 52 | } 53 | 54 | pub fn create_tracing_logger( 55 | no_color: bool, 56 | time_format: String, 57 | level: LogLevel, 58 | add_source: bool, 59 | ) -> Arc { 60 | TracingLogger::new_text_logger(no_color, time_format, level, add_source) 61 | } 62 | 63 | impl Logger for TracingLogger { 64 | // type LoggerType = TracingLogger; 65 | 66 | fn debug(&self, msg: &str, tags: &str) { 67 | debug!("{} {:?}", msg, [tags]); 68 | } 69 | 70 | fn info(&self, msg: &str, tags: &str) { 71 | info!("{} {:?}", msg, [tags]); 72 | } 73 | 74 | fn warn(&self, msg: &str, tags: &str) { 75 | warn!("{} {:?}", msg, [tags]); 76 | } 77 | 78 | fn error(&self, msg: &str, tags: &str) { 79 | error!("{} {:?}", msg, [tags]); 80 | } 81 | 82 | fn fatal(&self, msg: &str, tags: &str) { 83 | error!("{} {:?}", msg, [tags]); 84 | panic!("Fatal error occurred: {} {:?}", msg, [tags]); 85 | } 86 | 87 | fn log(&self, msg: &str, tags: &str) { 88 | match self.level { 89 | LogLevel::Fatal => { 90 | error!("Fatal"); 91 | self.fatal(msg, tags); 92 | } 93 | LogLevel::Error => { 94 | error!("Error"); 95 | self.error(msg, tags); 96 | } 97 | LogLevel::Warn => { 98 | warn!("Warn"); 99 | self.warn(msg, tags); 100 | } 101 | LogLevel::Info => { 102 | info!("Info"); 103 | self.info(msg, tags); 104 | } 105 | LogLevel::Debug => { 106 | debug!("Debug"); 107 | self.debug(msg, tags); 108 | } 109 | LogLevel::Trace => { 110 | trace!("Trace"); 111 | self.debug(msg, tags); 112 | } 113 | } 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | use crate::get_test_logger; 120 | 121 | #[test] 122 | fn test_log() { 123 | let logger = get_test_logger(); 124 | logger.log("Log", "info logged"); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /crates/m2_contracts/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 2 | CONTRACTS_REGISTRY_ADDR=0x5FbDB2315678afecb367f032d93F642f64180aa3 -------------------------------------------------------------------------------- /crates/m2_contracts/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | 16 | -------------------------------------------------------------------------------- /crates/m2_contracts/anvil/deploy-avs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export RPC_URL=http://localhost:8545 4 | export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 5 | export DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 6 | export CONTRACTS_REGISTRY_ADDR=0x5FbDB2315678afecb367f032d93F642f64180aa3 7 | 8 | # cd to the directory of this script so that this can be run from anywhere 9 | parent_path=$( 10 | cd "$(dirname "${BASH_SOURCE[0]}")" 11 | pwd -P 12 | ) 13 | cd "$parent_path" 14 | 15 | cd ../ 16 | forge script script/DeployMockAvs.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow -vvv 17 | forge script script/ContractsRegistry.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow 18 | 19 | -------------------------------------------------------------------------------- /crates/m2_contracts/anvil/deploy-eigenlayer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export RPC_URL=http://localhost:8545 4 | export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 5 | 6 | # Navigate to the script directory 7 | parent_path=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) 8 | cd "$parent_path" 9 | 10 | root_dir=$(realpath "$parent_path/../..") 11 | 12 | # Deploy Contracts 13 | cd "$root_dir/m2_contracts" 14 | forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast 15 | 16 | forge script script/DeployEigenLayerCore.s.sol:DeployEigenlayerCore --rpc-url $RPC_URL --broadcast --slow 17 | -------------------------------------------------------------------------------- /crates/m2_contracts/anvil/dump-state.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Enable the script to exit immediately if a command exits with a non-zero status 4 | set -o errexit -o nounset -o pipefail 5 | 6 | # Navigate to the script directory 7 | parent_path=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) 8 | cd "$parent_path" 9 | 10 | root_dir=$(realpath "$parent_path/../..") 11 | 12 | set -a 13 | source $parent_path/utils.sh 14 | # we overwrite some variables here because should always deploy to anvil (localhost) 15 | RPC_URL=http://localhost:8545 16 | DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 17 | set +a 18 | 19 | # # start an empty anvil chain in the background and dump its state to a json file upon exit 20 | start_anvil_docker "" $parent_path/m2_contracts_deployed_anvil_state 21 | # sleep 1 22 | 23 | CHAIN_ID=$(cast chain-id) 24 | 25 | # Deploy Contracts 26 | cd "$root_dir/m2_contracts" 27 | forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast 28 | 29 | forge script script/DeployEigenLayerCore.s.sol:DeployEigenlayerCore --rpc-url $RPC_URL --broadcast --slow 30 | 31 | forge script script/DeployMockAvs.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow -vvv 32 | forge script script/ContractsRegistry.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow 33 | 34 | -------------------------------------------------------------------------------- /crates/m2_contracts/anvil/start-anvil-chain-with-el-and-avs-deployed.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RPC_URL=http://localhost:8545 4 | 5 | # cd to the directory of this script so that this can be run from anywhere 6 | parent_path=$( 7 | cd "$(dirname "${BASH_SOURCE[0]}")" 8 | pwd -P 9 | ) 10 | cd "$parent_path" 11 | 12 | set -a 13 | source ./utils.sh 14 | set +a 15 | 16 | cleanup() { 17 | echo "Executing cleanup function..." 18 | set +e 19 | docker rm -f anvil 20 | exit_status=$? 21 | if [ $exit_status -ne 0 ]; then 22 | echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status" 23 | fi 24 | } 25 | trap 'cleanup $LINENO "$BASH_COMMAND"' EXIT 26 | 27 | # start an anvil instance that has eigenlayer contracts deployed 28 | start_anvil_docker $parent_path/dump_state.json "" 29 | -------------------------------------------------------------------------------- /crates/m2_contracts/anvil/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FOUNDRY_IMAGE=ghcr.io/foundry-rs/foundry:stable 4 | 5 | set -e -o nounset 6 | 7 | parent_path=$( 8 | cd "$(dirname "${BASH_SOURCE[0]}")" 9 | pwd -P 10 | ) 11 | 12 | 13 | clean_up() { 14 | # Check if the exit status is non-zero 15 | exit_status=$? 16 | if [ $exit_status -ne 0 ]; then 17 | echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status" 18 | fi 19 | } 20 | # Use trap to call the clean_up function when the script exits 21 | trap 'clean_up $LINENO "$BASH_COMMAND"' ERR 22 | 23 | # start_anvil_docker $LOAD_STATE_FILE $DUMP_STATE_FILE 24 | # this function will also take care of stopping the anvil container when the script exits 25 | start_anvil_docker() { 26 | LOAD_STATE_FILE=$1 27 | DUMP_STATE_FILE=$2 28 | LOAD_STATE_VOLUME_DOCKER_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "-v $LOAD_STATE_FILE:/load-state.json") 29 | DUMP_STATE_VOLUME_DOCKER_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "-v $DUMP_STATE_FILE:/dump-state.json") 30 | LOAD_STATE_ANVIL_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "--load-state /load-state.json") 31 | DUMP_STATE_ANVIL_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "--dump-state /dump-state.json") 32 | 33 | trap 'docker stop anvil 2>/dev/null || true' EXIT 34 | docker run --rm -d --name anvil -p 8545:8545 $LOAD_STATE_VOLUME_DOCKER_ARG $DUMP_STATE_VOLUME_DOCKER_ARG \ 35 | --entrypoint anvil \ 36 | $FOUNDRY_IMAGE \ 37 | $LOAD_STATE_ANVIL_ARG $DUMP_STATE_ANVIL_ARG --host 0.0.0.0 \ 38 | --timestamp 0 39 | sleep 2 40 | } 41 | -------------------------------------------------------------------------------- /crates/m2_contracts/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | fs_permissions = [{ access = "read-write", path = "./" }] 6 | solc = "0.8.27" 7 | via-ir = true 8 | optimizer = true 9 | 10 | 11 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config 12 | -------------------------------------------------------------------------------- /crates/m2_contracts/mock_avs_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "num_quorums": 1, 3 | "operator_params": [10000,15000,100], 4 | "operator_addr": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "contracts_registry_addr": "0x5FbDB2315678afecb367f032d93F642f64180aa3" 6 | } -------------------------------------------------------------------------------- /crates/m2_contracts/remappings.txt: -------------------------------------------------------------------------------- 1 | @eigenlayer/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/ 2 | @eigenlayer-middleware/=lib/eigenlayer-middleware/ 3 | @openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/ 4 | forge-std/=lib/forge-std/src/ 5 | @eigenlayer/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/ 6 | @eigenlayer-middleware/=lib/eigenlayer-middleware/ 7 | @openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/ 8 | eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/ 9 | @openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/ 10 | @openzeppelin-upgrades/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/ 11 | @openzeppelin-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/ 12 | ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/ 13 | eigenlayer-middleware/=lib/eigenlayer-middleware/ 14 | erc4626-tests/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/lib/erc4626-tests/ 15 | openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/ 16 | openzeppelin-contracts-upgradeable/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/ 17 | openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/ 18 | openzeppelin-contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/ 19 | openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/ 20 | zeus-templates/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/zeus-templates/src/ 21 | -------------------------------------------------------------------------------- /crates/m2_contracts/script/ContractsRegistry.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | 6 | import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; 7 | import {MockAvsDeploymentLib} from "./utils/MockAvsDeploymentLib.sol"; 8 | import {WriteToContractsRegistryLib} from "./utils/WriteToContractsRegistryLib.sol"; 9 | 10 | contract ContractsRegistry is Script { 11 | address private deployer; 12 | address public CONTRACT_REGISTRY; 13 | CoreDeploymentLib.DeploymentData coreConfigData; 14 | MockAvsDeploymentLib.DeploymentData avsConfigData; 15 | 16 | function setUp() public { 17 | deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); 18 | vm.label(deployer, "Deployer"); 19 | CONTRACT_REGISTRY = vm.envAddress("CONTRACTS_REGISTRY_ADDR"); 20 | 21 | coreConfigData = CoreDeploymentLib.readDeploymentJson("script/deployments/core/", "31337.json"); 22 | avsConfigData = MockAvsDeploymentLib.readDeploymentJson("script/deployments/mock-avs/", block.chainid); 23 | } 24 | 25 | function run() external { 26 | vm.startBroadcast(deployer); 27 | if (block.chainid == 31337 || block.chainid == 1337) { 28 | WriteToContractsRegistryLib.writeCoreContractsToRegistry(CONTRACT_REGISTRY, coreConfigData); 29 | WriteToContractsRegistryLib.writeMockAvsContractsToRegistry(CONTRACT_REGISTRY, avsConfigData); 30 | } 31 | vm.stopBroadcast(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/m2_contracts/script/DeployEigenLayerCore.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.12; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | import {console2} from "forge-std/console2.sol"; 6 | import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; 7 | import {UpgradeableProxyLib} from "./utils/UpgradeableProxyLib.sol"; 8 | 9 | contract DeployEigenlayerCore is Script { 10 | using CoreDeploymentLib for *; 11 | using UpgradeableProxyLib for address; 12 | 13 | address internal deployer; 14 | address internal proxyAdmin; 15 | CoreDeploymentLib.DeploymentData internal deploymentData; 16 | CoreDeploymentLib.DeploymentConfigData internal configData; 17 | 18 | function setUp() public virtual { 19 | deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); 20 | vm.label(deployer, "Deployer"); 21 | } 22 | 23 | function run() external { 24 | vm.startBroadcast(deployer); 25 | proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); 26 | deploymentData = CoreDeploymentLib.deployContracts(deployer, proxyAdmin, configData); 27 | vm.stopBroadcast(); 28 | string memory deploymentPath = "script/deployments/core/"; 29 | CoreDeploymentLib.writeDeploymentJson(deploymentPath, block.chainid, deploymentData); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/m2_contracts/script/deployments/core/31337.json: -------------------------------------------------------------------------------- 1 | {"lastUpdate":{"timestamp":"88","block_number":"1"},"addresses":{"proxyAdmin":"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512","delegation":"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9","delegationManagerImpl":"0x68b1d87f95878fe05b998f19b66f4baba5de1aed","avsDirectory":"0x5fc8d32690cc91d4c39d9d3abcbd16989f875707","avsDirectoryImpl":"0x3aa5ebb10dc797cac828524e59a333d0a371443c","strategyManager":"0xa513e6e4b8f2a923d98304ec87f64353c4d5c853","strategyManagerImpl":"0xc6e7df5e7b4f2a278906862b61205850344d4e7d","eigenPodManager":"0x8a791620dd6260079bf849dc5567adc3f2fdc318","eigenPodManagerImpl":"0x4ed7c70f96b99c776995fb64377f0d4ab3b0e1c1","strategyFactory":"0x9a9f2ccfde556a7e9ff0848998aa4a0cfd8863ae","rewardsCoordinator":"0xb7f8bc63bbcad18155201308c8f3540b07f84f5e","strategyBeacon":"0xc5a5c42992decbae36851359345fe25997f5c42d"}} -------------------------------------------------------------------------------- /crates/m2_contracts/script/deployments/core/m2/31337.json: -------------------------------------------------------------------------------- 1 | {"lastUpdate":{"timestamp":"1738245589","block_number":"1"},"addresses":{"proxyAdmin":"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512","delegation":"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9","delegationManagerImpl":"0x68b1d87f95878fe05b998f19b66f4baba5de1aed","avsDirectory":"0x5fc8d32690cc91d4c39d9d3abcbd16989f875707","avsDirectoryImpl":"0x3aa5ebb10dc797cac828524e59a333d0a371443c","strategyManager":"0xa513e6e4b8f2a923d98304ec87f64353c4d5c853","strategyManagerImpl":"0xc6e7df5e7b4f2a278906862b61205850344d4e7d","eigenPodManager":"0x8a791620dd6260079bf849dc5567adc3f2fdc318","eigenPodManagerImpl":"0x4ed7c70f96b99c776995fb64377f0d4ab3b0e1c1","strategyFactory":"0x9a9f2ccfde556a7e9ff0848998aa4a0cfd8863ae","rewardsCoordinator":"0xb7f8bc63bbcad18155201308c8f3540b07f84f5e","strategyBeacon":"0xc5a5c42992decbae36851359345fe25997f5c42d"}} -------------------------------------------------------------------------------- /crates/m2_contracts/script/deployments/mock-avs/31337.json: -------------------------------------------------------------------------------- 1 | {"lastUpdate":{"timestamp":"104","block_number":"36"},"addresses":{"proxyAdmin":"0xf5059a5d33d5853360d16c683c16e67980206f36","mockAvsServiceManager":"0x99bba657f2bbc93c02d617f8ba121cb8fc104acf","mockAvsServiceManagerImpl":"0x5081a39b8a5f0e35a8d959395a630b68b74dd30f","registryCoordinator":"0x5eb3bc0a489c5a8288765d2336659ebca68fcd00","blsapkRegistry":"0x809d550fca64d94bd9f66e60752a544199cfac3d","indexRegistry":"0x1291be112d480055dafd8a610b7d1e203891c274","stakeRegistry":"0x8f86403a4de0bb5791fa46b8e795c547942fe4cf","operatorStateRetriever":"0xcd8a1c3ba11cf5ecfa6267617243239504a98d90","strategy":"0x2b961e3959b79326a8e7f64ef0d2d825707669b5","token":"0x95401dc811bb5740090279ba06cfa8fcf6113778"}} -------------------------------------------------------------------------------- /crates/m2_contracts/script/input/31337/ops_addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 3 | "pauser": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 4 | "churner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "ejector": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 6 | } -------------------------------------------------------------------------------- /crates/m2_contracts/script/output/31337/eigenlayer_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "avsDirectory": "0x0165878A594ca255338adfa4d48449f69242Eb8F", 4 | "avsDirectoryImplementation": "0x9A676e781A523b5d0C0e43731313A708CB607508", 5 | "baseStrategyImplementation": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f", 6 | "delayedWithdrawalRouter": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", 7 | "delayedWithdrawalRouterImplementation": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE", 8 | "delegation": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", 9 | "delegationImplementation": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", 10 | "eigenLayerPauserReg": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", 11 | "eigenLayerProxyAdmin": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", 12 | "eigenPodBeacon": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", 13 | "eigenPodImplementation": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", 14 | "eigenPodManager": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", 15 | "eigenPodManagerImplementation": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", 16 | "emptyContract": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 17 | "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", 18 | "slasherImplementation": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", 19 | "strategies": "", 20 | "strategyManager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", 21 | "strategyManagerImplementation": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" 22 | }, 23 | "chainInfo": { 24 | "chainId": 31337, 25 | "deploymentBlock": 1 26 | }, 27 | "parameters": { 28 | "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 29 | "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 30 | } 31 | } -------------------------------------------------------------------------------- /crates/m2_contracts/script/output/31337/mockAvs_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "mockAvsServiceManager": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", 4 | "mockAvsServiceManagerImplementation": "0x0000000000000000000000000000000000000000", 5 | "operatorStateRetriever": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", 6 | "proxyAdmin": "0xc5a5C42992dECbae36851359345FE25997F5C42d", 7 | "registryCoordinator": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", 8 | "registryCoordinatorImplementation": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" 9 | } 10 | } -------------------------------------------------------------------------------- /crates/m2_contracts/script/output/31337/token_and_strategy_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "erc20mock": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1", 4 | "erc20mockstrategy": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0" 5 | } 6 | } -------------------------------------------------------------------------------- /crates/m2_contracts/script/utils/FundOperator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {MockERC20} from "../../src/MockERC20.sol"; 5 | 6 | library FundOperator { 7 | function fundOperator(address erc20, address operator, uint256 amount) internal { 8 | MockERC20 erc20Contract = MockERC20(erc20); 9 | 10 | erc20Contract.mint(operator, amount); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/m2_contracts/script/utils/UpgradeableProxyLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Vm} from "forge-std/Vm.sol"; 5 | import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; 6 | import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 7 | import {EmptyContract} from "@eigenlayer/test/mocks/EmptyContract.sol"; 8 | 9 | library UpgradeableProxyLib { 10 | bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 11 | bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 12 | 13 | Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); 14 | 15 | function deployProxyAdmin() internal returns (address) { 16 | return address(new ProxyAdmin()); 17 | } 18 | 19 | function setUpEmptyProxy(address admin) internal returns (address) { 20 | address emptyContract = address(new EmptyContract()); 21 | return address(new TransparentUpgradeableProxy(emptyContract, admin, "")); 22 | } 23 | 24 | function upgrade(address proxy, address impl) internal { 25 | ProxyAdmin admin = getProxyAdmin(proxy); 26 | admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), impl); 27 | } 28 | 29 | function upgradeAndCall(address proxy, address impl, bytes memory initData) internal { 30 | ProxyAdmin admin = getProxyAdmin(proxy); 31 | admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), impl, initData); 32 | } 33 | 34 | function getImplementation(address proxy) internal view returns (address) { 35 | bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); 36 | return address(uint160(uint256(value))); 37 | } 38 | 39 | function getProxyAdmin(address proxy) internal view returns (ProxyAdmin) { 40 | bytes32 value = vm.load(proxy, ADMIN_SLOT); 41 | return ProxyAdmin(address(uint160(uint256(value)))); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /crates/m2_contracts/script/utils/WriteToContractsRegistryLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Vm} from "forge-std/Vm.sol"; 5 | import {ContractsRegistry} from "../../src/ContractsRegistry.sol"; 6 | import {CoreDeploymentLib} from "./CoreDeploymentLib.sol"; 7 | import {MockAvsDeploymentLib} from "./MockAvsDeploymentLib.sol"; 8 | 9 | library WriteToContractsRegistryLib { 10 | function writeCoreContractsToRegistry( 11 | address contractsRegistryAddr, 12 | CoreDeploymentLib.DeploymentData memory deploymentdata 13 | ) internal { 14 | ContractsRegistry contractsRegistry = ContractsRegistry(contractsRegistryAddr); 15 | contractsRegistry.registerContract("delegationManager", address(deploymentdata.delegationManager)); 16 | contractsRegistry.registerContract("strategyManager", address(deploymentdata.strategyManager)); 17 | contractsRegistry.registerContract("avsDirectory", address(deploymentdata.avsDirectory)); 18 | contractsRegistry.registerContract("rewardsCoordinator", address(deploymentdata.rewardsCoordinator)); 19 | contractsRegistry.registerContract("pauserRegistry", address(deploymentdata.pauserRegistry)); 20 | } 21 | 22 | function writeMockAvsContractsToRegistry( 23 | address contractsRegistryAddr, 24 | MockAvsDeploymentLib.DeploymentData memory deploymentdata 25 | ) internal { 26 | ContractsRegistry contractsRegistry = ContractsRegistry(contractsRegistryAddr); 27 | 28 | contractsRegistry.registerContract("erc20MockStrategy", address(deploymentdata.strategy)); 29 | contractsRegistry.registerContract("mockAvsServiceManager", deploymentdata.mockAvsServiceManager); 30 | contractsRegistry.registerContract("mockAvsRegistryCoordinator", address(deploymentdata.registryCoordinator)); 31 | contractsRegistry.registerContract( 32 | "mockAvsOperatorStateRetriever", address(deploymentdata.operatorStateRetriever) 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /crates/m2_contracts/src/ContractsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.20; 3 | 4 | // ContractsRegistry store the address of all the contracts deployed for eigenlayer and avss 5 | // It is used for testing purpose only, so that we can retrieve the addresses without having to store them in a json file 6 | // This way integration testing against an anvil chain (started with a saved db) is self-contained 7 | // ASSUMPTION: right now we deploy this contract as the first deployment (nonce=0) using the first anvil address 8 | // 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 to make sure it's always at the address 0x5FbDB2315678afecb367f032d93F642f64180aa3 9 | // forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $PRIVATE_KEY 10 | contract ContractsRegistry { 11 | mapping(string => address) public contracts; 12 | mapping(uint256 => string) public contractNames; 13 | uint256 public contractCount; 14 | 15 | function registerContract(string memory name, address _contract) public { 16 | // we treat redeploys as a bug since this is only meant to be used for testing. 17 | // If new contracts need to be deployed just start from a fresh anvil state. 18 | require(contracts[name] == address(0), "contract already registered"); 19 | contracts[name] = _contract; 20 | contractNames[contractCount] = name; 21 | contractCount++; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/m2_contracts/src/MockAvsServiceManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import { 5 | ServiceManagerBase, 6 | IAVSDirectory, 7 | IRewardsCoordinator, 8 | IRegistryCoordinator, 9 | IStakeRegistry 10 | } from "@eigenlayer-middleware/src/ServiceManagerBase.sol"; 11 | import {BLSSignatureChecker} from "@eigenlayer-middleware/src/BLSSignatureChecker.sol"; 12 | 13 | contract MockAvsServiceManager is ServiceManagerBase, BLSSignatureChecker { 14 | constructor( 15 | IAVSDirectory _avsDirectory, 16 | IRegistryCoordinator _registryCoordinator, 17 | IStakeRegistry _stakeRegistry, 18 | address rewards_coordinator 19 | ) 20 | ServiceManagerBase(_avsDirectory, IRewardsCoordinator(rewards_coordinator), _registryCoordinator, _stakeRegistry) 21 | BLSSignatureChecker(_registryCoordinator) 22 | {} 23 | 24 | function initialize(address _initialOwner) external initializer { 25 | __ServiceManagerBase_init(_initialOwner, _initialOwner); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/m2_contracts/src/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.20; 3 | 4 | import {ERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockERC20 is ERC20("Mock Token", "MCK") { 7 | function mint(address account, uint256 amount) public { 8 | _mint(account, amount); 9 | } 10 | 11 | /// WARNING: Vulnerable, bypasses allowance check. Do not use in production! 12 | function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { 13 | super._transfer(from, to, amount); 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/metrics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-metrics" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "prometheus server for metrics" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | eigen-logging.workspace = true 18 | metrics.workspace = true 19 | metrics-exporter-prometheus.workspace = true 20 | metrics-util = "0.19.0" 21 | 22 | [dev-dependencies] 23 | # We don't use workspace due to: 24 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 25 | eigen-testing-utils = { path = "../../tests/testing-utils" } 26 | eigen-metrics-collectors-rpc-calls = { path = "./collectors/rpc_calls" } 27 | eigen-metrics-collectors-economic = { path = "./collectors/economic" } 28 | eigen-client-elcontracts = { path = "../chainio/clients/elcontracts" } 29 | eigen-client-avsregistry = { path = "../chainio/clients/avsregistry" } 30 | 31 | alloy.workspace = true 32 | num-bigint.workspace = true 33 | reqwest = "0.12.4" 34 | tokio.workspace = true 35 | -------------------------------------------------------------------------------- /crates/metrics/README.md: -------------------------------------------------------------------------------- 1 | # EigenMetrics 2 | 3 | Implementation of EigenLayer AVS node [spec](https://docs.eigenlayer.xyz/category/metrics) 4 | -------------------------------------------------------------------------------- /crates/metrics/collectors/economic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-metrics-collectors-economic" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "eigenlayer economic metrics" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | alloy.workspace = true 18 | eigen-logging.workspace = true 19 | eigen-types.workspace = true 20 | eigen-client-elcontracts.workspace = true 21 | eigen-client-avsregistry.workspace = true 22 | thiserror.workspace = true 23 | metrics.workspace = true 24 | num-bigint.workspace = true 25 | 26 | [dev-dependencies] 27 | # We don't use workspace due to: 28 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 29 | eigen-testing-utils = { path = "../../../../tests/testing-utils" } 30 | 31 | tokio.workspace = true 32 | -------------------------------------------------------------------------------- /crates/metrics/collectors/economic/src/error.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::ruint; 2 | use thiserror::Error; 3 | 4 | #[derive(Debug, Error)] 5 | pub enum CollectorMetricError { 6 | #[error("Collector metrics error ")] 7 | ElContractsError(#[from] eigen_client_elcontracts::error::ElContractsError), 8 | 9 | #[error("Operator is not registered")] 10 | OperatorNotRegistered, 11 | 12 | #[error("Collector metric error")] 13 | AvsRegistryError(#[from] eigen_client_avsregistry::error::AvsRegistryError), 14 | 15 | /// Parse Error 16 | #[error("Parse Error :{0}")] 17 | ParseError(#[from] ruint::ParseError), 18 | } 19 | -------------------------------------------------------------------------------- /crates/metrics/collectors/rpc_calls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-metrics-collectors-rpc-calls" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "eigenlayer rpc calls metrics" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | eigen-logging.workspace = true 18 | metrics.workspace = true 19 | -------------------------------------------------------------------------------- /crates/metrics/collectors/rpc_calls/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | use eigen_logging::logger::SharedLogger; 7 | use metrics::{describe_counter, describe_histogram, Key, Label}; 8 | 9 | /// RpcCallsMetrics 10 | #[derive(Debug)] 11 | pub struct RpcCallsMetrics { 12 | logger: SharedLogger, 13 | } 14 | 15 | impl RpcCallsMetrics { 16 | pub fn new(logger: SharedLogger) -> Self { 17 | describe_histogram!( 18 | "eigen_rpc_request_duration_seconds", 19 | "Duration of json-rpc in seconds from Ethereum Execution client " 20 | ); 21 | describe_counter!( 22 | "eigen_rpc_request_total", 23 | "Total of json-rpc requests from Ethereum Execution client " 24 | ); 25 | 26 | Self { logger } 27 | } 28 | 29 | /// set_rpc_request_duration_seconds 30 | pub fn set_rpc_request_duration_seconds( 31 | &self, 32 | method: &str, 33 | client_version: &str, 34 | duration: f64, 35 | ) { 36 | let key = Key::from_parts( 37 | "eigen_rpc_request_duration_seconds", 38 | vec![ 39 | Label::new("method ", method.to_string()), 40 | Label::new("client_version", client_version.to_string()), 41 | ], 42 | ); 43 | 44 | metrics::histogram!(key.to_string()).record(duration); 45 | self.logger.debug( 46 | "set rpc requet duration seconds , methods : {} , client_version: {}, duration: {} ", 47 | "eigen-metrics-collectors-rpc-calls.set_rpc_request_duration_seconds", 48 | ); 49 | } 50 | 51 | /// set_rpc_request_total 52 | pub fn set_rpc_request_total( 53 | &self, 54 | method: &str, 55 | client_version: &str, 56 | rpc_request_total: u64, 57 | ) { 58 | let key = Key::from_parts( 59 | "eigen_rpc_request_total", 60 | vec![ 61 | Label::new("method", method.to_string()), 62 | Label::new("client_version", client_version.to_string()), 63 | ], 64 | ); 65 | 66 | metrics::counter!(key.to_string()).absolute(rpc_request_total); 67 | self.logger.debug( 68 | "set rpc request total ", 69 | "eigen-metrics-collectors-rpc-calls.set_rpc_request_total", 70 | ); 71 | } 72 | 73 | pub fn logger(&self) -> &SharedLogger { 74 | &self.logger 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /crates/metrics/src/eigenmetrics.rs: -------------------------------------------------------------------------------- 1 | use eigen_logging::logger::SharedLogger; 2 | use metrics::{describe_gauge, gauge}; 3 | use std::fmt::Debug; 4 | 5 | // TODO(supernova) : feeearnedtotal is not turned on yet,so not implemented yet 6 | // https://github.com/Layr-Labs/eigensdk-go/blob/67787e959b727b115628a34e796df3a9ef42f646/metrics/eigenmetrics.go#L23 7 | #[derive(Debug)] 8 | pub struct EigenPerformanceMetrics { 9 | logger: SharedLogger, 10 | } 11 | 12 | impl EigenPerformanceMetrics { 13 | /// TODO(supernova): fee_earned_total is not yet implemented . As its not yet turned on 14 | /// The performance metric is a score between 0 and 100 and each developer can define their own way of calculating the score. 15 | /// The score is calculated based on the performance of the AVS Node and the performance of the backing services. 16 | pub fn new(logger: SharedLogger) -> Self { 17 | describe_gauge!("eigen_performance_score", "A gauge with performance score"); 18 | gauge!("eigen_performance_score").set(100_f64); 19 | Self { logger } 20 | } 21 | 22 | pub fn set_performance_score(&self, score: f64) { 23 | self.logger.debug( 24 | &format!("set performance score , new score {}", score), 25 | "eigen-metrics.set_performance_score", 26 | ); 27 | gauge!("eigen_performance_score").set(score); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/metrics/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | 7 | pub mod eigenmetrics; 8 | pub mod prometheus; 9 | -------------------------------------------------------------------------------- /crates/nodeapi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-nodeapi" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | license-file.workspace = true 8 | description = "eigenlayer nodeapi implementation" 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | serde_json.workspace =true 18 | ntex = { version = "2.0", features = ["tokio"] } 19 | serde.workspace = true 20 | tracing.workspace = true 21 | thiserror.workspace = true 22 | 23 | [dev-dependencies] 24 | reqwest.workspace = true 25 | tokio.workspace = true 26 | -------------------------------------------------------------------------------- /crates/nodeapi/src/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum NodeApiError { 5 | /// Service id not found 6 | #[error("Service with id {0} not found")] 7 | ServiceIdNotFound(String), 8 | 9 | /// Internal server error 10 | #[error("Internal server error")] 11 | InternalServerError, 12 | } 13 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 2 | CONTRACTS_REGISTRY_ADDR=0x5FbDB2315678afecb367f032d93F642f64180aa3 -------------------------------------------------------------------------------- /crates/operator_sets_contracts/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | 16 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/anvil/deploy-avs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export RPC_URL=http://localhost:8546 4 | export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 5 | export DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 6 | export CONTRACTS_REGISTRY_ADDR=0x5FbDB2315678afecb367f032d93F642f64180aa3 7 | 8 | # cd to the directory of this script so that this can be run from anywhere 9 | parent_path=$( 10 | cd "$(dirname "${BASH_SOURCE[0]}")" 11 | pwd -P 12 | ) 13 | cd "$parent_path" 14 | 15 | cd ../ 16 | forge script script/DeployMockAvs.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow -vvv 17 | 18 | forge script script/ContractsRegistry.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow 19 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/anvil/deploy-eigenlayer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export RPC_URL=http://localhost:8546 4 | export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 5 | 6 | # Navigate to the script directory 7 | parent_path=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) 8 | cd "$parent_path" 9 | 10 | root_dir=$(realpath "$parent_path/../..") 11 | 12 | # Deploy Contracts 13 | cd "$root_dir/operator_sets_contracts" 14 | forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast 15 | forge script script/DeployEigenLayerCore.s.sol:DeployEigenlayerCore --rpc-url $RPC_URL --broadcast --slow -vvv 16 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/anvil/dump-state.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Enable the script to exit immediately if a command exits with a non-zero status 4 | set -o errexit -o nounset -o pipefail 5 | 6 | # Navigate to the script directory 7 | parent_path=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P) 8 | cd "$parent_path" 9 | 10 | root_dir=$(realpath "$parent_path/../..") 11 | 12 | set -a 13 | source $parent_path/utils.sh 14 | # we overwrite some variables here because should always deploy to anvil (localhost) 15 | RPC_URL=http://localhost:8545 16 | DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 17 | set +a 18 | 19 | 20 | # CHAIN_ID=$(cast chain-id --rpc-url $RPC_URL) 21 | 22 | # # start an empty anvil chain in the background and dump its state to a json file upon exit 23 | start_anvil_docker "" $parent_path/operatorset_contracts_deployed_anvil_state 24 | 25 | # Deploy Contracts 26 | cd "$root_dir/operator_sets_contracts" 27 | forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast 28 | forge script script/DeployEigenLayerCore.s.sol:DeployEigenlayerCore --rpc-url $RPC_URL --broadcast --slow -vvv 29 | 30 | cd "$root_dir/operator_sets_contracts" 31 | forge script script/DeployMockAvs.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow -vvv 32 | forge script script/ContractsRegistry.s.sol --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast --slow 33 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/anvil/start-anvil-chain-with-el-and-avs-deployed.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RPC_URL=http://localhost:8545 4 | 5 | # cd to the directory of this script so that this can be run from anywhere 6 | parent_path=$( 7 | cd "$(dirname "${BASH_SOURCE[0]}")" 8 | pwd -P 9 | ) 10 | cd "$parent_path" 11 | 12 | set -a 13 | source ./utils.sh 14 | set +a 15 | 16 | cleanup() { 17 | echo "Executing cleanup function..." 18 | set +e 19 | docker rm -f anvil 20 | exit_status=$? 21 | if [ $exit_status -ne 0 ]; then 22 | echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status" 23 | fi 24 | } 25 | trap 'cleanup $LINENO "$BASH_COMMAND"' EXIT 26 | 27 | # start an anvil instance that has eigenlayer contracts deployed 28 | start_anvil_docker $parent_path/operatorset_contracts_deployed_anvil_state "" 29 | 30 | docker attach anvil 31 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/anvil/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FOUNDRY_IMAGE=ghcr.io/foundry-rs/foundry:stable 4 | 5 | set -e -o nounset 6 | 7 | parent_path=$( 8 | cd "$(dirname "${BASH_SOURCE[0]}")" 9 | pwd -P 10 | ) 11 | 12 | 13 | clean_up() { 14 | # Check if the exit status is non-zero 15 | exit_status=$? 16 | if [ $exit_status -ne 0 ]; then 17 | echo "Script exited due to set -e on line $1 with command '$2'. Exit status: $exit_status" 18 | fi 19 | } 20 | # Use trap to call the clean_up function when the script exits 21 | trap 'clean_up $LINENO "$BASH_COMMAND"' ERR 22 | 23 | # start_anvil_docker $LOAD_STATE_FILE $DUMP_STATE_FILE 24 | # this function will also take care of stopping the anvil container when the script exits 25 | start_anvil_docker() { 26 | LOAD_STATE_FILE=$1 27 | DUMP_STATE_FILE=$2 28 | LOAD_STATE_VOLUME_DOCKER_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "-v $LOAD_STATE_FILE:/load-state.json") 29 | DUMP_STATE_VOLUME_DOCKER_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "-v $DUMP_STATE_FILE:/dump-state.json") 30 | LOAD_STATE_ANVIL_ARG=$([[ -z $LOAD_STATE_FILE ]] && echo "" || echo "--load-state /load-state.json") 31 | DUMP_STATE_ANVIL_ARG=$([[ -z $DUMP_STATE_FILE ]] && echo "" || echo "--dump-state /dump-state.json") 32 | 33 | trap 'docker stop anvil 2>/dev/null || true' EXIT 34 | docker run --rm -d --name anvil -p 8545:8545 $LOAD_STATE_VOLUME_DOCKER_ARG $DUMP_STATE_VOLUME_DOCKER_ARG \ 35 | --entrypoint anvil \ 36 | $FOUNDRY_IMAGE \ 37 | $LOAD_STATE_ANVIL_ARG $DUMP_STATE_ANVIL_ARG --host 0.0.0.0 \ 38 | --timestamp 0 39 | sleep 2 40 | } 41 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | fs_permissions = [{ access = "read-write", path = "./" }] 6 | solc = "0.8.27" 7 | via-ir = true 8 | optimizer = true 9 | 10 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config 11 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/mock_avs_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "num_quorums": 1, 3 | "operator_params": [10000,15000,100], 4 | "operator_addr": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "operator_2_addr": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", 6 | "contracts_registry_addr": "0x5FbDB2315678afecb367f032d93F642f64180aa3" 7 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/remappings.txt: -------------------------------------------------------------------------------- 1 | @eigenlayer/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/ 2 | @eigenlayer-middleware/=lib/eigenlayer-middleware/ 3 | @openzeppelin/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/ 4 | forge-std/=lib/forge-std/src/ 5 | eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/ 6 | @openzeppelin-upgrades-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/ 7 | @openzeppelin-upgrades/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/ 8 | @openzeppelin-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/ 9 | ds-test/=lib/eigenlayer-middleware/lib/ds-test/src/ 10 | eigenlayer-middleware/=lib/eigenlayer-middleware/ 11 | erc4626-tests/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/lib/erc4626-tests/ 12 | openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/ 13 | openzeppelin-contracts-upgradeable/=lib/eigenlayer-middleware/lib/openzeppelin-contracts-upgradeable/ 14 | openzeppelin-contracts-v4.9.0/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/ 15 | openzeppelin-contracts/=lib/eigenlayer-middleware/lib/openzeppelin-contracts/ 16 | openzeppelin/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/ 17 | zeus-templates/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/zeus-templates/src/ 18 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/ContractsRegistry.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | 6 | import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; 7 | import {MockAvsDeploymentLib} from "./utils/MockAvsDeploymentLib.sol"; 8 | import {WriteToContractsRegistryLib} from "./utils/WriteToContractsRegistryLib.sol"; 9 | 10 | contract ContractsRegistry is Script { 11 | address private deployer; 12 | address public CONTRACT_REGISTRY; 13 | CoreDeploymentLib.DeploymentData coreConfigData; 14 | MockAvsDeploymentLib.DeploymentData avsConfigData; 15 | 16 | function setUp() public { 17 | deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); 18 | vm.label(deployer, "Deployer"); 19 | CONTRACT_REGISTRY = vm.envAddress("CONTRACTS_REGISTRY_ADDR"); 20 | 21 | coreConfigData = CoreDeploymentLib.readDeploymentJson("script/deployments/core/", "31337.json"); 22 | avsConfigData = MockAvsDeploymentLib.readDeploymentJson("script/deployments/mock-avs/", block.chainid); 23 | } 24 | 25 | function run() external { 26 | vm.startBroadcast(deployer); 27 | if (block.chainid == 31337 || block.chainid == 1337) { 28 | WriteToContractsRegistryLib.writeCoreContractsToRegistry(CONTRACT_REGISTRY, coreConfigData); 29 | WriteToContractsRegistryLib.writeMockAvsContractsToRegistry(CONTRACT_REGISTRY, avsConfigData); 30 | } 31 | vm.stopBroadcast(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/DeployEigenLayerCore.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.12; 3 | 4 | import {Script} from "forge-std/Script.sol"; 5 | import {CoreDeploymentLib} from "./utils/CoreDeploymentLib.sol"; 6 | import {UpgradeableProxyLib} from "./utils/UpgradeableProxyLib.sol"; 7 | import {console2} from "forge-std/console2.sol"; 8 | 9 | contract DeployEigenlayerCore is Script { 10 | using CoreDeploymentLib for *; 11 | using UpgradeableProxyLib for address; 12 | 13 | address internal _deployer; 14 | address internal _proxyAdmin; 15 | CoreDeploymentLib.DeploymentData internal _deploymentData; 16 | CoreDeploymentLib.DeploymentConfigData internal _configData; 17 | 18 | function setUp() public virtual { 19 | _deployer = vm.rememberKey(vm.envUint("PRIVATE_KEY")); 20 | vm.label(_deployer, "Deployer"); 21 | } 22 | 23 | function run() external { 24 | vm.startBroadcast(_deployer); 25 | _proxyAdmin = UpgradeableProxyLib.deployProxyAdmin(); 26 | _deploymentData = CoreDeploymentLib.deployContracts(_deployer, _proxyAdmin, _configData); 27 | vm.stopBroadcast(); 28 | string memory deploymentPath = "script/deployments/core/"; 29 | CoreDeploymentLib.writeDeploymentJson(deploymentPath, block.chainid, _deploymentData); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/deployments/core/31337.json: -------------------------------------------------------------------------------- 1 | {"lastUpdate":{"timestamp":"78","block_number":"1"},"addresses":{"proxyAdmin":"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512","delegation":"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9","delegationManagerImpl":"0xa85233c63b9ee964add6f2cffe00fd84eb32338f","avsDirectory":"0xb7f8bc63bbcad18155201308c8f3540b07f84f5e","avsDirectoryImpl":"0x7a2088a1bfc9d81c55368ae168c2c02570cb814f","strategyManager":"0xa513e6e4b8f2a923d98304ec87f64353c4d5c853","strategyManagerImpl":"0x09635f643e140090a9a8dcd712ed6285858cebef","eigenPodManager":"0x59b670e9fa9d0a427751af201d676719a970857b","strategyFactory":"0x3aa5ebb10dc797cac828524e59a333d0a371443c","rewardsCoordinator":"0x0dcd1bf9a1b36ce34237eeafef220932846bcd82","strategyBeacon":"0x1613beb3b2c4f22ee086b2b38c1476a3ce7f78e8","pauserRegistry":"0x9a9f2ccfde556a7e9ff0848998aa4a0cfd8863ae","allocationManager":"0x8a791620dd6260079bf849dc5567adc3f2fdc318","permissionController":"0x322813fd9a801c5507c9de605d63cea4f2ce6c44"}} -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/deployments/core/m2/31337.json: -------------------------------------------------------------------------------- 1 | {"lastUpdate":{"timestamp":"1738245589","block_number":"1"},"addresses":{"proxyAdmin":"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512","delegation":"0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9","delegationManagerImpl":"0x68b1d87f95878fe05b998f19b66f4baba5de1aed","avsDirectory":"0x5fc8d32690cc91d4c39d9d3abcbd16989f875707","avsDirectoryImpl":"0x3aa5ebb10dc797cac828524e59a333d0a371443c","strategyManager":"0xa513e6e4b8f2a923d98304ec87f64353c4d5c853","strategyManagerImpl":"0xc6e7df5e7b4f2a278906862b61205850344d4e7d","eigenPodManager":"0x8a791620dd6260079bf849dc5567adc3f2fdc318","eigenPodManagerImpl":"0x4ed7c70f96b99c776995fb64377f0d4ab3b0e1c1","strategyFactory":"0x9a9f2ccfde556a7e9ff0848998aa4a0cfd8863ae","rewardsCoordinator":"0xb7f8bc63bbcad18155201308c8f3540b07f84f5e","strategyBeacon":"0xc5a5c42992decbae36851359345fe25997f5c42d"}} -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/deployments/mock-avs/31337.json: -------------------------------------------------------------------------------- 1 | { 2 | "lastUpdate": { 3 | "timestamp": "99", 4 | "block_number": "45" 5 | }, 6 | "addresses": { 7 | "proxyAdmin": "0x5eb3bc0a489c5a8288765d2336659ebca68fcd00", 8 | "MockAvsServiceManager": "0xcd8a1c3ba11cf5ecfa6267617243239504a98d90", 9 | "MockAvsServiceManagerImpl": "0x36b58f5c1969b7b6591d752ea6f5486d069010ab", 10 | "registryCoordinator": "0x7bc06c482dead17c0e297afbc32f6e63d3846650", 11 | "blsapkRegistry": "0xfd471836031dc5108809d173a067e8486b9047a3", 12 | "indexRegistry": "0x1429859428c0abc9c2c47c8ee9fbaf82cfa0f20f", 13 | "stakeRegistry": "0x2bdcc0de6be1f7d2ee689a0342d76f52e8efaba3", 14 | "operatorStateRetriever": "0xb0d4afd8879ed9f52b28595d31b441d079b2ca07", 15 | "strategy": "0xec4cfde48eadca2bc63e94bb437bbeace1371bf3", 16 | "token": "0x36c02da8a0983159322a80ffe9f24b1acff8b570", 17 | "socketRegistry": "0x922d6956c99e12dfeb3224dea977d0939758a1fe", 18 | "tokenRewards": "0x809d550fca64d94bd9f66e60752a544199cfac3d" 19 | } 20 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/input/31337/ops_addresses.json: -------------------------------------------------------------------------------- 1 | { 2 | "communityMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 3 | "pauser": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 4 | "churner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 5 | "ejector": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 6 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/output/31337/eigenlayer_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "avsDirectory": "0x0165878A594ca255338adfa4d48449f69242Eb8F", 4 | "avsDirectoryImplementation": "0x9A676e781A523b5d0C0e43731313A708CB607508", 5 | "baseStrategyImplementation": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f", 6 | "delayedWithdrawalRouter": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", 7 | "delayedWithdrawalRouterImplementation": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE", 8 | "delegation": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", 9 | "delegationImplementation": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", 10 | "eigenLayerPauserReg": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", 11 | "eigenLayerProxyAdmin": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", 12 | "eigenPodBeacon": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", 13 | "eigenPodImplementation": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", 14 | "eigenPodManager": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", 15 | "eigenPodManagerImplementation": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", 16 | "emptyContract": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", 17 | "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", 18 | "slasherImplementation": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", 19 | "strategies": "", 20 | "strategyManager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", 21 | "strategyManagerImplementation": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" 22 | }, 23 | "chainInfo": { 24 | "chainId": 31337, 25 | "deploymentBlock": 1 26 | }, 27 | "parameters": { 28 | "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 29 | "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 30 | } 31 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/output/31337/mockAvs_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "mockAvsServiceManager": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", 4 | "mockAvsServiceManagerImplementation": "0x0000000000000000000000000000000000000000", 5 | "operatorStateRetriever": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", 6 | "proxyAdmin": "0xc5a5C42992dECbae36851359345FE25997F5C42d", 7 | "registryCoordinator": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690", 8 | "registryCoordinatorImplementation": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" 9 | } 10 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/output/31337/token_and_strategy_deployment_output.json: -------------------------------------------------------------------------------- 1 | { 2 | "addresses": { 3 | "erc20mock": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1", 4 | "erc20mockstrategy": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0" 5 | } 6 | } -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/utils/FundOperator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {MockERC20} from "../../src/MockERC20.sol"; 5 | 6 | library FundOperator { 7 | function fundOperator(address erc20, address operator, uint256 amount) internal { 8 | MockERC20 erc20Contract = MockERC20(erc20); 9 | 10 | erc20Contract.mint(operator, amount); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/utils/UpgradeableProxyLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Vm} from "forge-std/Vm.sol"; 5 | import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; 6 | import { 7 | TransparentUpgradeableProxy, 8 | ITransparentUpgradeableProxy 9 | } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 10 | import {EmptyContract} from "@eigenlayer/test/mocks/EmptyContract.sol"; 11 | 12 | library UpgradeableProxyLib { 13 | bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 14 | bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 15 | 16 | Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); 17 | 18 | function deployProxyAdmin() internal returns (address) { 19 | return address(new ProxyAdmin()); 20 | } 21 | 22 | function setUpEmptyProxy(address admin) internal returns (address) { 23 | address emptyContract = address(new EmptyContract()); 24 | return address(new TransparentUpgradeableProxy(emptyContract, admin, "")); 25 | } 26 | 27 | function upgrade(address proxy, address impl) internal { 28 | ProxyAdmin admin = getProxyAdmin(proxy); 29 | admin.upgrade(ITransparentUpgradeableProxy(payable(proxy)), impl); 30 | } 31 | 32 | function upgradeAndCall(address proxy, address impl, bytes memory initData) internal { 33 | ProxyAdmin admin = getProxyAdmin(proxy); 34 | admin.upgradeAndCall(ITransparentUpgradeableProxy(payable(proxy)), impl, initData); 35 | } 36 | 37 | function getImplementation(address proxy) internal view returns (address) { 38 | bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); 39 | return address(uint160(uint256(value))); 40 | } 41 | 42 | function getProxyAdmin(address proxy) internal view returns (ProxyAdmin) { 43 | bytes32 value = vm.load(proxy, ADMIN_SLOT); 44 | return ProxyAdmin(address(uint160(uint256(value)))); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/script/utils/WriteToContractsRegistryLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {Vm} from "forge-std/Vm.sol"; 5 | import {ContractsRegistry} from "../../src/ContractsRegistry.sol"; 6 | import {CoreDeploymentLib} from "./CoreDeploymentLib.sol"; 7 | import {MockAvsDeploymentLib} from "./MockAvsDeploymentLib.sol"; 8 | 9 | library WriteToContractsRegistryLib { 10 | function writeCoreContractsToRegistry( 11 | address contractsRegistryAddr, 12 | CoreDeploymentLib.DeploymentData memory deploymentdata 13 | ) internal { 14 | ContractsRegistry contractsRegistry = ContractsRegistry(contractsRegistryAddr); 15 | contractsRegistry.registerContract("delegationManager", address(deploymentdata.delegationManager)); 16 | contractsRegistry.registerContract("strategyManager", address(deploymentdata.strategyManager)); 17 | contractsRegistry.registerContract("avsDirectory", address(deploymentdata.avsDirectory)); 18 | contractsRegistry.registerContract("rewardsCoordinator", address(deploymentdata.rewardsCoordinator)); 19 | contractsRegistry.registerContract("pauserRegistry", address(deploymentdata.pauserRegistry)); 20 | contractsRegistry.registerContract("allocationManager", deploymentdata.allocationManager); 21 | contractsRegistry.registerContract("permissionController", deploymentdata.permissionController); 22 | } 23 | 24 | function writeMockAvsContractsToRegistry( 25 | address contractsRegistryAddr, 26 | MockAvsDeploymentLib.DeploymentData memory deploymentdata 27 | ) internal { 28 | ContractsRegistry contractsRegistry = ContractsRegistry(contractsRegistryAddr); 29 | 30 | contractsRegistry.registerContract("erc20MockStrategy", address(deploymentdata.strategy)); 31 | contractsRegistry.registerContract("mockAvsServiceManager", deploymentdata.mockAvsServiceManager); 32 | contractsRegistry.registerContract("mockAvsRegistryCoordinator", address(deploymentdata.registryCoordinator)); 33 | contractsRegistry.registerContract( 34 | "mockAvsOperatorStateRetriever", address(deploymentdata.operatorStateRetriever) 35 | ); 36 | contractsRegistry.registerContract("blsApkRegistry", address(deploymentdata.blsapkRegistry)); 37 | contractsRegistry.registerContract("socketRegistry", address(deploymentdata.socketRegistry)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/src/ContractsRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.20; 3 | 4 | // ContractsRegistry store the address of all the contracts deployed for eigenlayer and avss 5 | // It is used for testing purpose only, so that we can retrieve the addresses without having to store them in a json file 6 | // This way integration testing against an anvil chain (started with a saved db) is self-contained 7 | // ASSUMPTION: right now we deploy this contract as the first deployment (nonce=0) using the first anvil address 8 | // 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 to make sure it's always at the address 0x5FbDB2315678afecb367f032d93F642f64180aa3 9 | // forge create src/ContractsRegistry.sol:ContractsRegistry --rpc-url $RPC_URL --private-key $PRIVATE_KEY 10 | contract ContractsRegistry { 11 | mapping(string => address) public contracts; 12 | mapping(uint256 => string) public contractNames; 13 | uint256 public contractCount; 14 | 15 | function registerContract(string memory name, address _contract) public { 16 | // we treat redeploys as a bug since this is only meant to be used for testing. 17 | // If new contracts need to be deployed just start from a fresh anvil state. 18 | require(contracts[name] == address(0), "contract already registered"); 19 | contracts[name] = _contract; 20 | contractNames[contractCount] = name; 21 | contractCount++; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/src/MockAvsServiceManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.12; 3 | 4 | import {IAVSDirectory} from "@eigenlayer/contracts/interfaces/IAVSDirectory.sol"; 5 | import {IRewardsCoordinator} from "@eigenlayer/contracts/interfaces/IRewardsCoordinator.sol"; 6 | import {IBLSSignatureChecker} from "@eigenlayer-middleware/src/interfaces/IBLSSignatureChecker.sol"; 7 | import {IRegistryCoordinator} from "@eigenlayer-middleware/src/interfaces/IRegistryCoordinator.sol"; 8 | import {ServiceManagerBase} from "@eigenlayer-middleware/src/ServiceManagerBase.sol"; 9 | import {BLSSignatureChecker} from "@eigenlayer-middleware/src/BLSSignatureChecker.sol"; 10 | import {IStakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; 11 | import {ISlashingRegistryCoordinator} from "@eigenlayer-middleware/src/interfaces/ISlashingRegistryCoordinator.sol"; 12 | import {IPermissionController} from "@eigenlayer/contracts/permissions/PermissionController.sol"; 13 | import {IAllocationManager} from "@eigenlayer/contracts/interfaces/IAllocationManager.sol"; 14 | import {BLSSignatureChecker} from "@eigenlayer-middleware/src/BLSSignatureChecker.sol"; 15 | 16 | contract MockAvsServiceManager is ServiceManagerBase, BLSSignatureChecker { 17 | constructor( 18 | IAVSDirectory _avsDirectory, 19 | ISlashingRegistryCoordinator _slashingRegCoordinator, 20 | IStakeRegistry _stakeRegistry, 21 | address rewards_coordinator, 22 | IPermissionController _permissionController, 23 | IAllocationManager _allocationManager 24 | ) 25 | ServiceManagerBase( 26 | _avsDirectory, 27 | IRewardsCoordinator(rewards_coordinator), 28 | _slashingRegCoordinator, 29 | _stakeRegistry, 30 | _permissionController, 31 | _allocationManager 32 | ) 33 | BLSSignatureChecker(_slashingRegCoordinator) 34 | {} 35 | 36 | function initialize(address _initialOwner) external initializer { 37 | // TODO: setting _rewardsInitializer to be _initialOwner for now. 38 | // TODO: setting _slasher to be _initialOwner for now. 39 | __ServiceManagerBase_init(_initialOwner, _initialOwner); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /crates/operator_sets_contracts/src/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.20; 3 | 4 | import {ERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockERC20 is ERC20("Mock Token", "MCK") { 7 | function mint(address account, uint256 amount) public { 8 | _mint(account, amount); 9 | } 10 | 11 | /// WARNING: Vulnerable, bypasses allowance check. Do not use in production! 12 | function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { 13 | super._transfer(from, to, amount); 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/services/README.md: -------------------------------------------------------------------------------- 1 | # SDK services 2 | 3 | The eigensdk provides 3 services, namely : 4 | 5 | - **OperatorInfoServiceInMemory** 6 | - The `eigen-services-operatorsinfo` crate provides functionalities to manage and track operator information using an in-memory database. It supports querying past operato registrations, subscribing to new operator registration events, and retrieving operator information efficiently. 7 | - `eigen-services-avsregistry` 8 | - The `eigen-services-avsregistry` crate is a wrapper around AvsRegistryReader. 9 | -------------------------------------------------------------------------------- /crates/services/avsregistry/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-services-avsregistry" 3 | description = "Eigen Layer SDK services avsregistry" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | ark-bn254.workspace = true 20 | ark-ec.workspace = true 21 | async-trait.workspace = true 22 | eigen-client-avsregistry.workspace = true 23 | eigen-crypto-bls.workspace = true 24 | eigen-services-operatorsinfo.workspace = true 25 | eigen-types.workspace = true 26 | eigen-utils.workspace = true 27 | 28 | [dev-dependencies] 29 | # We don't use workspace due to: 30 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 31 | eigen-testing-utils = { path = "../../../tests/testing-utils" } 32 | 33 | hex.workspace = true 34 | tokio.workspace = true 35 | serde.workspace = true 36 | -------------------------------------------------------------------------------- /crates/services/avsregistry/README.md: -------------------------------------------------------------------------------- 1 | # Services AvsRegistry 2 | 3 | ## Example 4 | -------------------------------------------------------------------------------- /crates/services/bls_aggregation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-services-blsaggregation" 3 | description = "Eigen Layer SDK services blsaggregation" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | ark-bn254.workspace = true 20 | ark-ec.workspace = true 21 | eigen-client-avsregistry.workspace = true 22 | eigen-common.workspace = true 23 | eigen-crypto-bls.workspace = true 24 | eigen-crypto-bn254.workspace = true 25 | eigen-logging.workspace = true 26 | eigen-services-avsregistry.workspace = true 27 | eigen-types.workspace = true 28 | parking_lot.workspace = true 29 | thiserror.workspace = true 30 | tokio = { workspace = true, features = ["full"] } 31 | serde_json.workspace = true 32 | serde.workspace = true 33 | simple-mermaid = { version = "0.2.0", optional = true } 34 | 35 | [dev-dependencies] 36 | # We don't use workspace due to: 37 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 38 | eigen-testing-utils = { path = "../../../tests/testing-utils" } 39 | eigen-logging = { path = "../../logging" } 40 | eigen-utils = { path = "../../utils" } 41 | eigen-client-elcontracts = { path = "../../chainio/clients/elcontracts" } 42 | eigen-services-operatorsinfo = { path = "../../services/operatorsinfo" } 43 | 44 | serial_test = "3.1" 45 | sha2 = "0.10.8" 46 | testcontainers.workspace = true 47 | tokio-util = "0.7.11" 48 | 49 | # somehow required for doc-tests 50 | simple-mermaid = "0.2.0" 51 | 52 | [features] 53 | docs = ["simple-mermaid"] 54 | -------------------------------------------------------------------------------- /crates/services/bls_aggregation/README.md: -------------------------------------------------------------------------------- 1 | # BLS Aggregation Service 2 | 3 | Please check [lib.rs](https://github.com/Layr-Labs/eigensdk-rs/blob/dev/crates/services/bls_aggregation/src/lib.rs) for the full documentation. 4 | -------------------------------------------------------------------------------- /crates/services/bls_aggregation/diagram/sequence-bls.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | participant U as Aggregator 3 | participant SH as ServiceHandle 4 | participant AR as AggregateReceiver 5 | participant BLS as BlsAggregatorService 6 | 7 | note over U: The user creates the BLS Aggregator Service 8 | U->>BLS: new() 9 | note over U: The user start the service 10 | U->>BLS: start() 11 | 12 | note over BLS: Main loop is running in the background 13 | 14 | note over SH: ServiceHandle is returned when the service is started 15 | BLS->>SH: ServiceHandle 16 | 17 | note over AR: AggregateReceiver is returned when the service is started 18 | BLS->>AR: AggregateReceiver 19 | 20 | U->>SH: initialize_task() # REVIEW 21 | 22 | SH->>BLS: initialize_task() 23 | 24 | BLS->>BLS: single_task_aggregator() 25 | 26 | U->>SH: process_signature() # REVIEW 27 | 28 | SH->>BLS: process_signature() 29 | 30 | BLS->>BLS: verify_signature() 31 | 32 | BLS->>BLS: check_if_stake_thresholds_met() 33 | note over BLS: Threshold not reached yet 34 | 35 | U->>SH: process_signature() # REVIEW 36 | 37 | SH->>BLS: process_signature() 38 | 39 | BLS->>BLS: verify_signature() 40 | 41 | BLS->>BLS: check_if_stake_thresholds_met() 42 | note over BLS: Threshold reached 43 | 44 | BLS->>BLS: build_aggregated_response() 45 | 46 | BLS->>AR: send_aggregated_response() 47 | 48 | AR->>U: receive_aggregated_response() 49 | -------------------------------------------------------------------------------- /crates/services/bls_aggregation/src/bls_aggregation_service_error.rs: -------------------------------------------------------------------------------- 1 | use eigen_types::avs::SignatureVerificationError; 2 | use thiserror::Error; 3 | 4 | /// Possible errors raised in BLS aggregation 5 | #[derive(Error, Debug, Clone, PartialEq, Eq)] 6 | pub enum BlsAggregationServiceError { 7 | /// Task expired error 8 | #[error("task expired error")] 9 | TaskExpired, 10 | /// Task not found error 11 | #[error("task not found error")] 12 | TaskNotFound, 13 | /// Signature verification error. Wraps the error from the [`SignatureVerificationError`] enum. 14 | #[error("signature verification error")] 15 | SignatureVerificationError(SignatureVerificationError), 16 | /// Signature channel closed error 17 | #[error("signatures channel was closed, can't send signatures to aggregator")] 18 | SignaturesChannelClosed, 19 | /// AVS registry error 20 | #[error("Avs Registry Error")] 21 | RegistryError, 22 | /// Duplicate task index error 23 | #[error("duplicate task index error")] 24 | DuplicateTaskIndex, 25 | /// Sending to service error 26 | #[error("error sending to service")] 27 | SenderError, 28 | /// Receiving from service error 29 | #[error("error receiving from service")] 30 | ReceiverError, 31 | } 32 | -------------------------------------------------------------------------------- /crates/services/bls_aggregation/src/bls_aggregation_service_response.rs: -------------------------------------------------------------------------------- 1 | use eigen_crypto_bls::{BlsG1Point, BlsG2Point, Signature}; 2 | use eigen_types::avs::{TaskIndex, TaskResponseDigest}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// The response from the BLS aggregation service 6 | #[allow(unused)] 7 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 8 | pub struct BlsAggregationServiceResponse { 9 | pub task_index: TaskIndex, 10 | pub task_response_digest: TaskResponseDigest, 11 | pub non_signers_pub_keys_g1: Vec, 12 | pub quorum_apks_g1: Vec, 13 | pub signers_apk_g2: BlsG2Point, 14 | pub signers_agg_sig_g1: Signature, 15 | pub non_signer_quorum_bitmap_indices: Vec, 16 | pub quorum_apk_indices: Vec, 17 | pub total_stake_indices: Vec, 18 | pub non_signer_stake_indices: Vec>, 19 | } 20 | -------------------------------------------------------------------------------- /crates/services/operatorsinfo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-services-operatorsinfo" 3 | description = "Eigen Layer SDK services operatorsinfo" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | async-trait.workspace = true 20 | eigen-client-avsregistry.workspace = true 21 | eigen-common.workspace = true 22 | eigen-crypto-bls.workspace = true 23 | eigen-logging.workspace = true 24 | eigen-types.workspace = true 25 | eigen-utils.workspace = true 26 | futures-util.workspace = true 27 | tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } 28 | thiserror.workspace = true 29 | tokio-util = "0.7.11" 30 | futures.workspace = true 31 | eyre.workspace = true 32 | 33 | [dev-dependencies] 34 | # We don't use workspace due to: 35 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 36 | eigen-testing-utils = { path = "../../../tests/testing-utils" } 37 | eigen-logging = { path = "../../logging" } 38 | eigen-client-elcontracts = { path = "../../chainio/clients/elcontracts" } 39 | 40 | ark-bn254.workspace = true 41 | ark-std = { version = "0.4.0", default-features = false } 42 | ark-ff.workspace = true 43 | serial_test.workspace = true 44 | -------------------------------------------------------------------------------- /crates/services/operatorsinfo/README.md: -------------------------------------------------------------------------------- 1 | # Operators Info 2 | 3 | ## Example 4 | - [info-operator-service](https://github.com/Layr-Labs/eigensdk-rs/tree/main/examples/info-operator-service) -------------------------------------------------------------------------------- /crates/services/operatorsinfo/src/fake_operator_info.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::Address; 2 | use async_trait::async_trait; 3 | use eigen_crypto_bls::BlsKeyPair; 4 | use eigen_types::operator::{OperatorInfo, OperatorPubKeys}; 5 | 6 | use crate::{operator_info::OperatorInfoService, operatorsinfo_inmemory::OperatorInfoServiceError}; 7 | 8 | /// A fake implementation of the `OperatorInfoService` trait that can be used for testing or debug purposes. 9 | pub struct FakeOperatorInfoService { 10 | pub operator_info: OperatorInfo, 11 | } 12 | 13 | impl FakeOperatorInfoService { 14 | pub fn new(pubkeys: BlsKeyPair, socket: Option) -> Self { 15 | Self { 16 | operator_info: OperatorInfo { 17 | pub_keys: Some(OperatorPubKeys::from(pubkeys)), 18 | socket, 19 | }, 20 | } 21 | } 22 | } 23 | 24 | #[async_trait] 25 | impl OperatorInfoService for FakeOperatorInfoService { 26 | async fn get_operator_info( 27 | &self, 28 | _address: Address, 29 | ) -> Result, OperatorInfoServiceError> { 30 | Ok(self.operator_info.pub_keys.clone()) 31 | } 32 | 33 | async fn get_operator_socket( 34 | &self, 35 | _address: Address, 36 | ) -> Result, OperatorInfoServiceError> { 37 | Ok(self.operator_info.socket.clone()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/services/operatorsinfo/src/operator_info.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::Address; 2 | use async_trait::async_trait; 3 | use eigen_types::operator::OperatorPubKeys; 4 | 5 | use crate::operatorsinfo_inmemory::OperatorInfoServiceError; 6 | 7 | #[async_trait] 8 | pub trait OperatorInfoService { 9 | /// Get the operator info from the operator id 10 | /// 11 | /// # Arguments 12 | /// 13 | /// * `operator_id` - The operator id 14 | /// 15 | /// # Returns 16 | /// 17 | /// The operator public keys 18 | async fn get_operator_info( 19 | &self, 20 | address: Address, 21 | ) -> Result, OperatorInfoServiceError>; 22 | 23 | /// Get the operator socket from the operator id 24 | /// 25 | /// # Arguments 26 | /// 27 | /// * `operator_id` - The operator id 28 | /// 29 | /// # Returns 30 | /// 31 | /// The operator socket 32 | async fn get_operator_socket( 33 | &self, 34 | address: Address, 35 | ) -> Result, OperatorInfoServiceError>; 36 | } 37 | -------------------------------------------------------------------------------- /crates/signer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-signer" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "aws,keystore,web3,private_key signers" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [dependencies] 17 | alloy.workspace = true 18 | async-trait.workspace = true 19 | aws-sdk-kms.workspace = true 20 | eth-keystore.workspace = true 21 | serde.workspace = true 22 | thiserror.workspace = true 23 | url.workspace = true 24 | 25 | [dev-dependencies] 26 | # We don't use workspace due to: 27 | # https://github.com/rust-lang/cargo/issues/4242#issuecomment-2578428685 28 | eigen-testing-utils = { path = "../../tests/testing-utils" } 29 | 30 | aws-config.workspace = true 31 | testcontainers.workspace = true 32 | tokio.workspace = true 33 | -------------------------------------------------------------------------------- /crates/signer/README.md: -------------------------------------------------------------------------------- 1 | # Eigen Signer 2 | 3 | The `eigen-signer` crates provides utilities for creating and managing different types of signers for Ethereum transactions. 4 | This includes Private Key signers, keystore signers, AWS KMS-based signers and Web3Signer. 5 | 6 | ## Example 7 | -------------------------------------------------------------------------------- /crates/signer/mockdata/dummy.key.json: -------------------------------------------------------------------------------- 1 | { 2 | "crypto": { 3 | "cipher": "aes-128-ctr", 4 | "cipherparams": { 5 | "iv": "6087dab2f9fdbbfaddc31a909735c1e6" 6 | }, 7 | "ciphertext": "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", 8 | "kdf": "pbkdf2", 9 | "kdfparams": { 10 | "c": 262144, 11 | "dklen": 32, 12 | "prf": "hmac-sha256", 13 | "salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd" 14 | }, 15 | "mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2" 16 | }, 17 | "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", 18 | "version": 3 19 | } 20 | -------------------------------------------------------------------------------- /crates/signer/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | 6 | pub mod signer; 7 | pub mod web3_signer; 8 | -------------------------------------------------------------------------------- /crates/signer/src/web3_signer.rs: -------------------------------------------------------------------------------- 1 | use alloy::consensus::{transaction::RlpEcdsaDecodableTx, SignableTransaction, TxLegacy}; 2 | use alloy::network::TxSigner; 3 | use alloy::primitives::{Address, Bytes, TxKind, U256}; 4 | use alloy::rpc::client::{ClientBuilder, ReqwestClient, RpcCall}; 5 | use alloy::signers::Signature; 6 | use async_trait::async_trait; 7 | use serde::Serialize; 8 | use url::Url; 9 | 10 | /// A signer that sends an RPC request to sign a transaction remotely 11 | /// Implements `eth_signTransaction` method of Consensys Web3 Signer 12 | /// Reference: 13 | #[derive(Debug)] 14 | pub struct Web3Signer { 15 | /// Client used to send an RPC request 16 | pub client: ReqwestClient, 17 | /// Address of the account that intends to sign a transaction. 18 | /// It must match the `from` field in the transaction. 19 | pub address: Address, 20 | } 21 | 22 | /// Parameters for the `eth_signTransaction` method 23 | #[derive(Serialize, Clone, Debug)] 24 | #[serde(rename_all = "camelCase")] 25 | struct SignTransactionParams { 26 | from: String, 27 | to: TxKind, 28 | value: U256, 29 | gas: String, 30 | #[serde(skip_serializing_if = "Option::is_none")] 31 | gas_price: Option, 32 | nonce: String, 33 | data: String, 34 | } 35 | 36 | impl Web3Signer { 37 | pub fn new(address: Address, url: Url) -> Self { 38 | Web3Signer { 39 | client: ClientBuilder::default().http(url), 40 | address, 41 | } 42 | } 43 | } 44 | 45 | #[async_trait] 46 | impl TxSigner for Web3Signer { 47 | fn address(&self) -> Address { 48 | self.address 49 | } 50 | 51 | async fn sign_transaction( 52 | &self, 53 | tx: &mut dyn SignableTransaction, 54 | ) -> alloy::signers::Result { 55 | let params = SignTransactionParams { 56 | from: self.address.to_string(), 57 | to: tx.to().into(), 58 | value: tx.value(), 59 | gas: format!("0x{:x}", tx.gas_limit()), 60 | gas_price: tx.gas_price().map(|price| format!("0x{:x}", price)), 61 | nonce: format!("0x{:x}", tx.nonce()), 62 | data: Bytes::copy_from_slice(tx.input()).to_string(), 63 | }; 64 | 65 | let request: RpcCall, Bytes> = 66 | self.client.request("eth_signTransaction", vec![params]); 67 | let rlp_encoded_signed_tx = request.await.map_err(alloy::signers::Error::other)?; 68 | 69 | let signed_tx = TxLegacy::rlp_decode_signed(&mut rlp_encoded_signed_tx.as_ref()) 70 | .map_err(alloy::signers::Error::other)?; 71 | 72 | Ok(*signed_tx.signature()) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /crates/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-types" 3 | description = "Eigen Layer types " 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | # docs.rs-specific configuration 12 | # see https://docs.rs/about/metadata 13 | [package.metadata.docs.rs] 14 | all-features = true 15 | rustdoc-args = ["--cfg", "docsrs"] 16 | 17 | [dependencies] 18 | alloy.workspace = true 19 | ark-ff.workspace = true 20 | eigen-crypto-bls.workspace = true 21 | eigen-utils.workspace = true 22 | ethers.workspace = true 23 | serde_json.workspace = true 24 | serde.workspace = true 25 | thiserror.workspace = true 26 | url.workspace = true 27 | 28 | num-bigint = "0.4.4" 29 | regex = "1" 30 | mime-sniffer = "0.1" 31 | 32 | [dev-dependencies] 33 | tokio.workspace = true 34 | ark-bn254.workspace = true 35 | -------------------------------------------------------------------------------- /crates/types/README.md: -------------------------------------------------------------------------------- 1 | # Eigen types 2 | 3 | This crate contains commonly used type definitions used across the SDK. 4 | -------------------------------------------------------------------------------- /crates/types/src/avs.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::FixedBytes; 2 | use thiserror::Error; 3 | pub type TaskIndex = u32; 4 | 5 | pub type TaskResponseDigest = FixedBytes<32>; 6 | 7 | /// Error type for signature verification 8 | #[derive(Error, Debug, Clone, PartialEq, Eq)] 9 | pub enum SignatureVerificationError { 10 | #[error("incorrect signature error")] 11 | IncorrectSignature, 12 | #[error("operator public key not found")] 13 | OperatorPublicKeyNotFound, 14 | #[error("operator not found")] 15 | OperatorNotFound, 16 | #[error("duplicate signature error")] 17 | DuplicateSignature, 18 | } 19 | -------------------------------------------------------------------------------- /crates/types/src/avs_state.rs: -------------------------------------------------------------------------------- 1 | use crate::operator::OperatorId; 2 | use crate::operator::OperatorInfo; 3 | use crate::operator::QuorumNum; 4 | use alloy::primitives::U256; 5 | use eigen_crypto_bls::BlsG1Point; 6 | use ethers::types::U64; 7 | use std::collections::HashMap; 8 | 9 | #[derive(Clone, Debug, PartialEq, Eq)] 10 | pub struct OperatorAvsState { 11 | pub operator_id: OperatorId, 12 | pub operator_info: OperatorInfo, 13 | pub stake_per_quorum: HashMap, 14 | pub block_num: U64, 15 | } 16 | 17 | #[derive(Debug, PartialEq, Eq)] 18 | pub struct QuorumAvsState { 19 | pub quorum_num: u8, 20 | pub total_stake: U256, 21 | pub agg_pub_key_g1: BlsG1Point, 22 | pub block_num: u64, 23 | } 24 | -------------------------------------------------------------------------------- /crates/types/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc( 2 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 3 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 4 | )] 5 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 6 | 7 | pub mod avs; 8 | pub mod avs_state; 9 | pub mod operator; 10 | pub mod operator_metadata; 11 | pub mod operator_pubkeys; 12 | pub mod test; 13 | -------------------------------------------------------------------------------- /crates/types/src/operator_pubkeys.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::U256; 2 | use ark_ff::PrimeField; 3 | use eigen_crypto_bls::{BlsG1Point, BlsG2Point, BlsKeyPair}; 4 | use eigen_utils::slashing::middleware::blsapkregistry::BN254::{G1Point, G2Point}; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq)] 7 | pub struct OperatorPubKeys { 8 | pub g1_pub_key: BlsG1Point, 9 | pub g2_pub_key: BlsG2Point, 10 | } 11 | 12 | impl From for OperatorPubKeys { 13 | fn from(keypair: BlsKeyPair) -> Self { 14 | Self { 15 | g1_pub_key: keypair.public_key(), 16 | g2_pub_key: keypair.public_key_g2(), 17 | } 18 | } 19 | } 20 | 21 | impl OperatorPubKeys { 22 | pub fn to_contract_public_keys(&self) -> (G1Point, G2Point) { 23 | let x = self.g1_pub_key.g1().x; 24 | let y = self.g1_pub_key.g1().y; 25 | let g1 = G1Point { 26 | X: U256::from_limbs(x.into_bigint().0), 27 | Y: U256::from_limbs(y.into_bigint().0), 28 | }; 29 | 30 | let x2 = self.g2_pub_key.g2().x; 31 | let y2 = self.g2_pub_key.g2().y; 32 | let g2 = G2Point { 33 | X: [ 34 | U256::from_limbs(x2.c0.into_bigint().0), 35 | U256::from_limbs(x2.c1.into_bigint().0), 36 | ], 37 | Y: [ 38 | U256::from_limbs(y2.c0.into_bigint().0), 39 | U256::from_limbs(y2.c1.into_bigint().0), 40 | ], 41 | }; 42 | (g1, g2) 43 | } 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::OperatorPubKeys; 49 | use alloy::primitives::U256; 50 | use ark_bn254::{G1Affine, G2Affine}; 51 | use eigen_crypto_bls::{BlsG1Point, BlsG2Point}; 52 | 53 | #[test] 54 | fn test_operator_pub_keys() { 55 | let g1_pub_key = BlsG1Point::new(G1Affine { 56 | x: ark_ff::Fp::from(1), 57 | y: ark_ff::Fp::from(1), 58 | infinity: false, 59 | }); 60 | 61 | let g2_pub_key = BlsG2Point::new(G2Affine { 62 | x: ark_ff::QuadExtField { 63 | c0: ark_ff::Fp::from(1), 64 | c1: ark_ff::Fp::from(1), 65 | }, 66 | y: ark_ff::QuadExtField { 67 | c0: ark_ff::Fp::from(1), 68 | c1: ark_ff::Fp::from(1), 69 | }, 70 | infinity: false, 71 | }); 72 | 73 | let operator1_pubkeys = OperatorPubKeys { 74 | g1_pub_key, 75 | g2_pub_key, 76 | }; 77 | let (g1, g2) = operator1_pubkeys.to_contract_public_keys(); 78 | 79 | // assert g1 80 | let x_contract = g1.X; 81 | let y_contract = g1.Y; 82 | assert_eq!(x_contract, U256::from(1)); 83 | assert_eq!(y_contract, U256::from(1)); 84 | 85 | // assert g2 86 | let x_g2_contract_0 = g2.X[0]; 87 | let x_g2_contract_1 = g2.X[1]; 88 | let y_g2_contract_0 = g2.Y[0]; 89 | let y_g2_contract_1 = g2.Y[1]; 90 | 91 | assert_eq!(x_g2_contract_0, U256::from(1)); 92 | assert_eq!(x_g2_contract_1, U256::from(1)); 93 | assert_eq!(y_g2_contract_0, U256::from(1)); 94 | assert_eq!(y_g2_contract_1, U256::from(1)); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /crates/types/src/test.rs: -------------------------------------------------------------------------------- 1 | use crate::operator::QuorumNum; 2 | use alloy::primitives::{B256, U256}; 3 | use eigen_crypto_bls::BlsKeyPair; 4 | use std::collections::HashMap; 5 | 6 | type StakeAmount = U256; 7 | 8 | /// Test operator for testing purposes 9 | #[derive(Clone)] 10 | pub struct TestOperator { 11 | pub operator_id: B256, 12 | pub stake_per_quorum: HashMap, 13 | pub bls_keypair: BlsKeyPair, 14 | } 15 | 16 | impl TestOperator { 17 | /// Get the BLS keypair of the operator 18 | pub fn get_bls_keypair(&self) -> &BlsKeyPair { 19 | &self.bls_keypair 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-utils" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | description = "publicly exportable alloy bindings and utilities" 8 | license-file.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [lib] 17 | doctest = false 18 | 19 | [dependencies] 20 | alloy.workspace = true 21 | regex = "1" 22 | reqwest.workspace = true 23 | -------------------------------------------------------------------------------- /crates/utils/src/common.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | use reqwest::Error; 3 | use std::sync::OnceLock; 4 | 5 | static ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; 6 | 7 | pub async fn get_url_content(url: &str) -> Result { 8 | let response = reqwest::get(url).await?; 9 | response.text().await 10 | } 11 | 12 | /// Checks if the given string is a valid Ethereum address and it is not the zero address. 13 | /// 14 | /// # Arguments 15 | /// 16 | /// * `address` - A string slice that holds the Ethereum address. 17 | /// 18 | /// # Returns 19 | /// 20 | /// * `true` if the address is a valid Ethereum address and it is not the zero address. 21 | /// * `false` otherwise. 22 | pub fn is_valid_ethereum_address(address: &str) -> bool { 23 | static REGEX: OnceLock = OnceLock::new(); 24 | REGEX 25 | .get_or_init(|| Regex::new(r"(?i)^0x[0-9a-f]{40}$").expect("regex is valid")) 26 | .is_match(address) 27 | && address != ZERO_ADDRESS 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | 33 | #[test] 34 | fn test_is_valid_ethereum_address() { 35 | let tests = vec![ 36 | ( 37 | "valid address", 38 | "0x1234567890abcdef1234567890abcdef12345678", 39 | true, 40 | ), 41 | ( 42 | "uppercase", 43 | "0x1234567890ABCDEF1234567890ABCDEF12345678", 44 | true, 45 | ), 46 | ( 47 | "too short", 48 | "0x1234567890abcdef1234567890abcdef123456", 49 | false, 50 | ), 51 | ( 52 | "missing 0x prefix", 53 | "001234567890abcdef1234567890abcdef12345678", 54 | false, 55 | ), 56 | ( 57 | "non-hex characters", 58 | "0x1234567890abcdef1234567890abcdef123ÅÅÅÅÅ", 59 | false, 60 | ), 61 | ]; 62 | 63 | for (name, address, expected) in tests { 64 | let result = super::is_valid_ethereum_address(address); 65 | assert_eq!(expected, result, "{name}"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /crates/utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This module exports generated bindings. 2 | pub mod common; 3 | pub mod rewardsv2; 4 | pub mod slashing; 5 | 6 | use crate::slashing::core::allocationmanager::AllocationManager::OperatorSet; 7 | use crate::slashing::core::irewardscoordinator::IRewardsCoordinator::OperatorSet as RewardsOperatorSet; 8 | use crate::slashing::middleware::registrycoordinator::IStakeRegistryTypes::StrategyParams as RegistryCoordiinatorStrategyParams; 9 | use crate::slashing::middleware::stakeregistry::IStakeRegistryTypes::StrategyParams; 10 | /// Converts [`OperatorSet`] to [`RewardsOperatorSet`] 11 | pub fn convert_allocation_operator_set_to_rewards_operator_set( 12 | operator_set: OperatorSet, 13 | ) -> RewardsOperatorSet { 14 | RewardsOperatorSet { 15 | avs: operator_set.avs, 16 | id: operator_set.id, 17 | } 18 | } 19 | 20 | pub fn convert_stake_registry_strategy_params_to_registry_coordinator_strategy_params( 21 | params: StrategyParams, 22 | ) -> RegistryCoordiinatorStrategyParams { 23 | RegistryCoordiinatorStrategyParams { 24 | strategy: params.strategy, 25 | multiplier: params.multiplier, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/utils/src/rewardsv2/core/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#avsdirectory; 7 | pub mod r#delegationmanager; 8 | pub mod r#eigenpod; 9 | pub mod r#eigenpodmanager; 10 | pub mod r#erc20; 11 | pub mod r#ieigenpod; 12 | pub mod r#ieigenpodmanager; 13 | pub mod r#irewardscoordinator; 14 | pub mod r#islasher; 15 | pub mod r#istrategy; 16 | pub mod r#rewardscoordinator; 17 | pub mod r#slasher; 18 | pub mod r#strategymanager; 19 | -------------------------------------------------------------------------------- /crates/utils/src/rewardsv2/middleware/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#blsapkregistry; 7 | pub mod r#ecdsaservicemanagerbase; 8 | pub mod r#ecdsastakeregistry; 9 | pub mod r#iblssignaturechecker; 10 | pub mod r#ierc20; 11 | pub mod r#indexregistry; 12 | pub mod r#operatorstateretriever; 13 | pub mod r#registrycoordinator; 14 | pub mod r#servicemanagerbase; 15 | pub mod r#stakeregistry; 16 | -------------------------------------------------------------------------------- /crates/utils/src/rewardsv2/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod core; 2 | pub mod middleware; 3 | pub mod sdk; 4 | -------------------------------------------------------------------------------- /crates/utils/src/rewardsv2/sdk/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#contractsregistry; 7 | pub mod r#mockavsservicemanager; 8 | pub mod r#mockerc20; 9 | -------------------------------------------------------------------------------- /crates/utils/src/slashing/core/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#allocationmanager; 7 | pub mod r#avsdirectory; 8 | pub mod r#delegationmanager; 9 | pub mod r#eigenpod; 10 | pub mod r#eigenpodmanager; 11 | pub mod r#ieigenpod; 12 | pub mod r#ieigenpodmanager; 13 | pub mod r#irewardscoordinator; 14 | pub mod r#istrategy; 15 | pub mod r#permissioncontroller; 16 | pub mod r#strategymanager; 17 | -------------------------------------------------------------------------------- /crates/utils/src/slashing/middleware/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#blsapkregistry; 7 | pub mod r#iblssignaturechecker; 8 | pub mod r#ierc20; 9 | pub mod r#indexregistry; 10 | pub mod r#islashingregistrycoordinator; 11 | pub mod r#operatorstateretriever; 12 | pub mod r#registrycoordinator; 13 | pub mod r#servicemanagerbase; 14 | pub mod r#slashingregistrycoordinator; 15 | pub mod r#socketregistry; 16 | pub mod r#stakeregistry; 17 | -------------------------------------------------------------------------------- /crates/utils/src/slashing/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod core; 2 | pub mod middleware; 3 | pub mod sdk; 4 | -------------------------------------------------------------------------------- /crates/utils/src/slashing/sdk/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, clippy::all, rustdoc::all)] 2 | //! This module contains the sol! generated bindings for solidity contracts. 3 | //! This is autogenerated code. 4 | //! Do not manually edit these files. 5 | //! These files may be overwritten by the codegen system at any time. 6 | pub mod r#contractsregistry; 7 | pub mod r#mockavsservicemanager; 8 | pub mod r#mockerc20; 9 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Examples demonstrating how to interact with Eigen layer contracts using eigen-rs crates. 4 | 5 | ## OperatorsInfo 6 | 7 | Get all the operators registered at a block range and get the operator info using an async channel. 8 | 9 | ```sh 10 | cargo run -p info-operator-service 11 | ``` 12 | 13 | ## AvsRegistry Read 14 | 15 | Example : Getting an operator address from the operator id 16 | 17 | ```sh 18 | cargo run --example get_operator_from_id 19 | ``` 20 | 21 | ## Anvil utils(This requires a local anvil instance running using docker ) 22 | 23 | Get EigenLayer contract addresses for local anvil testing . These are predetermined addresses that are stored in a mapping using these [scripts](https://github.com/Layr-Labs/eigensdk-rs/blob/d9b40d806b4939c64bb7d3df0f6f2a542499bd27/crates/contracts/script/DeployMockAvsRegistries.s.sol#L202). 24 | 25 | ```sh 26 | make start-anvil-chain-with-contracts-deployed 27 | make start-anvil 28 | cargo run --example get_contracts_from_registry 29 | ``` 30 | -------------------------------------------------------------------------------- /examples/anvil-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples-anvil-utils" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | license-file.workspace = true 8 | authors.workspace = true 9 | description = "anvil utilities examples" 10 | 11 | [lints] 12 | workspace = true 13 | 14 | [dependencies] 15 | alloy.workspace = true 16 | 17 | eigen-client-avsregistry.workspace = true 18 | eigen-testing-utils.workspace = true 19 | eyre.workspace = true 20 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } 21 | -------------------------------------------------------------------------------- /examples/anvil-utils/examples/get_contracts_from_registry.rs: -------------------------------------------------------------------------------- 1 | //! Example to showcase testing EL contracts using anvil 2 | use eigen_testing_utils::{ 3 | anvil::start_anvil_container, 4 | anvil_constants::{ 5 | get_delegation_manager_address, get_erc20_mock_strategy, 6 | get_operator_state_retriever_address, get_registry_coordinator_address, 7 | get_service_manager_address, get_strategy_manager_address, 8 | }, 9 | }; 10 | use eyre::Result; 11 | 12 | /// Calling ContractsRegistry contract to extract the El contract addresses on anvil 13 | #[tokio::main] 14 | pub async fn main() -> Result<()> { 15 | let (_container, http_endpoint, _ws_endpoint) = start_anvil_container().await; 16 | 17 | get_service_manager_address(http_endpoint.clone()).await; 18 | get_registry_coordinator_address(http_endpoint.clone()).await; 19 | get_operator_state_retriever_address(http_endpoint.clone()).await; 20 | get_delegation_manager_address(http_endpoint.clone()).await; 21 | get_strategy_manager_address(http_endpoint.clone()).await; 22 | get_erc20_mock_strategy(http_endpoint).await; 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /examples/avsregistry-read/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples-avsregistry-read" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | license-file.workspace = true 8 | authors.workspace = true 9 | description = "avsregistry read examples" 10 | 11 | [lints] 12 | workspace = true 13 | 14 | [dependencies] 15 | alloy.workspace = true 16 | eigen-client-avsregistry.workspace = true 17 | eigen-logging.workspace = true 18 | eigen-testing-utils.workspace = true 19 | eyre.workspace = true 20 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } 21 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/get_operator_from_id.rs: -------------------------------------------------------------------------------- 1 | //! get operator from id 2 | use alloy::primitives::FixedBytes; 3 | use eigen_client_avsregistry::reader::{AvsRegistryChainReader, AvsRegistryReader}; 4 | use eigen_logging::get_test_logger; 5 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 6 | use eyre::Result; 7 | use std::str::FromStr; 8 | 9 | #[tokio::main] 10 | #[allow(clippy::expect_used)] 11 | async fn main() -> Result<()> { 12 | let holesky_provider = "https://holesky.drpc.org"; 13 | 14 | let avs_registry = AvsRegistryChainReader::new( 15 | get_test_logger().clone(), 16 | REGISTRY_COORDINATOR, 17 | OPERATOR_STATE_RETRIEVER, 18 | holesky_provider.to_string(), 19 | ) 20 | .await 21 | .expect("failed to build avs registry chain reader"); 22 | let operator_id = 23 | FixedBytes::from_str("0xb31102e4cf235efcb84545cb656b039782755994835365d1cd11764ccb4f2fdd") 24 | .expect("invalid operator id "); 25 | let operator_address = avs_registry.get_operator_from_id(*operator_id).await?; 26 | 27 | println!("operator address is :{:?}", operator_address); 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/get_operator_id.rs: -------------------------------------------------------------------------------- 1 | //! get operator id 2 | use alloy::primitives::{address, Address}; 3 | use eigen_client_avsregistry::reader::AvsRegistryChainReader; 4 | use eigen_logging::get_test_logger; 5 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 6 | use eyre::Result; 7 | 8 | #[tokio::main] 9 | #[allow(clippy::expect_used)] 10 | async fn main() -> Result<()> { 11 | let holesky_provider = "https://holesky.drpc.org"; 12 | let avs_registry = AvsRegistryChainReader::new( 13 | get_test_logger().clone(), 14 | REGISTRY_COORDINATOR, 15 | OPERATOR_STATE_RETRIEVER, 16 | holesky_provider.to_string(), 17 | ) 18 | .await 19 | .expect("failed to build avs registry chain reader"); 20 | 21 | let operator: Address = address!("1D79000206BAFfaE662fFCdba1C2a6176d14dF48"); 22 | let operator_id = avs_registry.get_operator_id(operator).await?; 23 | 24 | println!("operator id is :{:?}", operator_id); 25 | Ok(()) 26 | } 27 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/get_operator_stake_in_quorums_of_operator_at_current_block.rs: -------------------------------------------------------------------------------- 1 | //! get operators stake in quorums at current block 2 | use alloy::primitives::FixedBytes; 3 | use eigen_client_avsregistry::reader::AvsRegistryChainReader; 4 | use eigen_logging::get_test_logger; 5 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 6 | use eyre::Result; 7 | use std::str::FromStr; 8 | 9 | #[tokio::main] 10 | #[allow(clippy::expect_used)] 11 | async fn main() -> Result<()> { 12 | let holesky_provider = "https://holesky.drpc.org"; 13 | let avs_registry = AvsRegistryChainReader::new( 14 | get_test_logger().clone(), 15 | REGISTRY_COORDINATOR, 16 | OPERATOR_STATE_RETRIEVER, 17 | holesky_provider.to_string(), 18 | ) 19 | .await 20 | .expect("failed to build avs registry chain reader"); 21 | let operators_state = avs_registry 22 | .get_operator_stake_in_quorums_of_operator_at_current_block( 23 | FixedBytes::from_str( 24 | "0x9bdde6f82077712c6e1c9aa8e7fca47529effb948faafa1fa21aebd343fc7fec", 25 | ) 26 | .expect("wrong operator id"), 27 | ) 28 | .await?; 29 | 30 | println!("operator state at current block is {:?}", operators_state); 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/get_operators_stake_in_quorums_at_block.rs: -------------------------------------------------------------------------------- 1 | //! get operators stake in quorums at block 2 | use alloy::primitives::{hex::FromHex, Bytes}; 3 | use eigen_client_avsregistry::reader::{AvsRegistryChainReader, AvsRegistryReader}; 4 | use eigen_logging::get_test_logger; 5 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 6 | use eyre::Result; 7 | 8 | #[tokio::main] 9 | #[allow(clippy::expect_used)] 10 | async fn main() -> Result<()> { 11 | let holesky_provider = "https://holesky.drpc.org"; 12 | let avs_registry = AvsRegistryChainReader::new( 13 | get_test_logger().clone(), 14 | REGISTRY_COORDINATOR, 15 | OPERATOR_STATE_RETRIEVER, 16 | holesky_provider.to_string(), 17 | ) 18 | .await 19 | .expect("failed to build avs registry chain reader"); 20 | let block_num = 1741955; 21 | let _operators_state = avs_registry 22 | .get_operators_stake_in_quorums_at_block( 23 | block_num, 24 | Bytes::from_hex("0x00").expect("failed to generate bytes"), 25 | ) 26 | .await?; 27 | 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/get_quorum_count.rs: -------------------------------------------------------------------------------- 1 | //! get_quorum_count 2 | use eigen_client_avsregistry::reader::AvsRegistryChainReader; 3 | use eigen_logging::get_test_logger; 4 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 5 | use eyre::Result; 6 | 7 | #[tokio::main] 8 | #[allow(clippy::expect_used)] 9 | async fn main() -> Result<()> { 10 | let holesky_provider = "https://holesky.drpc.org"; 11 | let avs_registry = AvsRegistryChainReader::new( 12 | get_test_logger().clone(), 13 | REGISTRY_COORDINATOR, 14 | OPERATOR_STATE_RETRIEVER, 15 | holesky_provider.to_string(), 16 | ) 17 | .await 18 | .expect("failed to build avs registry chain reader"); 19 | 20 | let quorum_count = avs_registry.get_quorum_count().await?; 21 | 22 | println!("quorum count is :{:?}", quorum_count); 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /examples/avsregistry-read/examples/query_existing_registered_operator_pub_keys.rs: -------------------------------------------------------------------------------- 1 | //! query existing registered operator pub keys for a specific block range 2 | use eigen_client_avsregistry::reader::AvsRegistryChainReader; 3 | use eigen_logging::get_test_logger; 4 | use eigen_testing_utils::m2_holesky_constants::{OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR}; 5 | use eyre::Result; 6 | 7 | #[tokio::main] 8 | #[allow(clippy::expect_used)] 9 | async fn main() -> Result<()> { 10 | let holesky_provider = "https://holesky.drpc.org"; 11 | let avs_registry = AvsRegistryChainReader::new( 12 | get_test_logger().clone(), 13 | REGISTRY_COORDINATOR, 14 | OPERATOR_STATE_RETRIEVER, 15 | holesky_provider.to_string(), 16 | ) 17 | .await 18 | .expect("failed to build avs registry chain reader"); 19 | let start_block = 1722400; 20 | let to_block = 1748590; 21 | let operators_state = avs_registry 22 | .query_existing_registered_operator_pub_keys( 23 | start_block, 24 | to_block, 25 | holesky_provider.to_string(), 26 | ) 27 | .await?; 28 | 29 | println!( 30 | "operator state from block: {:?} to block: {:?} is {:?}", 31 | start_block, to_block, operators_state 32 | ); 33 | 34 | Ok(()) 35 | } 36 | -------------------------------------------------------------------------------- /examples/avsregistry-write/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples-avsregistry-write" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | repository.workspace = true 7 | license-file.workspace = true 8 | authors.workspace = true 9 | description = "avsregistry write examples" 10 | 11 | [lints] 12 | workspace = true 13 | 14 | [dependencies] 15 | alloy.workspace = true 16 | ark-bn254 = "0.4.0" 17 | ark-ec = { version = "0.4.2", default-features = false } 18 | ark-ff.workspace = true 19 | ark-serialize = "0.4" 20 | ark-std = { version = "0.4.0", default-features = false } 21 | eigen-client-avsregistry.workspace = true 22 | eigen-client-elcontracts.workspace = true 23 | eigen-crypto-bls.workspace = true 24 | eigen-crypto-bn254.workspace = true 25 | eigen-logging.workspace = true 26 | eigen-testing-utils.workspace = true 27 | eigen-types.workspace = true 28 | eigen-utils.workspace = true 29 | eigen-common.workspace = true 30 | eyre.workspace = true 31 | lazy_static = "1.5.0" 32 | tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } 33 | -------------------------------------------------------------------------------- /examples/info-operator-service/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "info-operator-service" 3 | description = "Example demonstrating the operatorsinfo crate" 4 | version.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | repository.workspace = true 8 | license-file.workspace = true 9 | 10 | [dependencies] 11 | alloy.workspace = true 12 | 13 | eigen-common.workspace = true 14 | eigen-client-avsregistry.workspace = true 15 | eigen-client-elcontracts.workspace = true 16 | eigen-crypto-bls.workspace = true 17 | eigen-logging.workspace = true 18 | eigen-testing-utils.workspace = true 19 | eigen-services-operatorsinfo.workspace = true 20 | eigen-utils.workspace = true 21 | tokio = { workspace = true, features = ["full"] } 22 | tracing.workspace = true 23 | tokio-util = "0.7.11" 24 | -------------------------------------------------------------------------------- /release-plz.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | changelog_update = false # disable changelog updates 3 | dependencies_update = true # update dependencies with `cargo update` 4 | pr_branch_prefix = "release-plz-" # PR branch prefix 5 | pr_name = "Release {{ package }} v{{ version }}" # template for the PR name 6 | pr_labels = ["release"] # add the `release` label to the release Pull Request 7 | release_always = true 8 | git_release_draft = false 9 | git_release_enable = false 10 | git_tag_enable = false 11 | 12 | [[package]] 13 | name = "eigensdk" 14 | git_tag_name = "v{{ version }}" 15 | git_tag_enable = true 16 | git_release_enable = true 17 | git_release_draft = true 18 | 19 | # Integration test packages 20 | [[package]] 21 | name = "chainio-integration-test" 22 | release = false 23 | -------------------------------------------------------------------------------- /scripts/bindings.patch: -------------------------------------------------------------------------------- 1 | diff --git i/crates/utils/src/slashing/core/allocationmanager.rs w/crates/utils/src/slashing/core/allocationmanager.rs 2 | index 8fae5b48..8eb9334d 100644 3 | --- i/crates/utils/src/slashing/core/allocationmanager.rs 4 | +++ w/crates/utils/src/slashing/core/allocationmanager.rs 5 | @@ -19,6 +19,8 @@ library IAllocationManagerTypes { 6 | clippy::empty_structs_with_brackets 7 | )] 8 | pub mod IAllocationManagerTypes { 9 | + use crate::slashing::core::allocationmanager::AllocationManager::OperatorSet; 10 | + 11 | use super::*; 12 | use alloy::sol_types as alloy_sol_types; 13 | /**```solidity 14 | -------------------------------------------------------------------------------- /scripts/generate_rewardsv2_bindings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Exit if any command fails 4 | set +e 5 | 6 | # Print each command executed (useful for debugging) 7 | # set -o xtrace 8 | 9 | generate_flags() { 10 | for contract in $@; do 11 | echo "$acc --select ^$contract\$" 12 | done 13 | } 14 | 15 | # cd to the directory of this script so that this can be run from anywhere 16 | parent_path=$( 17 | cd "$(dirname "$0")" 18 | pwd -P 19 | ) 20 | repo_root=$parent_path/.. 21 | cd $repo_root 22 | 23 | ### SDK bindings ### 24 | REWARDS_V2_SDK_CONTRACTS="MockAvsServiceManager ContractsRegistry MockERC20" 25 | REWARDS_V2_SDK_CONTRACTS_LOCATION=crates/m2_contracts 26 | REWARDS_V2_SDK_BINDINGS_PATH=crates/utils/src/rewardsv2/sdk 27 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 28 | REWARDS_V2_SDK_CONTRACTS_ARGS=$(generate_flags $REWARDS_V2_SDK_CONTRACTS) 29 | 30 | 31 | ### Middleware bindings ### 32 | REWARDS_V2_MIDDLEWARE_CONTRACTS="RegistryCoordinator IndexRegistry OperatorStateRetriever StakeRegistry BLSApkRegistry IBLSSignatureChecker ServiceManagerBase IERC20 ECDSAStakeRegistry ECDSAServiceManagerBase" 33 | REWARDS_V2_MIDDLEWARE_CONTRACTS_LOCATION=$REWARDS_V2_SDK_CONTRACTS_LOCATION/lib/eigenlayer-middleware 34 | REWARDS_V2_MIDDLEWARE_BINDINGS_PATH=crates/utils/src/rewardsv2/middleware 35 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 36 | REWARDS_V2_MIDDLEWARE_CONTRACTS_ARGS=$(generate_flags $REWARDS_V2_MIDDLEWARE_CONTRACTS) 37 | 38 | 39 | ### Core bindings ### 40 | REWARDS_V2_CORE_CONTRACTS="DelegationManager IRewardsCoordinator RewardsCoordinator StrategyManager IEigenPod EigenPod IEigenPodManager EigenPodManager IStrategy AVSDirectory AllocationManager PermissionController ERC20 Slasher ISlasher" 41 | REWARDS_V2_CORE_CONTRACTS_LOCATION=$REWARDS_V2_MIDDLEWARE_CONTRACTS_LOCATION/lib/eigenlayer-contracts 42 | REWARDS_V2_CORE_BINDINGS_PATH=crates/utils/src/rewardsv2/core 43 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 44 | REWARDS_V2_CORE_CONTRACTS_ARGS=$(generate_flags $REWARDS_V2_CORE_CONTRACTS) 45 | 46 | # Fetch submodules 47 | cd $REWARDS_V2_SDK_CONTRACTS_LOCATION && forge install 48 | cd $repo_root 49 | 50 | # Empty the directories before generating the bindings, ignore any errors 51 | rm $REWARDS_V2_SDK_BINDINGS_PATH/* || true 52 | rm $REWARDS_V2_MIDDLEWARE_BINDINGS_PATH/* || true 53 | rm $REWARDS_V2_CORE_BINDINGS_PATH/* || true 54 | 55 | # Compile all contracts 56 | cd $repo_root/$REWARDS_V2_SDK_CONTRACTS_LOCATION && forge build --force --skip test --skip script 57 | cd $repo_root/$REWARDS_V2_MIDDLEWARE_CONTRACTS_LOCATION && forge build --force --skip test --skip script 58 | cd $repo_root/$REWARDS_V2_CORE_CONTRACTS_LOCATION && forge build --force --skip test --skip script 59 | 60 | # Move back to repo root 61 | cd $repo_root 62 | 63 | # Generate SDK bindings 64 | forge bind --alloy --skip-build --bindings-path $REWARDS_V2_SDK_BINDINGS_PATH --overwrite \ 65 | --root $REWARDS_V2_SDK_CONTRACTS_LOCATION --module \ 66 | $REWARDS_V2_SDK_CONTRACTS_ARGS 67 | 68 | # Generate middleware bindings 69 | forge bind --alloy --skip-build --bindings-path $REWARDS_V2_MIDDLEWARE_BINDINGS_PATH --overwrite \ 70 | --root $REWARDS_V2_MIDDLEWARE_CONTRACTS_LOCATION --module \ 71 | $REWARDS_V2_MIDDLEWARE_CONTRACTS_ARGS 72 | 73 | # Generate core bindings 74 | forge bind --alloy --skip-build --bindings-path $REWARDS_V2_CORE_BINDINGS_PATH --overwrite \ 75 | --root $REWARDS_V2_CORE_CONTRACTS_LOCATION --module \ 76 | $REWARDS_V2_CORE_CONTRACTS_ARGS 77 | 78 | 79 | -------------------------------------------------------------------------------- /scripts/generate_slashing_bindings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Exit if any command fails 4 | set +e 5 | 6 | # Print each command executed (useful for debugging) 7 | # set -o xtrace 8 | 9 | generate_flags() { 10 | for contract in $@; do 11 | echo "$acc --select ^$contract\$" 12 | done 13 | } 14 | 15 | # cd to the directory of this script so that this can be run from anywhere 16 | parent_path=$( 17 | cd "$(dirname "$0")" 18 | pwd -P 19 | ) 20 | repo_root=$parent_path/.. 21 | cd $repo_root 22 | 23 | 24 | SDK_CONTRACTS="MockAvsServiceManager ContractsRegistry MockERC20" 25 | SDK_CONTRACTS_LOCATION=crates/operator_sets_contracts 26 | SDK_BINDINGS_PATH=crates/utils/src/slashing/sdk 27 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 28 | SDK_CONTRACTS_ARGS=$(generate_flags $SDK_CONTRACTS) 29 | 30 | 31 | ### Middleware bindings ### 32 | MIDDLEWARE_CONTRACTS="IndexRegistry OperatorStateRetriever StakeRegistry BLSApkRegistry IBLSSignatureChecker ServiceManagerBase IERC20 SlashingRegistryCoordinator ISlashingRegistryCoordinator RegistryCoordinator SocketRegistry" 33 | MIDDLEWARE_CONTRACTS_LOCATION=$SDK_CONTRACTS_LOCATION/lib/eigenlayer-middleware 34 | MIDDLEWARE_BINDINGS_PATH=crates/utils/src/slashing/middleware 35 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 36 | MIDDLEWARE_CONTRACTS_ARGS=$(generate_flags $MIDDLEWARE_CONTRACTS) 37 | 38 | 39 | ### Core bindings ### 40 | CORE_CONTRACTS="DelegationManager IRewardsCoordinator StrategyManager IEigenPod EigenPod IEigenPodManager EigenPodManager IStrategy AVSDirectory AllocationManager PermissionController" 41 | CORE_CONTRACTS_LOCATION=$MIDDLEWARE_CONTRACTS_LOCATION/lib/eigenlayer-contracts 42 | CORE_BINDINGS_PATH=crates/utils/src/slashing/core 43 | # The echo is to remove quotes, and the patsubst to make the regex match the full text only 44 | CORE_CONTRACTS_ARGS=$(generate_flags $CORE_CONTRACTS) 45 | 46 | 47 | # Fetch submodules 48 | cd $SDK_CONTRACTS_LOCATION && forge install 49 | cd $repo_root 50 | 51 | # Empty the directories before generating the bindings, ignore any errors 52 | rm $SDK_BINDINGS_PATH/* || true 53 | rm $MIDDLEWARE_BINDINGS_PATH/* || true 54 | rm $CORE_BINDINGS_PATH/* || true 55 | 56 | # Compile all contracts 57 | cd $repo_root/$SDK_CONTRACTS_LOCATION && forge build --force --skip test --skip script 58 | cd $repo_root/$MIDDLEWARE_CONTRACTS_LOCATION && forge build --force --skip test --skip script 59 | cd $repo_root/$CORE_CONTRACTS_LOCATION && forge build --force --skip test --skip script 60 | 61 | # Move back to repo root 62 | cd $repo_root 63 | 64 | 65 | # Generate SDK bindings 66 | forge bind --alloy --skip-build --bindings-path $SDK_BINDINGS_PATH --overwrite \ 67 | --root $SDK_CONTRACTS_LOCATION --module \ 68 | $SDK_CONTRACTS_ARGS 69 | 70 | # Generate middleware bindings 71 | forge bind --alloy --skip-build --bindings-path $MIDDLEWARE_BINDINGS_PATH --overwrite \ 72 | --root $MIDDLEWARE_CONTRACTS_LOCATION --module \ 73 | $MIDDLEWARE_CONTRACTS_ARGS 74 | 75 | # Generate core bindings 76 | forge bind --alloy --skip-build --bindings-path $CORE_BINDINGS_PATH --overwrite \ 77 | --root $CORE_CONTRACTS_LOCATION --module \ 78 | $CORE_CONTRACTS_ARGS -------------------------------------------------------------------------------- /tests/integration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chainio-integration-test" 3 | description = "Integration tests for chainio clients" 4 | 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | repository.workspace = true 9 | license-file.workspace = true 10 | 11 | [lints] 12 | workspace = true 13 | 14 | [dev-dependencies] 15 | tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } 16 | alloy.workspace = true 17 | async-trait.workspace = true 18 | num-bigint = "0.4.4" 19 | ark-ff.workspace = true 20 | thiserror.workspace = true 21 | tracing.workspace = true 22 | eigen-common.workspace = true 23 | eigen-logging.workspace = true 24 | eigen-testing-utils.workspace = true 25 | eigen-utils.workspace = true 26 | futures-util.workspace = true 27 | -------------------------------------------------------------------------------- /tests/testing-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "eigen-testing-utils" 3 | description = "Testing utils for eigen." 4 | version.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | license-file.workspace = true 8 | repository.workspace = true 9 | 10 | # docs.rs-specific configuration 11 | # see https://docs.rs/about/metadata 12 | [package.metadata.docs.rs] 13 | all-features = true 14 | rustdoc-args = ["--cfg", "docsrs"] 15 | 16 | [lints] 17 | workspace = true 18 | 19 | [dependencies] 20 | alloy.workspace = true 21 | eigen-client-avsregistry.workspace = true 22 | eigen-logging.workspace = true 23 | eigen-client-elcontracts.workspace = true 24 | eigen-common.workspace = true 25 | eigen-utils.workspace = true 26 | eigen-crypto-bls.workspace = true 27 | serde.workspace = true 28 | serde_json.workspace = true 29 | testcontainers.workspace = true 30 | url.workspace = true 31 | -------------------------------------------------------------------------------- /tests/testing-utils/README.md: -------------------------------------------------------------------------------- 1 | # Eigen Testing Utils 2 | 3 | The `eigen-testing-utils` crate provides a set of utilities for testing Ethereum-based contracts and services within the Eigen ecosystem. This crate is designed to simplify interactions with local Anvil instances and Holesky/Mainnet environments by providing constant addresses and helper functions to retrieve important contract addresses. 4 | 5 | ## Anvil Utilities 6 | 7 | ### Anvil Constants 8 | 9 | Provides utilities for interacting with local Anvil instances. Key components include: 10 | 11 | - CONTRACTS_REGISTRY: The address of the local Anvil Contracts Registry. 12 | - ANVIL_RPC_URL: A static instance of the local Anvil RPC URL configured with required fillers. 13 | 14 | ### Key Functions 15 | 16 | - get_service_manager_address(): Retrieves the address of the service manager contract. 17 | - get_registry_coordinator_address(): Retrieves the address of the registry coordinator contract. 18 | - get_operator_state_retriever_address(): Retrieves the address of the operator state retriever contract. 19 | - get_delegation_manager_address(): Retrieves the address of the delegation manager contract. 20 | - get_strategy_manager_address(): Retrieves the address of the strategy manager contract. 21 | - get_erc20_mock_strategy(): Retrieves the address of the ERC20 mock strategy contract. 22 | - get_proxy_admin(): Retrieves the address of the proxy admin contract. 23 | 24 | ## Holesky Constants 25 | 26 | Contains predefined addresses for various contracts on the Holesky test network. 27 | 28 | ### Holesky Key Addresses 29 | 30 | - DELEGATION_MANAGER_ADDRESS: Address of the delegation manager. 31 | - STRATEGY_MANAGER_ADDRESS: Address of the strategy manager. 32 | - EIGENPOD_MANAGER_ADDRESS: Address of the Eigenpod manager. 33 | - AVS_DIRECTORY_ADDRESS: Address of the AVS directory. 34 | - SLASHER_ADDRESS: Address of the slasher. 35 | - REWARDS_COORDINATOR: Address of the rewards coordinator. 36 | And various strategy base addresses. 37 | 38 | ## Mainnet Constants 39 | 40 | Contains predefined addresses for various contracts on the Ethereum mainnet. 41 | 42 | ### Mainnet Key Addresses 43 | 44 | - DELEGATION_MANAGER_ADDRESS: Address of the delegation manager. 45 | - STRATEGY_MANAGER_ADDRESS: Address of the strategy manager. 46 | - EIGENPOD_MANAGER_ADDRESS: Address of the Eigenpod manager. 47 | - AVS_DIRECTORY_ADDRESS: Address of the AVS directory. 48 | - SLASHER_ADDRESS: Address of the slasher. 49 | - StrategyBase_cbETH: Address of the cbETH strategy base. 50 | - StrategyBase_stETH: Address of the stETH strategy base. 51 | And various other strategy base addresses. 52 | 53 | ## Example 54 | 55 | - [get_contracts_from_registry](https://github.com/Layr-Labs/eigensdk-rs/blob/main/examples/anvil-utils/examples/get_contracts_from_registry.rs) 56 | -------------------------------------------------------------------------------- /tests/testing-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! testing utilities for eigenlayer 2 | 3 | #![doc( 4 | html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", 5 | issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" 6 | )] 7 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 8 | 9 | /// EigenLayer constants compatible with mainnet. 10 | pub mod mainnet_constants; 11 | 12 | /// Holesky EigenLayer contract m2 compatible constants. 13 | pub mod m2_holesky_constants; 14 | 15 | /// Anvil constants 16 | #[allow(clippy::unwrap_used)] 17 | pub mod anvil_constants; 18 | 19 | /// Test data read from JSON files, used for compliance testing. 20 | pub mod test_data; 21 | 22 | /// Transaction utilities for testing. 23 | pub mod transaction; 24 | 25 | /// Anvil utilities for testing. 26 | #[allow(clippy::unwrap_used)] 27 | #[allow(clippy::expect_used)] 28 | pub mod anvil; 29 | 30 | /// Utilities for building elcontracts and avs registries 31 | #[allow(clippy::unwrap_used)] 32 | pub mod chain_clients; 33 | -------------------------------------------------------------------------------- /tests/testing-utils/src/test_data.rs: -------------------------------------------------------------------------------- 1 | use serde::{de::DeserializeOwned, Deserialize}; 2 | use std::fmt::Debug; 3 | use std::fs::File; 4 | use std::{env, io::BufReader}; 5 | 6 | /// Test data for generic loading of JSON data files. 7 | #[derive(Deserialize, Debug)] 8 | pub struct TestData { 9 | /// Input data read from JSON file. 10 | pub input: T, 11 | // output: BlsAggregationServiceResponse, 12 | } 13 | 14 | impl TestData { 15 | /// Create a new instance of `TestData` with the given input data. 16 | /// If the `TEST_DATA_PATH` environment variable is set, it reads the JSON file from the path, 17 | /// otherwise (or if it fails) it uses the default input data. 18 | /// 19 | /// # Arguments 20 | /// 21 | /// * `default_input` - The default input data to use if the JSON file is not found or fails to read. 22 | /// 23 | /// # Returns 24 | /// 25 | /// A new instance of `TestData` with the input data read from the JSON file or the default input data. 26 | pub fn new(default_input: T) -> Self { 27 | if let Ok(path) = env::var("TEST_DATA_PATH") { 28 | let Ok(file) = File::open(path) else { 29 | return TestData { 30 | input: default_input, 31 | }; 32 | }; 33 | let reader = BufReader::new(file); 34 | let Ok(ret) = serde_json::from_reader(reader) else { 35 | return TestData { 36 | input: default_input, 37 | }; 38 | }; 39 | ret 40 | } else { 41 | // use default values 42 | TestData { 43 | input: default_input, 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/testing-utils/src/transaction.rs: -------------------------------------------------------------------------------- 1 | use alloy::primitives::FixedBytes; 2 | use alloy::providers::{PendingTransactionBuilder, PendingTransactionError, ProviderBuilder}; 3 | use alloy::rpc::types::eth::TransactionReceipt; 4 | use alloy::transports::TransportErrorKind; 5 | use url::Url; 6 | 7 | /// Wait for a transaction to finish and return its receipt. 8 | /// 9 | /// # Arguments 10 | /// 11 | /// `rpc_url` - The RPC URL. 12 | /// `tx_hash` - The hash of the transaction. 13 | /// 14 | /// # Returns 15 | /// 16 | /// A [`TransactionReceipt`] containing the transaction receipt. 17 | pub async fn wait_transaction( 18 | rpc_url: &str, 19 | tx_hash: FixedBytes<32>, 20 | ) -> Result { 21 | let url = Url::parse(rpc_url).map_err(|_| TransportErrorKind::custom_str("Invalid RPC URL"))?; 22 | let root_provider = ProviderBuilder::new() 23 | .disable_recommended_fillers() 24 | .on_http(url); 25 | let pending_tx = PendingTransactionBuilder::new(root_provider, tx_hash); 26 | pending_tx.get_receipt().await 27 | } 28 | --------------------------------------------------------------------------------