# AI Pack: relay-client-go

- Description: Relay Go client and SDK.
- Remote: https://github.com/symbioticfi/relay
- Remote ref: HEAD
- Commit: a31495693d096e304e310262ebe968756dca246a
- Generated (UTC): 2026-06-02T10:22:21.999Z
- Repomix: 1.14.1
- Preset: common
- Ignore patterns: .gitignore, .dockerignore, .prettierignore, .npmignore, .nvmrc, .editorconfig, .gitattributes, **/.github/**, **/.husky/**, **/.vscode/**, **/.idea/**, \*_/.DS_Store, node_modules/, dist/, build/, .turbo/, .next/, out/, cache/, broadcast/, bin/, coverage_, \*.test, target/
- Flags: compress

---

This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix.
The content has been processed where content has been compressed (code blocks are separated by ⋮---- delimiter).

# File Summary

## Purpose

This file contains a packed representation of a subset of the repository's contents that is considered the most important context.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.

## File Format

The content is organized as follows:

1. This summary section
2. Repository information
3. Directory structure
4. Repository files (if enabled)
5. Multiple file entries, each consisting of:
   a. A header with the file path (## File: path/to/file)
   b. The full contents of the file in a code block

## Usage Guidelines

- This file should be treated as read-only. Any changes should be made to the
  original repository files, not this packed version.
- When processing this file, use the file path to distinguish
  between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
  the same level of security as you would the original repository.

## Notes

- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Files matching these patterns are excluded: .gitignore, .dockerignore, .prettierignore, .npmignore, .nvmrc, .editorconfig, .gitattributes, **/.github/**, **/.husky/**, **/.vscode/**, **/.idea/**, \*_/.DS_Store, node_modules/, dist/, build/, .turbo/, .next/, out/, cache/, broadcast/, bin/, coverage_, \*.test, target/
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Content has been compressed - code blocks are separated by ⋮---- delimiter
- Files are sorted by Git change count (files with more changes are at the bottom)

# Directory Structure

```
api/
  client/
    examples/
      main.go
      README.md
    v1/
      client.go
      types.go
    LICENSE
  proto/
    v1/
      api.proto
cmd/
  relay/
    root/
      app.go
      config.go
      root.go
    main.go
  utils/
    cmd-helpers/
      external_voting_power.go
      helpers.go
    keys/
      add.go
      cmd.go
      print.go
      remove.go
      update.go
    network/
      cmd.go
      genesis.go
      info.go
      printers.go
    operator/
      cmd.go
      info.go
      invalidate_old_signatures.go
      register_key_artifact_test.go
      register_key_artifact.go
      register_key.go
      register_operator.go
      register_with_signature.go
      unregister_operator.go
      unregister_with_signature.go
    prune/
      cmd.go
      run_test.go
      run.go
    root/
      root.go
    main.go
docs/
  api/
    v1/
      api.swagger.json
      doc.md
      index.html
  cli/
    relay/
      relay_sidecar.md
    utils/
      utils_keys_add.md
      utils_keys_list.md
      utils_keys_remove.md
      utils_keys_update.md
      utils_keys.md
      utils_network_generate-genesis.md
      utils_network_info.md
      utils_network.md
      utils_operator_info.md
      utils_operator_invalidate-old-signatures.md
      utils_operator_register-key-artifact.md
      utils_operator_register-key.md
      utils_operator_register-operator-with-signature.md
      utils_operator_register-operator.md
      utils_operator_register-signature.md
      utils_operator_unregister-operator-with-signature.md
      utils_operator_unregister-operator.md
      utils_operator_unregister-signature.md
      utils_operator.md
      utils_prune.md
      utils_version.md
      utils.md
  core/
    architecture.md
    epoch_progression.md
    external_voting_power_providers.md
    keys_and_quorum.md
    sign_message.md
    signature_aggregation.md
    types.md
    valset_commitment.md
    valset_derivation.md
  votingpower/
    v1/
      doc.md
      index.html
      votingpower.swagger.json
e2e/
  scripts/
    deploy.sh
    deployer.Dockerfile
    generate_network.sh
    genesis-generator.sh
    sidecar-start.sh
  tests/
    evm/
      abi/
        IOptInService.abi.json
        MockERC20.abi.json
        OpNetVaultAutoDeployLogic.abi.json
        Vault.abi.json
      gen/
        mockERC20.go
        opNetVaultAutoDeployLogic.go
        optInService.go
        vault.go
      client.go
    api_test.go
    epoch_test.go
    external_voting_power_provider_test.go
    genesis_test.go
    http_gateway_test.go
    metadata_test.go
    operator_test.go
    settlement_test.go
    sidecar.yaml
    sign_test.go
    sync_test.go
    types_test.go
  README.md
  setup.sh
hack/
  codegen/
    generate-client-types.go
  docgen/
    generate-cli-docs.go
internal/
  client/
    p2p/
      proto/
        v1/
          message_grpc.pb.go
          message.pb.go
          message.proto
      broadcast_signature_aggregated_message.go
      broadcast_signature_generated_message.go
      discovery_integration_test.go
      discovery_test.go
      discovery.go
      p2p_broadcast_test.go
      p2p_grpc_handler.go
      p2p_grpc_send_want_aggregation_proofs_request_test.go
      p2p_grpc_send_want_aggregation_proofs_request.go
      p2p_grpc_send_want_signatures_request_test.go
      p2p_grpc_send_want_signatures_request.go
      p2p_grpc_test.go
      p2p_handle_message_test.go
      p2p_handle_message_unit_test.go
      p2p_handle_message.go
      p2p_sync_peer_state_test.go
      p2p_sync_peer_state.go
      p2p_test.go
      p2p.go
    repository/
      badger/
        proto/
          v1/
            badger.pb.go
            badger.proto
        badger_repository_add_proof.go
        badger_repository_add_signature.go
        badger_repository_aggregation_proof_pending_test.go
        badger_repository_aggregation_proof_test.go
        badger_repository_aggregation_proof.go
        badger_repository_network_config_test.go
        badger_repository_network_config.go
        badger_repository_next_valset_data_test.go
        badger_repository_next_valset_data.go
        badger_repository_proof_commits_test.go
        badger_repository_proof_commits.go
        badger_repository_proto_test.go
        badger_repository_prune_test.go
        badger_repository_prune.go
        badger_repository_signature_map_test.go
        badger_repository_signature_map.go
        badger_repository_signature_request_test.go
        badger_repository_signature_request.go
        badger_repository_signature_test.go
        badger_repository_signature.go
        badger_repository_test.go
        badger_repository_transaction_test.go
        badger_repository_transaction.go
        badger_repository_validator_set_test.go
        badger_repository_validator_set.go
        badger_repository.go
        pagination_fuzz_test.go
      bbolt/
        bbolt_repository_add_proof.go
        bbolt_repository_add_signature.go
        bbolt_repository_aggregation_proof_test.go
        bbolt_repository_aggregation_proof.go
        bbolt_repository_network_config_test.go
        bbolt_repository_network_config.go
        bbolt_repository_next_valset_data.go
        bbolt_repository_proof_commits_test.go
        bbolt_repository_proof_commits.go
        bbolt_repository_prune_test.go
        bbolt_repository_prune.go
        bbolt_repository_signature_map_test.go
        bbolt_repository_signature_request_test.go
        bbolt_repository_signature_test.go
        bbolt_repository_signature.go
        bbolt_repository_test.go
        bbolt_repository_validator_set_test.go
        bbolt_repository_validator_set.go
        bbolt_repository.go
        pagination_fuzz_test.go
      cache/
        generic_cache.go
      cached/
        cached_repository.go
      codec/
        codec.go
      loadtest/
        savesignature_test.go
      repoutil/
        cursor.go
        metrics.go
  entity/
    entity_aggregation_proof_sync_test.go
    entity_error.go
    entity_signature_map_test.go
    entity_signature_map.go
    entity_signature_request.go
    entity_signature_sync.go
    p2p_entity.go
  gen/
    api/
      v1/
        api_grpc.pb.go
        api.pb.go
        api.pb.gw.go
    votingpower/
      v1/
        votingpower_grpc.pb.go
        votingpower.pb.go
  usecase/
    aggregation-policy/
      low-cost/
        low_cost_policy.go
      low-latency/
        low_latency_policy.go
      types/
        types.go
      aggregation_policies.go
    aggregator-app/
      mocks/
        aggregator_app.go
      aggregator_app_test.go
      aggregator_app.go
    api-server/
      mocks/
        app_mock.go
      app.go
      get_aggregation_proof_v1_test.go
      get_aggregation_proof_v1.go
      get_aggregation_proofs_by_epoch_v1_test.go
      get_aggregation_proofs_by_epoch_v1.go
      get_aggregation_status_v1_test.go
      get_aggregation_status_v1.go
      get_current_epoch_v1_test.go
      get_current_epoch_v1.go
      get_custom_schedule_node_status_v1_test.go
      get_custom_schedule_node_status_v1.go
      get_last_all_committed_v1_test.go
      get_last_all_committed_v1.go
      get_last_committed_v1_test.go
      get_last_committed_v1.go
      get_local_validator_v1_test.go
      get_local_validator_v1.go
      get_signature_request_ids_by_epoch_v1_test.go
      get_signature_request_ids_by_epoch_v1.go
      get_signature_request_v1_test.go
      get_signature_request_v1.go
      get_signature_requests_by_epoch_v1_test.go
      get_signature_requests_by_epoch_v1.go
      get_signature_v1.go
      get_signatures_by_epoch_v1_test.go
      get_signatures_by_epoch_v1.go
      get_signatures_v1_test.go
      get_validator_by_address_v1_test.go
      get_validator_by_address_v1.go
      get_validator_by_key_v1_test.go
      get_validator_by_key_v1.go
      get_validator_set_header_v1_test.go
      get_validator_set_header_v1.go
      get_validator_set_v1_test.go
      get_validator_set_v1.go
      get_validatorset_metadata_v1_test.go
      get_validatorset_metadata_v1.go
      helpers_test.go
      http_test.go
      http.go
      interceptors_test.go
      interceptors.go
      listen_proofs_v1_test.go
      listen_proofs_v1.go
      listen_signature_v1.go
      listen_signatures_v1_test.go
      listen_validator_set_v1_test.go
      listen_validator_set_v1.go
      pagination_handler_fuzz_test.go
      pagination.go
      sign_message_v1_test.go
      sign_message_v1.go
    broadcaster/
      doc.go
      hub_test.go
      hub.go
    entity-processor/
      mocks/
        entity_processor.go
      entity_processor_test.go
      entity_processor.go
    key-provider/
      cache_key_provider.go
      env_provider.go
      key_provider.go
      key_store_provider_test.go
      key_store_provider.go
      simple_key_provider.go
    key-registerer/
      key_registerer_test.go
      key-registerer.go
    metrics/
      metrics_app.go
      metrics_grpc.go
      metrics.go
    pruner/
      mocks/
        pruner_mocks.go
      pruner_uc_test.go
      pruner_uc.go
    signature-listener/
      mocks/
        signature_listener_uc.go
      signature_listener_uc_test.go
      signature_listener_uc.go
    signer-app/
      mocks/
        signer_app.go
      signer_app_handle_signature_aggregated_message.go
      signer_app_test.go
      signer_app.go
    sync-provider/
      sync_provider_build_want_aggregation_proofs_request.go
      sync_provider_build_want_signatures_map.go
      sync_provider_handle_want_aggregation_proofs_request.go
      sync_provider_handle_want_signatures.go
      sync_provider_process_received_aggregation_proofs.go
      sync_provider_process_received_signatures.go
      sync_provider_process_received_test.go
      sync_provider_test.go
      sync_provider.go
    sync-runner/
      sync_runner.go
    valset-listener/
      valset_generator_handle_agg_proof.go
      valset_listener_uc.go
    valset-status-tracker/
      status_tracker.go
pkg/
  log/
    context_handler.go
    log_test.go
    log.go
    prettylog.go
  proof/
    circuit.go
    helpers_test.go
    helpers.go
    proof_test.go
    proof.go
  server/
    interceptors.go
    metrics_server.go
  signals/
    signal_test.go
    signal.go
  tracing/
    helpers.go
    tracing.go
symbiotic/
  client/
    evm/
      abi/
        KeyRegistry.abi.json
        OperatorRegistry.abi.json
        Settlement.abi.json
        ValSetDriver.abi.json
        VotingPowerProvider.abi.json
      gen/
        keyRegistry.go
        multicall3.go
        operatorRegistry.go
        settlement.go
        valsetDriver.go
        votingPowerProvider.go
      mocks/
        eth.go
      eth_commit_valset.go
      eth_operator.go
      eth_set_genesis_test.go
      eth_set_genesis.go
      eth_settlement.go
      eth_test.go
      eth_tracing.go
      eth_verify_quorum_sig_test.go
      eth_verify_quorum_sig.go
      eth.go
      multicall_test.go
      multicall.go
    votingpower/
      chainid_domain_test.go
      chainid_domain.go
      client_test.go
      client.go
  entity/
    entity_test.go
    entity.go
    evm_entity.go
    key_tag_entity_test.go
    key_tag_entity.go
    key.go
  usecase/
    aggregator/
      aggregator-types/
        aggregator.go
      blsBn254Simple/
        aggregator_test.go
        aggregator.go
      blsBn254ZK/
        aggregator_test.go
        aggregator.go
      helpers/
        helpers_test.go
        helpers.go
      aggregators_test.go
      aggregators.go
    crypto/
      bls12381/
        key_test.go
        key.go
      blsBn254/
        key_test.go
        key.go
      ecdsaSecp256k1/
        key_test.go
        key.go
      keys.go
    ssz/
      ssz.go
      types.go
    valset-deriver/
      mocks/
        deriver.go
      valset_deriver_test.go
      valset_deriver.go
  symbiotic.go
votingpower/
  proto/
    v1/
      votingpower.proto
.env.example
.gitmodules
.golangci.yml
buf.badger.gen.yaml
buf.gen.yaml
buf.lock
buf.p2p.gen.yaml
buf.votingpower.gen.yaml
buf.yaml
CONTRIBUTING.md
DEVELOPMENT.md
Dockerfile
example.config.yaml
go.mod
LICENSE
Makefile
README.md
```

# Files

## File: api/client/examples/main.go

```go
// Basic usage example for the Symbiotic Relay Go client.
//
// This example demonstrates how to:
// 1. Connect to a Symbiotic Relay server
// 2. Get the current epoch
// 3. Sign a message
// 4. Retrieve aggregation proofs
// 5. Get validator set information
// 6. Get individual signatures
// 7. Get signature request IDs by epoch
// 8. Get signature requests by epoch
// 9. Get a signature request by request ID
// 10. Stream signatures in real-time
// 11. Stream aggregation proofs in real-time
// 12. Stream validator set changes in real-time
⋮----
package main
⋮----
import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/go-errors/errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	client "github.com/symbioticfi/relay/api/client/v1"
)
⋮----
"context"
"fmt"
"log"
"os"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
⋮----
client "github.com/symbioticfi/relay/api/client/v1"
⋮----
// RelayClient wraps the Symbiotic client with helpful methods
type RelayClient struct {
	client *client.SymbioticClient
	conn   *grpc.ClientConn
}
⋮----
// NewRelayClient creates a new client connected to the specified server URL
func NewRelayClient(serverURL string) (*RelayClient, error)
⋮----
// Create gRPC connection
⋮----
// Create the symbiotic client
⋮----
// Close closes the gRPC connection
func (rc *RelayClient) Close() error
⋮----
// GetCurrentEpoch gets the current epoch information
func (rc *RelayClient) GetCurrentEpoch(ctx context.Context) (*client.GetCurrentEpochResponse, error)
⋮----
// GetLastAllCommitted gets the last all committed epochs for all chains
func (rc *RelayClient) GetLastAllCommitted(ctx context.Context) (*client.GetLastAllCommittedResponse, error)
⋮----
// SignMessage signs a message using the specified key tag
func (rc *RelayClient) SignMessage(ctx context.Context, keyTag uint32, message []byte, requiredEpoch *uint64) (*client.SignMessageResponse, error)
⋮----
// GetAggregationProof gets aggregation proof for a specific request
func (rc *RelayClient) GetAggregationProof(ctx context.Context, requestID string) (*client.GetAggregationProofResponse, error)
⋮----
// GetSignatures gets individual signatures for a request
func (rc *RelayClient) GetSignatures(ctx context.Context, requestID string) (*client.GetSignaturesResponse, error)
⋮----
// GetSignatureRequestIDsByEpoch gets one page of signature request IDs for a
// given epoch. pageSize=0 lets the server pick a default; from="" starts from
// the beginning. Use the response's NextFrom to fetch subsequent pages.
func (rc *RelayClient) GetSignatureRequestIDsByEpoch(ctx context.Context, epoch uint64, pageSize uint32, from string) (*client.GetSignatureRequestIDsByEpochResponse, error)
⋮----
// GetSignatureRequestsByEpoch gets one page of signature requests for a given
// epoch. See GetSignatureRequestIDsByEpoch for pagination semantics.
func (rc *RelayClient) GetSignatureRequestsByEpoch(ctx context.Context, epoch uint64, pageSize uint32, from string) (*client.GetSignatureRequestsByEpochResponse, error)
⋮----
// GetSignatureRequest gets a signature request by its request ID
func (rc *RelayClient) GetSignatureRequest(ctx context.Context, requestID string) (*client.GetSignatureRequestResponse, error)
⋮----
// GetValidatorSet gets validator set information
func (rc *RelayClient) GetValidatorSet(ctx context.Context, epoch *uint64) (*client.GetValidatorSetResponse, error)
⋮----
// ListenSignatures streams signatures in real-time
func (rc *RelayClient) ListenSignatures(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenSignaturesResponse], error)
⋮----
// ListenProofs streams aggregation proofs in real-time
func (rc *RelayClient) ListenProofs(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenProofsResponse], error)
⋮----
// ListenValidatorSet streams validator set changes in real-time
func (rc *RelayClient) ListenValidatorSet(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenValidatorSetResponse], error)
⋮----
func main()
⋮----
// Initialize client
⋮----
// Create context with timeout
⋮----
// Example 1: Get current epoch
⋮----
// Example 2: Get suggested epoch
⋮----
// Example 3: Get validator set
⋮----
// Display some validator details
⋮----
// Example 4: Sign a message
⋮----
// Example 5: Get aggregation proof (this might fail if signing is not complete)
⋮----
// Example 6: Get individual signatures
⋮----
// Example 7: Get signature request IDs by epoch (paginated — loop until next_from is empty).
⋮----
var allIDs []string
⋮----
// Example 8: Get signature requests by epoch (paginated).
⋮----
var allReqs []*client.SignatureRequest
⋮----
// Example 9: Get a signature request by request ID
⋮----
// Example 10: Listen to signatures stream
⋮----
// Create a new context with a shorter timeout for streaming example
⋮----
// Start listening from a specific epoch (optional)
var startEpoch *uint64
⋮----
epoch := epochResponse.GetEpoch() - 1 // Start from previous epoch to get some historical data
⋮----
// Example 11: Listen to aggregation proofs stream
⋮----
// Example 12: Listen to validator set changes stream
```

## File: api/client/examples/README.md

````markdown
# Symbiotic Relay Client Examples

This directory contains example code demonstrating how to use the [Symbiotic Relay Go client library](../v1/) to interact with a Symbiotic Relay server.

## Basic Usage Example

The example shows how to:

1. Connect to a Symbiotic Relay server
2. Get current epoch information
3. Sign messages
4. Retrieve aggregation proofs and signatures
5. Get validator set information
6. Use streaming responses for real-time updates

## Prerequisites

Before running the examples, ensure you have:

- **[Go 1.26 or later](https://golang.org/doc/install)** installed
- **Access to a running Symbiotic Relay Network**
- **Network connectivity** to the relay server
- **Valid key configurations** on the relay server (for signing operations)

## Running the Example

```bash
cd api/client/examples
go run main.go
```

By default, the example will try to connect to `localhost:8080`. You can specify a different server URL by setting the `RELAY_SERVER_URL` environment variable:

```bash
RELAY_SERVER_URL=my-relay-server:8081 go run main.go
```

NOTE: for the signature/proof generation to work you need to run the script for all active relay servers to get the majority consensus to generate proof.

## Integration with Your Application

To integrate this client into your own application:

1. **Import the client package**:

    ```go
    import client "github.com/symbioticfi/relay/api/client/v1"
    ```

2. **Create a connection**:

    ```go
    conn, err := grpc.Dial(serverURL, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        return err
    }
    client := client.NewSymbioticClient(conn)
    ```

3. **Use the client methods** as demonstrated in the [example](main.go)

4. **Handle errors appropriately** for your use case

5. **Ensure proper connection cleanup** with `defer conn.Close()`

## More Examples

For a more comprehensive example of using the client library in a real-world application, see:

- **[Symbiotic Super Sum Example](https://github.com/symbioticfi/symbiotic-super-sum/tree/main/off-chain)**

## API Reference

For complete API documentation, refer to:

- **API Documentation**: [`docs/api/v1/doc.md`](../../../docs/api/v1/doc.md)
- **Protocol Buffer definitions**: [`api/proto/v1/api.proto`](../../proto/v1/api.proto)
- **Generated Go types**: [`api/client/v1/types.go`](../v1/types.go)
- **Client interface**: [`api/client/v1/client.go`](../v1/client.go)

## License

This client library and example code are licensed under the MIT License. See the [LICENSE](../LICENSE) file for details.
````

## File: api/client/v1/client.go

```go
package v1
⋮----
import (
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"google.golang.org/grpc"
)
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"google.golang.org/grpc"
⋮----
// SymbioticClient wraps the generated gRPC client
type SymbioticClient struct {
	apiv1.SymbioticAPIServiceClient
}
⋮----
// NewSymbioticClient creates a new client instance for symbiotic relay
func NewSymbioticClient(conn grpc.ClientConnInterface) *SymbioticClient
```

## File: api/client/v1/types.go

```go
// Code generated by generate-client-types. DO NOT EDIT.
package v1
⋮----
import (
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
)
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
⋮----
// Exported types for client usage
⋮----
// Enums
⋮----
// Enum constants
const (
	// ErrorCode values
	ErrorCode_ERROR_CODE_UNSPECIFIED = apiv1.ErrorCode_ERROR_CODE_UNSPECIFIED
	ErrorCode_ERROR_CODE_NO_DATA = apiv1.ErrorCode_ERROR_CODE_NO_DATA
	ErrorCode_ERROR_CODE_INTERNAL = apiv1.ErrorCode_ERROR_CODE_INTERNAL
	ErrorCode_ERROR_CODE_NOT_AGGREGATOR = apiv1.ErrorCode_ERROR_CODE_NOT_AGGREGATOR

	// SigningStatus values
	SigningStatus_SIGNING_STATUS_UNSPECIFIED = apiv1.SigningStatus_SIGNING_STATUS_UNSPECIFIED
	SigningStatus_SIGNING_STATUS_PENDING = apiv1.SigningStatus_SIGNING_STATUS_PENDING
	SigningStatus_SIGNING_STATUS_COMPLETED = apiv1.SigningStatus_SIGNING_STATUS_COMPLETED
	SigningStatus_SIGNING_STATUS_FAILED = apiv1.SigningStatus_SIGNING_STATUS_FAILED
	SigningStatus_SIGNING_STATUS_TIMEOUT = apiv1.SigningStatus_SIGNING_STATUS_TIMEOUT

	// ValidatorSetStatus values
	ValidatorSetStatus_VALIDATOR_SET_STATUS_UNSPECIFIED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_UNSPECIFIED
	ValidatorSetStatus_VALIDATOR_SET_STATUS_DERIVED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_DERIVED
	ValidatorSetStatus_VALIDATOR_SET_STATUS_AGGREGATED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_AGGREGATED
	ValidatorSetStatus_VALIDATOR_SET_STATUS_COMMITTED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_COMMITTED
)
⋮----
// ErrorCode values
⋮----
// SigningStatus values
⋮----
// ValidatorSetStatus values
⋮----
// Request types
⋮----
// Response types
⋮----
// Data types
```

## File: api/client/LICENSE

```
MIT License

Copyright (c) 2025 Symbiotic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

## File: api/proto/v1/api.proto

```protobuf
syntax = "proto3";

package api.proto.v1;

import "google/protobuf/timestamp.proto";
import "google/api/annotations.proto";

option go_package = "github.com/symbioticfi/relay/api/proto/v1";

// SymbioticAPI provides access to the Symbiotic relay functions
service SymbioticAPIService {
  // Sign a message
  rpc SignMessage(SignMessageRequest) returns (SignMessageResponse) {
    option (google.api.http) = {
      post: "/v1/sign"
      body: "*"
    };
  }

  // Get aggregation proof
  rpc GetAggregationProof(GetAggregationProofRequest) returns (GetAggregationProofResponse) {
    option (google.api.http) = {
      get: "/v1/aggregation/proof/{request_id}"
    };
  }

  // Get aggregation proofs by epoch
  rpc GetAggregationProofsByEpoch(GetAggregationProofsByEpochRequest) returns (GetAggregationProofsByEpochResponse) {
    option (google.api.http) = {
      get: "/v1/aggregation/proofs/epoch/{epoch}"
    };
  }

  // Get current epoch
  rpc GetCurrentEpoch(GetCurrentEpochRequest) returns (GetCurrentEpochResponse) {
    option (google.api.http) = {
      get: "/v1/epoch/current"
    };
  }

  // Get signature by request id
  rpc GetSignatures(GetSignaturesRequest) returns (GetSignaturesResponse) {
    option (google.api.http) = {
      get: "/v1/signatures/{request_id}"
    };
  }

  // Get signature by epoch
  rpc GetSignaturesByEpoch(GetSignaturesByEpochRequest) returns (GetSignaturesByEpochResponse) {
    option (google.api.http) = {
      get: "/v1/signatures/epoch/{epoch}"
    };
  }

  // Get all signature request IDs by epoch
  rpc GetSignatureRequestIDsByEpoch(GetSignatureRequestIDsByEpochRequest) returns (GetSignatureRequestIDsByEpochResponse) {
    option (google.api.http) = {
      get: "/v1/signature-request-ids/epoch/{epoch}"
    };
  }

  // Get all signature requests by epoch
  rpc GetSignatureRequestsByEpoch(GetSignatureRequestsByEpochRequest) returns (GetSignatureRequestsByEpochResponse) {
    option (google.api.http) = {
      get: "/v1/signature-requests/epoch/{epoch}"
    };
  }

  // Get signature request by request id
  rpc GetSignatureRequest(GetSignatureRequestRequest) returns (GetSignatureRequestResponse) {
    option (google.api.http) = {
      get: "/v1/signature-request/{request_id}"
    };
  }

  // Get aggregation status, can be sent only to aggregator nodes
  rpc GetAggregationStatus(GetAggregationStatusRequest) returns (GetAggregationStatusResponse) {
    option (google.api.http) = {
      get: "/v1/aggregation/status/{request_id}"
    };
  }

  // Get current validator set
  rpc GetValidatorSet(GetValidatorSetRequest) returns (GetValidatorSetResponse) {
    option (google.api.http) = {
      get: "/v1/validator-set"
    };
  }

  // Get validator by address
  rpc GetValidatorByAddress(GetValidatorByAddressRequest) returns (GetValidatorByAddressResponse) {
    option (google.api.http) = {
      get: "/v1/validator/address/{address}"
    };
  }

  // Get validator by key
  rpc GetValidatorByKey(GetValidatorByKeyRequest) returns (GetValidatorByKeyResponse) {
    option (google.api.http) = {
      get: "/v1/validator/key/{key_tag}/{on_chain_key}"
    };
  }

  // Get local validator
  rpc GetLocalValidator(GetLocalValidatorRequest) returns (GetLocalValidatorResponse) {
    option (google.api.http) = {
      get: "/v1/validator/local"
    };
  }

  // Get validator set header
  rpc GetValidatorSetHeader(GetValidatorSetHeaderRequest) returns (GetValidatorSetHeaderResponse) {
    option (google.api.http) = {
      get: "/v1/validator-set/header"
    };
  }

  // Get last committed epoch for a specific settlement chain
  rpc GetLastCommitted(GetLastCommittedRequest) returns (GetLastCommittedResponse) {
    option (google.api.http) = {
      get: "/v1/committed/chain/{settlement_chain_id}"
    };
  }

  // Get last committed epochs for all settlement chains
  rpc GetLastAllCommitted(GetLastAllCommittedRequest) returns (GetLastAllCommittedResponse) {
    option (google.api.http) = {
      get: "/v1/committed/all"
    };
  }

  // Get validator set metadata like extra data and request id to fetch aggregation and signature requests
  rpc GetValidatorSetMetadata(GetValidatorSetMetadataRequest) returns (GetValidatorSetMetadataResponse) {
    option (google.api.http) = {
      get: "/v1/validator-set/metadata"
    };
  }

  // Checks if the current node should be active based on a custom schedule derived from the validator set.
  // This enables external applications to use the relay's validator set for coordinating distributed tasks,
  // such as deciding which application instances should commit data on-chain or perform other coordinated actions.
  // The schedule ensures deterministic but randomized selection of active nodes at any given time.
  rpc GetCustomScheduleNodeStatus(GetCustomScheduleNodeStatusRequest) returns (GetCustomScheduleNodeStatusResponse) {
    option (google.api.http) = {
      get: "/v1/validator-set/custom-schedule/node-status"
    };
  }

  // Stream signatures in real-time. If start_epoch is provided, sends historical data first
  rpc ListenSignatures(ListenSignaturesRequest) returns (stream ListenSignaturesResponse) {
    option (google.api.http) = {
      get: "/v1/stream/signatures"
    };
  }

  // Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first
  rpc ListenProofs(ListenProofsRequest) returns (stream ListenProofsResponse) {
    option (google.api.http) = {
      get: "/v1/stream/proofs"
    };
  }

  // Stream validator set changes in real-time. If start_epoch is provided, sends historical data first
  rpc ListenValidatorSet(ListenValidatorSetRequest) returns (stream ListenValidatorSetResponse) {
    option (google.api.http) = {
      get: "/v1/stream/validator-set"
    };
  }
}

// Request to check if the current node should be active in a custom schedule.
// The validator set is divided into groups that rotate through time slots.
// Use this to coordinate distributed tasks among multiple application instances.
message GetCustomScheduleNodeStatusRequest {
  // Epoch number to use for the validator set (optional, defaults to current epoch)
  optional uint64 epoch = 1;

  // Custom seed for randomizing the schedule (optional). Different seeds produce different schedules
  // for the same epoch, allowing multiple independent scheduling schemes. If not provided, the schedule
  // is deterministic based on epoch alone.
  optional bytes seed = 2;

  // Duration of each time slot in seconds. Determines how frequently active groups rotate.
  // Example: 60 seconds means a new group becomes active every minute.
  uint64 slot_duration_seconds = 3;

  // Maximum validators per group. Controls redundancy: 1 for single-instance actions (less redundancy),
  // 2+ for multi-instance actions (more reliability). All validators in a group are active simultaneously.
  uint32 max_participants_per_slot = 4;

  // Minimum validators required to form a remainder group. When dividing validators into groups,
  // any remainder smaller than this is not scheduled. Set equal to max for strict group sizes.
  uint32 min_participants_per_slot = 5;
}

// Response indicating whether the current node should be active now.
message GetCustomScheduleNodeStatusResponse {
  // True if this node is active in the current time slot and should perform the scheduled action.
  // False if this node should wait (another group is active). When multiple validators share a slot,
  // all return true simultaneously, enabling coordinated redundancy.
  bool is_active = 1;

  // Start time of the current active slot. This marks the beginning of the current slot time window.
  // Can be used to determine how much time is left in the slot.
  google.protobuf.Timestamp current_slot_start_time = 2;

  // End time of the current active slot. This marks the end of the current slot time window.
  // Can be used to determine how much time is left in the slot.
  google.protobuf.Timestamp current_slot_end_time = 3;
}

// Request message for signing a message
message SignMessageRequest {
  // Key tag identifier (0-127)
  uint32 key_tag = 1;

  // Message to be signed
  bytes message = 2;

  // Required epoch (optional, if not provided latest committed epoch will be used)
  optional uint64 required_epoch = 3;
}

// Response message for sign message request
message SignMessageResponse {
  // Hash of the signature request
  string request_id = 1;

  // Epoch number
  uint64 epoch = 2;
}

// Request message for listening to signatures stream
message ListenSignaturesRequest {
  // Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates
  // If not provided, only signatures generated after stream creation will be sent
  optional uint64 start_epoch = 1;
}

// Response message for signatures stream
message ListenSignaturesResponse {
  // Id of the signature request
  string request_id = 1;

  // Epoch number
  uint64 epoch = 2;

  // Signature data
  Signature signature = 3;
}

// Request message for listening to aggregation proofs stream
message ListenProofsRequest {
  // Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates
  // If not provided, only proofs generated after stream creation will be sent
  optional uint64 start_epoch = 1;
}

// Response message for aggregation proofs stream
message ListenProofsResponse {
  // Id of the request
  string request_id = 1;

  // Epoch number
  uint64 epoch = 2;

  // Final aggregation proof
  AggregationProof aggregation_proof = 3;
}

// Request message for listening to validator set changes stream
message ListenValidatorSetRequest {
  // Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates
  // If not provided, only validator sets generated after stream creation will be sent
  optional uint64 start_epoch = 1;
}

// Response message for validator set changes stream
message ListenValidatorSetResponse {
  // The validator set
  ValidatorSet validator_set = 1;
}

// Request message for getting aggregation proof
message GetAggregationProofRequest {
  string request_id = 1;
}


// Request message for getting aggregation proof
message GetAggregationProofsByEpochRequest {
  // Epoch number
  uint64 epoch = 1;
  // Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
  uint32 page_size = 2;
  // Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
  string from = 3;
}

// Request message for getting current epoch
message GetCurrentEpochRequest {}

// Request message for getting signatures
message GetSignaturesRequest {
  string request_id = 1;
}

// Request message for getting signatures by epoch
message GetSignaturesByEpochRequest {
  // Epoch number
  uint64 epoch = 1;
  // Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
  uint32 page_size = 2;
  // Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
  string from = 3;
}

// Response message for getting signatures
message GetSignaturesResponse {
  // List of signatures
  repeated Signature signatures = 1;
}

// Response message for getting signatures by epoch
message GetSignaturesByEpochResponse {
  // List of signatures
  repeated Signature signatures = 1;
  // Cursor to retrieve the next page. Empty when this is the last page.
  string next_from = 2;
}

// Request message for getting all signature request IDs by epoch
message GetSignatureRequestIDsByEpochRequest {
  // Epoch number
  uint64 epoch = 1;
  // Maximum number of items to return. 0 = server default (1000). Server clamps to max (10000).
  uint32 page_size = 2;
  // Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
  string from = 3;
}

// Response message for getting all signature request IDs by epoch
message GetSignatureRequestIDsByEpochResponse {
  // List of all signature request IDs for the epoch
  repeated string request_ids = 1;
  // Cursor to retrieve the next page. Empty when this is the last page.
  string next_from = 2;
}

// Request message for getting all signature requests by epoch
message GetSignatureRequestsByEpochRequest {
  // Epoch number
  uint64 epoch = 1;
  // Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
  uint32 page_size = 2;
  // Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
  string from = 3;
}

// Response message for getting all signature requests by epoch
message GetSignatureRequestsByEpochResponse {
  // List of all signature requests for the epoch
  repeated SignatureRequest signature_requests = 1;
  // Cursor to retrieve the next page. Empty when this is the last page.
  string next_from = 2;
}

// Request message for getting signature request
message GetSignatureRequestRequest {
  string request_id = 1;
}

// Request message for getting aggregation status
message GetAggregationStatusRequest {
  string request_id = 1;
}

// Request message for getting validator set
message GetValidatorSetRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;
}

// Request message for getting validator by address
message GetValidatorByAddressRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;

  // Validator address (required)
  string address = 2;
}


// Request message for getting validator by key
message GetValidatorByKeyRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;

  // Validator key tag (required)
  uint32 key_tag = 2;

  // Validator on chain (public) key (required)
  bytes on_chain_key = 3;
}

// Request message for getting local validator
message GetLocalValidatorRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;
}

// Request message for getting validator set header
message GetValidatorSetHeaderRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;
}

// Request message for getting validator set metadata
message GetValidatorSetMetadataRequest {
  // Epoch number (optional, if not provided current epoch will be used)
  optional uint64 epoch = 1;
}

// Response message for getting current epoch
message GetCurrentEpochResponse {
  // Epoch number
  uint64 epoch = 1;

  // Epoch start time
  google.protobuf.Timestamp start_time = 2;
}

// SignatureRequest represents a signature request
message SignatureRequest {
  // Request ID
  string request_id = 1;

  // Key tag identifier (0-127)
  uint32 key_tag = 2;

  // Message to be signed
  bytes message = 3;

  // Required epoch
  uint64 required_epoch = 4;
}

// Response message for getting signature request
message GetSignatureRequestResponse {
  SignatureRequest signature_request = 1;
}

// Response message for getting aggregation proof
message GetAggregationProofResponse {
  AggregationProof aggregation_proof = 1;
}

// Response message for getting aggregation proof
message GetAggregationProofsByEpochResponse {
  repeated AggregationProof aggregation_proofs = 1;
  // Cursor to retrieve the next page. Empty when this is the last page.
  string next_from = 2;
}

// Response message for getting aggregation proof
message AggregationProof {
  // Message hash
  bytes message_hash = 2;

  // Proof data
  bytes proof = 3;

  // Request ID
  string request_id = 4;
}

// Response message for getting aggregation status
message GetAggregationStatusResponse {
  // Current voting power of the aggregator (big integer as string)
  string current_voting_power = 1;

  // List of operator addresses that signed the request
  repeated string signer_operators = 2;
}

// Digital signature
message Signature {
  // Signature data
  bytes signature = 1;

  // Message hash
  bytes message_hash = 2;

  // Public key
  bytes public_key = 3;

  // Request ID
  string request_id = 4;
}

// Response message for getting validator set
message GetValidatorSetResponse {
  // The validator set
  ValidatorSet validator_set = 1;
}

// Response message for getting validator by address
message GetValidatorByAddressResponse {
  // The validator
  Validator validator = 1;
}

// Response message for getting validator by key
message GetValidatorByKeyResponse {
  // The validator
  Validator validator = 1;
}

// Response message for getting local validator
message GetLocalValidatorResponse {
  // The validator
  Validator validator = 1;
}

message ExtraData {
  bytes key = 1;
  bytes value = 2;
}

// Response message for getting validator set header
message GetValidatorSetMetadataResponse {
  repeated ExtraData extra_data = 1;
  bytes commitment_data = 2;
  string request_id = 3;
}

// Response message for getting validator set header
message GetValidatorSetHeaderResponse {
  // Version of the validator set
  uint32 version = 1;

  // Key tag required to commit next validator set
  uint32 required_key_tag = 2;

  // Validator set epoch
  uint64 epoch = 3;

  // Epoch capture timestamp
  google.protobuf.Timestamp capture_timestamp = 4;

  // Quorum threshold (big integer as string)
  string quorum_threshold = 5;

  // Total voting power (big integer as string)
  string total_voting_power = 6;

  // Validators SSZ Merkle root (hex string)
  string validators_ssz_mroot = 7;
}

// Validator set status enumeration
enum ValidatorSetStatus {
  // Default/unknown status
  VALIDATOR_SET_STATUS_UNSPECIFIED = 0;

  // Derived status
  VALIDATOR_SET_STATUS_DERIVED = 1;

  // Aggregated status
  VALIDATOR_SET_STATUS_AGGREGATED = 2;

  // Committed status
  VALIDATOR_SET_STATUS_COMMITTED = 3;
}

// Validator information
message Validator {
  // Operator address (hex string)
  string operator = 1;

  // Voting power of the validator (big integer as string)
  string voting_power = 2;

  // Indicates if the validator is active
  bool is_active = 3;

  // List of cryptographic keys
  repeated Key keys = 4;

  // List of validator vaults
  repeated ValidatorVault vaults = 5;
}

// Cryptographic key
message Key {
  // Key tag identifier (0-127)
  uint32 tag = 1;

  // Key payload
  bytes payload = 2;
}

// Validator vault information
message ValidatorVault {
  // Chain identifier
  uint64 chain_id = 1;

  // Vault address
  string vault = 2;

  // Voting power for this vault (big integer as string)
  string voting_power = 3;
}


// Signing process status enumeration
enum SigningStatus {
  // Default/unknown status
  SIGNING_STATUS_UNSPECIFIED = 0;

  // Request has been created and is waiting for signatures
  SIGNING_STATUS_PENDING = 1;

  // Signing process completed successfully with proof
  SIGNING_STATUS_COMPLETED = 2;

  // Signing process failed
  SIGNING_STATUS_FAILED = 3;

  // Signing request timed out
  SIGNING_STATUS_TIMEOUT = 4;
}

// Error code enumeration
enum ErrorCode {
  // Default/unknown error
  ERROR_CODE_UNSPECIFIED = 0;

  // No data found
  ERROR_CODE_NO_DATA = 1;

  // Internal server error
  ERROR_CODE_INTERNAL = 2;

  // Not an aggregator node
  ERROR_CODE_NOT_AGGREGATOR = 3;
}

// Request message for getting last committed epoch for a specific settlement chain
message GetLastCommittedRequest {
  // Settlement chain ID
  uint64 settlement_chain_id = 1;
}

// Response message for getting last committed epoch
message GetLastCommittedResponse {
  // Settlement chain ID
  uint64 settlement_chain_id = 1;
  ChainEpochInfo  epoch_info = 2;
}

// Request message for getting last committed epochs for all chains
message GetLastAllCommittedRequest {
  // No parameters needed
}

// Response message for getting all last committed epochs
message GetLastAllCommittedResponse {
  // List of settlement chains with their last committed epochs
  map<uint64, ChainEpochInfo> epoch_infos = 1;

  // Suggested epoch info for signatures, it is the minimum commited epoch among all chains
  ChainEpochInfo suggested_epoch_info = 2;
}

// Settlement chain with its last committed epoch
message ChainEpochInfo {
  // Last committed epoch for this chain
  uint64 last_committed_epoch = 1;

  // Epoch start time
  google.protobuf.Timestamp start_time = 2;
}

message ValidatorSet {
  // Version of the validator set
  uint32 version = 1;

  // Key tag required to commit next validator set
  uint32 required_key_tag = 2;

  // Validator set epoch
  uint64 epoch = 3;

  // Epoch capture timestamp
  google.protobuf.Timestamp capture_timestamp = 4;

  // Quorum threshold (big integer as string)
  string quorum_threshold = 5;

  // Status of validator set header
  ValidatorSetStatus status = 6;

  // List of validators
  repeated Validator validators = 7;
}
```

## File: cmd/relay/root/app.go

```go
package root
⋮----
import (
	"context"
	"log/slog"
	"net/http"
	"path/filepath"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/go-errors/errors"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p/core/crypto"
	"github.com/libp2p/go-libp2p/p2p/security/noise"
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
	"golang.org/x/sync/errgroup"

	"github.com/symbioticfi/relay/internal/client/p2p"
	"github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/entity"
	aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
	aggregatorApp "github.com/symbioticfi/relay/internal/usecase/aggregator-app"
	api_server "github.com/symbioticfi/relay/internal/usecase/api-server"
	entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/internal/usecase/pruner"
	signatureListener "github.com/symbioticfi/relay/internal/usecase/signature-listener"
	signerApp "github.com/symbioticfi/relay/internal/usecase/signer-app"
	sync_provider "github.com/symbioticfi/relay/internal/usecase/sync-provider"
	sync_runner "github.com/symbioticfi/relay/internal/usecase/sync-runner"
	valsetListener "github.com/symbioticfi/relay/internal/usecase/valset-listener"
	valsetStatusTracker "github.com/symbioticfi/relay/internal/usecase/valset-status-tracker"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/proof"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/pkg/tracing"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"context"
"log/slog"
"net/http"
"path/filepath"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/go-errors/errors"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
"golang.org/x/sync/errgroup"
⋮----
"github.com/symbioticfi/relay/internal/client/p2p"
"github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/entity"
aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
aggregatorApp "github.com/symbioticfi/relay/internal/usecase/aggregator-app"
api_server "github.com/symbioticfi/relay/internal/usecase/api-server"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/internal/usecase/pruner"
signatureListener "github.com/symbioticfi/relay/internal/usecase/signature-listener"
signerApp "github.com/symbioticfi/relay/internal/usecase/signer-app"
sync_provider "github.com/symbioticfi/relay/internal/usecase/sync-provider"
sync_runner "github.com/symbioticfi/relay/internal/usecase/sync-runner"
valsetListener "github.com/symbioticfi/relay/internal/usecase/valset-listener"
valsetStatusTracker "github.com/symbioticfi/relay/internal/usecase/valset-status-tracker"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/proof"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/pkg/tracing"
"github.com/symbioticfi/relay/symbiotic/client/evm"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
var (
	badgerFilePatterns = []string{"*.vlog", "MANIFEST"}
	bboltFilePatterns  = []string{"relay.db"}
)
⋮----
func detectStorageFiles(dir string, patterns []string) (bool, error)
⋮----
func runApp(ctx context.Context) error
⋮----
var keyProvider *keyprovider.CacheKeyProvider
⋮----
var err error
⋮----
var externalVPClient *votingpower.Client
⋮----
var baseRepo cached.Repository
⋮----
var prover *proof.ZkProver
⋮----
// Load all missing epochs before starting services
⋮----
// also start monitoring for new epochs immediately so that we don't miss any epochs while starting other services
⋮----
// Initialize tracing with instance ID from P2P service
⋮----
InstanceID: p2pService.ID(), // Use P2P ID as unique instance identifier
⋮----
var aggApp *aggregatorApp.AggregatorApp
⋮----
func initP2PService(ctx context.Context, cfg config, keyProvider keyprovider.KeyProvider, provider *sync_provider.Syncer, mtr *metrics.Metrics) (*p2p.Service, *p2p.DiscoveryService, error)
⋮----
// pad to make 20 byte to 32 bytes
⋮----
// TODO: include p2p key in valset
⋮----
libp2p.PrivateNetwork(swarmPSK), // Use a private network with the provided swarm key
libp2p.Identity(p2pIdentityPK),  // Use the provided identity private key to sign messages that will be sent over the P2P gossip sub
```

## File: cmd/relay/root/config.go

```go
package root
⋮----
import (
	"context"
	"fmt"
	"io/fs"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/spf13/pflag"

	p2pclient "github.com/symbioticfi/relay/internal/client/p2p"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"

	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)
⋮----
"context"
"fmt"
"io/fs"
"reflect"
"strconv"
"strings"
"time"
⋮----
"github.com/spf13/pflag"
⋮----
p2pclient "github.com/symbioticfi/relay/internal/client/p2p"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"github.com/spf13/cobra"
"github.com/spf13/viper"
⋮----
// The config can be populated from command-line flags, environment variables, and a config.yaml file.
const (
	storageTypeBadger = "badger"
	storageTypeBbolt  = "bbolt"
)
⋮----
// Priority order (highest to lowest):
// 1. Command-line flags
// 2. Environment variables (prefixed with SYMB_ and dashes replaced by underscores)
// 3. config.yaml file (specified by --config or default "config.yaml")
type config struct {
	StorageDir   string `mapstructure:"storage-dir"`
	StorageType  string `mapstructure:"storage-type"`
	CircuitsDir  string `mapstructure:"circuits-dir"`
	MaxUnsigners uint64 `mapstructure:"aggregation-policy-max-unsigners"`

	Log                          LogConfig                    `mapstructure:"log" validate:"required"`
	API                          APIConfig                    `mapstructure:"api" validate:"required"`
	Metrics                      MetricsConfig                `mapstructure:"metrics"`
	Driver                       CMDCrossChainAddress         `mapstructure:"driver" validate:"required"`
	SecretKeys                   CMDSecretKeySlice            `mapstructure:"secret-keys"`
	KeyStore                     KeyStore                     `mapstructure:"keystore"`
	SignalCfg                    signals.Config               `mapstructure:"signal"`
	Cache                        CacheConfig                  `mapstructure:"cache"`
	Sync                         SyncConfig                   `mapstructure:"sync"`
	KeyCache                     KeyCache                     `mapstructure:"key-cache"`
	P2P                          P2PConfig                    `mapstructure:"p2p" validate:"required"`
	Evm                          EvmConfig                    `mapstructure:"evm" validate:"required"`
	ExternalVotingPowerProviders []votingpower.ProviderConfig `mapstructure:"external-voting-power-providers"`
	ForceRole                    ForceRole                    `mapstructure:"force-role"`
	Retention                    RetentionConfig              `mapstructure:"retention"`
	Pruner                       PrunerConfig                 `mapstructure:"pruner"`
	Aggregation                  AggregationConfig            `mapstructure:"aggregation"`
	Tracing                      TracingConfig                `mapstructure:"tracing"`
	Badger                       BadgerConfig                 `mapstructure:"badger"`
	Bbolt                        BboltConfig                  `mapstructure:"bbolt"`
}
⋮----
type LogConfig struct {
	Level string `mapstructure:"level" validate:"oneof=debug info warn error"`
	Mode  string `mapstructure:"mode" validate:"oneof=json text pretty"`
}
⋮----
type APIConfig struct {
	ListenAddress     string `mapstructure:"listen" validate:"required"`
	MaxAllowedStreams uint64 `mapstructure:"max-allowed-streams" validate:"required"`
	VerboseLogging    bool   `mapstructure:"verbose-logging"`
	HTTPGateway       bool   `mapstructure:"http-gateway"`
}
⋮----
type MetricsConfig struct {
	ListenAddress string `mapstructure:"listen"`
	PprofEnabled  bool   `mapstructure:"pprof"`
}
⋮----
type CMDCrossChainAddress struct {
	ChainID uint64 `mapstructure:"chain-id" validate:"required"`
	Address string `mapstructure:"address" validate:"required"`
}
⋮----
type CMDSecretKeySlice []CMDSecretKey
⋮----
func (s *CMDSecretKeySlice) String() string
⋮----
func (s *CMDSecretKeySlice) Set(str string) error
⋮----
func (s *CMDSecretKeySlice) Type() string
⋮----
type CMDSecretKey struct {
	Namespace string `validate:"required"`
	KeyType   uint8  `validate:"required"`
	KeyId     int    `validate:"required"`
	Secret    string `validate:"required"`
}
⋮----
func (c *CMDSecretKey) FromStr(str string) (*CMDSecretKey, error)
⋮----
// CMDGasPriceMap is a map of chain ID to gas price in wei
// Used for per-chain fallback gas price configuration
type CMDGasPriceMap map[uint64]uint64
⋮----
// Parse format: chainID=gasPrice
⋮----
type KeyStore struct {
	Path     string `json:"path"`
	Password string `json:"password"`
}
type CacheConfig struct {
	NetworkConfigCacheSize int `mapstructure:"network-config-size"`
	ValidatorSetCacheSize  int `mapstructure:"validator-set-size"`
}
⋮----
type SyncConfig struct {
	Enabled      bool          `mapstructure:"enabled"`
	Period       time.Duration `mapstructure:"period"`
	Timeout      time.Duration `mapstructure:"timeout"`
	EpochsToSync uint64        `mapstructure:"epochs"`
}
⋮----
type KeyCache struct {
	// max size of the cache
	Size    int  `mapstructure:"size"`
	Enabled bool `mapstructure:"enabled"`
}
⋮----
// max size of the cache
⋮----
type P2PConfig struct {
	ListenAddress   string                          `mapstructure:"listen" validate:"required"`
	Bootnodes       []string                        `mapstructure:"bootnodes"`
	DHTMode         string                          `mapstructure:"dht-mode" validate:"oneof=auto server client disabled"`
	MDnsEnabled     bool                            `mapstructure:"mdns"`
	PublishTimeout  time.Duration                   `mapstructure:"publish-timeout"`
	SyncPeerBackoff p2pclient.SyncPeerBackoffConfig `mapstructure:"sync-peer-backoff"`
}
⋮----
type EvmConfig struct {
	Chains            []string       `mapstructure:"chains" validate:"required"`
	MaxCalls          int            `mapstructure:"max-calls"`
	FallbackGasPrices CMDGasPriceMap `mapstructure:"fallback-gas-prices"`
}
⋮----
type ForceRole struct {
	Aggregator bool `mapstructure:"aggregator"`
	Committer  bool `mapstructure:"committer"`
}
⋮----
type RetentionConfig struct {
	ValSetEpochs    uint64 `mapstructure:"valset-epochs"`
	ProofEpochs     uint64 `mapstructure:"proof-epochs"`
	SignatureEpochs uint64 `mapstructure:"signature-epochs"`
}
⋮----
type PrunerConfig struct {
	Enabled    bool          `mapstructure:"enabled"`
	Interval   time.Duration `mapstructure:"interval"`
	BatchSize  int           `mapstructure:"batch-size"`
	BatchPause time.Duration `mapstructure:"batch-pause"`
}
⋮----
type AggregationConfig struct {
	WorkerCount           int                      `mapstructure:"worker-count" validate:"min=1"`
	CrossEpochAggregation bool                     `mapstructure:"cross-epoch-aggregation"`
	Catchup               AggregationCatchupConfig `mapstructure:"catchup"`
}
⋮----
type AggregationCatchupConfig struct {
	Enabled             bool          `mapstructure:"enabled"`
	Interval            time.Duration `mapstructure:"interval"`
	EpochsToCheck       int           `mapstructure:"epochs-to-check"`
	EpochsOffset        int           `mapstructure:"epochs-offset"`
	MaxRequestsPerCycle int           `mapstructure:"max-requests-per-cycle"`
}
⋮----
type TracingConfig struct {
	Enabled    bool    `mapstructure:"enabled"`
	Endpoint   string  `mapstructure:"endpoint"`
	SampleRate float64 `mapstructure:"sample-rate"`
}
⋮----
type BboltConfig struct {
	InitialMmapSize  int           `mapstructure:"initial-mmap-size"`
	CompactOnStartup bool          `mapstructure:"compact-on-startup"`
	NoFreelistSync   bool          `mapstructure:"no-freelist-sync"`
	MaxBatchDelay    time.Duration `mapstructure:"max-batch-delay"`
	MaxBatchSize     int           `mapstructure:"max-batch-size"`
	StatsLogInterval time.Duration `mapstructure:"stats-log-interval"`
}
⋮----
type BadgerConfig struct {
	BlockCacheSize          int64         `mapstructure:"block-cache-size"`
	MemTableSize            int64         `mapstructure:"mem-table-size"`
	NumMemtables            int           `mapstructure:"num-memtables"`
	NumLevelZeroTables      int           `mapstructure:"num-level-zero-tables"`
	NumLevelZeroTablesStall int           `mapstructure:"num-level-zero-tables-stall"`
	CompactL0OnClose        bool          `mapstructure:"compact-l0-on-close"`
	NumCompactors           int           `mapstructure:"num-compactors"`
	ValueLogFileSize        int64         `mapstructure:"value-log-file-size"`
	ValueLogGCInterval      time.Duration `mapstructure:"value-log-gc-interval"`
	ValueLogGCDiscardRatio  float64       `mapstructure:"value-log-gc-discard-ratio"`
}
⋮----
func (c config) Validate() error
⋮----
// Validate that sync.epochs doesn't exceed retention.valset-epochs
⋮----
// Pruning valset entities without also pruning the dependent proof /
// signature data leaves orphans, so require all three to be set together
// when valset retention is configured, and keep proof / signature retention
// no larger than valset retention so dependents are removed first.
⋮----
// Validate badger: num-level-zero-tables-stall must be > num-level-zero-tables (badger fatals otherwise).
⋮----
effectiveL0Tables = 5 // badger default
⋮----
effectiveL0Stall = 15 // badger default
⋮----
var (
	configFile string
)
⋮----
func addRootFlags(cmd *cobra.Command)
⋮----
func DecodeFlagToStruct(fromType reflect.Type, toType reflect.Type, from interface
⋮----
// Handle CMDGasPriceMap from YAML map[string]interface{}
⋮----
// if not string return as is
⋮----
// Handle time.Duration specifically
⋮----
// if fromType implements pflag.Value then we can parse it from string
⋮----
func initConfig(cmd *cobra.Command, _ []string) error
⋮----
var cfg config
⋮----
// pflags allows to implement custom types by implementing pflag.Value (we can define how to parse struct from string)
// but[1] viper converts back struct defined flags to string automatically using String() method :(
// but[2] fortunately viper allows to pass decoder that we can use to convert string back to struct :D
⋮----
type contextKeyStruct struct{}
⋮----
func ctxWithCfg(ctx context.Context, cfg config) context.Context
func cfgFromCtx(ctx context.Context) config
```

## File: cmd/relay/root/root.go

```go
package root
⋮----
import (
	"context"
	"log/slog"
	"os"
	"os/signal"
	"syscall"

	"github.com/spf13/cobra"
)
⋮----
"context"
"log/slog"
"os"
"os/signal"
"syscall"
⋮----
"github.com/spf13/cobra"
⋮----
var Version = "local"
var BuildTime = "unknown"
⋮----
func NewRootCommand() *cobra.Command
⋮----
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:               "relay_sidecar",
	Short:             "Relay sidecar for signature aggregation",
	Long:              "A P2P service for collecting and aggregating signatures for Ethereum contracts.",
	SilenceUsage:      true,
	SilenceErrors:     true,
	PersistentPreRunE: initConfig,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runApp(signalContext(cmd.Context()))
	},
}
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
```

## File: cmd/relay/main.go

```go
package main
⋮----
import (
	"context"
	"log/slog"
	"os"

	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/cmd/relay/root"
)
⋮----
"context"
"log/slog"
"os"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/cmd/relay/root"
⋮----
func main()
```

## File: cmd/utils/cmd-helpers/external_voting_power.go

```go
package cmdhelpers
⋮----
import (
	"strconv"
	"strings"
	"time"

	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
)
⋮----
"strconv"
"strings"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
⋮----
func ExternalVotingPowerProviderConfigs(
	entries []string,
) ([]votingpower.ProviderConfig, error)
⋮----
func parseProviderConfigEntry(entry string) (votingpower.ProviderConfig, error)
⋮----
func parseHeaders(raw string) (map[string]string, error)
```

## File: cmd/utils/cmd-helpers/helpers.go

```go
package cmdhelpers
⋮----
import (
	"fmt"
	"math/big"
	"sort"
	"strconv"
	"strings"
	"syscall"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"golang.org/x/term"
)
⋮----
"fmt"
"math/big"
"sort"
"strconv"
"strings"
"syscall"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"golang.org/x/term"
⋮----
type SecretKeyMapFlag struct {
	Secrets map[uint64]string
}
⋮----
func (s *SecretKeyMapFlag) String() string
⋮----
sort.Strings(parts) // Optional: consistent output order
⋮----
func (s *SecretKeyMapFlag) Set(val string) error
⋮----
func (s *SecretKeyMapFlag) Type() string
⋮----
func GetPassword() (string, error)
⋮----
func PrintTreeValidator(leveledList pterm.LeveledList, validator symbiotic.Validator, valset symbiotic.ValidatorSet) pterm.LeveledList
⋮----
func GetPct(value *big.Int, total *big.Int) float64
```

## File: cmd/utils/keys/add.go

```go
package keys
⋮----
import (
	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/spf13/cobra"
)
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var addKeyCmd = &cobra.Command{
	Use:   "add",
	Short: "Add key",
	RunE: func(cmd *cobra.Command, args []string) error {
		if addFlags.PrivateKey == "" && !addFlags.Generate {
			return errors.New("add --generate if private key omitted")
		}

		if !addFlags.EvmNs && !addFlags.RelayNs && !addFlags.P2PNs {
			return errors.New("either --evm or --relay or --p2p must be specified")
		}
		if (addFlags.EvmNs && addFlags.RelayNs) || (addFlags.EvmNs && addFlags.P2PNs) || (addFlags.RelayNs && addFlags.P2PNs) {
			return errors.New("only one namespace can be specified at a time")
		}

		if addFlags.EvmNs {
			if addFlags.ChainID < 0 {
				return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
			}
			return addKeyWithNamespace(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(addFlags.ChainID), addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
		} else if addFlags.RelayNs {
			if addFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
				return errors.New("key tag is required for relay namespace")
			}
			kt := symbiotic.KeyTag(addFlags.KeyTag)
			if kt.Type() == symbiotic.KeyTypeInvalid {
				return errors.New("invalid key tag, type not supported")
			}
			keyId := kt & 0x0F
			return addKeyWithNamespace(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
		} else if addFlags.P2PNs {
			return addKeyWithNamespace(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
		}
		return errors.New("either --evm or --relay or --p2p must be specified")
	},
}
⋮----
func addKeyWithNamespace(ns string, keyType symbiotic.KeyType, id int, generate bool, force bool, privateKey string) error
⋮----
var err error
```

## File: cmd/utils/keys/cmd.go

```go
package keys
⋮----
import (
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/spf13/cobra"
)
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/spf13/cobra"
⋮----
func NewKeysCmd() *cobra.Command
⋮----
var keysCmd = &cobra.Command{
	Use:   "keys",
	Short: "Keys tool",
}
⋮----
type GlobalFlags struct {
	Path     string
	Password string
}
⋮----
type AddFlags struct {
	EvmNs      bool
	RelayNs    bool
	P2PNs      bool
	KeyTag     uint8
	ChainID    int64
	PrivateKey string
	Generate   bool
	Force      bool
}
⋮----
type RemoveFlags struct {
	EvmNs   bool
	RelayNs bool
	P2PNs   bool
	KeyTag  uint8
	ChainID int64
}
⋮----
type UpdateFlags struct {
	EvmNs      bool
	RelayNs    bool
	P2PNs      bool
	KeyTag     uint8
	ChainID    int64
	PrivateKey string
	Force      bool
}
⋮----
var globalFlags GlobalFlags
var addFlags AddFlags
⋮----
var removeFlags RemoveFlags
var updateFlags UpdateFlags
⋮----
func initFlags()
```

## File: cmd/utils/keys/print.go

```go
package keys
⋮----
import (
	"strconv"

	"github.com/pterm/pterm"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/spf13/cobra"
)
⋮----
"strconv"
⋮----
"github.com/pterm/pterm"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/spf13/cobra"
⋮----
var printKeysCmd = &cobra.Command{
	Use:   "list",
	Short: "Print all keys",
	RunE: func(cmd *cobra.Command, args []string) error {
		var err error

		if globalFlags.Password == "" {
			globalFlags.Password, err = cmdhelpers.GetPassword()
			if err != nil {
				return err
			}
		}

		keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
		if err != nil {
			return err
		}

		aliases := keyStore.GetAliases()

		tableData := pterm.TableData{{"#", "Alias", "Key Tag (Symb Keys)", "Public Key"}}
		for i, alias := range aliases {
			ns, kType, id, err := keyprovider.AliasToKeyTypeId(alias)
			if err != nil {
				return err
			}
			pk, err := keyStore.GetPrivateKeyByNamespaceTypeId(ns, kType, id)
			if err != nil {
				return err
			}
			prettyPk, err := pk.PublicKey().OnChain().MarshalText()
			if err != nil {
				return err
			}
			tag := "-"
			// for other namespace no guarantees can be made about the key id size
			if ns == keyprovider.SYMBIOTIC_KEY_NAMESPACE {
				kTag, err := entity.KeyTagFromTypeAndId(kType, uint8(id))
				if err != nil {
					return err
				}
				tag = kTag.String()
			}
			tableData = append(tableData, []string{
				strconv.Itoa(i + 1),
				alias,
				tag,
				string(prettyPk),
			})
		}
		return pterm.DefaultTable.WithHasHeader().WithData(tableData).Render()
	},
}
⋮----
var err error
⋮----
// for other namespace no guarantees can be made about the key id size
```

## File: cmd/utils/keys/remove.go

```go
package keys
⋮----
import (
	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/go-errors/errors"
	"github.com/spf13/cobra"
)
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var removeKeyCmd = &cobra.Command{
	Use:   "remove",
	Short: "Remove key",
	RunE: func(cmd *cobra.Command, args []string) error {
		var err error

		if globalFlags.Password == "" {
			globalFlags.Password, err = cmdhelpers.GetPassword()
			if err != nil {
				return err
			}
		}

		keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
		if err != nil {
			return err
		}

		if removeFlags.EvmNs {
			if removeFlags.ChainID < 0 {
				return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
			}
			return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(removeFlags.ChainID), globalFlags.Password)
		} else if removeFlags.RelayNs {
			if removeFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
				return errors.New("key tag is required for relay namespace")
			}
			kt := symbiotic.KeyTag(removeFlags.KeyTag)
			if kt.Type() == symbiotic.KeyTypeInvalid {
				return errors.New("invalid key tag, type not supported")
			}
			keyId := kt & 0x0F
			return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), globalFlags.Password)
		} else if removeFlags.P2PNs {
			return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, globalFlags.Password)
		}
		return errors.New("either --evm or --relay or --p2p must be specified")
	},
}
⋮----
var err error
```

## File: cmd/utils/keys/update.go

```go
package keys
⋮----
import (
	"github.com/ethereum/go-ethereum/common"
	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/go-errors/errors"
	"github.com/spf13/cobra"
)
⋮----
"github.com/ethereum/go-ethereum/common"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var updateKeyCmd = &cobra.Command{
	Use:   "update",
	Short: "Update key",
	RunE: func(cmd *cobra.Command, args []string) error {
		var err error

		if globalFlags.Password == "" {
			globalFlags.Password, err = cmdhelpers.GetPassword()
			if err != nil {
				return err
			}
		}

		keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
		if err != nil {
			return err
		}

		if updateFlags.PrivateKey == "" {
			return errors.New("private key is required for update")
		}

		privKeyBytes := common.FromHex(updateFlags.PrivateKey)

		if updateFlags.EvmNs {
			if updateFlags.ChainID < 0 {
				return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
			}
			exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(updateFlags.ChainID))
			if err != nil {
				return err
			}

			if !exists {
				return errors.New("key doesn't exist")
			}

			key, err := crypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, privKeyBytes)
			if err != nil {
				return err
			}

			return keyStore.AddKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(updateFlags.ChainID), key, globalFlags.Password, true)
		} else if updateFlags.RelayNs {
			if updateFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
				return errors.New("key tag is required for relay namespace")
			}
			kt := symbiotic.KeyTag(updateFlags.KeyTag)
			if kt.Type() == symbiotic.KeyTypeInvalid {
				return errors.New("invalid key tag, type not supported")
			}
			keyId := kt & 0x0F

			exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId))
			if err != nil {
				return err
			}

			if !exists {
				return errors.New("key doesn't exist")
			}

			key, err := crypto.NewPrivateKey(kt.Type(), privKeyBytes)
			if err != nil {
				return err
			}

			return keyStore.AddKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), key, globalFlags.Password, true)
		} else if updateFlags.P2PNs {
			exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID)
			if err != nil {
				return err
			}

			if !exists {
				return errors.New("key doesn't exist")
			}

			key, err := crypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, privKeyBytes)
			if err != nil {
				return err
			}

			return keyStore.AddKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, key, globalFlags.Password, true)
		}
		return errors.New("either --evm or --relay or --p2p must be specified")
	},
}
⋮----
var err error
```

## File: cmd/utils/network/cmd.go

```go
package network
⋮----
import (
	"context"
	"os"
	"os/signal"
	"syscall"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"

	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"context"
"os"
"os/signal"
"syscall"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
func NewNetworkCmd() *cobra.Command
⋮----
var networkCmd = &cobra.Command{
	Use:   "network",
	Short: "Network tool",
}
⋮----
type GlobalFlags struct {
	Chains                       []string
	DriverAddress                string
	DriverChainId                uint64
	ExternalVotingPowerProviders []string
}
⋮----
type InfoFlags struct {
	Validators     bool
	ValidatorsFull bool
	Addresses      bool
	Settlement     bool
	Epoch          uint64
}
⋮----
type GenesisFlags struct {
	Json    bool
	Commit  bool
	Epoch   int64
	Output  string
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
var globalFlags GlobalFlags
var infoFlags InfoFlags
var genesisFlags GenesisFlags
⋮----
func initFlags()
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
```

## File: cmd/utils/network/genesis.go

```go
package network
⋮----
import (
	"log/slog"
	"os"
	"strconv"
	"time"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"log/slog"
"os"
"strconv"
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/client/evm"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var genesisCmd = &cobra.Command{
	Use:   "generate-genesis",
	Short: "Generate genesis validator set header",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
		})
		if err != nil {
			return err
		}

		if genesisFlags.Commit {
			privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
			for _, chainId := range evmClient.GetChains() {
				secret, ok := genesisFlags.Secrets.Secrets[chainId]
				if !ok {
					secret, _ = privateKeyInput.Show("Enter private key for chain with ID: " + strconv.Itoa(int(chainId)))
				}
				pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
				if err != nil {
					return err
				}
				err = kp.AddKeyByNamespaceTypeId(
					keyprovider.EVM_KEY_NAMESPACE,
					symbiotic.KeyTypeEcdsaSecp256k1,
					int(chainId),
					pk,
				)
				if err != nil {
					return err
				}
			}
		}

		providerConfigs, err := cmdhelpers.ExternalVotingPowerProviderConfigs(globalFlags.ExternalVotingPowerProviders)
		if err != nil {
			return err
		}

		var externalVPClient *votingpower.Client
		if len(providerConfigs) > 0 {
			externalVPClient, err = votingpower.NewClient(ctx, providerConfigs)
			if err != nil {
				return errors.Errorf("failed to create external voting power client: %w", err)
			}
			defer func() {
				if err := externalVPClient.Close(); err != nil {
					slog.WarnContext(ctx, "Failed to close external voting power client", "error", err)
				}
			}()
		}

		spinner := getSpinner("Fetching on-chain network config...")

		deriver, err := valsetDeriver.NewDeriver(evmClient, externalVPClient)
		if err != nil {
			return errors.Errorf("failed to create deriver: %w", err)
		}

		currentOnchainEpoch := symbiotic.Epoch(0)
		if genesisFlags.Epoch >= 0 {
			currentOnchainEpoch = symbiotic.Epoch(genesisFlags.Epoch)
		} else {
			currentOnchainEpoch, err = evmClient.GetCurrentEpoch(ctx)
			if err != nil {
				return errors.Errorf("failed to get current epoch: %w", err)
			}
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}
		spinner.Success()

		spinner = getSpinner("Fetching on-chain validators data...")

		newValset, err := deriver.GetValidatorSet(ctx, currentOnchainEpoch, networkConfig)
		if err != nil {
			return errors.Errorf("failed to get validator set extra for epoch %d: %w", currentOnchainEpoch, err)
		}

		spinner.Success()

		spinner = getSpinner("Building header and extra data...")

		// header generation is clear now
		header, err := newValset.GetHeader()
		if err != nil {
			return errors.Errorf("failed to generate validator set header: %w", err)
		}

		aggregator, err := aggregator.NewAggregator(networkConfig.VerificationType, nil)
		if err != nil {
			return errors.Errorf("failed to create aggregator: %w", err)
		}

		// extra data generation is also clear but still in deriver
		extraData, err := aggregator.GenerateExtraData(ctx, newValset, networkConfig.RequiredKeyTags)
		if err != nil {
			return errors.Errorf("failed to generate extra data: %w", err)
		}

		spinner.Success()

		jsonData := printHeaderWithExtraDataToJSON(header, extraData)

		if !genesisFlags.Json {
			panels := pterm.Panels{
				{
					{Data: pterm.DefaultBox.WithTitle("Validator Set Header").Sprint(
						printHeaderTable(header),
					)},
				},
				{
					{Data: pterm.DefaultBox.WithTitle("Extra Data").Sprint(
						printExtraDataTable(extraData),
					)},
				},
			}

			pterm.DefaultPanel.WithPanels(panels).Render()
		} else {
			pterm.Println(jsonData)
		}

		if genesisFlags.Output != "" {
			err = os.WriteFile(genesisFlags.Output, []byte(jsonData), 0600)
			if err != nil {
				return errors.Errorf("failed to write output file: %w", err)
			}
			pterm.Success.Println("Genesis data written to " + genesisFlags.Output)
		}

		if genesisFlags.Commit {
			for _, settlement := range networkConfig.Settlements {
				spinner = getSpinner("Setting genesis on " + settlement.Address.String())
				txResult, err := evmClient.SetGenesis(
					ctx,
					settlement,
					header,
					extraData)
				if err != nil {
					spinner.Fail("Transaction failed: ", err)
					return errors.Errorf("failed to set genesis for network %d: %w", settlement.ChainId, err)
				}
				spinner.Success("Transaction hash: ", txResult.TxHash.String())
			}
		}

		return nil
	},
}
⋮----
var externalVPClient *votingpower.Client
⋮----
// header generation is clear now
⋮----
// extra data generation is also clear but still in deriver
⋮----
func getSpinner(text string) *pterm.SpinnerPrinter
```

## File: cmd/utils/network/info.go

```go
package network
⋮----
import (
	"log/slog"
	"time"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/samber/lo"
	"github.com/spf13/cobra"
	"golang.org/x/sync/errgroup"
)
⋮----
"log/slog"
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/samber/lo"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
⋮----
// maxEpochsToCheck caps how many epochs the `network info` command scans when
// counting missed valset header commitments. Above this we log a warning and
// truncate to avoid an O(N) allocation on operator misconfiguration (e.g., RPC
// returning an absurdly large epoch number).
const maxEpochsToCheck = 100_000
⋮----
var infoCmd = &cobra.Command{
	Use:   "info",
	Short: "Print network information",
	RunE: func(cmd *cobra.Command, args []string) error {
		var err error
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		providerConfigs, err := cmdhelpers.ExternalVotingPowerProviderConfigs(globalFlags.ExternalVotingPowerProviders)
		if err != nil {
			return err
		}

		var externalVPClient *votingpower.Client
		if len(providerConfigs) > 0 {
			externalVPClient, err = votingpower.NewClient(ctx, providerConfigs)
			if err != nil {
				return errors.Errorf("failed to create external voting power client: %w", err)
			}
			defer func() {
				if err := externalVPClient.Close(); err != nil {
					slog.WarnContext(ctx, "Failed to close external voting power client", "error", err)
				}
			}()
		}

		deriver, err := valsetDeriver.NewDeriver(evmClient, externalVPClient)
		if err != nil {
			return errors.Errorf("failed to create deriver: %w", err)
		}

		epoch := symbiotic.Epoch(infoFlags.Epoch)
		if infoFlags.Epoch == 0 {
			epoch, err = evmClient.GetCurrentEpoch(ctx)
			if err != nil {
				return errors.Errorf("Failed to get current epoch: %w", err)
			}
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, epoch)
		if err != nil {
			return errors.Errorf("Failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, epoch)
		if err != nil {
			return errors.Errorf("Failed to get config: %w", err)
		}

		epochDuration, err := evmClient.GetEpochDuration(ctx, epoch)
		if err != nil {
			return errors.Errorf("Failed to get epoch duration: %w", err)
		}

		valset, err := deriver.GetValidatorSet(ctx, epoch, networkConfig)
		if err != nil {
			return errors.Errorf("Failed to get validator set: %w", err)
		}

		// row with info and config
		panels := pterm.Panels{
			{
				{Data: pterm.DefaultBox.WithTitle("Network info").Sprint(
					printNetworkInfo(epoch, captureTimestamp, &networkConfig, &valset),
				)},
				{Data: pterm.DefaultBox.WithTitle("Network config").Sprint(
					printNetworkConfig(epochDuration, &networkConfig),
				)},
			},
		}

		// row with addresses [optional]
		if infoFlags.Addresses {
			panels = append(panels, []pterm.Panel{
				{Data: pterm.DefaultBox.WithTitle("Addresses").Sprint(
					printAddresses(symbiotic.CrossChainAddress{
						ChainId: globalFlags.DriverChainId,
						Address: common.HexToAddress(globalFlags.DriverAddress),
					}, &networkConfig),
				)},
			})
		}

		// row with settlements info
		if infoFlags.Settlement {
			settlementData := make([]settlementReplicaData, len(networkConfig.Settlements))

			eg, egCtx := errgroup.WithContext(ctx)
			eg.SetLimit(5)
			for i, settlement := range networkConfig.Settlements {
				eg.Go(func() error {
					isCommitted, err := evmClient.IsValsetHeaderCommittedAt(egCtx, settlement, epoch)
					if err != nil {
						return errors.Errorf("Failed to get latest epoch: %w", err)
					}
					settlementData[i].IsCommitted = isCommitted

					if isCommitted {
						headerHash, err := evmClient.GetHeaderHashAt(egCtx, settlement, epoch)
						if err != nil {
							return errors.Errorf("Failed to get header hash: %w", err)
						}
						settlementData[i].HeaderHash = headerHash
					}

					lastCommittedHeaderEpoch, err := evmClient.GetLastCommittedHeaderEpoch(ctx, settlement)
					if err != nil {
						return errors.Errorf("Failed to get last committed header epoch: %w", err)
					}
					settlementData[i].LastCommittedHeaderEpoch = uint64(lastCommittedHeaderEpoch)

					startEpoch := symbiotic.Epoch(0)
					epochCount := uint64(epoch) + 1
					if epochCount > maxEpochsToCheck {
						slog.WarnContext(egCtx, "Epoch range exceeds safety limit; missed epoch count is computed only over the most recent epochs",
							"epoch", epoch, "limit", maxEpochsToCheck,
						)
						epochCount = maxEpochsToCheck
						startEpoch = epoch - symbiotic.Epoch(maxEpochsToCheck-1)
					}
					epochsToCheck := lo.RepeatBy(int(epochCount), func(i int) symbiotic.Epoch {
						return startEpoch + symbiotic.Epoch(i)
					})

					commitmentResults, err := evmClient.IsValsetHeaderCommittedAtEpochs(egCtx, settlement, epochsToCheck)
					if err != nil {
						return errors.Errorf("Failed to check epoch commitments: %w", err)
					}

					settlementData[i].MissedEpochs = uint64(lo.CountBy(commitmentResults, func(committed bool) bool { return !committed }))

					return nil
				})
			}

			if err := eg.Wait(); err != nil {
				return err
			}
			header, err := valset.GetHeader()
			if err != nil {
				return errors.Errorf("Failed to get header: %w", err)
			}
			panels = append(panels, []pterm.Panel{
				{Data: pterm.DefaultBox.WithTitle("Settlement").Sprint(
					printSettlementData(header, networkConfig, settlementData),
				)},
			})
		}

		// row with validators [optional]
		if infoFlags.ValidatorsFull {
			panels = append(panels, []pterm.Panel{
				{Data: pterm.DefaultBox.WithTitle("Validators").Sprint(
					printValidatorsTree(valset),
				)},
			})
		} else if infoFlags.Validators {
			panels = append(panels, []pterm.Panel{
				{Data: pterm.DefaultBox.WithTitle("Validators").Sprint(
					printValidatorsTable(valset),
				)},
			})
		}

		pterm.DefaultPanel.WithPanels(panels).Render()

		return nil
	},
}
⋮----
var err error
⋮----
var externalVPClient *votingpower.Client
⋮----
// row with info and config
⋮----
// row with addresses [optional]
⋮----
// row with settlements info
⋮----
// row with validators [optional]
```

## File: cmd/utils/network/printers.go

```go
package network
⋮----
import (
	"encoding/json"
	"fmt"
	"math/big"
	"strconv"
	"strings"
	"time"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/ethereum/go-ethereum/common"
	"github.com/pterm/pterm"
	"github.com/pterm/pterm/putils"
	"github.com/samber/lo"
)
⋮----
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/samber/lo"
⋮----
type settlementReplicaData struct {
	IsCommitted              bool
	HeaderHash               common.Hash
	MissedEpochs             uint64
	LastCommittedHeaderEpoch uint64
}
⋮----
func printAddresses(driver symbiotic.CrossChainAddress, networkConfig *symbiotic.NetworkConfig) string
⋮----
func printNetworkConfig(epochDuration uint64, networkConfig *symbiotic.NetworkConfig) string
⋮----
func printNetworkInfo(epoch symbiotic.Epoch, epochStart symbiotic.Timestamp, networkConfig *symbiotic.NetworkConfig, valset *symbiotic.ValidatorSet) string
⋮----
func printValidatorsTree(valset symbiotic.ValidatorSet) string
⋮----
// Render the tree structure using the default tree printer.
⋮----
func printValidatorsTable(valset symbiotic.ValidatorSet) string
⋮----
func printHeaderTable(header symbiotic.ValidatorSetHeader) string
⋮----
func printExtraDataTable(extraData symbiotic.ExtraDataList) string
⋮----
func printHeaderWithExtraDataToJSON(validatorSetHeader symbiotic.ValidatorSetHeader, extraDataList symbiotic.ExtraDataList) string
⋮----
type jsonHeader struct {
		Version            uint8    `json:"version"`
		ValidatorsSszMRoot string   `json:"validatorsSszMRoot"` // hex string
		Epoch              uint64   `json:"epoch"`
		RequiredKeyTag     uint8    `json:"requiredKeyTag"`
		CaptureTimestamp   uint64   `json:"captureTimestamp"`
		QuorumThreshold    *big.Int `json:"quorumThreshold"`
		TotalVotingPower   *big.Int `json:"totalVotingPower"`
	}
⋮----
ValidatorsSszMRoot string   `json:"validatorsSszMRoot"` // hex string
⋮----
type jsonExtraData struct {
		Key   string `json:"key"`   // hex string
		Value string `json:"value"` // hex string
	}
⋮----
Key   string `json:"key"`   // hex string
Value string `json:"value"` // hex string
⋮----
type jsonValidatorSetHeaderWithExtraData struct {
		Header        jsonHeader      `json:"header"`
		ExtraDataList []jsonExtraData `json:"extraData"`
	}
⋮----
func printSettlementData(
	valsetHeader symbiotic.ValidatorSetHeader,
	networkConfig symbiotic.NetworkConfig,
	settlementData []settlementReplicaData,
) string
```

## File: cmd/utils/operator/cmd.go

```go
package operator
⋮----
import (
	"context"
	"os"
	"os/signal"
	"syscall"

	"github.com/go-errors/errors"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"context"
"os"
"os/signal"
"syscall"
⋮----
"github.com/go-errors/errors"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
func NewOperatorCmd() *cobra.Command
⋮----
var operatorCmd = &cobra.Command{
	Use:   "operator",
	Short: "Operator tool",
}
⋮----
type GlobalFlags struct {
	Chains                []string
	DriverAddress         string
	DriverChainId         uint64
	VotingProviderChainId uint64
}
⋮----
type InfoFlags struct {
	Epoch                        uint64
	Path                         string
	Password                     string
	KeyTag                       uint8
	ExternalVotingPowerProviders []string
}
⋮----
type RegisterKeyFlags struct {
	Secrets  cmdhelpers.SecretKeyMapFlag
	Path     string
	Password string
	KeyTag   uint8
}
⋮----
type RegisterKeyArtifactFlags struct {
	Path            string
	Password        string
	KeyTag          uint8
	OperatorAddress string
}
⋮----
type InvalidateOldSignaturesFlags struct {
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type RegisterOperatorWithSignatureFlags struct {
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type UnregisterOperatorWithSignatureFlags struct {
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type RegisterOperatorFlags struct {
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type UnregisterOperatorFlags struct {
	Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
var globalFlags GlobalFlags
var infoFlags InfoFlags
var registerKeyFlags RegisterKeyFlags
var registerKeyArtifactFlags RegisterKeyArtifactFlags
var invalidateOldSignaturesFlags InvalidateOldSignaturesFlags
var registerOperatorWithSignatureFlags RegisterOperatorWithSignatureFlags
var unregisterOperatorWithSignatureFlags UnregisterOperatorWithSignatureFlags
var registerOperatorFlags RegisterOperatorFlags
var unregisterOperatorFlags UnregisterOperatorFlags
⋮----
func initFlags()
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
⋮----
// findVotingPowerProviderByChainId finds a voting power provider by chain id from the list
func findVotingPowerProviderByChainId(providers []symbiotic.CrossChainAddress, chainId uint64) (symbiotic.CrossChainAddress, error)
```

## File: cmd/utils/operator/info.go

```go
package operator
⋮----
import (
	"log/slog"
	"time"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/pterm/pterm/putils"
	"github.com/spf13/cobra"
)
⋮----
"log/slog"
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/spf13/cobra"
⋮----
var infoCmd = &cobra.Command{
	Use:   "info",
	Short: "Print operator information",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		providerConfigs, err := cmdhelpers.ExternalVotingPowerProviderConfigs(infoFlags.ExternalVotingPowerProviders)
		if err != nil {
			return err
		}

		var externalVPClient *votingpower.Client
		if len(providerConfigs) > 0 {
			externalVPClient, err = votingpower.NewClient(ctx, providerConfigs)
			if err != nil {
				return errors.Errorf("failed to create external voting power client: %w", err)
			}
			defer func() {
				if err := externalVPClient.Close(); err != nil {
					slog.WarnContext(ctx, "Failed to close external voting power client", "error", err)
				}
			}()
		}

		if infoFlags.Password == "" {
			infoFlags.Password, err = cmdhelpers.GetPassword()
			if err != nil {
				return errors.Errorf("failed to get password: %w", err)
			}
		}

		if infoFlags.Epoch == 0 {
			epoch, err := evmClient.GetCurrentEpoch(ctx)
			if err != nil {
				return errors.Errorf("failed to get current epoch: %w", err)
			}
			infoFlags.Epoch = uint64(epoch)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, symbiotic.Epoch(infoFlags.Epoch))
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, symbiotic.Epoch(infoFlags.Epoch))
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		epoch, err := evmClient.GetLastCommittedHeaderEpoch(ctx, networkConfig.Settlements[0])
		if err != nil {
			return errors.Errorf("failed to get valset header: %w", err)
		}

		deriver, err := valsetDeriver.NewDeriver(evmClient, externalVPClient)
		if err != nil {
			return errors.Errorf("failed to create valset deriver: %w", err)
		}

		valset, err := deriver.GetValidatorSet(ctx, epoch, networkConfig)
		if err != nil {
			return errors.Errorf("failed to get validator set: %w", err)
		}

		keyStore, err := keyprovider.NewKeystoreProvider(infoFlags.Path, infoFlags.Password)
		if err != nil {
			return err
		}

		kt := symbiotic.KeyTag(infoFlags.KeyTag)
		pk, err := keyStore.GetPrivateKey(kt)
		if err != nil {
			return err
		}

		validator, found := valset.FindValidatorByKey(kt, pk.PublicKey().OnChain())
		if !found {
			return errors.Errorf("validator not found for key: %d %s", kt, common.Bytes2Hex(pk.PublicKey().Raw()))
		}

		leveledList := pterm.LeveledList{}
		leveledList = cmdhelpers.PrintTreeValidator(leveledList, validator, valset)
		text, _ := pterm.DefaultTree.WithRoot(putils.TreeFromLeveledList(leveledList)).Srender()
		panels := pterm.Panels{{{Data: pterm.DefaultBox.WithTitle("Operator info").Sprint(text)}}}
		pterm.DefaultPanel.WithPanels(panels).Render()

		return nil
	},
}
⋮----
var externalVPClient *votingpower.Client
```

## File: cmd/utils/operator/invalidate_old_signatures.go

```go
package operator
⋮----
import (
	"strconv"
	"time"

	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var invalidateOldSignaturesCmd = &cobra.Command{
	Use:   "invalidate-old-signatures",
	Short: "Invalidate old signatures for operator",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		currentOnChainEpoch, err := evmClient.GetCurrentEpoch(ctx)
		if err != nil {
			return errors.Errorf("failed to get current epoch: %w", err)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnChainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnChainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		if len(networkConfig.VotingPowerProviders) == 0 {
			return errors.New("no voting power providers found in network config")
		}

		votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
		if err != nil {
			return err
		}

		// Load the operator key for the voting power provider's chain
		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := invalidateOldSignaturesFlags.Secrets.Secrets[votingPowerProvider.ChainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
		}

		pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
		if err != nil {
			return err
		}
		err = kp.AddKeyByNamespaceTypeId(
			keyprovider.EVM_KEY_NAMESPACE,
			symbiotic.KeyTypeEcdsaSecp256k1,
			int(votingPowerProvider.ChainId),
			pk,
		)
		if err != nil {
			return err
		}

		txResult, err := evmClient.InvalidateOldSignatures(ctx, votingPowerProvider)
		if err != nil {
			return errors.Errorf("failed to invalidate old signatures: %w", err)
		}

		pterm.Success.Println("Old signatures invalidated! TxHash:", txResult.TxHash.String())

		return nil
	},
}
⋮----
// Load the operator key for the voting power provider's chain
```

## File: cmd/utils/operator/register_key_artifact_test.go

```go
package operator
⋮----
import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"strconv"
	"sync"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"github.com/stretchr/testify/require"

	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strconv"
"sync"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
"github.com/symbioticfi/relay/internal/usecase/metrics"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestRegisterKeyArtifactECDSA(t *testing.T)
⋮----
var actual registrationArtifactJSON
⋮----
func TestRegisterKeyArtifactUsesOperatorAddress(t *testing.T)
⋮----
func TestRegisterKeyArtifactRequiresOperatorAddress(t *testing.T)
⋮----
func TestRegisterKeyArtifactBLSIncludesExtraData(t *testing.T)
⋮----
func TestRegisterKeyArtifactBLS12381IncludesExtraData(t *testing.T)
⋮----
func stubRegisterKeyDependencies(t *testing.T, artifact key_registerer.RegistrationArtifact) func()
⋮----
func stubRegisterKeyDependenciesWithBuilder(t *testing.T, builder *staticRegisterKeyArtifactBuilder) func()
⋮----
type staticRegisterKeyArtifactBuilder struct {
	artifact            key_registerer.RegistrationArtifact
	buildArtifactCalled bool
	registerCalled      bool
	operatorAddress     common.Address
}
⋮----
type registrationArtifactJSON struct {
	KeyTag       uint8  `json:"keyTag"`
	KeyHex       string `json:"keyHex"`
	SignatureHex string `json:"signatureHex"`
	ExtraDataHex string `json:"extraDataHex"`
}
⋮----
func (s *staticRegisterKeyArtifactBuilder) BuildArtifact(
	_ context.Context,
	_ symbioticCrypto.PrivateKey,
	_ symbiotic.KeyTag,
	operatorAddress common.Address,
) (key_registerer.RegistrationArtifact, error)
⋮----
func (s *staticRegisterKeyArtifactBuilder) Register(
	_ context.Context,
	_ symbioticCrypto.PrivateKey,
	_ symbiotic.KeyTag,
	operatorAddress common.Address,
) (symbiotic.TxResult, error)
⋮----
func createOperatorTestKeystore(t *testing.T, keyTag symbiotic.KeyTag, privateKey symbioticCrypto.PrivateKey) string
⋮----
func runOperatorCommand(t *testing.T, args ...string) (string, error)
⋮----
func runRegisterKeyArtifactCommand(t *testing.T, keyTag symbiotic.KeyTag, keystorePath string, operatorAddress common.Address) (string, error)
⋮----
func newTestRegisterKeyRPCServer(t *testing.T) *httptest.Server
⋮----
var req struct {
				ID     json.RawMessage `json:"id"`
				Method string          `json:"method"`
			}
⋮----
var result any
⋮----
var (
	registerKeyRPCServerOnce sync.Once
	registerKeyRPCServer     *httptest.Server
	testOperatorCmdOnce      sync.Once
	testOperatorCmd          *cobra.Command
)
⋮----
func keyTagArg(keyTag symbiotic.KeyTag) string
⋮----
const testKeystorePassword = "password"
```

## File: cmd/utils/operator/register_key_artifact.go

```go
package operator
⋮----
import (
	"context"
	"encoding/json"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/spf13/cobra"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"encoding/json"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type registerKeyArtifactBuilder interface {
	BuildArtifact(ctx context.Context, pk symbioticCrypto.PrivateKey, kt symbiotic.KeyTag, operatorAddress common.Address) (key_registerer.RegistrationArtifact, error)
	Register(ctx context.Context, pk symbioticCrypto.PrivateKey, kt symbiotic.KeyTag, operatorAddress common.Address) (symbiotic.TxResult, error)
}
⋮----
type registerKeyBuildConfig struct {
	EVMClient evm.IEvmClient
}
⋮----
var newRegisterKeyArtifactMetrics = func() *metrics.Metrics {
⋮----
var newRegisterKeyArtifactBuilder = func(cfg registerKeyBuildConfig) (registerKeyArtifactBuilder, error) {
⋮----
var registerKeyArtifactCmd = &cobra.Command{
	Use:   "register-key-artifact",
	Short: "Build operator key registration artifact without submitting a transaction",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		if registerKeyArtifactFlags.OperatorAddress == "" {
			return errors.New("--operator-address is required")
		}
		if !common.IsHexAddress(registerKeyArtifactFlags.OperatorAddress) {
			return errors.New("--operator-address must be a valid hex address")
		}

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        newRegisterKeyArtifactMetrics(),
		})
		if err != nil {
			return err
		}

		kt := symbiotic.KeyTag(registerKeyArtifactFlags.KeyTag)
		pk, err := loadRegisterKeyArtifactPrivateKey(registerKeyArtifactFlags.Path, &registerKeyArtifactFlags.Password, kt)
		if err != nil {
			return err
		}

		keyReg, err := newRegisterKeyArtifactBuilder(registerKeyBuildConfig{
			EVMClient: evmClient,
		})
		if err != nil {
			return errors.Errorf("failed to create registerer: %w", err)
		}

		artifact, err := keyReg.BuildArtifact(ctx, pk, kt, common.HexToAddress(registerKeyArtifactFlags.OperatorAddress))
		if err != nil {
			return errors.Errorf("failed to build registration artifact: %w", err)
		}

		encodedArtifact, err := json.Marshal(artifact)
		if err != nil {
			return errors.Errorf("failed to encode registration artifact: %w", err)
		}
		_, err = cmd.OutOrStdout().Write(append(encodedArtifact, '\n'))
		return err
	},
}
⋮----
func loadRegisterKeyArtifactPrivateKey(path string, password *string, kt symbiotic.KeyTag) (symbioticCrypto.PrivateKey, error)
```

## File: cmd/utils/operator/register_key.go

```go
package operator
⋮----
import (
	"log/slog"
	"strconv"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"

	cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"log/slog"
"strconv"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
var registerKeyCmd = &cobra.Command{
	Use:   "register-key",
	Short: "Register operator key in key registry",
	RunE: func(cmd *cobra.Command, args []string) error {
		var err error
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		// TODO multiple chains key registration support
		if len(evmClient.GetChains()) != 1 {
			return errors.New("only single chain is supported")
		}
		chainId := evmClient.GetChains()[0]

		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := registerKeyFlags.Secrets.Secrets[chainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter private key for chain with ID: " + strconv.Itoa(int(chainId)))
		}
		evmPK, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
		if err != nil {
			return err
		}
		err = kp.AddKeyByNamespaceTypeId(
			keyprovider.EVM_KEY_NAMESPACE,
			symbiotic.KeyTypeEcdsaSecp256k1,
			int(chainId),
			evmPK,
		)
		if err != nil {
			return err
		}

		if registerKeyFlags.Password == "" {
			registerKeyFlags.Password, err = cmdhelpers.GetPassword()
			if err != nil {
				return err
			}
		}

		keyStore, err := keyprovider.NewKeystoreProvider(registerKeyFlags.Path, registerKeyFlags.Password)
		if err != nil {
			return err
		}

		kt := symbiotic.KeyTag(registerKeyFlags.KeyTag)
		pk, err := keyStore.GetPrivateKey(kt)
		if err != nil {
			return errors.Errorf("failed to get private key  for keyTag %v from keystore: %w", kt, err)
		}

		ecdsaPk, err := crypto.HexToECDSA(secret)
		if err != nil {
			return err
		}
		operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)

		keyReg, err := key_registerer.NewRegisterer(key_registerer.Config{
			EVMClient: evmClient,
		})
		if err != nil {
			return errors.Errorf("failed to create registerer: %w", err)
		}

		// Use the adjusted signature for registration
		txResult, err := keyReg.Register(ctx, pk, kt, operator)
		if err != nil {
			return errors.Errorf("failed to register key: %w", err)
		}

		slog.InfoContext(ctx, "Operator Key registered!", "txHash", txResult.TxHash.String(), "key-tag", kt)

		return nil
	},
}
⋮----
var err error
⋮----
// TODO multiple chains key registration support
⋮----
// Use the adjusted signature for registration
```

## File: cmd/utils/operator/register_operator.go

```go
package operator
⋮----
import (
	"strconv"
	"time"

	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var registerOperatorCmd = &cobra.Command{
	Use:   "register-operator",
	Short: "Register operator on-chain via VotingPowerProvider",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
		if err != nil {
			return errors.Errorf("failed to get current epoch: %w", err)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		if len(networkConfig.VotingPowerProviders) == 0 {
			return errors.New("no voting power providers found in network config")
		}

		votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
		if err != nil {
			return err
		}

		// Load the operator key for the voting power provider's chain
		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := registerOperatorFlags.Secrets.Secrets[votingPowerProvider.ChainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
		}

		pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
		if err != nil {
			return err
		}
		err = kp.AddKeyByNamespaceTypeId(
			keyprovider.EVM_KEY_NAMESPACE,
			symbiotic.KeyTypeEcdsaSecp256k1,
			int(votingPowerProvider.ChainId),
			pk,
		)
		if err != nil {
			return err
		}

		txResult, err := evmClient.RegisterOperatorVotingPowerProvider(ctx, votingPowerProvider)
		if err != nil {
			return errors.Errorf("failed to register operator: %w", err)
		}

		pterm.Success.Println("Operator registered! TxHash:", txResult.TxHash.String())

		return nil
	},
}
⋮----
// Load the operator key for the voting power provider's chain
```

## File: cmd/utils/operator/register_with_signature.go

```go
package operator
⋮----
import (
	"strconv"
	"time"

	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/math"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var registerOperatorWithSignatureCmd = &cobra.Command{
	Use:   "register-operator-with-signature",
	Short: "Generate EIP-712 signature for operator registration",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := registerOperatorWithSignatureFlags.Secrets.Secrets[globalFlags.DriverChainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(globalFlags.DriverChainId)))
		}

		ecdsaPk, err := crypto.HexToECDSA(secret)
		if err != nil {
			return errors.Errorf("failed to parse private key: %w", err)
		}
		operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)

		currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
		if err != nil {
			return errors.Errorf("failed to get current epoch: %w", err)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		// Find VotingPowerProvider by chain ID
		if len(networkConfig.VotingPowerProviders) == 0 {
			return errors.New("no voting power providers found in network config")
		}
		votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
		if err != nil {
			return err
		}

		eip712Domain, err := evmClient.GetVotingPowerProviderEip712Domain(ctx, votingPowerProvider)
		if err != nil {
			return errors.Errorf("failed to get eip712 domain: %w", err)
		}

		nonce, err := evmClient.GetOperatorNonce(ctx, votingPowerProvider, operator)
		if err != nil {
			return errors.Errorf("failed to get operator nonce: %w", err)
		}

		// Build EIP-712 typed data for RegisterOperator
		typedData := apitypes.TypedData{
			Types: apitypes.Types{
				"EIP712Domain": []apitypes.Type{
					{Name: "name", Type: "string"},
					{Name: "version", Type: "string"},
					{Name: "chainId", Type: "uint256"},
					{Name: "verifyingContract", Type: "address"},
				},
				"RegisterOperator": []apitypes.Type{
					{Name: "operator", Type: "address"},
					{Name: "nonce", Type: "uint256"},
				},
			},
			PrimaryType: "RegisterOperator",
			Domain: apitypes.TypedDataDomain{
				Name:              eip712Domain.Name,
				Version:           eip712Domain.Version,
				ChainId:           (*math.HexOrDecimal256)(eip712Domain.ChainId),
				VerifyingContract: eip712Domain.VerifyingContract.Hex(),
			},
			Message: apitypes.TypedDataMessage{
				"operator": operator.Hex(),
				"nonce":    (*math.HexOrDecimal256)(nonce),
			},
		}

		typedDataHash, _, err := apitypes.TypedDataAndHash(typedData)
		if err != nil {
			return errors.Errorf("failed to hash typed data: %w", err)
		}

		signature, err := crypto.Sign(typedDataHash, ecdsaPk)
		if err != nil {
			return errors.Errorf("failed to sign: %w", err)
		}

		// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
		if len(signature) == 65 {
			signature[64] += 27
		}

		pterm.Success.Printf("0x%x\n", signature)

		return nil
	},
}
⋮----
// Find VotingPowerProvider by chain ID
⋮----
// Build EIP-712 typed data for RegisterOperator
⋮----
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
```

## File: cmd/utils/operator/unregister_operator.go

```go
package operator
⋮----
import (
	"strconv"
	"time"

	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var unregisterOperatorCmd = &cobra.Command{
	Use:   "unregister-operator",
	Short: "Unregister operator on-chain via VotingPowerProvider",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		kp, err := keyprovider.NewSimpleKeystoreProvider()
		if err != nil {
			return err
		}

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			KeyProvider:    kp,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
		if err != nil {
			return errors.Errorf("failed to get current epoch: %w", err)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		if len(networkConfig.VotingPowerProviders) == 0 {
			return errors.New("no voting power providers found in network config")
		}

		votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
		if err != nil {
			return err
		}

		// Load the operator key for the voting power provider's chain
		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := unregisterOperatorFlags.Secrets.Secrets[votingPowerProvider.ChainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
		}

		pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
		if err != nil {
			return err
		}
		err = kp.AddKeyByNamespaceTypeId(
			keyprovider.EVM_KEY_NAMESPACE,
			symbiotic.KeyTypeEcdsaSecp256k1,
			int(votingPowerProvider.ChainId),
			pk,
		)
		if err != nil {
			return err
		}

		txResult, err := evmClient.UnregisterOperatorVotingPowerProvider(ctx, votingPowerProvider)
		if err != nil {
			return errors.Errorf("failed to unregister operator: %w", err)
		}

		pterm.Success.Println("Operator unregistered! TxHash:", txResult.TxHash.String())

		return nil
	},
}
⋮----
// Load the operator key for the voting power provider's chain
```

## File: cmd/utils/operator/unregister_with_signature.go

```go
package operator
⋮----
import (
	"strconv"
	"time"

	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/math"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var unregisterOperatorWithSignatureCmd = &cobra.Command{
	Use:   "unregister-operator-with-signature",
	Short: "Generate EIP-712 signature for operator unregistration",
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := signalContext(cmd.Context())

		evmClient, err := evm.NewEvmClient(ctx, evm.Config{
			ChainURLs: globalFlags.Chains,
			DriverAddress: symbiotic.CrossChainAddress{
				ChainId: globalFlags.DriverChainId,
				Address: common.HexToAddress(globalFlags.DriverAddress),
			},
			RequestTimeout: 5 * time.Second,
			Metrics:        metrics.New(metrics.Config{}),
		})
		if err != nil {
			return err
		}

		privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
		secret, ok := unregisterOperatorWithSignatureFlags.Secrets.Secrets[globalFlags.DriverChainId]
		if !ok {
			secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(globalFlags.DriverChainId)))
		}

		ecdsaPk, err := crypto.HexToECDSA(secret)
		if err != nil {
			return errors.Errorf("failed to parse private key: %w", err)
		}
		operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)

		currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
		if err != nil {
			return errors.Errorf("failed to get current epoch: %w", err)
		}

		captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get capture timestamp: %w", err)
		}

		networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
		if err != nil {
			return errors.Errorf("failed to get config: %w", err)
		}

		// Find VotingPowerProvider by chain ID
		if len(networkConfig.VotingPowerProviders) == 0 {
			return errors.New("no voting power providers found in network config")
		}
		votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
		if err != nil {
			return err
		}

		eip712Domain, err := evmClient.GetVotingPowerProviderEip712Domain(ctx, votingPowerProvider)
		if err != nil {
			return errors.Errorf("failed to get eip712 domain: %w", err)
		}

		nonce, err := evmClient.GetOperatorNonce(ctx, votingPowerProvider, operator)
		if err != nil {
			return errors.Errorf("failed to get operator nonce: %w", err)
		}

		// Build EIP-712 typed data for UnregisterOperator
		typedData := apitypes.TypedData{
			Types: apitypes.Types{
				"EIP712Domain": []apitypes.Type{
					{Name: "name", Type: "string"},
					{Name: "version", Type: "string"},
					{Name: "chainId", Type: "uint256"},
					{Name: "verifyingContract", Type: "address"},
				},
				"UnregisterOperator": []apitypes.Type{
					{Name: "operator", Type: "address"},
					{Name: "nonce", Type: "uint256"},
				},
			},
			PrimaryType: "UnregisterOperator",
			Domain: apitypes.TypedDataDomain{
				Name:              eip712Domain.Name,
				Version:           eip712Domain.Version,
				ChainId:           (*math.HexOrDecimal256)(eip712Domain.ChainId),
				VerifyingContract: eip712Domain.VerifyingContract.Hex(),
			},
			Message: apitypes.TypedDataMessage{
				"operator": operator.Hex(),
				"nonce":    (*math.HexOrDecimal256)(nonce),
			},
		}

		typedDataHash, _, err := apitypes.TypedDataAndHash(typedData)
		if err != nil {
			return errors.Errorf("failed to hash typed data: %w", err)
		}

		signature, err := crypto.Sign(typedDataHash, ecdsaPk)
		if err != nil {
			return errors.Errorf("failed to sign: %w", err)
		}

		// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
		if len(signature) == 65 {
			signature[64] += 27
		}

		pterm.Success.Printf("0x%x\n", signature)

		return nil
	},
}
⋮----
// Find VotingPowerProvider by chain ID
⋮----
// Build EIP-712 typed data for UnregisterOperator
⋮----
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
```

## File: cmd/utils/prune/cmd.go

```go
package prune
⋮----
import (
	"github.com/spf13/cobra"
)
⋮----
"github.com/spf13/cobra"
⋮----
type Flags struct {
	StorageDir           string
	ValsetEpochs         uint64
	ProofEpochs          uint64
	SignatureEpochs      uint64
	Compact              bool
	BadgerFlattenWorkers int
	PruneBatchSize       int
	AssumeYes            bool
}
⋮----
var flags Flags
⋮----
func NewPruneCmd() *cobra.Command
```

## File: cmd/utils/prune/run_test.go

```go
package prune
⋮----
import (
	"math"
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"
)
⋮----
"math"
"os"
"path/filepath"
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
func TestDetectStorageType(t *testing.T)
⋮----
func TestDetectStorageType_NonexistentDir(t *testing.T)
⋮----
func TestHumanBytes_ClampedAtExabyte(t *testing.T)
⋮----
// math.MaxInt64 ≈ 8 EiB, the largest int64 value — must clamp to E (exa)
// without indexing past the suffix table.
⋮----
_ = humanBytes(1 << 60)       // 1 EiB
_ = humanBytes(math.MaxInt64) // ~8 EiB
```

## File: cmd/utils/prune/run.go

```go
package prune
⋮----
import (
	"context"
	"io"
	"log/slog"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/go-errors/errors"
	"github.com/pterm/pterm"
	"golang.org/x/term"

	"github.com/symbioticfi/relay/internal/client/repository/badger"
	"github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/usecase/pruner"
)
⋮----
"context"
"io"
"log/slog"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"golang.org/x/term"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/badger"
"github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/usecase/pruner"
⋮----
const (
	storageTypeBadger = "badger"
	storageTypeBbolt  = "bbolt"

	bboltDBFilename = "relay.db"
)
⋮----
var (
	badgerFilePatterns = []string{"*.vlog", "MANIFEST"}
	bboltFilePatterns  = []string{bboltDBFilename}
)
⋮----
func run(ctx context.Context, f Flags) error
⋮----
// Silence library slog so it doesn't interleave with pterm output and
// break spinner animations. Errors propagate via returned error values.
⋮----
// Mirror pruner.Config.Validate so we fail before opening the DB (which
// takes an exclusive lock and may take seconds on large stores).
⋮----
var runErr error
⋮----
func runBbolt(ctx context.Context, f Flags) error
⋮----
// Open repo once, run prune, and (if --compact) reuse the same handle
// for compaction so we don't pay a second RW open + freelist build.
⋮----
// Compact-only: skip our RW open entirely. CompactDB opens its own handle.
⋮----
func runBboltSession(ctx context.Context, f Flags) error
⋮----
closed = true // CompactAndClose always closes the handle, success or failure.
⋮----
func runBadger(ctx context.Context, f Flags) error
⋮----
BlockCacheSize:           -1, // -1 = badger default; 0 means "disabled"
⋮----
// Final L0 compaction happens in Close (CompactL0OnClose=true).
// Mark closed before the error check so the deferred Close can't run
// on a partially-closed DB.
⋮----
func runPruneOnce(ctx context.Context, cfg pruner.Config, f Flags) error
⋮----
// progressReporter drives a sequence of pterm progress bars: one bar per
// entity-type, each starting at 0 and advancing as epochs are pruned. The
// bars stack vertically since pruner pass ordering is sequential.
type progressReporter struct {
	bar           *pterm.ProgressbarPrinter
	currentEntity string
	currentValue  uint64
}
⋮----
func newProgressReporter() *progressReporter
⋮----
func (p *progressReporter) Report(entityType string, current, total uint64)
⋮----
func (p *progressReporter) Stop()
⋮----
func confirmBackup(f Flags, storageType string) error
⋮----
func detectStorageType(dir string) (string, error)
⋮----
func matchAny(dir string, patterns []string) (bool, error)
⋮----
func fileSize(path string) (int64, error)
⋮----
func dirSize(dir string) (int64, error)
⋮----
var total int64
⋮----
func printSizeReport(before int64, beforeErr error, after int64, afterErr error, duration time.Duration)
⋮----
func reductionPct(before, after int64) float64
⋮----
func humanBytes(n int64) string
⋮----
const unit = 1024
⋮----
const suffixes = "KMGTPE"
```

## File: cmd/utils/root/root.go

```go
package root
⋮----
import (
	"runtime"

	"github.com/symbioticfi/relay/cmd/utils/keys"
	"github.com/symbioticfi/relay/cmd/utils/network"
	"github.com/symbioticfi/relay/cmd/utils/operator"
	"github.com/symbioticfi/relay/cmd/utils/prune"
	"github.com/symbioticfi/relay/pkg/log"

	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
)
⋮----
"runtime"
⋮----
"github.com/symbioticfi/relay/cmd/utils/keys"
"github.com/symbioticfi/relay/cmd/utils/network"
"github.com/symbioticfi/relay/cmd/utils/operator"
"github.com/symbioticfi/relay/cmd/utils/prune"
"github.com/symbioticfi/relay/pkg/log"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
type config struct {
	logLevel string
	logMode  string
}
⋮----
var Version = "local"
var BuildTime = "unknown"
⋮----
var cfg config
⋮----
func NewRootCommand() *cobra.Command
⋮----
var rootCmd = &cobra.Command{
	Use:   "utils",
	Short: "Utils tool",
	PreRun: func(cmd *cobra.Command, args []string) {
		log.Init(cfg.logLevel, cfg.logMode)
	},
}
⋮----
var versionCommand = &cobra.Command{
	Use:   "version",
	Short: "Print the version of the utils tool",
	Run: func(cmd *cobra.Command, args []string) {
		pterm.Info.Println("Utils tool version:", Version)
		pterm.Info.Println("Go version:", runtime.Version())
		pterm.Info.Println("OS/Arch:", runtime.GOOS+"/"+runtime.GOARCH)
		pterm.Info.Println("Build time:", BuildTime)
	},
}
```

## File: cmd/utils/main.go

```go
package main
⋮----
import (
	"os"

	"github.com/pterm/pterm"
	"github.com/symbioticfi/relay/cmd/utils/root"
)
⋮----
"os"
⋮----
"github.com/pterm/pterm"
"github.com/symbioticfi/relay/cmd/utils/root"
⋮----
func main()
```

## File: docs/api/v1/api.swagger.json

```json
{
    "swagger": "2.0",
    "info": {
        "title": "v1/api.proto",
        "version": "version not set"
    },
    "tags": [
        {
            "name": "SymbioticAPIService"
        }
    ],
    "consumes": ["application/json"],
    "produces": ["application/json"],
    "paths": {
        "/v1/aggregation/proof/{requestId}": {
            "get": {
                "summary": "Get aggregation proof",
                "operationId": "SymbioticAPIService_GetAggregationProof",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetAggregationProofResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "requestId",
                        "in": "path",
                        "required": true,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/aggregation/proofs/epoch/{epoch}": {
            "get": {
                "summary": "Get aggregation proofs by epoch",
                "operationId": "SymbioticAPIService_GetAggregationProofsByEpoch",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetAggregationProofsByEpochResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "pageSize",
                        "description": "Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "from",
                        "description": "Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.",
                        "in": "query",
                        "required": false,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/aggregation/status/{requestId}": {
            "get": {
                "summary": "Get aggregation status, can be sent only to aggregator nodes",
                "operationId": "SymbioticAPIService_GetAggregationStatus",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetAggregationStatusResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "requestId",
                        "in": "path",
                        "required": true,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/committed/all": {
            "get": {
                "summary": "Get last committed epochs for all settlement chains",
                "operationId": "SymbioticAPIService_GetLastAllCommitted",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetLastAllCommittedResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/committed/chain/{settlementChainId}": {
            "get": {
                "summary": "Get last committed epoch for a specific settlement chain",
                "operationId": "SymbioticAPIService_GetLastCommitted",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetLastCommittedResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "settlementChainId",
                        "description": "Settlement chain ID",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/epoch/current": {
            "get": {
                "summary": "Get current epoch",
                "operationId": "SymbioticAPIService_GetCurrentEpoch",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetCurrentEpochResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/sign": {
            "post": {
                "summary": "Sign a message",
                "operationId": "SymbioticAPIService_SignMessage",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/SignMessageResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/SignMessageRequest"
                        }
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/signature-request-ids/epoch/{epoch}": {
            "get": {
                "summary": "Get all signature request IDs by epoch",
                "operationId": "SymbioticAPIService_GetSignatureRequestIDsByEpoch",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetSignatureRequestIDsByEpochResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "pageSize",
                        "description": "Maximum number of items to return. 0 = server default (1000). Server clamps to max (10000).",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "from",
                        "description": "Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.",
                        "in": "query",
                        "required": false,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/signature-request/{requestId}": {
            "get": {
                "summary": "Get signature request by request id",
                "operationId": "SymbioticAPIService_GetSignatureRequest",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetSignatureRequestResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "requestId",
                        "in": "path",
                        "required": true,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/signature-requests/epoch/{epoch}": {
            "get": {
                "summary": "Get all signature requests by epoch",
                "operationId": "SymbioticAPIService_GetSignatureRequestsByEpoch",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetSignatureRequestsByEpochResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "pageSize",
                        "description": "Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "from",
                        "description": "Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.",
                        "in": "query",
                        "required": false,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/signatures/epoch/{epoch}": {
            "get": {
                "summary": "Get signature by epoch",
                "operationId": "SymbioticAPIService_GetSignaturesByEpoch",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetSignaturesByEpochResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "pageSize",
                        "description": "Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "from",
                        "description": "Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.",
                        "in": "query",
                        "required": false,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/signatures/{requestId}": {
            "get": {
                "summary": "Get signature by request id",
                "operationId": "SymbioticAPIService_GetSignatures",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetSignaturesResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "requestId",
                        "in": "path",
                        "required": true,
                        "type": "string"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/stream/proofs": {
            "get": {
                "summary": "Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first",
                "operationId": "SymbioticAPIService_ListenProofs",
                "responses": {
                    "200": {
                        "description": "A successful response.(streaming responses)",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "$ref": "#/definitions/ListenProofsResponse"
                                },
                                "error": {
                                    "$ref": "#/definitions/Status"
                                }
                            },
                            "title": "Stream result of ListenProofsResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "startEpoch",
                        "description": "Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates\nIf not provided, only proofs generated after stream creation will be sent",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/stream/signatures": {
            "get": {
                "summary": "Stream signatures in real-time. If start_epoch is provided, sends historical data first",
                "operationId": "SymbioticAPIService_ListenSignatures",
                "responses": {
                    "200": {
                        "description": "A successful response.(streaming responses)",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "$ref": "#/definitions/ListenSignaturesResponse"
                                },
                                "error": {
                                    "$ref": "#/definitions/Status"
                                }
                            },
                            "title": "Stream result of ListenSignaturesResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "startEpoch",
                        "description": "Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates\nIf not provided, only signatures generated after stream creation will be sent",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/stream/validator-set": {
            "get": {
                "summary": "Stream validator set changes in real-time. If start_epoch is provided, sends historical data first",
                "operationId": "SymbioticAPIService_ListenValidatorSet",
                "responses": {
                    "200": {
                        "description": "A successful response.(streaming responses)",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "$ref": "#/definitions/ListenValidatorSetResponse"
                                },
                                "error": {
                                    "$ref": "#/definitions/Status"
                                }
                            },
                            "title": "Stream result of ListenValidatorSetResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "startEpoch",
                        "description": "Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates\nIf not provided, only validator sets generated after stream creation will be sent",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator-set": {
            "get": {
                "summary": "Get current validator set",
                "operationId": "SymbioticAPIService_GetValidatorSet",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetValidatorSetResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator-set/custom-schedule/node-status": {
            "get": {
                "summary": "Checks if the current node should be active based on a custom schedule derived from the validator set.\nThis enables external applications to use the relay's validator set for coordinating distributed tasks,\nsuch as deciding which application instances should commit data on-chain or perform other coordinated actions.\nThe schedule ensures deterministic but randomized selection of active nodes at any given time.",
                "operationId": "SymbioticAPIService_GetCustomScheduleNodeStatus",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetCustomScheduleNodeStatusResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number to use for the validator set (optional, defaults to current epoch)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "seed",
                        "description": "Custom seed for randomizing the schedule (optional). Different seeds produce different schedules\nfor the same epoch, allowing multiple independent scheduling schemes. If not provided, the schedule\nis deterministic based on epoch alone.",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "byte"
                    },
                    {
                        "name": "slotDurationSeconds",
                        "description": "Duration of each time slot in seconds. Determines how frequently active groups rotate.\nExample: 60 seconds means a new group becomes active every minute.",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    },
                    {
                        "name": "maxParticipantsPerSlot",
                        "description": "Maximum validators per group. Controls redundancy: 1 for single-instance actions (less redundancy),\n2+ for multi-instance actions (more reliability). All validators in a group are active simultaneously.",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "minParticipantsPerSlot",
                        "description": "Minimum validators required to form a remainder group. When dividing validators into groups,\nany remainder smaller than this is not scheduled. Set equal to max for strict group sizes.",
                        "in": "query",
                        "required": false,
                        "type": "integer",
                        "format": "int64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator-set/header": {
            "get": {
                "summary": "Get validator set header",
                "operationId": "SymbioticAPIService_GetValidatorSetHeader",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetValidatorSetHeaderResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator-set/metadata": {
            "get": {
                "summary": "Get validator set metadata like extra data and request id to fetch aggregation and signature requests",
                "operationId": "SymbioticAPIService_GetValidatorSetMetadata",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetValidatorSetMetadataResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator/address/{address}": {
            "get": {
                "summary": "Get validator by address",
                "operationId": "SymbioticAPIService_GetValidatorByAddress",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetValidatorByAddressResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "address",
                        "description": "Validator address (required)",
                        "in": "path",
                        "required": true,
                        "type": "string"
                    },
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator/key/{keyTag}/{onChainKey}": {
            "get": {
                "summary": "Get validator by key",
                "operationId": "SymbioticAPIService_GetValidatorByKey",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetValidatorByKeyResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "keyTag",
                        "description": "Validator key tag (required)",
                        "in": "path",
                        "required": true,
                        "type": "integer",
                        "format": "int64"
                    },
                    {
                        "name": "onChainKey",
                        "description": "Validator on chain (public) key (required)",
                        "in": "path",
                        "required": true,
                        "type": "string",
                        "format": "byte"
                    },
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        },
        "/v1/validator/local": {
            "get": {
                "summary": "Get local validator",
                "operationId": "SymbioticAPIService_GetLocalValidator",
                "responses": {
                    "200": {
                        "description": "A successful response.",
                        "schema": {
                            "$ref": "#/definitions/GetLocalValidatorResponse"
                        }
                    },
                    "default": {
                        "description": "An unexpected error response.",
                        "schema": {
                            "$ref": "#/definitions/Status"
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "epoch",
                        "description": "Epoch number (optional, if not provided current epoch will be used)",
                        "in": "query",
                        "required": false,
                        "type": "string",
                        "format": "uint64"
                    }
                ],
                "tags": ["SymbioticAPIService"]
            }
        }
    },
    "definitions": {
        "AggregationProof": {
            "type": "object",
            "properties": {
                "messageHash": {
                    "type": "string",
                    "format": "byte",
                    "title": "Message hash"
                },
                "proof": {
                    "type": "string",
                    "format": "byte",
                    "title": "Proof data"
                },
                "requestId": {
                    "type": "string",
                    "title": "Request ID"
                }
            },
            "title": "Response message for getting aggregation proof"
        },
        "Any": {
            "type": "object",
            "properties": {
                "@type": {
                    "type": "string"
                }
            },
            "additionalProperties": {}
        },
        "ChainEpochInfo": {
            "type": "object",
            "properties": {
                "lastCommittedEpoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Last committed epoch for this chain"
                },
                "startTime": {
                    "type": "string",
                    "format": "date-time",
                    "title": "Epoch start time"
                }
            },
            "title": "Settlement chain with its last committed epoch"
        },
        "ExtraData": {
            "type": "object",
            "properties": {
                "key": {
                    "type": "string",
                    "format": "byte"
                },
                "value": {
                    "type": "string",
                    "format": "byte"
                }
            }
        },
        "GetAggregationProofResponse": {
            "type": "object",
            "properties": {
                "aggregationProof": {
                    "$ref": "#/definitions/AggregationProof"
                }
            },
            "title": "Response message for getting aggregation proof"
        },
        "GetAggregationProofsByEpochResponse": {
            "type": "object",
            "properties": {
                "aggregationProofs": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/AggregationProof"
                    }
                },
                "nextFrom": {
                    "type": "string",
                    "description": "Cursor to retrieve the next page. Empty when this is the last page."
                }
            },
            "title": "Response message for getting aggregation proof"
        },
        "GetAggregationStatusResponse": {
            "type": "object",
            "properties": {
                "currentVotingPower": {
                    "type": "string",
                    "title": "Current voting power of the aggregator (big integer as string)"
                },
                "signerOperators": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "title": "List of operator addresses that signed the request"
                }
            },
            "title": "Response message for getting aggregation status"
        },
        "GetCurrentEpochResponse": {
            "type": "object",
            "properties": {
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Epoch number"
                },
                "startTime": {
                    "type": "string",
                    "format": "date-time",
                    "title": "Epoch start time"
                }
            },
            "title": "Response message for getting current epoch"
        },
        "GetCustomScheduleNodeStatusResponse": {
            "type": "object",
            "properties": {
                "isActive": {
                    "type": "boolean",
                    "description": "True if this node is active in the current time slot and should perform the scheduled action.\nFalse if this node should wait (another group is active). When multiple validators share a slot,\nall return true simultaneously, enabling coordinated redundancy."
                },
                "currentSlotStartTime": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Start time of the current active slot. This marks the beginning of the current slot time window.\nCan be used to determine how much time is left in the slot."
                },
                "currentSlotEndTime": {
                    "type": "string",
                    "format": "date-time",
                    "description": "End time of the current active slot. This marks the end of the current slot time window.\nCan be used to determine how much time is left in the slot."
                }
            },
            "description": "Response indicating whether the current node should be active now."
        },
        "GetLastAllCommittedResponse": {
            "type": "object",
            "properties": {
                "epochInfos": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/ChainEpochInfo"
                    },
                    "title": "List of settlement chains with their last committed epochs"
                },
                "suggestedEpochInfo": {
                    "$ref": "#/definitions/ChainEpochInfo",
                    "title": "Suggested epoch info for signatures, it is the minimum commited epoch among all chains"
                }
            },
            "title": "Response message for getting all last committed epochs"
        },
        "GetLastCommittedResponse": {
            "type": "object",
            "properties": {
                "settlementChainId": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Settlement chain ID"
                },
                "epochInfo": {
                    "$ref": "#/definitions/ChainEpochInfo"
                }
            },
            "title": "Response message for getting last committed epoch"
        },
        "GetLocalValidatorResponse": {
            "type": "object",
            "properties": {
                "validator": {
                    "$ref": "#/definitions/Validator",
                    "title": "The validator"
                }
            },
            "title": "Response message for getting local validator"
        },
        "GetSignatureRequestIDsByEpochResponse": {
            "type": "object",
            "properties": {
                "requestIds": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "title": "List of all signature request IDs for the epoch"
                },
                "nextFrom": {
                    "type": "string",
                    "description": "Cursor to retrieve the next page. Empty when this is the last page."
                }
            },
            "title": "Response message for getting all signature request IDs by epoch"
        },
        "GetSignatureRequestResponse": {
            "type": "object",
            "properties": {
                "signatureRequest": {
                    "$ref": "#/definitions/SignatureRequest"
                }
            },
            "title": "Response message for getting signature request"
        },
        "GetSignatureRequestsByEpochResponse": {
            "type": "object",
            "properties": {
                "signatureRequests": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/SignatureRequest"
                    },
                    "title": "List of all signature requests for the epoch"
                },
                "nextFrom": {
                    "type": "string",
                    "description": "Cursor to retrieve the next page. Empty when this is the last page."
                }
            },
            "title": "Response message for getting all signature requests by epoch"
        },
        "GetSignaturesByEpochResponse": {
            "type": "object",
            "properties": {
                "signatures": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Signature"
                    },
                    "title": "List of signatures"
                },
                "nextFrom": {
                    "type": "string",
                    "description": "Cursor to retrieve the next page. Empty when this is the last page."
                }
            },
            "title": "Response message for getting signatures by epoch"
        },
        "GetSignaturesResponse": {
            "type": "object",
            "properties": {
                "signatures": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Signature"
                    },
                    "title": "List of signatures"
                }
            },
            "title": "Response message for getting signatures"
        },
        "GetValidatorByAddressResponse": {
            "type": "object",
            "properties": {
                "validator": {
                    "$ref": "#/definitions/Validator",
                    "title": "The validator"
                }
            },
            "title": "Response message for getting validator by address"
        },
        "GetValidatorByKeyResponse": {
            "type": "object",
            "properties": {
                "validator": {
                    "$ref": "#/definitions/Validator",
                    "title": "The validator"
                }
            },
            "title": "Response message for getting validator by key"
        },
        "GetValidatorSetHeaderResponse": {
            "type": "object",
            "properties": {
                "version": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Version of the validator set"
                },
                "requiredKeyTag": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Key tag required to commit next validator set"
                },
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Validator set epoch"
                },
                "captureTimestamp": {
                    "type": "string",
                    "format": "date-time",
                    "title": "Epoch capture timestamp"
                },
                "quorumThreshold": {
                    "type": "string",
                    "title": "Quorum threshold (big integer as string)"
                },
                "totalVotingPower": {
                    "type": "string",
                    "title": "Total voting power (big integer as string)"
                },
                "validatorsSszMroot": {
                    "type": "string",
                    "title": "Validators SSZ Merkle root (hex string)"
                }
            },
            "title": "Response message for getting validator set header"
        },
        "GetValidatorSetMetadataResponse": {
            "type": "object",
            "properties": {
                "extraData": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/ExtraData"
                    }
                },
                "commitmentData": {
                    "type": "string",
                    "format": "byte"
                },
                "requestId": {
                    "type": "string"
                }
            },
            "title": "Response message for getting validator set header"
        },
        "GetValidatorSetResponse": {
            "type": "object",
            "properties": {
                "validatorSet": {
                    "$ref": "#/definitions/ValidatorSet",
                    "title": "The validator set"
                }
            },
            "title": "Response message for getting validator set"
        },
        "Key": {
            "type": "object",
            "properties": {
                "tag": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Key tag identifier (0-127)"
                },
                "payload": {
                    "type": "string",
                    "format": "byte",
                    "title": "Key payload"
                }
            },
            "title": "Cryptographic key"
        },
        "ListenProofsResponse": {
            "type": "object",
            "properties": {
                "requestId": {
                    "type": "string",
                    "title": "Id of the request"
                },
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Epoch number"
                },
                "aggregationProof": {
                    "$ref": "#/definitions/AggregationProof",
                    "title": "Final aggregation proof"
                }
            },
            "title": "Response message for aggregation proofs stream"
        },
        "ListenSignaturesResponse": {
            "type": "object",
            "properties": {
                "requestId": {
                    "type": "string",
                    "title": "Id of the signature request"
                },
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Epoch number"
                },
                "signature": {
                    "$ref": "#/definitions/Signature",
                    "title": "Signature data"
                }
            },
            "title": "Response message for signatures stream"
        },
        "ListenValidatorSetResponse": {
            "type": "object",
            "properties": {
                "validatorSet": {
                    "$ref": "#/definitions/ValidatorSet",
                    "title": "The validator set"
                }
            },
            "title": "Response message for validator set changes stream"
        },
        "SignMessageRequest": {
            "type": "object",
            "properties": {
                "keyTag": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Key tag identifier (0-127)"
                },
                "message": {
                    "type": "string",
                    "format": "byte",
                    "title": "Message to be signed"
                },
                "requiredEpoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Required epoch (optional, if not provided latest committed epoch will be used)"
                }
            },
            "title": "Request message for signing a message"
        },
        "SignMessageResponse": {
            "type": "object",
            "properties": {
                "requestId": {
                    "type": "string",
                    "title": "Hash of the signature request"
                },
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Epoch number"
                }
            },
            "title": "Response message for sign message request"
        },
        "Signature": {
            "type": "object",
            "properties": {
                "signature": {
                    "type": "string",
                    "format": "byte",
                    "title": "Signature data"
                },
                "messageHash": {
                    "type": "string",
                    "format": "byte",
                    "title": "Message hash"
                },
                "publicKey": {
                    "type": "string",
                    "format": "byte",
                    "title": "Public key"
                },
                "requestId": {
                    "type": "string",
                    "title": "Request ID"
                }
            },
            "title": "Digital signature"
        },
        "SignatureRequest": {
            "type": "object",
            "properties": {
                "requestId": {
                    "type": "string",
                    "title": "Request ID"
                },
                "keyTag": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Key tag identifier (0-127)"
                },
                "message": {
                    "type": "string",
                    "format": "byte",
                    "title": "Message to be signed"
                },
                "requiredEpoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Required epoch"
                }
            },
            "title": "SignatureRequest represents a signature request"
        },
        "Status": {
            "type": "object",
            "properties": {
                "code": {
                    "type": "integer",
                    "format": "int32"
                },
                "message": {
                    "type": "string"
                },
                "details": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Any"
                    }
                }
            }
        },
        "Validator": {
            "type": "object",
            "properties": {
                "operator": {
                    "type": "string",
                    "title": "Operator address (hex string)"
                },
                "votingPower": {
                    "type": "string",
                    "title": "Voting power of the validator (big integer as string)"
                },
                "isActive": {
                    "type": "boolean",
                    "title": "Indicates if the validator is active"
                },
                "keys": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Key"
                    },
                    "title": "List of cryptographic keys"
                },
                "vaults": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/ValidatorVault"
                    },
                    "title": "List of validator vaults"
                }
            },
            "title": "Validator information"
        },
        "ValidatorSet": {
            "type": "object",
            "properties": {
                "version": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Version of the validator set"
                },
                "requiredKeyTag": {
                    "type": "integer",
                    "format": "int64",
                    "title": "Key tag required to commit next validator set"
                },
                "epoch": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Validator set epoch"
                },
                "captureTimestamp": {
                    "type": "string",
                    "format": "date-time",
                    "title": "Epoch capture timestamp"
                },
                "quorumThreshold": {
                    "type": "string",
                    "title": "Quorum threshold (big integer as string)"
                },
                "status": {
                    "$ref": "#/definitions/ValidatorSetStatus",
                    "title": "Status of validator set header"
                },
                "validators": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Validator"
                    },
                    "title": "List of validators"
                }
            }
        },
        "ValidatorSetStatus": {
            "type": "string",
            "enum": [
                "VALIDATOR_SET_STATUS_UNSPECIFIED",
                "VALIDATOR_SET_STATUS_DERIVED",
                "VALIDATOR_SET_STATUS_AGGREGATED",
                "VALIDATOR_SET_STATUS_COMMITTED"
            ],
            "default": "VALIDATOR_SET_STATUS_UNSPECIFIED",
            "description": "- VALIDATOR_SET_STATUS_UNSPECIFIED: Default/unknown status\n - VALIDATOR_SET_STATUS_DERIVED: Derived status\n - VALIDATOR_SET_STATUS_AGGREGATED: Aggregated status\n - VALIDATOR_SET_STATUS_COMMITTED: Committed status",
            "title": "Validator set status enumeration"
        },
        "ValidatorVault": {
            "type": "object",
            "properties": {
                "chainId": {
                    "type": "string",
                    "format": "uint64",
                    "title": "Chain identifier"
                },
                "vault": {
                    "type": "string",
                    "title": "Vault address"
                },
                "votingPower": {
                    "type": "string",
                    "title": "Voting power for this vault (big integer as string)"
                }
            },
            "title": "Validator vault information"
        }
    }
}
```

## File: docs/api/v1/doc.md

```markdown
# Protocol Documentation

<a name="top"></a>

## Table of Contents

- [v1/api.proto](#v1_api-proto)
    - [AggregationProof](#api-proto-v1-AggregationProof)
    - [ChainEpochInfo](#api-proto-v1-ChainEpochInfo)
    - [ExtraData](#api-proto-v1-ExtraData)
    - [GetAggregationProofRequest](#api-proto-v1-GetAggregationProofRequest)
    - [GetAggregationProofResponse](#api-proto-v1-GetAggregationProofResponse)
    - [GetAggregationProofsByEpochRequest](#api-proto-v1-GetAggregationProofsByEpochRequest)
    - [GetAggregationProofsByEpochResponse](#api-proto-v1-GetAggregationProofsByEpochResponse)
    - [GetAggregationStatusRequest](#api-proto-v1-GetAggregationStatusRequest)
    - [GetAggregationStatusResponse](#api-proto-v1-GetAggregationStatusResponse)
    - [GetCurrentEpochRequest](#api-proto-v1-GetCurrentEpochRequest)
    - [GetCurrentEpochResponse](#api-proto-v1-GetCurrentEpochResponse)
    - [GetCustomScheduleNodeStatusRequest](#api-proto-v1-GetCustomScheduleNodeStatusRequest)
    - [GetCustomScheduleNodeStatusResponse](#api-proto-v1-GetCustomScheduleNodeStatusResponse)
    - [GetLastAllCommittedRequest](#api-proto-v1-GetLastAllCommittedRequest)
    - [GetLastAllCommittedResponse](#api-proto-v1-GetLastAllCommittedResponse)
    - [GetLastAllCommittedResponse.EpochInfosEntry](#api-proto-v1-GetLastAllCommittedResponse-EpochInfosEntry)
    - [GetLastCommittedRequest](#api-proto-v1-GetLastCommittedRequest)
    - [GetLastCommittedResponse](#api-proto-v1-GetLastCommittedResponse)
    - [GetLocalValidatorRequest](#api-proto-v1-GetLocalValidatorRequest)
    - [GetLocalValidatorResponse](#api-proto-v1-GetLocalValidatorResponse)
    - [GetSignatureRequestIDsByEpochRequest](#api-proto-v1-GetSignatureRequestIDsByEpochRequest)
    - [GetSignatureRequestIDsByEpochResponse](#api-proto-v1-GetSignatureRequestIDsByEpochResponse)
    - [GetSignatureRequestRequest](#api-proto-v1-GetSignatureRequestRequest)
    - [GetSignatureRequestResponse](#api-proto-v1-GetSignatureRequestResponse)
    - [GetSignatureRequestsByEpochRequest](#api-proto-v1-GetSignatureRequestsByEpochRequest)
    - [GetSignatureRequestsByEpochResponse](#api-proto-v1-GetSignatureRequestsByEpochResponse)
    - [GetSignaturesByEpochRequest](#api-proto-v1-GetSignaturesByEpochRequest)
    - [GetSignaturesByEpochResponse](#api-proto-v1-GetSignaturesByEpochResponse)
    - [GetSignaturesRequest](#api-proto-v1-GetSignaturesRequest)
    - [GetSignaturesResponse](#api-proto-v1-GetSignaturesResponse)
    - [GetValidatorByAddressRequest](#api-proto-v1-GetValidatorByAddressRequest)
    - [GetValidatorByAddressResponse](#api-proto-v1-GetValidatorByAddressResponse)
    - [GetValidatorByKeyRequest](#api-proto-v1-GetValidatorByKeyRequest)
    - [GetValidatorByKeyResponse](#api-proto-v1-GetValidatorByKeyResponse)
    - [GetValidatorSetHeaderRequest](#api-proto-v1-GetValidatorSetHeaderRequest)
    - [GetValidatorSetHeaderResponse](#api-proto-v1-GetValidatorSetHeaderResponse)
    - [GetValidatorSetMetadataRequest](#api-proto-v1-GetValidatorSetMetadataRequest)
    - [GetValidatorSetMetadataResponse](#api-proto-v1-GetValidatorSetMetadataResponse)
    - [GetValidatorSetRequest](#api-proto-v1-GetValidatorSetRequest)
    - [GetValidatorSetResponse](#api-proto-v1-GetValidatorSetResponse)
    - [Key](#api-proto-v1-Key)
    - [ListenProofsRequest](#api-proto-v1-ListenProofsRequest)
    - [ListenProofsResponse](#api-proto-v1-ListenProofsResponse)
    - [ListenSignaturesRequest](#api-proto-v1-ListenSignaturesRequest)
    - [ListenSignaturesResponse](#api-proto-v1-ListenSignaturesResponse)
    - [ListenValidatorSetRequest](#api-proto-v1-ListenValidatorSetRequest)
    - [ListenValidatorSetResponse](#api-proto-v1-ListenValidatorSetResponse)
    - [SignMessageRequest](#api-proto-v1-SignMessageRequest)
    - [SignMessageResponse](#api-proto-v1-SignMessageResponse)
    - [Signature](#api-proto-v1-Signature)
    - [SignatureRequest](#api-proto-v1-SignatureRequest)
    - [Validator](#api-proto-v1-Validator)
    - [ValidatorSet](#api-proto-v1-ValidatorSet)
    - [ValidatorVault](#api-proto-v1-ValidatorVault)
    - [ErrorCode](#api-proto-v1-ErrorCode)
    - [SigningStatus](#api-proto-v1-SigningStatus)
    - [ValidatorSetStatus](#api-proto-v1-ValidatorSetStatus)
    - [SymbioticAPIService](#api-proto-v1-SymbioticAPIService)

- [Scalar Value Types](#scalar-value-types)

<a name="v1_api-proto"></a>

<p align="right"><a href="#top">Top</a></p>

## v1/api.proto

<a name="api-proto-v1-AggregationProof"></a>

### AggregationProof

Response message for getting aggregation proof

| Field        | Type              | Label | Description  |
| ------------ | ----------------- | ----- | ------------ |
| message_hash | [bytes](#bytes)   |       | Message hash |
| proof        | [bytes](#bytes)   |       | Proof data   |
| request_id   | [string](#string) |       | Request ID   |

<a name="api-proto-v1-ChainEpochInfo"></a>

### ChainEpochInfo

Settlement chain with its last committed epoch

| Field                | Type                                                    | Label | Description                         |
| -------------------- | ------------------------------------------------------- | ----- | ----------------------------------- |
| last_committed_epoch | [uint64](#uint64)                                       |       | Last committed epoch for this chain |
| start_time           | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |       | Epoch start time                    |

<a name="api-proto-v1-ExtraData"></a>

### ExtraData

| Field | Type            | Label | Description |
| ----- | --------------- | ----- | ----------- |
| key   | [bytes](#bytes) |       |             |
| value | [bytes](#bytes) |       |             |

<a name="api-proto-v1-GetAggregationProofRequest"></a>

### GetAggregationProofRequest

Request message for getting aggregation proof

| Field      | Type              | Label | Description |
| ---------- | ----------------- | ----- | ----------- |
| request_id | [string](#string) |       |             |

<a name="api-proto-v1-GetAggregationProofResponse"></a>

### GetAggregationProofResponse

Response message for getting aggregation proof

| Field             | Type                                               | Label | Description |
| ----------------- | -------------------------------------------------- | ----- | ----------- |
| aggregation_proof | [AggregationProof](#api-proto-v1-AggregationProof) |       |             |

<a name="api-proto-v1-GetAggregationProofsByEpochRequest"></a>

### GetAggregationProofsByEpochRequest

Request message for getting aggregation proof

| Field     | Type              | Label | Description                                                                                                  |
| --------- | ----------------- | ----- | ------------------------------------------------------------------------------------------------------------ |
| epoch     | [uint64](#uint64) |       | Epoch number                                                                                                 |
| page_size | [uint32](#uint32) |       | Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).                    |
| from      | [string](#string) |       | Opaque pagination cursor from a previous response&#39;s `next_from`. Empty string starts from the beginning. |

<a name="api-proto-v1-GetAggregationProofsByEpochResponse"></a>

### GetAggregationProofsByEpochResponse

Response message for getting aggregation proof

| Field              | Type                                               | Label    | Description                                                         |
| ------------------ | -------------------------------------------------- | -------- | ------------------------------------------------------------------- |
| aggregation_proofs | [AggregationProof](#api-proto-v1-AggregationProof) | repeated |                                                                     |
| next_from          | [string](#string)                                  |          | Cursor to retrieve the next page. Empty when this is the last page. |

<a name="api-proto-v1-GetAggregationStatusRequest"></a>

### GetAggregationStatusRequest

Request message for getting aggregation status

| Field      | Type              | Label | Description |
| ---------- | ----------------- | ----- | ----------- |
| request_id | [string](#string) |       |             |

<a name="api-proto-v1-GetAggregationStatusResponse"></a>

### GetAggregationStatusResponse

Response message for getting aggregation status

| Field                | Type              | Label    | Description                                                    |
| -------------------- | ----------------- | -------- | -------------------------------------------------------------- |
| current_voting_power | [string](#string) |          | Current voting power of the aggregator (big integer as string) |
| signer_operators     | [string](#string) | repeated | List of operator addresses that signed the request             |

<a name="api-proto-v1-GetCurrentEpochRequest"></a>

### GetCurrentEpochRequest

Request message for getting current epoch

<a name="api-proto-v1-GetCurrentEpochResponse"></a>

### GetCurrentEpochResponse

Response message for getting current epoch

| Field      | Type                                                    | Label | Description      |
| ---------- | ------------------------------------------------------- | ----- | ---------------- |
| epoch      | [uint64](#uint64)                                       |       | Epoch number     |
| start_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |       | Epoch start time |

<a name="api-proto-v1-GetCustomScheduleNodeStatusRequest"></a>

### GetCustomScheduleNodeStatusRequest

Request to check if the current node should be active in a custom schedule.
The validator set is divided into groups that rotate through time slots.
Use this to coordinate distributed tasks among multiple application instances.

| Field                     | Type              | Label    | Description                                                                                                                                                                                                                                 |
| ------------------------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| epoch                     | [uint64](#uint64) | optional | Epoch number to use for the validator set (optional, defaults to current epoch)                                                                                                                                                             |
| seed                      | [bytes](#bytes)   | optional | Custom seed for randomizing the schedule (optional). Different seeds produce different schedules for the same epoch, allowing multiple independent scheduling schemes. If not provided, the schedule is deterministic based on epoch alone. |
| slot_duration_seconds     | [uint64](#uint64) |          | Duration of each time slot in seconds. Determines how frequently active groups rotate. Example: 60 seconds means a new group becomes active every minute.                                                                                   |
| max_participants_per_slot | [uint32](#uint32) |          | Maximum validators per group. Controls redundancy: 1 for single-instance actions (less redundancy), 2&#43; for multi-instance actions (more reliability). All validators in a group are active simultaneously.                              |
| min_participants_per_slot | [uint32](#uint32) |          | Minimum validators required to form a remainder group. When dividing validators into groups, any remainder smaller than this is not scheduled. Set equal to max for strict group sizes.                                                     |

<a name="api-proto-v1-GetCustomScheduleNodeStatusResponse"></a>

### GetCustomScheduleNodeStatusResponse

Response indicating whether the current node should be active now.

| Field                   | Type                                                    | Label | Description                                                                                                                                                                                                                                                     |
| ----------------------- | ------------------------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| is_active               | [bool](#bool)                                           |       | True if this node is active in the current time slot and should perform the scheduled action. False if this node should wait (another group is active). When multiple validators share a slot, all return true simultaneously, enabling coordinated redundancy. |
| current_slot_start_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |       | Start time of the current active slot. This marks the beginning of the current slot time window. Can be used to determine how much time is left in the slot.                                                                                                    |
| current_slot_end_time   | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |       | End time of the current active slot. This marks the end of the current slot time window. Can be used to determine how much time is left in the slot.                                                                                                            |

<a name="api-proto-v1-GetLastAllCommittedRequest"></a>

### GetLastAllCommittedRequest

Request message for getting last committed epochs for all chains

No parameters needed

<a name="api-proto-v1-GetLastAllCommittedResponse"></a>

### GetLastAllCommittedResponse

Response message for getting all last committed epochs

| Field                | Type                                                                                                     | Label    | Description                                                                            |
| -------------------- | -------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| epoch_infos          | [GetLastAllCommittedResponse.EpochInfosEntry](#api-proto-v1-GetLastAllCommittedResponse-EpochInfosEntry) | repeated | List of settlement chains with their last committed epochs                             |
| suggested_epoch_info | [ChainEpochInfo](#api-proto-v1-ChainEpochInfo)                                                           |          | Suggested epoch info for signatures, it is the minimum commited epoch among all chains |

<a name="api-proto-v1-GetLastAllCommittedResponse-EpochInfosEntry"></a>

### GetLastAllCommittedResponse.EpochInfosEntry

| Field | Type                                           | Label | Description |
| ----- | ---------------------------------------------- | ----- | ----------- |
| key   | [uint64](#uint64)                              |       |             |
| value | [ChainEpochInfo](#api-proto-v1-ChainEpochInfo) |       |             |

<a name="api-proto-v1-GetLastCommittedRequest"></a>

### GetLastCommittedRequest

Request message for getting last committed epoch for a specific settlement chain

| Field               | Type              | Label | Description         |
| ------------------- | ----------------- | ----- | ------------------- |
| settlement_chain_id | [uint64](#uint64) |       | Settlement chain ID |

<a name="api-proto-v1-GetLastCommittedResponse"></a>

### GetLastCommittedResponse

Response message for getting last committed epoch

| Field               | Type                                           | Label | Description         |
| ------------------- | ---------------------------------------------- | ----- | ------------------- |
| settlement_chain_id | [uint64](#uint64)                              |       | Settlement chain ID |
| epoch_info          | [ChainEpochInfo](#api-proto-v1-ChainEpochInfo) |       |                     |

<a name="api-proto-v1-GetLocalValidatorRequest"></a>

### GetLocalValidatorRequest

Request message for getting local validator

| Field | Type              | Label    | Description                                                         |
| ----- | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |

<a name="api-proto-v1-GetLocalValidatorResponse"></a>

### GetLocalValidatorResponse

Response message for getting local validator

| Field     | Type                                 | Label | Description   |
| --------- | ------------------------------------ | ----- | ------------- |
| validator | [Validator](#api-proto-v1-Validator) |       | The validator |

<a name="api-proto-v1-GetSignatureRequestIDsByEpochRequest"></a>

### GetSignatureRequestIDsByEpochRequest

Request message for getting all signature request IDs by epoch

| Field     | Type              | Label | Description                                                                                                  |
| --------- | ----------------- | ----- | ------------------------------------------------------------------------------------------------------------ |
| epoch     | [uint64](#uint64) |       | Epoch number                                                                                                 |
| page_size | [uint32](#uint32) |       | Maximum number of items to return. 0 = server default (1000). Server clamps to max (10000).                  |
| from      | [string](#string) |       | Opaque pagination cursor from a previous response&#39;s `next_from`. Empty string starts from the beginning. |

<a name="api-proto-v1-GetSignatureRequestIDsByEpochResponse"></a>

### GetSignatureRequestIDsByEpochResponse

Response message for getting all signature request IDs by epoch

| Field       | Type              | Label    | Description                                                         |
| ----------- | ----------------- | -------- | ------------------------------------------------------------------- |
| request_ids | [string](#string) | repeated | List of all signature request IDs for the epoch                     |
| next_from   | [string](#string) |          | Cursor to retrieve the next page. Empty when this is the last page. |

<a name="api-proto-v1-GetSignatureRequestRequest"></a>

### GetSignatureRequestRequest

Request message for getting signature request

| Field      | Type              | Label | Description |
| ---------- | ----------------- | ----- | ----------- |
| request_id | [string](#string) |       |             |

<a name="api-proto-v1-GetSignatureRequestResponse"></a>

### GetSignatureRequestResponse

Response message for getting signature request

| Field             | Type                                               | Label | Description |
| ----------------- | -------------------------------------------------- | ----- | ----------- |
| signature_request | [SignatureRequest](#api-proto-v1-SignatureRequest) |       |             |

<a name="api-proto-v1-GetSignatureRequestsByEpochRequest"></a>

### GetSignatureRequestsByEpochRequest

Request message for getting all signature requests by epoch

| Field     | Type              | Label | Description                                                                                                  |
| --------- | ----------------- | ----- | ------------------------------------------------------------------------------------------------------------ |
| epoch     | [uint64](#uint64) |       | Epoch number                                                                                                 |
| page_size | [uint32](#uint32) |       | Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).                    |
| from      | [string](#string) |       | Opaque pagination cursor from a previous response&#39;s `next_from`. Empty string starts from the beginning. |

<a name="api-proto-v1-GetSignatureRequestsByEpochResponse"></a>

### GetSignatureRequestsByEpochResponse

Response message for getting all signature requests by epoch

| Field              | Type                                               | Label    | Description                                                         |
| ------------------ | -------------------------------------------------- | -------- | ------------------------------------------------------------------- |
| signature_requests | [SignatureRequest](#api-proto-v1-SignatureRequest) | repeated | List of all signature requests for the epoch                        |
| next_from          | [string](#string)                                  |          | Cursor to retrieve the next page. Empty when this is the last page. |

<a name="api-proto-v1-GetSignaturesByEpochRequest"></a>

### GetSignaturesByEpochRequest

Request message for getting signatures by epoch

| Field     | Type              | Label | Description                                                                                                  |
| --------- | ----------------- | ----- | ------------------------------------------------------------------------------------------------------------ |
| epoch     | [uint64](#uint64) |       | Epoch number                                                                                                 |
| page_size | [uint32](#uint32) |       | Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).                    |
| from      | [string](#string) |       | Opaque pagination cursor from a previous response&#39;s `next_from`. Empty string starts from the beginning. |

<a name="api-proto-v1-GetSignaturesByEpochResponse"></a>

### GetSignaturesByEpochResponse

Response message for getting signatures by epoch

| Field      | Type                                 | Label    | Description                                                         |
| ---------- | ------------------------------------ | -------- | ------------------------------------------------------------------- |
| signatures | [Signature](#api-proto-v1-Signature) | repeated | List of signatures                                                  |
| next_from  | [string](#string)                    |          | Cursor to retrieve the next page. Empty when this is the last page. |

<a name="api-proto-v1-GetSignaturesRequest"></a>

### GetSignaturesRequest

Request message for getting signatures

| Field      | Type              | Label | Description |
| ---------- | ----------------- | ----- | ----------- |
| request_id | [string](#string) |       |             |

<a name="api-proto-v1-GetSignaturesResponse"></a>

### GetSignaturesResponse

Response message for getting signatures

| Field      | Type                                 | Label    | Description        |
| ---------- | ------------------------------------ | -------- | ------------------ |
| signatures | [Signature](#api-proto-v1-Signature) | repeated | List of signatures |

<a name="api-proto-v1-GetValidatorByAddressRequest"></a>

### GetValidatorByAddressRequest

Request message for getting validator by address

| Field   | Type              | Label    | Description                                                         |
| ------- | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch   | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |
| address | [string](#string) |          | Validator address (required)                                        |

<a name="api-proto-v1-GetValidatorByAddressResponse"></a>

### GetValidatorByAddressResponse

Response message for getting validator by address

| Field     | Type                                 | Label | Description   |
| --------- | ------------------------------------ | ----- | ------------- |
| validator | [Validator](#api-proto-v1-Validator) |       | The validator |

<a name="api-proto-v1-GetValidatorByKeyRequest"></a>

### GetValidatorByKeyRequest

Request message for getting validator by key

| Field        | Type              | Label    | Description                                                         |
| ------------ | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch        | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |
| key_tag      | [uint32](#uint32) |          | Validator key tag (required)                                        |
| on_chain_key | [bytes](#bytes)   |          | Validator on chain (public) key (required)                          |

<a name="api-proto-v1-GetValidatorByKeyResponse"></a>

### GetValidatorByKeyResponse

Response message for getting validator by key

| Field     | Type                                 | Label | Description   |
| --------- | ------------------------------------ | ----- | ------------- |
| validator | [Validator](#api-proto-v1-Validator) |       | The validator |

<a name="api-proto-v1-GetValidatorSetHeaderRequest"></a>

### GetValidatorSetHeaderRequest

Request message for getting validator set header

| Field | Type              | Label    | Description                                                         |
| ----- | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |

<a name="api-proto-v1-GetValidatorSetHeaderResponse"></a>

### GetValidatorSetHeaderResponse

Response message for getting validator set header

| Field                | Type                                                    | Label | Description                                   |
| -------------------- | ------------------------------------------------------- | ----- | --------------------------------------------- |
| version              | [uint32](#uint32)                                       |       | Version of the validator set                  |
| required_key_tag     | [uint32](#uint32)                                       |       | Key tag required to commit next validator set |
| epoch                | [uint64](#uint64)                                       |       | Validator set epoch                           |
| capture_timestamp    | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |       | Epoch capture timestamp                       |
| quorum_threshold     | [string](#string)                                       |       | Quorum threshold (big integer as string)      |
| total_voting_power   | [string](#string)                                       |       | Total voting power (big integer as string)    |
| validators_ssz_mroot | [string](#string)                                       |       | Validators SSZ Merkle root (hex string)       |

<a name="api-proto-v1-GetValidatorSetMetadataRequest"></a>

### GetValidatorSetMetadataRequest

Request message for getting validator set metadata

| Field | Type              | Label    | Description                                                         |
| ----- | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |

<a name="api-proto-v1-GetValidatorSetMetadataResponse"></a>

### GetValidatorSetMetadataResponse

Response message for getting validator set header

| Field           | Type                                 | Label    | Description |
| --------------- | ------------------------------------ | -------- | ----------- |
| extra_data      | [ExtraData](#api-proto-v1-ExtraData) | repeated |             |
| commitment_data | [bytes](#bytes)                      |          |             |
| request_id      | [string](#string)                    |          |             |

<a name="api-proto-v1-GetValidatorSetRequest"></a>

### GetValidatorSetRequest

Request message for getting validator set

| Field | Type              | Label    | Description                                                         |
| ----- | ----------------- | -------- | ------------------------------------------------------------------- |
| epoch | [uint64](#uint64) | optional | Epoch number (optional, if not provided current epoch will be used) |

<a name="api-proto-v1-GetValidatorSetResponse"></a>

### GetValidatorSetResponse

Response message for getting validator set

| Field         | Type                                       | Label | Description       |
| ------------- | ------------------------------------------ | ----- | ----------------- |
| validator_set | [ValidatorSet](#api-proto-v1-ValidatorSet) |       | The validator set |

<a name="api-proto-v1-Key"></a>

### Key

Cryptographic key

| Field   | Type              | Label | Description                |
| ------- | ----------------- | ----- | -------------------------- |
| tag     | [uint32](#uint32) |       | Key tag identifier (0-127) |
| payload | [bytes](#bytes)   |       | Key payload                |

<a name="api-proto-v1-ListenProofsRequest"></a>

### ListenProofsRequest

Request message for listening to aggregation proofs stream

| Field       | Type              | Label    | Description                                                                                                                                                                                                               |
| ----------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| start_epoch | [uint64](#uint64) | optional | Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates If not provided, only proofs generated after stream creation will be sent |

<a name="api-proto-v1-ListenProofsResponse"></a>

### ListenProofsResponse

Response message for aggregation proofs stream

| Field             | Type                                               | Label | Description             |
| ----------------- | -------------------------------------------------- | ----- | ----------------------- |
| request_id        | [string](#string)                                  |       | Id of the request       |
| epoch             | [uint64](#uint64)                                  |       | Epoch number            |
| aggregation_proof | [AggregationProof](#api-proto-v1-AggregationProof) |       | Final aggregation proof |

<a name="api-proto-v1-ListenSignaturesRequest"></a>

### ListenSignaturesRequest

Request message for listening to signatures stream

| Field       | Type              | Label    | Description                                                                                                                                                                                                                       |
| ----------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| start_epoch | [uint64](#uint64) | optional | Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates If not provided, only signatures generated after stream creation will be sent |

<a name="api-proto-v1-ListenSignaturesResponse"></a>

### ListenSignaturesResponse

Response message for signatures stream

| Field      | Type                                 | Label | Description                 |
| ---------- | ------------------------------------ | ----- | --------------------------- |
| request_id | [string](#string)                    |       | Id of the signature request |
| epoch      | [uint64](#uint64)                    |       | Epoch number                |
| signature  | [Signature](#api-proto-v1-Signature) |       | Signature data              |

<a name="api-proto-v1-ListenValidatorSetRequest"></a>

### ListenValidatorSetRequest

Request message for listening to validator set changes stream

| Field       | Type              | Label    | Description                                                                                                                                                                                                                               |
| ----------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| start_epoch | [uint64](#uint64) | optional | Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates If not provided, only validator sets generated after stream creation will be sent |

<a name="api-proto-v1-ListenValidatorSetResponse"></a>

### ListenValidatorSetResponse

Response message for validator set changes stream

| Field         | Type                                       | Label | Description       |
| ------------- | ------------------------------------------ | ----- | ----------------- |
| validator_set | [ValidatorSet](#api-proto-v1-ValidatorSet) |       | The validator set |

<a name="api-proto-v1-SignMessageRequest"></a>

### SignMessageRequest

Request message for signing a message

| Field          | Type              | Label    | Description                                                                    |
| -------------- | ----------------- | -------- | ------------------------------------------------------------------------------ |
| key_tag        | [uint32](#uint32) |          | Key tag identifier (0-127)                                                     |
| message        | [bytes](#bytes)   |          | Message to be signed                                                           |
| required_epoch | [uint64](#uint64) | optional | Required epoch (optional, if not provided latest committed epoch will be used) |

<a name="api-proto-v1-SignMessageResponse"></a>

### SignMessageResponse

Response message for sign message request

| Field      | Type              | Label | Description                   |
| ---------- | ----------------- | ----- | ----------------------------- |
| request_id | [string](#string) |       | Hash of the signature request |
| epoch      | [uint64](#uint64) |       | Epoch number                  |

<a name="api-proto-v1-Signature"></a>

### Signature

Digital signature

| Field        | Type              | Label | Description    |
| ------------ | ----------------- | ----- | -------------- |
| signature    | [bytes](#bytes)   |       | Signature data |
| message_hash | [bytes](#bytes)   |       | Message hash   |
| public_key   | [bytes](#bytes)   |       | Public key     |
| request_id   | [string](#string) |       | Request ID     |

<a name="api-proto-v1-SignatureRequest"></a>

### SignatureRequest

SignatureRequest represents a signature request

| Field          | Type              | Label | Description                |
| -------------- | ----------------- | ----- | -------------------------- |
| request_id     | [string](#string) |       | Request ID                 |
| key_tag        | [uint32](#uint32) |       | Key tag identifier (0-127) |
| message        | [bytes](#bytes)   |       | Message to be signed       |
| required_epoch | [uint64](#uint64) |       | Required epoch             |

<a name="api-proto-v1-Validator"></a>

### Validator

Validator information

| Field        | Type                                           | Label    | Description                                           |
| ------------ | ---------------------------------------------- | -------- | ----------------------------------------------------- |
| operator     | [string](#string)                              |          | Operator address (hex string)                         |
| voting_power | [string](#string)                              |          | Voting power of the validator (big integer as string) |
| is_active    | [bool](#bool)                                  |          | Indicates if the validator is active                  |
| keys         | [Key](#api-proto-v1-Key)                       | repeated | List of cryptographic keys                            |
| vaults       | [ValidatorVault](#api-proto-v1-ValidatorVault) | repeated | List of validator vaults                              |

<a name="api-proto-v1-ValidatorSet"></a>

### ValidatorSet

| Field             | Type                                                    | Label    | Description                                   |
| ----------------- | ------------------------------------------------------- | -------- | --------------------------------------------- |
| version           | [uint32](#uint32)                                       |          | Version of the validator set                  |
| required_key_tag  | [uint32](#uint32)                                       |          | Key tag required to commit next validator set |
| epoch             | [uint64](#uint64)                                       |          | Validator set epoch                           |
| capture_timestamp | [google.protobuf.Timestamp](#google-protobuf-Timestamp) |          | Epoch capture timestamp                       |
| quorum_threshold  | [string](#string)                                       |          | Quorum threshold (big integer as string)      |
| status            | [ValidatorSetStatus](#api-proto-v1-ValidatorSetStatus)  |          | Status of validator set header                |
| validators        | [Validator](#api-proto-v1-Validator)                    | repeated | List of validators                            |

<a name="api-proto-v1-ValidatorVault"></a>

### ValidatorVault

Validator vault information

| Field        | Type              | Label | Description                                         |
| ------------ | ----------------- | ----- | --------------------------------------------------- |
| chain_id     | [uint64](#uint64) |       | Chain identifier                                    |
| vault        | [string](#string) |       | Vault address                                       |
| voting_power | [string](#string) |       | Voting power for this vault (big integer as string) |

<a name="api-proto-v1-ErrorCode"></a>

### ErrorCode

Error code enumeration

| Name                      | Number | Description            |
| ------------------------- | ------ | ---------------------- |
| ERROR_CODE_UNSPECIFIED    | 0      | Default/unknown error  |
| ERROR_CODE_NO_DATA        | 1      | No data found          |
| ERROR_CODE_INTERNAL       | 2      | Internal server error  |
| ERROR_CODE_NOT_AGGREGATOR | 3      | Not an aggregator node |

<a name="api-proto-v1-SigningStatus"></a>

### SigningStatus

Signing process status enumeration

| Name                       | Number | Description                                            |
| -------------------------- | ------ | ------------------------------------------------------ |
| SIGNING_STATUS_UNSPECIFIED | 0      | Default/unknown status                                 |
| SIGNING_STATUS_PENDING     | 1      | Request has been created and is waiting for signatures |
| SIGNING_STATUS_COMPLETED   | 2      | Signing process completed successfully with proof      |
| SIGNING_STATUS_FAILED      | 3      | Signing process failed                                 |
| SIGNING_STATUS_TIMEOUT     | 4      | Signing request timed out                              |

<a name="api-proto-v1-ValidatorSetStatus"></a>

### ValidatorSetStatus

Validator set status enumeration

| Name                             | Number | Description            |
| -------------------------------- | ------ | ---------------------- |
| VALIDATOR_SET_STATUS_UNSPECIFIED | 0      | Default/unknown status |
| VALIDATOR_SET_STATUS_DERIVED     | 1      | Derived status         |
| VALIDATOR_SET_STATUS_AGGREGATED  | 2      | Aggregated status      |
| VALIDATOR_SET_STATUS_COMMITTED   | 3      | Committed status       |

<a name="api-proto-v1-SymbioticAPIService"></a>

### SymbioticAPIService

SymbioticAPI provides access to the Symbiotic relay functions

| Method Name                   | Request Type                                                                               | Response Type                                                                                | Description                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ----------------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SignMessage                   | [SignMessageRequest](#api-proto-v1-SignMessageRequest)                                     | [SignMessageResponse](#api-proto-v1-SignMessageResponse)                                     | Sign a message                                                                                                                                                                                                                                                                                                                                                                                                                   |
| GetAggregationProof           | [GetAggregationProofRequest](#api-proto-v1-GetAggregationProofRequest)                     | [GetAggregationProofResponse](#api-proto-v1-GetAggregationProofResponse)                     | Get aggregation proof                                                                                                                                                                                                                                                                                                                                                                                                            |
| GetAggregationProofsByEpoch   | [GetAggregationProofsByEpochRequest](#api-proto-v1-GetAggregationProofsByEpochRequest)     | [GetAggregationProofsByEpochResponse](#api-proto-v1-GetAggregationProofsByEpochResponse)     | Get aggregation proofs by epoch                                                                                                                                                                                                                                                                                                                                                                                                  |
| GetCurrentEpoch               | [GetCurrentEpochRequest](#api-proto-v1-GetCurrentEpochRequest)                             | [GetCurrentEpochResponse](#api-proto-v1-GetCurrentEpochResponse)                             | Get current epoch                                                                                                                                                                                                                                                                                                                                                                                                                |
| GetSignatures                 | [GetSignaturesRequest](#api-proto-v1-GetSignaturesRequest)                                 | [GetSignaturesResponse](#api-proto-v1-GetSignaturesResponse)                                 | Get signature by request id                                                                                                                                                                                                                                                                                                                                                                                                      |
| GetSignaturesByEpoch          | [GetSignaturesByEpochRequest](#api-proto-v1-GetSignaturesByEpochRequest)                   | [GetSignaturesByEpochResponse](#api-proto-v1-GetSignaturesByEpochResponse)                   | Get signature by epoch                                                                                                                                                                                                                                                                                                                                                                                                           |
| GetSignatureRequestIDsByEpoch | [GetSignatureRequestIDsByEpochRequest](#api-proto-v1-GetSignatureRequestIDsByEpochRequest) | [GetSignatureRequestIDsByEpochResponse](#api-proto-v1-GetSignatureRequestIDsByEpochResponse) | Get all signature request IDs by epoch                                                                                                                                                                                                                                                                                                                                                                                           |
| GetSignatureRequestsByEpoch   | [GetSignatureRequestsByEpochRequest](#api-proto-v1-GetSignatureRequestsByEpochRequest)     | [GetSignatureRequestsByEpochResponse](#api-proto-v1-GetSignatureRequestsByEpochResponse)     | Get all signature requests by epoch                                                                                                                                                                                                                                                                                                                                                                                              |
| GetSignatureRequest           | [GetSignatureRequestRequest](#api-proto-v1-GetSignatureRequestRequest)                     | [GetSignatureRequestResponse](#api-proto-v1-GetSignatureRequestResponse)                     | Get signature request by request id                                                                                                                                                                                                                                                                                                                                                                                              |
| GetAggregationStatus          | [GetAggregationStatusRequest](#api-proto-v1-GetAggregationStatusRequest)                   | [GetAggregationStatusResponse](#api-proto-v1-GetAggregationStatusResponse)                   | Get aggregation status, can be sent only to aggregator nodes                                                                                                                                                                                                                                                                                                                                                                     |
| GetValidatorSet               | [GetValidatorSetRequest](#api-proto-v1-GetValidatorSetRequest)                             | [GetValidatorSetResponse](#api-proto-v1-GetValidatorSetResponse)                             | Get current validator set                                                                                                                                                                                                                                                                                                                                                                                                        |
| GetValidatorByAddress         | [GetValidatorByAddressRequest](#api-proto-v1-GetValidatorByAddressRequest)                 | [GetValidatorByAddressResponse](#api-proto-v1-GetValidatorByAddressResponse)                 | Get validator by address                                                                                                                                                                                                                                                                                                                                                                                                         |
| GetValidatorByKey             | [GetValidatorByKeyRequest](#api-proto-v1-GetValidatorByKeyRequest)                         | [GetValidatorByKeyResponse](#api-proto-v1-GetValidatorByKeyResponse)                         | Get validator by key                                                                                                                                                                                                                                                                                                                                                                                                             |
| GetLocalValidator             | [GetLocalValidatorRequest](#api-proto-v1-GetLocalValidatorRequest)                         | [GetLocalValidatorResponse](#api-proto-v1-GetLocalValidatorResponse)                         | Get local validator                                                                                                                                                                                                                                                                                                                                                                                                              |
| GetValidatorSetHeader         | [GetValidatorSetHeaderRequest](#api-proto-v1-GetValidatorSetHeaderRequest)                 | [GetValidatorSetHeaderResponse](#api-proto-v1-GetValidatorSetHeaderResponse)                 | Get validator set header                                                                                                                                                                                                                                                                                                                                                                                                         |
| GetLastCommitted              | [GetLastCommittedRequest](#api-proto-v1-GetLastCommittedRequest)                           | [GetLastCommittedResponse](#api-proto-v1-GetLastCommittedResponse)                           | Get last committed epoch for a specific settlement chain                                                                                                                                                                                                                                                                                                                                                                         |
| GetLastAllCommitted           | [GetLastAllCommittedRequest](#api-proto-v1-GetLastAllCommittedRequest)                     | [GetLastAllCommittedResponse](#api-proto-v1-GetLastAllCommittedResponse)                     | Get last committed epochs for all settlement chains                                                                                                                                                                                                                                                                                                                                                                              |
| GetValidatorSetMetadata       | [GetValidatorSetMetadataRequest](#api-proto-v1-GetValidatorSetMetadataRequest)             | [GetValidatorSetMetadataResponse](#api-proto-v1-GetValidatorSetMetadataResponse)             | Get validator set metadata like extra data and request id to fetch aggregation and signature requests                                                                                                                                                                                                                                                                                                                            |
| GetCustomScheduleNodeStatus   | [GetCustomScheduleNodeStatusRequest](#api-proto-v1-GetCustomScheduleNodeStatusRequest)     | [GetCustomScheduleNodeStatusResponse](#api-proto-v1-GetCustomScheduleNodeStatusResponse)     | Checks if the current node should be active based on a custom schedule derived from the validator set. This enables external applications to use the relay&#39;s validator set for coordinating distributed tasks, such as deciding which application instances should commit data on-chain or perform other coordinated actions. The schedule ensures deterministic but randomized selection of active nodes at any given time. |
| ListenSignatures              | [ListenSignaturesRequest](#api-proto-v1-ListenSignaturesRequest)                           | [ListenSignaturesResponse](#api-proto-v1-ListenSignaturesResponse) stream                    | Stream signatures in real-time. If start_epoch is provided, sends historical data first                                                                                                                                                                                                                                                                                                                                          |
| ListenProofs                  | [ListenProofsRequest](#api-proto-v1-ListenProofsRequest)                                   | [ListenProofsResponse](#api-proto-v1-ListenProofsResponse) stream                            | Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first                                                                                                                                                                                                                                                                                                                                  |
| ListenValidatorSet            | [ListenValidatorSetRequest](#api-proto-v1-ListenValidatorSetRequest)                       | [ListenValidatorSetResponse](#api-proto-v1-ListenValidatorSetResponse) stream                | Stream validator set changes in real-time. If start_epoch is provided, sends historical data first                                                                                                                                                                                                                                                                                                                               |

## Scalar Value Types

| .proto Type                    | Notes                                                                                                                                           | C++    | Java       | Python      | Go      | C#         | PHP            | Ruby                           |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ---------- | ----------- | ------- | ---------- | -------------- | ------------------------------ |
| <a name="double" /> double     |                                                                                                                                                 | double | double     | float       | float64 | double     | float          | Float                          |
| <a name="float" /> float       |                                                                                                                                                 | float  | float      | float       | float32 | float      | float          | Float                          |
| <a name="int32" /> int32       | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="int64" /> int64       | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="uint32" /> uint32     | Uses variable-length encoding.                                                                                                                  | uint32 | int        | int/long    | uint32  | uint       | integer        | Bignum or Fixnum (as required) |
| <a name="uint64" /> uint64     | Uses variable-length encoding.                                                                                                                  | uint64 | long       | int/long    | uint64  | ulong      | integer/string | Bignum or Fixnum (as required) |
| <a name="sint32" /> sint32     | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.                            | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="sint64" /> sint64     | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.                            | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="fixed32" /> fixed32   | Always four bytes. More efficient than uint32 if values are often greater than 2^28.                                                            | uint32 | int        | int         | uint32  | uint       | integer        | Bignum or Fixnum (as required) |
| <a name="fixed64" /> fixed64   | Always eight bytes. More efficient than uint64 if values are often greater than 2^56.                                                           | uint64 | long       | int/long    | uint64  | ulong      | integer/string | Bignum                         |
| <a name="sfixed32" /> sfixed32 | Always four bytes.                                                                                                                              | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="sfixed64" /> sfixed64 | Always eight bytes.                                                                                                                             | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="bool" /> bool         |                                                                                                                                                 | bool   | boolean    | boolean     | bool    | bool       | boolean        | TrueClass/FalseClass           |
| <a name="string" /> string     | A string must always contain UTF-8 encoded or 7-bit ASCII text.                                                                                 | string | String     | str/unicode | string  | string     | string         | String (UTF-8)                 |
| <a name="bytes" /> bytes       | May contain any arbitrary sequence of bytes.                                                                                                    | string | ByteString | str         | []byte  | ByteString | string         | String (ASCII-8BIT)            |
```

## File: docs/api/v1/index.html

```html
<!DOCTYPE html>

<html>
    <head>
        <title>Protocol Documentation</title>
        <meta charset="UTF-8" />
        <link
            rel="stylesheet"
            type="text/css"
            href="https://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic"
        />
        <style>
            body {
                width: 60em;
                margin: 1em auto;
                color: #222;
                font-family: "Ubuntu", sans-serif;
                padding-bottom: 4em;
            }

            h1 {
                font-weight: normal;
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
            }

            h2 {
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
                margin: 1.5em 0;
            }

            h3 {
                font-weight: normal;
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
            }

            a {
                text-decoration: none;
                color: #567e25;
            }

            table {
                width: 100%;
                font-size: 80%;
                border-collapse: collapse;
            }

            thead {
                font-weight: 700;
                background-color: #dcdcdc;
            }

            tbody tr:nth-child(even) {
                background-color: #fbfbfb;
            }

            td {
                border: 1px solid #ccc;
                padding: 0.5ex 2ex;
            }

            td p {
                text-indent: 1em;
                margin: 0;
            }

            td p:nth-child(1) {
                text-indent: 0;
            }

            .field-table td:nth-child(1) {
                width: 10em;
            }
            .field-table td:nth-child(2) {
                width: 10em;
            }
            .field-table td:nth-child(3) {
                width: 6em;
            }
            .field-table td:nth-child(4) {
                width: auto;
            }

            .extension-table td:nth-child(1) {
                width: 10em;
            }
            .extension-table td:nth-child(2) {
                width: 10em;
            }
            .extension-table td:nth-child(3) {
                width: 10em;
            }
            .extension-table td:nth-child(4) {
                width: 5em;
            }
            .extension-table td:nth-child(5) {
                width: auto;
            }

            .enum-table td:nth-child(1) {
                width: 10em;
            }
            .enum-table td:nth-child(2) {
                width: 10em;
            }
            .enum-table td:nth-child(3) {
                width: auto;
            }

            .scalar-value-types-table tr {
                height: 3em;
            }

            #toc-container ul {
                list-style-type: none;
                padding-left: 1em;
                line-height: 180%;
                margin: 0;
            }
            #toc > li > a {
                font-weight: bold;
            }

            .file-heading {
                width: 100%;
                display: table;
                border-bottom: 1px solid #aaa;
                margin: 4em 0 1.5em 0;
            }
            .file-heading h2 {
                border: none;
                display: table-cell;
            }
            .file-heading a {
                text-align: right;
                display: table-cell;
            }

            .badge {
                width: 1.6em;
                height: 1.6em;
                display: inline-block;

                line-height: 1.6em;
                text-align: center;
                font-weight: bold;
                font-size: 60%;

                color: #89ba48;
                background-color: #dff0c8;

                margin: 0.5ex 1em 0.5ex -1em;
                border: 1px solid #fbfbfb;
                border-radius: 1ex;
            }
        </style>

        <link rel="stylesheet" type="text/css" href="stylesheet.css" />
    </head>

    <body>
        <h1 id="title">Protocol Documentation</h1>

        <h2>Table of Contents</h2>

        <div id="toc-container">
            <ul id="toc">
                <li>
                    <a href="#v1%2fapi.proto">v1/api.proto</a>
                    <ul>
                        <li>
                            <a href="#api.proto.v1.AggregationProof"
                                ><span class="badge">M</span>AggregationProof</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ChainEpochInfo"
                                ><span class="badge">M</span>ChainEpochInfo</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ExtraData"
                                ><span class="badge">M</span>ExtraData</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationProofRequest"
                                ><span class="badge">M</span>GetAggregationProofRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationProofResponse"
                                ><span class="badge">M</span>GetAggregationProofResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationProofsByEpochRequest"
                                ><span class="badge">M</span>GetAggregationProofsByEpochRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationProofsByEpochResponse"
                                ><span class="badge">M</span>GetAggregationProofsByEpochResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationStatusRequest"
                                ><span class="badge">M</span>GetAggregationStatusRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetAggregationStatusResponse"
                                ><span class="badge">M</span>GetAggregationStatusResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetCurrentEpochRequest"
                                ><span class="badge">M</span>GetCurrentEpochRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetCurrentEpochResponse"
                                ><span class="badge">M</span>GetCurrentEpochResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetCustomScheduleNodeStatusRequest"
                                ><span class="badge">M</span>GetCustomScheduleNodeStatusRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetCustomScheduleNodeStatusResponse"
                                ><span class="badge">M</span>GetCustomScheduleNodeStatusResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLastAllCommittedRequest"
                                ><span class="badge">M</span>GetLastAllCommittedRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLastAllCommittedResponse"
                                ><span class="badge">M</span>GetLastAllCommittedResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry"
                                ><span class="badge">M</span
                                >GetLastAllCommittedResponse.EpochInfosEntry</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLastCommittedRequest"
                                ><span class="badge">M</span>GetLastCommittedRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLastCommittedResponse"
                                ><span class="badge">M</span>GetLastCommittedResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLocalValidatorRequest"
                                ><span class="badge">M</span>GetLocalValidatorRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetLocalValidatorResponse"
                                ><span class="badge">M</span>GetLocalValidatorResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestIDsByEpochRequest"
                                ><span class="badge">M</span>GetSignatureRequestIDsByEpochRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestIDsByEpochResponse"
                                ><span class="badge">M</span
                                >GetSignatureRequestIDsByEpochResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestRequest"
                                ><span class="badge">M</span>GetSignatureRequestRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestResponse"
                                ><span class="badge">M</span>GetSignatureRequestResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestsByEpochRequest"
                                ><span class="badge">M</span>GetSignatureRequestsByEpochRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignatureRequestsByEpochResponse"
                                ><span class="badge">M</span>GetSignatureRequestsByEpochResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignaturesByEpochRequest"
                                ><span class="badge">M</span>GetSignaturesByEpochRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignaturesByEpochResponse"
                                ><span class="badge">M</span>GetSignaturesByEpochResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignaturesRequest"
                                ><span class="badge">M</span>GetSignaturesRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetSignaturesResponse"
                                ><span class="badge">M</span>GetSignaturesResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorByAddressRequest"
                                ><span class="badge">M</span>GetValidatorByAddressRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorByAddressResponse"
                                ><span class="badge">M</span>GetValidatorByAddressResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorByKeyRequest"
                                ><span class="badge">M</span>GetValidatorByKeyRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorByKeyResponse"
                                ><span class="badge">M</span>GetValidatorByKeyResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetHeaderRequest"
                                ><span class="badge">M</span>GetValidatorSetHeaderRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetHeaderResponse"
                                ><span class="badge">M</span>GetValidatorSetHeaderResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetMetadataRequest"
                                ><span class="badge">M</span>GetValidatorSetMetadataRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetMetadataResponse"
                                ><span class="badge">M</span>GetValidatorSetMetadataResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetRequest"
                                ><span class="badge">M</span>GetValidatorSetRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.GetValidatorSetResponse"
                                ><span class="badge">M</span>GetValidatorSetResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.Key"><span class="badge">M</span>Key</a>
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenProofsRequest"
                                ><span class="badge">M</span>ListenProofsRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenProofsResponse"
                                ><span class="badge">M</span>ListenProofsResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenSignaturesRequest"
                                ><span class="badge">M</span>ListenSignaturesRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenSignaturesResponse"
                                ><span class="badge">M</span>ListenSignaturesResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenValidatorSetRequest"
                                ><span class="badge">M</span>ListenValidatorSetRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ListenValidatorSetResponse"
                                ><span class="badge">M</span>ListenValidatorSetResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.SignMessageRequest"
                                ><span class="badge">M</span>SignMessageRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.SignMessageResponse"
                                ><span class="badge">M</span>SignMessageResponse</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.Signature"
                                ><span class="badge">M</span>Signature</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.SignatureRequest"
                                ><span class="badge">M</span>SignatureRequest</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.Validator"
                                ><span class="badge">M</span>Validator</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ValidatorSet"
                                ><span class="badge">M</span>ValidatorSet</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ValidatorVault"
                                ><span class="badge">M</span>ValidatorVault</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ErrorCode"
                                ><span class="badge">E</span>ErrorCode</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.SigningStatus"
                                ><span class="badge">E</span>SigningStatus</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.ValidatorSetStatus"
                                ><span class="badge">E</span>ValidatorSetStatus</a
                            >
                        </li>

                        <li>
                            <a href="#api.proto.v1.SymbioticAPIService"
                                ><span class="badge">S</span>SymbioticAPIService</a
                            >
                        </li>
                    </ul>
                </li>

                <li><a href="#scalar-value-types">Scalar Value Types</a></li>
            </ul>
        </div>

        <div class="file-heading">
            <h2 id="v1/api.proto">v1/api.proto</h2>
            <a href="#title">Top</a>
        </div>
        <p></p>

        <h3 id="api.proto.v1.AggregationProof">AggregationProof</h3>
        <p>Response message for getting aggregation proof</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>message_hash</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Message hash</p></td>
                </tr>

                <tr>
                    <td>proof</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Proof data</p></td>
                </tr>

                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Request ID</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ChainEpochInfo">ChainEpochInfo</h3>
        <p>Settlement chain with its last committed epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>last_committed_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Last committed epoch for this chain</p></td>
                </tr>

                <tr>
                    <td>start_time</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td><p>Epoch start time</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ExtraData">ExtraData</h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>key</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>

                <tr>
                    <td>value</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationProofRequest">GetAggregationProofRequest</h3>
        <p>Request message for getting aggregation proof</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationProofResponse">GetAggregationProofResponse</h3>
        <p>Response message for getting aggregation proof</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>aggregation_proof</td>
                    <td><a href="#api.proto.v1.AggregationProof">AggregationProof</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationProofsByEpochRequest">
            GetAggregationProofsByEpochRequest
        </h3>
        <p>Request message for getting aggregation proof</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>page_size</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Maximum number of items to return. 0 = server default (100). Server
                            clamps to max (1000).
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>
                            Opaque pagination cursor from a previous response&#39;s `next_from`.
                            Empty string starts from the beginning.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationProofsByEpochResponse">
            GetAggregationProofsByEpochResponse
        </h3>
        <p>Response message for getting aggregation proof</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>aggregation_proofs</td>
                    <td><a href="#api.proto.v1.AggregationProof">AggregationProof</a></td>
                    <td>repeated</td>
                    <td><p></p></td>
                </tr>

                <tr>
                    <td>next_from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>Cursor to retrieve the next page. Empty when this is the last page.</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationStatusRequest">GetAggregationStatusRequest</h3>
        <p>Request message for getting aggregation status</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetAggregationStatusResponse">GetAggregationStatusResponse</h3>
        <p>Response message for getting aggregation status</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>current_voting_power</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Current voting power of the aggregator (big integer as string)</p></td>
                </tr>

                <tr>
                    <td>signer_operators</td>
                    <td><a href="#string">string</a></td>
                    <td>repeated</td>
                    <td><p>List of operator addresses that signed the request</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetCurrentEpochRequest">GetCurrentEpochRequest</h3>
        <p>Request message for getting current epoch</p>

        <h3 id="api.proto.v1.GetCurrentEpochResponse">GetCurrentEpochResponse</h3>
        <p>Response message for getting current epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>start_time</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td><p>Epoch start time</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetCustomScheduleNodeStatusRequest">
            GetCustomScheduleNodeStatusRequest
        </h3>
        <p>Request to check if the current node should be active in a custom schedule.</p>
        <p>The validator set is divided into groups that rotate through time slots.</p>
        <p>Use this to coordinate distributed tasks among multiple application instances.</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Epoch number to use for the validator set (optional, defaults to current
                            epoch)
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>seed</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Custom seed for randomizing the schedule (optional). Different seeds
                            produce different schedules for the same epoch, allowing multiple
                            independent scheduling schemes. If not provided, the schedule is
                            deterministic based on epoch alone.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>slot_duration_seconds</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td>
                        <p>
                            Duration of each time slot in seconds. Determines how frequently active
                            groups rotate. Example: 60 seconds means a new group becomes active
                            every minute.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>max_participants_per_slot</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Maximum validators per group. Controls redundancy: 1 for single-instance
                            actions (less redundancy), 2&#43; for multi-instance actions (more
                            reliability). All validators in a group are active simultaneously.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>min_participants_per_slot</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Minimum validators required to form a remainder group. When dividing
                            validators into groups, any remainder smaller than this is not
                            scheduled. Set equal to max for strict group sizes.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetCustomScheduleNodeStatusResponse">
            GetCustomScheduleNodeStatusResponse
        </h3>
        <p>Response indicating whether the current node should be active now.</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>is_active</td>
                    <td><a href="#bool">bool</a></td>
                    <td></td>
                    <td>
                        <p>
                            True if this node is active in the current time slot and should perform
                            the scheduled action. False if this node should wait (another group is
                            active). When multiple validators share a slot, all return true
                            simultaneously, enabling coordinated redundancy.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>current_slot_start_time</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td>
                        <p>
                            Start time of the current active slot. This marks the beginning of the
                            current slot time window. Can be used to determine how much time is left
                            in the slot.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>current_slot_end_time</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td>
                        <p>
                            End time of the current active slot. This marks the end of the current
                            slot time window. Can be used to determine how much time is left in the
                            slot.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLastAllCommittedRequest">GetLastAllCommittedRequest</h3>
        <p>Request message for getting last committed epochs for all chains</p>
        <p>No parameters needed</p>

        <h3 id="api.proto.v1.GetLastAllCommittedResponse">GetLastAllCommittedResponse</h3>
        <p>Response message for getting all last committed epochs</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch_infos</td>
                    <td>
                        <a href="#api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry"
                            >GetLastAllCommittedResponse.EpochInfosEntry</a
                        >
                    </td>
                    <td>repeated</td>
                    <td><p>List of settlement chains with their last committed epochs</p></td>
                </tr>

                <tr>
                    <td>suggested_epoch_info</td>
                    <td><a href="#api.proto.v1.ChainEpochInfo">ChainEpochInfo</a></td>
                    <td></td>
                    <td>
                        <p>
                            Suggested epoch info for signatures, it is the minimum commited epoch
                            among all chains
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry">
            GetLastAllCommittedResponse.EpochInfosEntry
        </h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>key</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>

                <tr>
                    <td>value</td>
                    <td><a href="#api.proto.v1.ChainEpochInfo">ChainEpochInfo</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLastCommittedRequest">GetLastCommittedRequest</h3>
        <p>Request message for getting last committed epoch for a specific settlement chain</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>settlement_chain_id</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Settlement chain ID</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLastCommittedResponse">GetLastCommittedResponse</h3>
        <p>Response message for getting last committed epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>settlement_chain_id</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Settlement chain ID</p></td>
                </tr>

                <tr>
                    <td>epoch_info</td>
                    <td><a href="#api.proto.v1.ChainEpochInfo">ChainEpochInfo</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLocalValidatorRequest">GetLocalValidatorRequest</h3>
        <p>Request message for getting local validator</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetLocalValidatorResponse">GetLocalValidatorResponse</h3>
        <p>Response message for getting local validator</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>validator</td>
                    <td><a href="#api.proto.v1.Validator">Validator</a></td>
                    <td></td>
                    <td><p>The validator</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestIDsByEpochRequest">
            GetSignatureRequestIDsByEpochRequest
        </h3>
        <p>Request message for getting all signature request IDs by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>page_size</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Maximum number of items to return. 0 = server default (1000). Server
                            clamps to max (10000).
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>
                            Opaque pagination cursor from a previous response&#39;s `next_from`.
                            Empty string starts from the beginning.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestIDsByEpochResponse">
            GetSignatureRequestIDsByEpochResponse
        </h3>
        <p>Response message for getting all signature request IDs by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_ids</td>
                    <td><a href="#string">string</a></td>
                    <td>repeated</td>
                    <td><p>List of all signature request IDs for the epoch</p></td>
                </tr>

                <tr>
                    <td>next_from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>Cursor to retrieve the next page. Empty when this is the last page.</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestRequest">GetSignatureRequestRequest</h3>
        <p>Request message for getting signature request</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestResponse">GetSignatureRequestResponse</h3>
        <p>Response message for getting signature request</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>signature_request</td>
                    <td><a href="#api.proto.v1.SignatureRequest">SignatureRequest</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestsByEpochRequest">
            GetSignatureRequestsByEpochRequest
        </h3>
        <p>Request message for getting all signature requests by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>page_size</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Maximum number of items to return. 0 = server default (100). Server
                            clamps to max (1000).
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>
                            Opaque pagination cursor from a previous response&#39;s `next_from`.
                            Empty string starts from the beginning.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignatureRequestsByEpochResponse">
            GetSignatureRequestsByEpochResponse
        </h3>
        <p>Response message for getting all signature requests by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>signature_requests</td>
                    <td><a href="#api.proto.v1.SignatureRequest">SignatureRequest</a></td>
                    <td>repeated</td>
                    <td><p>List of all signature requests for the epoch</p></td>
                </tr>

                <tr>
                    <td>next_from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>Cursor to retrieve the next page. Empty when this is the last page.</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignaturesByEpochRequest">GetSignaturesByEpochRequest</h3>
        <p>Request message for getting signatures by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>page_size</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td>
                        <p>
                            Maximum number of items to return. 0 = server default (100). Server
                            clamps to max (1000).
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>
                            Opaque pagination cursor from a previous response&#39;s `next_from`.
                            Empty string starts from the beginning.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignaturesByEpochResponse">GetSignaturesByEpochResponse</h3>
        <p>Response message for getting signatures by epoch</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>signatures</td>
                    <td><a href="#api.proto.v1.Signature">Signature</a></td>
                    <td>repeated</td>
                    <td><p>List of signatures</p></td>
                </tr>

                <tr>
                    <td>next_from</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td>
                        <p>Cursor to retrieve the next page. Empty when this is the last page.</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignaturesRequest">GetSignaturesRequest</h3>
        <p>Request message for getting signatures</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetSignaturesResponse">GetSignaturesResponse</h3>
        <p>Response message for getting signatures</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>signatures</td>
                    <td><a href="#api.proto.v1.Signature">Signature</a></td>
                    <td>repeated</td>
                    <td><p>List of signatures</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorByAddressRequest">GetValidatorByAddressRequest</h3>
        <p>Request message for getting validator by address</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>

                <tr>
                    <td>address</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Validator address (required)</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorByAddressResponse">GetValidatorByAddressResponse</h3>
        <p>Response message for getting validator by address</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>validator</td>
                    <td><a href="#api.proto.v1.Validator">Validator</a></td>
                    <td></td>
                    <td><p>The validator</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorByKeyRequest">GetValidatorByKeyRequest</h3>
        <p>Request message for getting validator by key</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>

                <tr>
                    <td>key_tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Validator key tag (required)</p></td>
                </tr>

                <tr>
                    <td>on_chain_key</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Validator on chain (public) key (required)</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorByKeyResponse">GetValidatorByKeyResponse</h3>
        <p>Response message for getting validator by key</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>validator</td>
                    <td><a href="#api.proto.v1.Validator">Validator</a></td>
                    <td></td>
                    <td><p>The validator</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetHeaderRequest">GetValidatorSetHeaderRequest</h3>
        <p>Request message for getting validator set header</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetHeaderResponse">GetValidatorSetHeaderResponse</h3>
        <p>Response message for getting validator set header</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>version</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Version of the validator set</p></td>
                </tr>

                <tr>
                    <td>required_key_tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Key tag required to commit next validator set</p></td>
                </tr>

                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Validator set epoch</p></td>
                </tr>

                <tr>
                    <td>capture_timestamp</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td><p>Epoch capture timestamp</p></td>
                </tr>

                <tr>
                    <td>quorum_threshold</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Quorum threshold (big integer as string)</p></td>
                </tr>

                <tr>
                    <td>total_voting_power</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Total voting power (big integer as string)</p></td>
                </tr>

                <tr>
                    <td>validators_ssz_mroot</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Validators SSZ Merkle root (hex string)</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetMetadataRequest">GetValidatorSetMetadataRequest</h3>
        <p>Request message for getting validator set metadata</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetMetadataResponse">GetValidatorSetMetadataResponse</h3>
        <p>Response message for getting validator set header</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>extra_data</td>
                    <td><a href="#api.proto.v1.ExtraData">ExtraData</a></td>
                    <td>repeated</td>
                    <td><p></p></td>
                </tr>

                <tr>
                    <td>commitment_data</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>

                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetRequest">GetValidatorSetRequest</h3>
        <p>Request message for getting validator set</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>Epoch number (optional, if not provided current epoch will be used)</p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.GetValidatorSetResponse">GetValidatorSetResponse</h3>
        <p>Response message for getting validator set</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>validator_set</td>
                    <td><a href="#api.proto.v1.ValidatorSet">ValidatorSet</a></td>
                    <td></td>
                    <td><p>The validator set</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.Key">Key</h3>
        <p>Cryptographic key</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Key tag identifier (0-127)</p></td>
                </tr>

                <tr>
                    <td>payload</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Key payload</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenProofsRequest">ListenProofsRequest</h3>
        <p>Request message for listening to aggregation proofs stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>start_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Optional: start epoch. If provided, stream will first send all
                            historical proofs starting from this epoch, then continue with real-time
                            updates If not provided, only proofs generated after stream creation
                            will be sent
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenProofsResponse">ListenProofsResponse</h3>
        <p>Response message for aggregation proofs stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Id of the request</p></td>
                </tr>

                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>aggregation_proof</td>
                    <td><a href="#api.proto.v1.AggregationProof">AggregationProof</a></td>
                    <td></td>
                    <td><p>Final aggregation proof</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenSignaturesRequest">ListenSignaturesRequest</h3>
        <p>Request message for listening to signatures stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>start_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Optional: start epoch. If provided, stream will first send all
                            historical signatures starting from this epoch, then continue with
                            real-time updates If not provided, only signatures generated after
                            stream creation will be sent
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenSignaturesResponse">ListenSignaturesResponse</h3>
        <p>Response message for signatures stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Id of the signature request</p></td>
                </tr>

                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>

                <tr>
                    <td>signature</td>
                    <td><a href="#api.proto.v1.Signature">Signature</a></td>
                    <td></td>
                    <td><p>Signature data</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenValidatorSetRequest">ListenValidatorSetRequest</h3>
        <p>Request message for listening to validator set changes stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>start_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Optional: start epoch. If provided, stream will first send all
                            historical validator sets starting from this epoch, then continue with
                            real-time updates If not provided, only validator sets generated after
                            stream creation will be sent
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ListenValidatorSetResponse">ListenValidatorSetResponse</h3>
        <p>Response message for validator set changes stream</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>validator_set</td>
                    <td><a href="#api.proto.v1.ValidatorSet">ValidatorSet</a></td>
                    <td></td>
                    <td><p>The validator set</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.SignMessageRequest">SignMessageRequest</h3>
        <p>Request message for signing a message</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>key_tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Key tag identifier (0-127)</p></td>
                </tr>

                <tr>
                    <td>message</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Message to be signed</p></td>
                </tr>

                <tr>
                    <td>required_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td>optional</td>
                    <td>
                        <p>
                            Required epoch (optional, if not provided latest committed epoch will be
                            used)
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.SignMessageResponse">SignMessageResponse</h3>
        <p>Response message for sign message request</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Hash of the signature request</p></td>
                </tr>

                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Epoch number</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.Signature">Signature</h3>
        <p>Digital signature</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>signature</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Signature data</p></td>
                </tr>

                <tr>
                    <td>message_hash</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Message hash</p></td>
                </tr>

                <tr>
                    <td>public_key</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Public key</p></td>
                </tr>

                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Request ID</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.SignatureRequest">SignatureRequest</h3>
        <p>SignatureRequest represents a signature request</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>request_id</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Request ID</p></td>
                </tr>

                <tr>
                    <td>key_tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Key tag identifier (0-127)</p></td>
                </tr>

                <tr>
                    <td>message</td>
                    <td><a href="#bytes">bytes</a></td>
                    <td></td>
                    <td><p>Message to be signed</p></td>
                </tr>

                <tr>
                    <td>required_epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Required epoch</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.Validator">Validator</h3>
        <p>Validator information</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>operator</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Operator address (hex string)</p></td>
                </tr>

                <tr>
                    <td>voting_power</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Voting power of the validator (big integer as string)</p></td>
                </tr>

                <tr>
                    <td>is_active</td>
                    <td><a href="#bool">bool</a></td>
                    <td></td>
                    <td><p>Indicates if the validator is active</p></td>
                </tr>

                <tr>
                    <td>keys</td>
                    <td><a href="#api.proto.v1.Key">Key</a></td>
                    <td>repeated</td>
                    <td><p>List of cryptographic keys</p></td>
                </tr>

                <tr>
                    <td>vaults</td>
                    <td><a href="#api.proto.v1.ValidatorVault">ValidatorVault</a></td>
                    <td>repeated</td>
                    <td><p>List of validator vaults</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ValidatorSet">ValidatorSet</h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>version</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Version of the validator set</p></td>
                </tr>

                <tr>
                    <td>required_key_tag</td>
                    <td><a href="#uint32">uint32</a></td>
                    <td></td>
                    <td><p>Key tag required to commit next validator set</p></td>
                </tr>

                <tr>
                    <td>epoch</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Validator set epoch</p></td>
                </tr>

                <tr>
                    <td>capture_timestamp</td>
                    <td><a href="#google.protobuf.Timestamp">google.protobuf.Timestamp</a></td>
                    <td></td>
                    <td><p>Epoch capture timestamp</p></td>
                </tr>

                <tr>
                    <td>quorum_threshold</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Quorum threshold (big integer as string)</p></td>
                </tr>

                <tr>
                    <td>status</td>
                    <td><a href="#api.proto.v1.ValidatorSetStatus">ValidatorSetStatus</a></td>
                    <td></td>
                    <td><p>Status of validator set header</p></td>
                </tr>

                <tr>
                    <td>validators</td>
                    <td><a href="#api.proto.v1.Validator">Validator</a></td>
                    <td>repeated</td>
                    <td><p>List of validators</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ValidatorVault">ValidatorVault</h3>
        <p>Validator vault information</p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>chain_id</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Chain identifier</p></td>
                </tr>

                <tr>
                    <td>vault</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Vault address</p></td>
                </tr>

                <tr>
                    <td>voting_power</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Voting power for this vault (big integer as string)</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ErrorCode">ErrorCode</h3>
        <p>Error code enumeration</p>
        <table class="enum-table">
            <thead>
                <tr>
                    <td>Name</td>
                    <td>Number</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>ERROR_CODE_UNSPECIFIED</td>
                    <td>0</td>
                    <td><p>Default/unknown error</p></td>
                </tr>

                <tr>
                    <td>ERROR_CODE_NO_DATA</td>
                    <td>1</td>
                    <td><p>No data found</p></td>
                </tr>

                <tr>
                    <td>ERROR_CODE_INTERNAL</td>
                    <td>2</td>
                    <td><p>Internal server error</p></td>
                </tr>

                <tr>
                    <td>ERROR_CODE_NOT_AGGREGATOR</td>
                    <td>3</td>
                    <td><p>Not an aggregator node</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.SigningStatus">SigningStatus</h3>
        <p>Signing process status enumeration</p>
        <table class="enum-table">
            <thead>
                <tr>
                    <td>Name</td>
                    <td>Number</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>SIGNING_STATUS_UNSPECIFIED</td>
                    <td>0</td>
                    <td><p>Default/unknown status</p></td>
                </tr>

                <tr>
                    <td>SIGNING_STATUS_PENDING</td>
                    <td>1</td>
                    <td><p>Request has been created and is waiting for signatures</p></td>
                </tr>

                <tr>
                    <td>SIGNING_STATUS_COMPLETED</td>
                    <td>2</td>
                    <td><p>Signing process completed successfully with proof</p></td>
                </tr>

                <tr>
                    <td>SIGNING_STATUS_FAILED</td>
                    <td>3</td>
                    <td><p>Signing process failed</p></td>
                </tr>

                <tr>
                    <td>SIGNING_STATUS_TIMEOUT</td>
                    <td>4</td>
                    <td><p>Signing request timed out</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.ValidatorSetStatus">ValidatorSetStatus</h3>
        <p>Validator set status enumeration</p>
        <table class="enum-table">
            <thead>
                <tr>
                    <td>Name</td>
                    <td>Number</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>VALIDATOR_SET_STATUS_UNSPECIFIED</td>
                    <td>0</td>
                    <td><p>Default/unknown status</p></td>
                </tr>

                <tr>
                    <td>VALIDATOR_SET_STATUS_DERIVED</td>
                    <td>1</td>
                    <td><p>Derived status</p></td>
                </tr>

                <tr>
                    <td>VALIDATOR_SET_STATUS_AGGREGATED</td>
                    <td>2</td>
                    <td><p>Aggregated status</p></td>
                </tr>

                <tr>
                    <td>VALIDATOR_SET_STATUS_COMMITTED</td>
                    <td>3</td>
                    <td><p>Committed status</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="api.proto.v1.SymbioticAPIService">SymbioticAPIService</h3>
        <p>SymbioticAPI provides access to the Symbiotic relay functions</p>
        <table class="enum-table">
            <thead>
                <tr>
                    <td>Method Name</td>
                    <td>Request Type</td>
                    <td>Response Type</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>SignMessage</td>
                    <td><a href="#api.proto.v1.SignMessageRequest">SignMessageRequest</a></td>
                    <td><a href="#api.proto.v1.SignMessageResponse">SignMessageResponse</a></td>
                    <td><p>Sign a message</p></td>
                </tr>

                <tr>
                    <td>GetAggregationProof</td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationProofRequest"
                            >GetAggregationProofRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationProofResponse"
                            >GetAggregationProofResponse</a
                        >
                    </td>
                    <td><p>Get aggregation proof</p></td>
                </tr>

                <tr>
                    <td>GetAggregationProofsByEpoch</td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationProofsByEpochRequest"
                            >GetAggregationProofsByEpochRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationProofsByEpochResponse"
                            >GetAggregationProofsByEpochResponse</a
                        >
                    </td>
                    <td><p>Get aggregation proofs by epoch</p></td>
                </tr>

                <tr>
                    <td>GetCurrentEpoch</td>
                    <td>
                        <a href="#api.proto.v1.GetCurrentEpochRequest">GetCurrentEpochRequest</a>
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetCurrentEpochResponse">GetCurrentEpochResponse</a>
                    </td>
                    <td><p>Get current epoch</p></td>
                </tr>

                <tr>
                    <td>GetSignatures</td>
                    <td><a href="#api.proto.v1.GetSignaturesRequest">GetSignaturesRequest</a></td>
                    <td><a href="#api.proto.v1.GetSignaturesResponse">GetSignaturesResponse</a></td>
                    <td><p>Get signature by request id</p></td>
                </tr>

                <tr>
                    <td>GetSignaturesByEpoch</td>
                    <td>
                        <a href="#api.proto.v1.GetSignaturesByEpochRequest"
                            >GetSignaturesByEpochRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetSignaturesByEpochResponse"
                            >GetSignaturesByEpochResponse</a
                        >
                    </td>
                    <td><p>Get signature by epoch</p></td>
                </tr>

                <tr>
                    <td>GetSignatureRequestIDsByEpoch</td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestIDsByEpochRequest"
                            >GetSignatureRequestIDsByEpochRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestIDsByEpochResponse"
                            >GetSignatureRequestIDsByEpochResponse</a
                        >
                    </td>
                    <td><p>Get all signature request IDs by epoch</p></td>
                </tr>

                <tr>
                    <td>GetSignatureRequestsByEpoch</td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestsByEpochRequest"
                            >GetSignatureRequestsByEpochRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestsByEpochResponse"
                            >GetSignatureRequestsByEpochResponse</a
                        >
                    </td>
                    <td><p>Get all signature requests by epoch</p></td>
                </tr>

                <tr>
                    <td>GetSignatureRequest</td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestRequest"
                            >GetSignatureRequestRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetSignatureRequestResponse"
                            >GetSignatureRequestResponse</a
                        >
                    </td>
                    <td><p>Get signature request by request id</p></td>
                </tr>

                <tr>
                    <td>GetAggregationStatus</td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationStatusRequest"
                            >GetAggregationStatusRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetAggregationStatusResponse"
                            >GetAggregationStatusResponse</a
                        >
                    </td>
                    <td><p>Get aggregation status, can be sent only to aggregator nodes</p></td>
                </tr>

                <tr>
                    <td>GetValidatorSet</td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetRequest">GetValidatorSetRequest</a>
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetResponse">GetValidatorSetResponse</a>
                    </td>
                    <td><p>Get current validator set</p></td>
                </tr>

                <tr>
                    <td>GetValidatorByAddress</td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorByAddressRequest"
                            >GetValidatorByAddressRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorByAddressResponse"
                            >GetValidatorByAddressResponse</a
                        >
                    </td>
                    <td><p>Get validator by address</p></td>
                </tr>

                <tr>
                    <td>GetValidatorByKey</td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorByKeyRequest"
                            >GetValidatorByKeyRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorByKeyResponse"
                            >GetValidatorByKeyResponse</a
                        >
                    </td>
                    <td><p>Get validator by key</p></td>
                </tr>

                <tr>
                    <td>GetLocalValidator</td>
                    <td>
                        <a href="#api.proto.v1.GetLocalValidatorRequest"
                            >GetLocalValidatorRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetLocalValidatorResponse"
                            >GetLocalValidatorResponse</a
                        >
                    </td>
                    <td><p>Get local validator</p></td>
                </tr>

                <tr>
                    <td>GetValidatorSetHeader</td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetHeaderRequest"
                            >GetValidatorSetHeaderRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetHeaderResponse"
                            >GetValidatorSetHeaderResponse</a
                        >
                    </td>
                    <td><p>Get validator set header</p></td>
                </tr>

                <tr>
                    <td>GetLastCommitted</td>
                    <td>
                        <a href="#api.proto.v1.GetLastCommittedRequest">GetLastCommittedRequest</a>
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetLastCommittedResponse"
                            >GetLastCommittedResponse</a
                        >
                    </td>
                    <td><p>Get last committed epoch for a specific settlement chain</p></td>
                </tr>

                <tr>
                    <td>GetLastAllCommitted</td>
                    <td>
                        <a href="#api.proto.v1.GetLastAllCommittedRequest"
                            >GetLastAllCommittedRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetLastAllCommittedResponse"
                            >GetLastAllCommittedResponse</a
                        >
                    </td>
                    <td><p>Get last committed epochs for all settlement chains</p></td>
                </tr>

                <tr>
                    <td>GetValidatorSetMetadata</td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetMetadataRequest"
                            >GetValidatorSetMetadataRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetValidatorSetMetadataResponse"
                            >GetValidatorSetMetadataResponse</a
                        >
                    </td>
                    <td>
                        <p>
                            Get validator set metadata like extra data and request id to fetch
                            aggregation and signature requests
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>GetCustomScheduleNodeStatus</td>
                    <td>
                        <a href="#api.proto.v1.GetCustomScheduleNodeStatusRequest"
                            >GetCustomScheduleNodeStatusRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.GetCustomScheduleNodeStatusResponse"
                            >GetCustomScheduleNodeStatusResponse</a
                        >
                    </td>
                    <td>
                        <p>
                            Checks if the current node should be active based on a custom schedule
                            derived from the validator set. This enables external applications to
                            use the relay&#39;s validator set for coordinating distributed tasks,
                            such as deciding which application instances should commit data on-chain
                            or perform other coordinated actions. The schedule ensures deterministic
                            but randomized selection of active nodes at any given time.
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>ListenSignatures</td>
                    <td>
                        <a href="#api.proto.v1.ListenSignaturesRequest">ListenSignaturesRequest</a>
                    </td>
                    <td>
                        <a href="#api.proto.v1.ListenSignaturesResponse"
                            >ListenSignaturesResponse</a
                        >
                        stream
                    </td>
                    <td>
                        <p>
                            Stream signatures in real-time. If start_epoch is provided, sends
                            historical data first
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>ListenProofs</td>
                    <td><a href="#api.proto.v1.ListenProofsRequest">ListenProofsRequest</a></td>
                    <td>
                        <a href="#api.proto.v1.ListenProofsResponse">ListenProofsResponse</a> stream
                    </td>
                    <td>
                        <p>
                            Stream aggregation proofs in real-time. If start_epoch is provided,
                            sends historical data first
                        </p>
                    </td>
                </tr>

                <tr>
                    <td>ListenValidatorSet</td>
                    <td>
                        <a href="#api.proto.v1.ListenValidatorSetRequest"
                            >ListenValidatorSetRequest</a
                        >
                    </td>
                    <td>
                        <a href="#api.proto.v1.ListenValidatorSetResponse"
                            >ListenValidatorSetResponse</a
                        >
                        stream
                    </td>
                    <td>
                        <p>
                            Stream validator set changes in real-time. If start_epoch is provided,
                            sends historical data first
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h4>Methods with HTTP bindings</h4>
        <table>
            <thead>
                <tr>
                    <td>Method Name</td>
                    <td>Method</td>
                    <td>Pattern</td>
                    <td>Body</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>SignMessage</td>
                    <td>POST</td>
                    <td>/v1/sign</td>
                    <td>*</td>
                </tr>

                <tr>
                    <td>GetAggregationProof</td>
                    <td>GET</td>
                    <td>/v1/aggregation/proof/{request_id}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetAggregationProofsByEpoch</td>
                    <td>GET</td>
                    <td>/v1/aggregation/proofs/epoch/{epoch}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetCurrentEpoch</td>
                    <td>GET</td>
                    <td>/v1/epoch/current</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetSignatures</td>
                    <td>GET</td>
                    <td>/v1/signatures/{request_id}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetSignaturesByEpoch</td>
                    <td>GET</td>
                    <td>/v1/signatures/epoch/{epoch}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetSignatureRequestIDsByEpoch</td>
                    <td>GET</td>
                    <td>/v1/signature-request-ids/epoch/{epoch}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetSignatureRequestsByEpoch</td>
                    <td>GET</td>
                    <td>/v1/signature-requests/epoch/{epoch}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetSignatureRequest</td>
                    <td>GET</td>
                    <td>/v1/signature-request/{request_id}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetAggregationStatus</td>
                    <td>GET</td>
                    <td>/v1/aggregation/status/{request_id}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetValidatorSet</td>
                    <td>GET</td>
                    <td>/v1/validator-set</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetValidatorByAddress</td>
                    <td>GET</td>
                    <td>/v1/validator/address/{address}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetValidatorByKey</td>
                    <td>GET</td>
                    <td>/v1/validator/key/{key_tag}/{on_chain_key}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetLocalValidator</td>
                    <td>GET</td>
                    <td>/v1/validator/local</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetValidatorSetHeader</td>
                    <td>GET</td>
                    <td>/v1/validator-set/header</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetLastCommitted</td>
                    <td>GET</td>
                    <td>/v1/committed/chain/{settlement_chain_id}</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetLastAllCommitted</td>
                    <td>GET</td>
                    <td>/v1/committed/all</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetValidatorSetMetadata</td>
                    <td>GET</td>
                    <td>/v1/validator-set/metadata</td>
                    <td></td>
                </tr>

                <tr>
                    <td>GetCustomScheduleNodeStatus</td>
                    <td>GET</td>
                    <td>/v1/validator-set/custom-schedule/node-status</td>
                    <td></td>
                </tr>

                <tr>
                    <td>ListenSignatures</td>
                    <td>GET</td>
                    <td>/v1/stream/signatures</td>
                    <td></td>
                </tr>

                <tr>
                    <td>ListenProofs</td>
                    <td>GET</td>
                    <td>/v1/stream/proofs</td>
                    <td></td>
                </tr>

                <tr>
                    <td>ListenValidatorSet</td>
                    <td>GET</td>
                    <td>/v1/stream/validator-set</td>
                    <td></td>
                </tr>
            </tbody>
        </table>

        <h2 id="scalar-value-types">Scalar Value Types</h2>
        <table class="scalar-value-types-table">
            <thead>
                <tr>
                    <td>.proto Type</td>
                    <td>Notes</td>
                    <td>C++</td>
                    <td>Java</td>
                    <td>Python</td>
                    <td>Go</td>
                    <td>C#</td>
                    <td>PHP</td>
                    <td>Ruby</td>
                </tr>
            </thead>
            <tbody>
                <tr id="double">
                    <td>double</td>
                    <td></td>
                    <td>double</td>
                    <td>double</td>
                    <td>float</td>
                    <td>float64</td>
                    <td>double</td>
                    <td>float</td>
                    <td>Float</td>
                </tr>

                <tr id="float">
                    <td>float</td>
                    <td></td>
                    <td>float</td>
                    <td>float</td>
                    <td>float</td>
                    <td>float32</td>
                    <td>float</td>
                    <td>float</td>
                    <td>Float</td>
                </tr>

                <tr id="int32">
                    <td>int32</td>
                    <td>
                        Uses variable-length encoding. Inefficient for encoding negative numbers –
                        if your field is likely to have negative values, use sint32 instead.
                    </td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="int64">
                    <td>int64</td>
                    <td>
                        Uses variable-length encoding. Inefficient for encoding negative numbers –
                        if your field is likely to have negative values, use sint64 instead.
                    </td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="uint32">
                    <td>uint32</td>
                    <td>Uses variable-length encoding.</td>
                    <td>uint32</td>
                    <td>int</td>
                    <td>int/long</td>
                    <td>uint32</td>
                    <td>uint</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="uint64">
                    <td>uint64</td>
                    <td>Uses variable-length encoding.</td>
                    <td>uint64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>uint64</td>
                    <td>ulong</td>
                    <td>integer/string</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sint32">
                    <td>sint32</td>
                    <td>
                        Uses variable-length encoding. Signed int value. These more efficiently
                        encode negative numbers than regular int32s.
                    </td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sint64">
                    <td>sint64</td>
                    <td>
                        Uses variable-length encoding. Signed int value. These more efficiently
                        encode negative numbers than regular int64s.
                    </td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="fixed32">
                    <td>fixed32</td>
                    <td>
                        Always four bytes. More efficient than uint32 if values are often greater
                        than 2^28.
                    </td>
                    <td>uint32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>uint32</td>
                    <td>uint</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="fixed64">
                    <td>fixed64</td>
                    <td>
                        Always eight bytes. More efficient than uint64 if values are often greater
                        than 2^56.
                    </td>
                    <td>uint64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>uint64</td>
                    <td>ulong</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="sfixed32">
                    <td>sfixed32</td>
                    <td>Always four bytes.</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sfixed64">
                    <td>sfixed64</td>
                    <td>Always eight bytes.</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="bool">
                    <td>bool</td>
                    <td></td>
                    <td>bool</td>
                    <td>boolean</td>
                    <td>boolean</td>
                    <td>bool</td>
                    <td>bool</td>
                    <td>boolean</td>
                    <td>TrueClass/FalseClass</td>
                </tr>

                <tr id="string">
                    <td>string</td>
                    <td>A string must always contain UTF-8 encoded or 7-bit ASCII text.</td>
                    <td>string</td>
                    <td>String</td>
                    <td>str/unicode</td>
                    <td>string</td>
                    <td>string</td>
                    <td>string</td>
                    <td>String (UTF-8)</td>
                </tr>

                <tr id="bytes">
                    <td>bytes</td>
                    <td>May contain any arbitrary sequence of bytes.</td>
                    <td>string</td>
                    <td>ByteString</td>
                    <td>str</td>
                    <td>[]byte</td>
                    <td>ByteString</td>
                    <td>string</td>
                    <td>String (ASCII-8BIT)</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>
```

## File: docs/cli/relay/relay_sidecar.md

````markdown
# `relay sidecar` Command Reference

## relay_sidecar

Relay sidecar for signature aggregation

### Synopsis

A P2P service for collecting and aggregating signatures for Ethereum contracts.

```
relay_sidecar [flags]
```

### Options

```
      --aggregation-policy-max-unsigners uint            Max unsigners for low cost agg policy (default 50)
      --aggregation.catchup.enabled                      Enable periodic aggregation catch-up loop (default true)
      --aggregation.catchup.epochs-offset int            Number of epochs back from latest to skip before scanning begins
      --aggregation.catchup.epochs-to-check int          Number of epochs to scan per catch-up cycle (default 20)
      --aggregation.catchup.interval duration            How often to run aggregation catch-up (default 1m0s)
      --aggregation.catchup.max-requests-per-cycle int   Max requests to check per cycle (0 = unlimited)
      --aggregation.cross-epoch-aggregation              Allow latest-epoch aggregators to aggregate proofs for older epochs when original aggregators are offline
      --aggregation.worker-count int                     Max simultaneous proof aggregations, reduce for ZK circuits with high memory and cpu usage (default 10)
      --api.http-gateway                                 Enable HTTP/JSON REST API gateway on /api/v1/* path
      --api.listen string                                API Server listener address
      --api.max-allowed-streams uint                     Max allowed streams count API Server (default 100)
      --api.verbose-logging                              Enable verbose logging for the API Server
      --badger.block-cache-size int                      BadgerDB block cache size in bytes, 0 = disabled (default 33554432)
      --badger.compact-l0-on-close                       BadgerDB compact L0 on graceful shutdown (default true)
      --badger.mem-table-size int                        BadgerDB memtable size in bytes (default 16777216)
      --badger.num-compactors int                        BadgerDB concurrent compaction goroutines (default 4)
      --badger.num-level-zero-tables int                 BadgerDB L0 tables before compaction triggers (default 2)
      --badger.num-level-zero-tables-stall int           BadgerDB L0 tables before writes stall (default 4)
      --badger.num-memtables int                         BadgerDB number of memtables (default 2)
      --badger.value-log-file-size int                   BadgerDB value log file size in bytes, 512 MB (default 536870912)
      --badger.value-log-gc-discard-ratio float          BadgerDB value log GC discard ratio (0.0-1.0) (default 0.5)
      --badger.value-log-gc-interval duration            BadgerDB value log GC interval, 0 = disabled (default 5m0s)
      --bbolt.compact-on-startup                         Compact database on startup to reclaim free pages (default true)
      --bbolt.initial-mmap-size int                      Initial mmap size in bytes (0 = default)
      --bbolt.max-batch-delay duration                   Max delay before flushing a batch write (0 = bbolt default 10ms) (default 2ms)
      --bbolt.max-batch-size int                         Max operations per batch write (0 = bbolt default 1000)
      --bbolt.no-freelist-sync                           Skip writing freelist to disk on every commit (faster writes, slower startup) (default true)
      --bbolt.stats-log-interval duration                Interval for logging bbolt database stats (0 = disabled)
      --cache.network-config-size int                    Network config cache size (default 10)
      --cache.validator-set-size int                     Validator set cache size (default 10)
      --circuits-dir string                              Directory path to load zk circuits from, if empty then zk prover is disabled
      --config string                                    Path to config file (default "config.yaml")
      --driver.address string                            Driver contract address
      --driver.chain-id uint                             Driver contract chain id
      --evm.chains strings                               Chains, comma separated rpc-url,..
      --evm.fallback-gas-prices gas-price-map            Per-chain fallback gas prices in wei when eth_maxPriorityFeePerGas is not supported (e.g., --evm.fallback-gas-prices 1=2000000000)
      --evm.max-calls int                                Max calls in multicall
      --force-role.aggregator                            Force node to act as aggregator regardless of deterministic scheduling
      --force-role.committer                             Force node to act as committer regardless of deterministic scheduling
  -h, --help                                             help for relay_sidecar
      --key-cache.enabled                                Enable key cache (default true)
      --key-cache.size int                               Key cache size (default 100)
      --keystore.password string                         Password for the keystore file, if provided will be used to decrypt the keystore file
      --keystore.path string                             Path to optional keystore file, if provided will be used instead of secret-keys flag
      --log.level string                                 Log level (debug, info, warn, error) (default "info")
      --log.mode string                                  Log mode (text, pretty, json) (default "json")
      --metrics.listen string                            Http listener address for metrics endpoint
      --metrics.pprof                                    Enable pprof debug endpoints
      --p2p.bootnodes strings                            List of bootnodes in multiaddr format
      --p2p.dht-mode string                              DHT mode: auto, server, client, disabled (default "server")
      --p2p.listen string                                P2P listen address
      --p2p.mdns                                         Enable mDNS discovery for P2P
      --p2p.publish-timeout duration                     Maximum time a single pubsub publish may block (default 10s)
      --p2p.sync-peer-backoff.base float                 Exponential base for failed sync peer cooldown backoff (default 2)
      --p2p.sync-peer-backoff.max-backoff duration       Maximum cooldown before retrying a failed sync peer (default 2m0s)
      --p2p.sync-peer-backoff.min-backoff duration       Minimum cooldown before retrying a failed sync peer (default 15s)
      --pruner.batch-pause duration                      Pause between prune batches to yield to live writers (bbolt only — badger has no batching) (0 = no pause) (default 100ms)
      --pruner.batch-size int                            Number of request IDs to delete per database transaction during pruning (0 = unbatched) (default 100)
      --pruner.enabled                                   Enable automatic pruning of old epoch data
      --pruner.interval duration                         How often to run pruning (default 1h0m0s)
      --retention.proof-epochs uint                      Number of historical proof epochs to retain (0 = unlimited)
      --retention.signature-epochs uint                  Number of historical signature epochs to retain (0 = unlimited)
      --retention.valset-epochs uint                     Number of historical validator set epochs to retain (0 = unlimited)
      --secret-keys secret-key-slice                     Secret keys, comma separated {namespace}/{type}/{id}/{secret},..
      --signal.buffer-size int                           Signal buffer size (default 20)
      --signal.worker-count int                          Signal worker count (default 10)
      --storage-dir string                               Dir to store data (default ".data")
      --storage-type string                              Storage backend type (badger, bbolt) (default "bbolt")
      --sync.enabled                                     Enable signature syncer (default true)
      --sync.epochs uint                                 Number of recent epochs to sync from peers on startup (default 5)
      --sync.period duration                             Signature sync period (default 5s)
      --sync.timeout duration                            Signature sync timeout (default 1m0s)
      --tracing.enabled                                  Enable distributed tracing
      --tracing.endpoint string                          OTLP endpoint for tracing (e.g., Jaeger) (default "localhost:4317")
      --tracing.sample-rate float                        Trace sampling rate (0.0 to 1.0) (default 1)
```
````

## File: docs/cli/utils/utils_keys_add.md

````markdown
# `utils keys add` Command Reference

## utils keys add

Add key

```
utils keys add [flags]
```

### Options

```
      --chain-id int         chain id for evm keys, use 0 for default key for all chains (default -1)
      --evm                  use evm namespace keys
      --force                force overwrite key
      --generate             generate key
  -h, --help                 help for add
      --key-tag uint8        key tag for relay keys (default 255)
      --p2p                  use p2p key
      --private-key string   private key to add in hex
      --relay                use relay namespace keys
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
      --password string    Keystore password
  -p, --path string        Path to keystore (default "./keystore.jks")
```

### SEE ALSO

- [utils keys](utils_keys.md) - Keys tool
````

## File: docs/cli/utils/utils_keys_list.md

````markdown
# `utils keys list` Command Reference

## utils keys list

Print all keys

```
utils keys list [flags]
```

### Options

```
  -h, --help   help for list
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
      --password string    Keystore password
  -p, --path string        Path to keystore (default "./keystore.jks")
```

### SEE ALSO

- [utils keys](utils_keys.md) - Keys tool
````

## File: docs/cli/utils/utils_keys_remove.md

````markdown
# `utils keys remove` Command Reference

## utils keys remove

Remove key

```
utils keys remove [flags]
```

### Options

```
      --chain-id int    chain id for evm keys, use 0 for default key for all chains (default -1)
      --evm             use evm namespace keys
  -h, --help            help for remove
      --key-tag uint8   key tag for relay keys (default 255)
      --p2p             use p2p key
      --relay           use relay namespace keys
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
      --password string    Keystore password
  -p, --path string        Path to keystore (default "./keystore.jks")
```

### SEE ALSO

- [utils keys](utils_keys.md) - Keys tool
````

## File: docs/cli/utils/utils_keys_update.md

````markdown
# `utils keys update` Command Reference

## utils keys update

Update key

```
utils keys update [flags]
```

### Options

```
      --chain-id int         chain id for evm keys, use 0 for default key for all chains (default -1)
      --evm                  use evm namespace keys
      --force                force overwrite key
  -h, --help                 help for update
      --key-tag uint8        key tag for relay keys (default 255)
      --p2p                  use p2p key
      --private-key string   private key to add in hex
      --relay                use relay namespace keys
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
      --password string    Keystore password
  -p, --path string        Path to keystore (default "./keystore.jks")
```

### SEE ALSO

- [utils keys](utils_keys.md) - Keys tool
````

## File: docs/cli/utils/utils_keys.md

````markdown
# `utils keys` Command Reference

## utils keys

Keys tool

### Options

```
  -h, --help              help for keys
      --password string   Keystore password
  -p, --path string       Path to keystore (default "./keystore.jks")
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils](utils.md) - Utils tool
- [utils keys add](utils_keys_add.md) - Add key
- [utils keys list](utils_keys_list.md) - Print all keys
- [utils keys remove](utils_keys_remove.md) - Remove key
- [utils keys update](utils_keys_update.md) - Update key
````

## File: docs/cli/utils/utils_network_generate-genesis.md

````markdown
# `utils network generate-genesis` Command Reference

## utils network generate-genesis

Generate genesis validator set header

```
utils network generate-genesis [flags]
```

### Options

```
      --commit                     Commit genesis flag
  -e, --epoch int                  Epoch to generate genesis for (default: current epoch - 1) (default -1)
  -h, --help                       help for generate-genesis
  -j, --json                       Print as json
  -o, --output string              Output file path
      --secret-keys secretKeyMap   Secret key for genesis commit  in format 'chainId:key,chainId:key' (e.g. '1:0xabc,137:0xdef')
```

### Options inherited from parent commands

```
  -c, --chains strings                               Chains rpc url, comma separated
      --driver.address string                        Driver contract address
      --driver.chainid uint                          Driver contract chain id
      --external-voting-power-provider stringArray   External voting power provider config in format 'id=<id>,url=<url>[,secure=<bool>][,ca-cert-file=<path>][,server-name=<name>][,timeout=<duration>][,headers=<k:v|k2:v2>]'
      --log.level string                             log level(info, debug, warn, error) (default "info")
      --log.mode string                              log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils network](utils_network.md) - Network tool
````

## File: docs/cli/utils/utils_network_info.md

````markdown
# `utils network info` Command Reference

## utils network info

Print network information

```
utils network info [flags]
```

### Options

```
  -a, --addresses         Print addresses
  -e, --epoch uint        Network epoch to fetch info (0 = current)
  -h, --help              help for info
  -s, --settlement        Print settlement info
  -v, --validators        Print compact validators info
  -V, --validators-full   Print full validators info
```

### Options inherited from parent commands

```
  -c, --chains strings                               Chains rpc url, comma separated
      --driver.address string                        Driver contract address
      --driver.chainid uint                          Driver contract chain id
      --external-voting-power-provider stringArray   External voting power provider config in format 'id=<id>,url=<url>[,secure=<bool>][,ca-cert-file=<path>][,server-name=<name>][,timeout=<duration>][,headers=<k:v|k2:v2>]'
      --log.level string                             log level(info, debug, warn, error) (default "info")
      --log.mode string                              log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils network](utils_network.md) - Network tool
````

## File: docs/cli/utils/utils_network.md

````markdown
# `utils network` Command Reference

## utils network

Network tool

### Options

```
  -c, --chains strings                               Chains rpc url, comma separated
      --driver.address string                        Driver contract address
      --driver.chainid uint                          Driver contract chain id
      --external-voting-power-provider stringArray   External voting power provider config in format 'id=<id>,url=<url>[,secure=<bool>][,ca-cert-file=<path>][,server-name=<name>][,timeout=<duration>][,headers=<k:v|k2:v2>]'
  -h, --help                                         help for network
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils](utils.md) - Utils tool
- [utils network generate-genesis](utils_network_generate-genesis.md) - Generate genesis validator set header
- [utils network info](utils_network_info.md) - Print network information
````

## File: docs/cli/utils/utils_operator_info.md

````markdown
# `utils operator info` Command Reference

## utils operator info

Print operator information

```
utils operator info [flags]
```

### Options

```
  -e, --epoch uint                                   Network epoch to fetch info
      --external-voting-power-provider stringArray   External voting power provider config in format 'id=<id>,url=<url>[,secure=<bool>][,ca-cert-file=<path>][,server-name=<name>][,timeout=<duration>][,headers=<k:v|k2:v2>]'
  -h, --help                                         help for info
      --key-tag uint8                                key tag (default 255)
      --password string                              Keystore password
  -p, --path string                                  Path to keystore (default "./keystore.jks")
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_invalidate-old-signatures.md

````markdown
# `utils operator invalidate-old-signatures` Command Reference

## utils operator invalidate-old-signatures

Invalidate old signatures for operator

```
utils operator invalidate-old-signatures [flags]
```

### Options

```
  -h, --help                       help for invalidate-old-signatures
      --secret-keys secretKeyMap   Secret key for signing in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_register-key-artifact.md

````markdown
# `utils operator register-key-artifact` Command Reference

## utils operator register-key-artifact

Build operator key registration artifact without submitting a transaction

```
utils operator register-key-artifact [flags]
```

### Options

```
  -h, --help                      help for register-key-artifact
      --key-tag uint8             key tag (default 255)
      --operator-address string   operator address used for artifact generation
      --password string           Keystore password
  -p, --path string               Path to keystore (default "./keystore.jks")
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_register-key.md

````markdown
# `utils operator register-key` Command Reference

## utils operator register-key

Register operator key in key registry

```
utils operator register-key [flags]
```

### Options

```
  -h, --help                       help for register-key
      --key-tag uint8              key tag (default 255)
      --password string            Keystore password
  -p, --path string                Path to keystore (default "./keystore.jks")
      --secret-keys secretKeyMap   Secret key for key register in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_register-operator-with-signature.md

````markdown
# `utils operator register-operator-with-signature` Command Reference

## utils operator register-operator-with-signature

Generate EIP-712 signature for operator registration

```
utils operator register-operator-with-signature [flags]
```

### Options

```
  -h, --help                       help for register-operator-with-signature
      --secret-keys secretKeyMap   Secret key for signing in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_register-operator.md

````markdown
# `utils operator register-operator` Command Reference

## utils operator register-operator

Register operator on-chain via VotingPowerProvider

```
utils operator register-operator [flags]
```

### Options

```
  -h, --help                       help for register-operator
      --secret-keys secretKeyMap   Secret key for operator in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_register-signature.md

````markdown
# `utils operator register-signature` Command Reference

## utils operator register-signature

Generate EIP-712 signature for operator registration

```
utils operator register-signature [flags]
```

### Options

```
  -h, --help                       help for register-signature
      --secret-keys secretKeyMap   Secret key for signing in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings          Chains rpc url, comma separated
      --driver.address string   Driver contract address
      --driver.chainid uint     Driver contract chain id
      --log.level string        log level(info, debug, warn, error) (default "info")
      --log.mode string         log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_unregister-operator-with-signature.md

````markdown
# `utils operator unregister-operator-with-signature` Command Reference

## utils operator unregister-operator-with-signature

Generate EIP-712 signature for operator unregistration

```
utils operator unregister-operator-with-signature [flags]
```

### Options

```
  -h, --help                       help for unregister-operator-with-signature
      --secret-keys secretKeyMap   Secret key for signing in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_unregister-operator.md

````markdown
# `utils operator unregister-operator` Command Reference

## utils operator unregister-operator

Unregister operator on-chain via VotingPowerProvider

```
utils operator unregister-operator [flags]
```

### Options

```
  -h, --help                       help for unregister-operator
      --secret-keys secretKeyMap   Secret key for operator in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
      --log.level string                log level(info, debug, warn, error) (default "info")
      --log.mode string                 log mode(pretty, text, json) (default "text")
      --voting-provider-chain-id uint   Voting power provider chain id
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator_unregister-signature.md

````markdown
# `utils operator unregister-signature` Command Reference

## utils operator unregister-signature

Generate EIP-712 signature for operator unregistration

```
utils operator unregister-signature [flags]
```

### Options

```
  -h, --help                       help for unregister-signature
      --secret-keys secretKeyMap   Secret key for signing in format 'chainId:key' (e.g. '1:0xabc')
```

### Options inherited from parent commands

```
  -c, --chains strings          Chains rpc url, comma separated
      --driver.address string   Driver contract address
      --driver.chainid uint     Driver contract chain id
      --log.level string        log level(info, debug, warn, error) (default "info")
      --log.mode string         log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils operator](utils_operator.md) - Operator tool
````

## File: docs/cli/utils/utils_operator.md

````markdown
# `utils operator` Command Reference

## utils operator

Operator tool

### Options

```
  -c, --chains strings                  Chains rpc url, comma separated
      --driver.address string           Driver contract address
      --driver.chainid uint             Driver contract chain id
  -h, --help                            help for operator
      --voting-provider-chain-id uint   Voting power provider chain id
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils](utils.md) - Utils tool
- [utils operator info](utils_operator_info.md) - Print operator information
- [utils operator invalidate-old-signatures](utils_operator_invalidate-old-signatures.md) - Invalidate old signatures for operator
- [utils operator register-key](utils_operator_register-key.md) - Register operator key in key registry
- [utils operator register-key-artifact](utils_operator_register-key-artifact.md) - Build operator key registration artifact without submitting a transaction
- [utils operator register-operator](utils_operator_register-operator.md) - Register operator on-chain via VotingPowerProvider
- [utils operator register-operator-with-signature](utils_operator_register-operator-with-signature.md) - Generate EIP-712 signature for operator registration
- [utils operator unregister-operator](utils_operator_unregister-operator.md) - Unregister operator on-chain via VotingPowerProvider
- [utils operator unregister-operator-with-signature](utils_operator_unregister-operator-with-signature.md) - Generate EIP-712 signature for operator unregistration
````

## File: docs/cli/utils/utils_prune.md

````markdown
# `utils prune` Command Reference

## utils prune

Prune old epoch data from the relay storage (offline)

### Synopsis

Offline pruning of valset / proof / signature entities older than the configured retention. Optionally compacts the database when --compact is set. The sidecar must be stopped (the DB is opened with an exclusive file-lock).

WARNING: this command rewrites the storage directory in place. Take a filesystem-level backup of --storage-dir before running. bbolt compaction writes to a tmp file and atomically renames, so the original survives a crash; badger compaction relies on its WAL/manifest for recovery, which is crash-safe by design but not bulletproof under SIGKILL or disk failure.

Pass --yes / -y to skip the interactive backup confirmation (required in non-interactive environments such as CI).

```
utils prune [flags]
```

### Options

```
      --badger.flatten-workers int        Number of parallel workers for badger Flatten (only when --compact is set) (default 4)
      --compact                           After pruning, compact the database file (bbolt: rewrite; badger: Flatten + value log GC) (default true)
  -h, --help                              help for prune
      --prune-batch-size int              Number of request IDs to delete per database transaction (larger = faster but holds writer lock longer) (default 1000)
      --retention.proof-epochs uint       Keep this many most-recent epochs of aggregation proofs (0 = skip)
      --retention.signature-epochs uint   Keep this many most-recent epochs of signatures (0 = skip)
      --retention.valset-epochs uint      Keep this many most-recent epochs of valset data (0 = skip)
      --storage-dir string                Directory containing the relay storage (badger or bbolt) (default ".data")
  -y, --yes                               Skip the interactive backup confirmation prompt (required for non-interactive use, e.g. CI)
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils](utils.md) - Utils tool
````

## File: docs/cli/utils/utils_version.md

````markdown
# `utils version` Command Reference

## utils version

Print the version of the utils tool

```
utils version [flags]
```

### Options

```
  -h, --help   help for version
```

### Options inherited from parent commands

```
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils](utils.md) - Utils tool
````

## File: docs/cli/utils/utils.md

````markdown
# `utils` Command Reference

## utils

Utils tool

### Options

```
  -h, --help               help for utils
      --log.level string   log level(info, debug, warn, error) (default "info")
      --log.mode string    log mode(pretty, text, json) (default "text")
```

### SEE ALSO

- [utils keys](utils_keys.md) - Keys tool
- [utils network](utils_network.md) - Network tool
- [utils operator](utils_operator.md) - Operator tool
- [utils prune](utils_prune.md) - Prune old epoch data from the relay storage (offline)
- [utils version](utils_version.md) - Print the version of the utils tool
````

## File: docs/core/architecture.md

```markdown
# Architecture Overview

## Introduction

The Symbiotic Relay is a distributed system that enables cryptographic signature aggregation and validator set management across multiple blockchain networks. The system coordinates validator nodes to produce aggregation proofs that can be verified on-chain, enabling trustless verification of collective validator consensus.

**See**: [Core Types Reference](./types.md) for detailed type definitions

## System Architecture

The system operates through four main interconnected processes:

1. **Valset Derivation**: Derives validator sets from on-chain data across multiple chains
2. **Signature Aggregation**: Aggregates individual validator signatures into cryptographic proofs
3. **Valset Commitment**: Commits validator sets to settlement contracts with cryptographic proofs
4. **Sign Message API**: Provides an API for client applications to request signatures from the network

## Core Components

### Validator Set Management

The system maintains a chain of validator sets (see [`ValidatorSet`](./types.md#validatorset)), where each epoch has a derived validator set that represents the voting power distribution at that point in time. Validator sets are deterministically derived from on-chain data, ensuring all nodes compute the same set.

**See**: [Epoch Progression](./epoch_progression.md) for how epochs progress from creation through derivation to commitment

### Signature Aggregation

The system uses BLS (Boneh-Lynn-Shacham) signatures on the BN254 curve, which allows efficient aggregation of multiple signatures into a single proof. This enables quorum-based signing where a threshold of validator voting power must sign for a proof to be generated.

### Cross-Chain Coordination

The system operates across multiple blockchain networks:

- **Driver Chain**: Contains the ValSetDriver contract that defines epochs and network configuration
- **Settlement Chains**: Multiple chains where validator sets are committed for cross-chain verification
- **Voting Power Provider Chains**: Chains where voting power providers are deployed, allowing voting power aggregation across networks

### On-Chain Verification

All aggregation proofs (see [`AggregationProof`](./types.md#aggregationproof)) can be verified on-chain using settlement contracts, enabling trustless verification without requiring trust in the relay nodes themselves.

## Process Key Flows

### 1. Valset Derivation

When a new epoch occurs in the ValSetDriver contract, the system derives a new validator set by:

- Querying voting powers from VotingPowerProvider contracts across multiple chains
- Retrieving validator keys from the KeyRegistry
- Forming validators according to network configuration rules
- Calculating quorum thresholds and assigning roles

**See**: [Valset Derivation](./valset_derivation.md) for detailed flow

### 2. Signature Aggregation

When a signature request is created (either from valset commitment or API calls), the system:

- Distributes the request to all validator nodes
- Collects individual signatures via P2P network
- Aggregates signatures into a single proof when quorum is reached
- Broadcasts the proof to all nodes

**See**: [Signature Aggregation](./signature_aggregation.md) for detailed flow

### 3. Valset Commitment

After a valset is derived and an aggregation proof is generated, the system:

- Generates valset header and extra data (aggregated public keys)
- Creates commitment data for signing
- Commits the valset to settlement contracts on multiple chains
- Verifies each commitment against the previous committed valset

**See**: [Valset Commitment](./valset_commitment.md) for detailed flow

### 4. Sign Message API

Client applications can request signatures from the network by:

- Calling the SignMessage API on their respective nodes with the same data
- Waiting for the aggregation process to complete
- Retrieving the aggregation proof from their node
- Verifying the proof on-chain using settlement contracts

**See**: [Sign Message API](./sign_message.md) for detailed flow

## Key Design Principles

### Determinism

All processes are deterministic, ensuring that all nodes produce the same results from the same inputs. This includes:

- Validator set (see [`ValidatorSet`](./types.md#validatorset)) derivation from on-chain data
- Request ID calculation from message, key tag (see [`KeyTag`](./types.md#keytag)), and epoch
- Aggregation proof (see [`AggregationProof`](./types.md#aggregationproof)) generation from the same set of signatures

### Finality Guarantees

All on-chain queries use finalized blocks to ensure data consistency and prevent reorgs. This ensures that validator sets are derived from stable, irreversible blockchain state.

### Quorum-Based Security

All critical operations require a quorum of validator voting power:

- Valset commitments must be signed by sufficient validators
- API signature requests require quorum before aggregation
- Proofs explicitly track which validators signed and which did not

### Multi-Chain Support

The system is designed to operate across multiple blockchain networks:

- Voting power can be aggregated from providers on different chains
- Validator sets are committed to multiple settlement chains
- Proofs can be verified on any settlement chain

## Cryptographic Foundation

The system uses **BN254 Simple** aggregation for:

- **Extra Data Generation**: Aggregating validator public keys
- **Signature Aggregation**: Combining individual signatures into proofs
- **On-Chain Verification**: Efficient pairing checks on settlement contracts

BN254 Simple provides:

- Efficient aggregation of multiple signatures
- Single pairing check for verification regardless of signer count
- Explicit tracking of non-signers for quorum calculation

## System Lifecycle

1. **Genesis**: The first valset header and extra data are set through trusted genesis functionality on settlement contracts
2. **Epoch Transitions**: New epochs trigger valset derivation (see [Epoch Progression](./epoch_progression.md) for detailed lifecycle)
3. **Commitment Cycles**: Each derived valset is committed to settlement contracts with aggregation proofs
4. **API Requests**: Client applications can request signatures at any time, which are aggregated and can be verified on-chain

## Inter-Process Dependencies

The processes are interconnected:

- **Valset Derivation** → Creates validator sets that enable signing
- **Valset Commitment** → Requires aggregation proof from **Signature Aggregation**
- **Signature Aggregation** → Can be triggered by **Valset Commitment** or **Sign Message API**
- **Sign Message API** → Uses the same aggregation infrastructure as valset commitments

All processes rely on the same validator set structure (see [`ValidatorSet`](./types.md#validatorset)) and aggregation mechanisms, ensuring consistency across the system.

**See**: [Core Types Reference](./types.md) for complete type definitions

## Related specifications

- [Epoch Progression](./epoch_progression.md)
- [Validator Set Derivation](./valset_commitment.md)
- [Validator Set Commitment](./valset_commitment.md)
- [Keys and quorum](./keys_and_quorum.md)
- [Signature Aggregation](./signature_aggregation.md)
- [Sign Message API](./sign_message.md)
- [Core Types Reference](./types.md)
```

## File: docs/core/epoch_progression.md

````markdown
# Epoch Progression

## Description

Epoch progression defines how the relay observes new epochs from `ValSetDriver` contract, waits for finality on every chain that contributes data, and derives deterministic validator sets. Multiple epochs can be in-flight simultaneously, and application builders must decide which epoch is considered “active” for their use case.

**See also**:

- [`ValidatorSet`](./types.md#validatorset) for the resulting structure
- [`NetworkConfig`](./types.md#networkconfig) for the data required to derive the set

## Key Concepts

- **Epoch Capture Timestamp**: Each epoch specifies a capture timestamp that serves as the canonical point-in-time for fetching voting power, keys, and other data. All derivations use this timestamp.
- **Finality Requirements**: The capture timestamp must be finalized on both the driver chain and every provider chain (VotingPowerProvider, KeyRegistry, Settlement) before the epoch can be derived. Until finality is confirmed, the epoch remains pending.
- **Slashable Epochs**: If an epoch’s capture timestamp falls within a vault’s slashing window (equal to its epoch duration), multiple epochs can be slashable concurrently. The relay retains all epochs whose timestamps intersect active slashing windows.
- **Active Epoch Selection**: It is up to downstream applications (“app builders”) to decide which epoch to treat as active. Common strategies are listed [below](#active-epoch-selection).

## Process Overview

1. **Driver Epoch Triggered**: The `ValSetDriver` enters to a new epoch by current timestamp.
2. **Driver Finality**: The relay waits until the capture timestamp is finalized on the driver chain. Reorgs before finality are ignored.
3. **Provider Finality**: The relay verifies that every required provider chain (VotingPowerProviders, KeyRegistry) has finalized blocks covering the capture timestamp.
4. **Derivation**: Once finality is confirmed everywhere, the relay derives the validator set for that epoch using the capture timestamp, producing a deterministic `ValidatorSet`.
5. **Retention / Slashing Window**: Epochs remain slashable for the duration of the vault’s epoch window. Multiple overlapping epochs can exist; the relay keeps them available for signing.
6. **Settlement commitment**: Epoch is committed in settlement contract and available for on-chain verification.
7. **Application Consumption**: App builders select which derived epoch to treat as active depending on their logic.

## Sequence Diagram

```mermaid
sequenceDiagram
    participant Driver as ValSetDriver<br/>(Driver Chain)
    participant Finality as Finality Watcher
    participant Providers as Provider Chains<br/>(VotingPower/Keys)
    participant Settlement as Settlement Contracts<br/>(Multiple Chains)
    participant Deriver as Valset Deriver

    Driver->>Driver: Emit NewEpoch(epoch, captureTimestamp)
    note over Driver: Epoch triggered on-chain

    Driver->>Finality: Notify captureTimestamp
    Finality->>Driver: Wait for driver finality
    note over Finality: Blocks until driver chain finalizes timestamp

    Finality->>Providers: Check provider finality at captureTimestamp
    note over Providers: Ensure each VotingPower/Key chain finalized

    Providers-->>Finality: All provider chains finalized

    Finality->>Settlement: Check settlement finality at captureTimestamp
    note over Settlement: Ensure each settlement chain finalized

    Settlement-->>Finality: All settlement chains finalized
    Finality-->>Deriver: Finality confirmed

    Deriver->>Deriver: Fetch config & data at captureTimestamp
    Deriver->>Deriver: Derive ValidatorSet(epoch)
    note over Deriver: Deterministic valset

    Deriver-->>App: Epoch available for selection
```

## Epoch Lifecycle

The following state machine diagram illustrates the progression of an epoch through its three main stages:

```mermaid
stateDiagram-v2
    [*] --> Created: ValSetDriver enters new epoch

    Created --> Derived: All chains finalized<br/>Valset derived

    Derived --> Committed: Commitment transaction<br/>sent & finalized

    Committed --> [*]

    note right of Created
        Epoch exists in driver contract
        Waiting for finality on all chains
    end note

    note right of Derived
        Valset is deterministic
        Available for signing
        Latest Derived strategy available
    end note

    note right of Committed
        Valset committed to settlement
        On-chain verification available
        Latest by Settlement strategy available
        Lagged -1 strategy available
    end note
```

## Practical Notes

- **Finality Sources**: The relay uses finalized block numbers (e.g., `rpc.FinalizedBlockNumber` for EVM chains). Operators should tune RPC endpoints to ensure up-to-date finality signals.
- **Multiple Slashable Epochs**: Because capture timestamps may overlap slashing windows, keep storage for all recent epochs whose timestamps are within any vault’s slashing duration.
- **Error Handling**: If any provider chain fails to finalize, the epoch remains pending and derivation retries later. Epoch IDs never regress; they remain ordered even if finality lags.

## Active Epoch Selection

Application builders must decide which epoch to treat as "active" for their use case. The choice depends on the application's requirements for on-chain verification, tolerance for timing risks, and need for settlement contract readiness.

### Selection Strategies

#### Latest Derived

Use the newest epoch that has passed finality on all required chains (driver and provider chains). At this point, the valset is deterministic and available for signing operations.

**Characteristics:**

- **Valset Status**: Derived and finalized, ready for signing
- **Settlement Status**: May not yet be committed to settlement contracts
- **On-Chain Verification**: Proofs cannot be verified on-chain until commitment is finalized
- **Use Cases**:
    - Applications that sign messages but don't immediately verify proofs on-chain
    - Off-chain operations that need the latest validator set or if on-chain verification is not required

**Discovery**: Can use [`GetCurrentEpoch`](../api/v1/doc.md#getcurrentepochrequest) API method

#### Lagged (Latest - 1)

Use the epoch that is one behind the latest derived epoch. This strategy ensures that the valset header has been most likely committed to all required settlement contracts and provides a safety buffer against edge timing risks.

**Characteristics:**

- **Valset Status**: Derived, finalized, and most likely committed to settlement contracts
- **Settlement Status**: Likely committed and finalized on settlement chains
- **On-Chain Verification**: Proofs can be verified on-chain immediately
- **Use Cases**:
    - Applications that requires immediate on-chain verification but can tolerate minial risks of missed header commitment.

**Discovery**: Can use [`GetCurrentEpoch`](../api/v1/doc.md#getcurrentepochrequest) API method.

#### Latest by Settlement

Use the latest epoch that is logged on-chain in a specific settlement contract. This approach queries the settlement contract directly to determine the most recent committed epoch.

**Characteristics:**

- **Valset Status**: Committed and finalized on the target settlement chain
- **Settlement Status**: Confirmed on-chain via contract query
- **On-Chain Verification**: Guaranteed to be verifiable on the queried chain
- **Use Cases**:
    - Applications that requires guaranteed immediate on-chain verification

**Discovery**: Can use [`GetLastAllCommitted`](../api/v1/doc.md#getlastallcommittedrequest) or [`GetLastCommitted`](../api/v1/doc.md#getlastcommittedrequest) API methods.

#### Custom

Filter epochs by application-specific criteria beyond finality and commitment status.

**Common Criteria:**

- **Aggregator Availability**: Ensure sufficient aggregator nodes are online
- **Voting Power Threshold**: Require minimum total voting power
- **Validator Count**: Require minimum number of active validators
- **Time-Based**: Use epochs within a specific time window
- **Chain-Specific**: Ensure commitment on specific settlement chains

**Use Cases:**

- Applications with specific security or operational requirements
- Multi-chain applications with complex verification needs
- Systems that need to ensure operational readiness before using an epoch

**Discovery**: Check API [reference](../api/v1/doc.md) to justify most suitable method.

### Comparison Table

| Strategy                 | Valset Deterministic | Off-Chain Verification | On-Chain Verification |
| ------------------------ | -------------------- | ---------------------- | --------------------- |
| **Latest Finalized**     | ✅ Yes               | ✅ Guaranteed          | ❌ Not available      |
| **Lagged (Latest - 1)**  | ✅ Yes               | ✅ Guaranteed          | ✅ Likely             |
| **Latest by Settlement** | ✅ Yes               | ✅ Guaranteed          | ✅ Guaranteed         |
| **Custom**               | ✅ Yes               | ✅ Yes                 | Varies                |

## References

- [`Valset Derivation`](./valset_derivation.md) for the derivation pipeline
- [`Types`](./types.md) for core structures such as `ValidatorSet`, `ValidatorSetHeader`, and SSZ details
````

## File: docs/core/external_voting_power_providers.md

````markdown
# External Voting Power Providers

## Description

External voting power providers allow relay to derive operator voting power from off-chain gRPC services instead of EVM `VotingPowerProvider` contracts.

Routing is selected by on-chain voting power provider `chainId`:

- `4_000_000_000 .. 4_100_000_000` (inclusive): external gRPC provider
- all other chain IDs: EVM provider contract

This routing is used during validator set derivation (see [Validator Set Derivation](./valset_derivation.md)).

## Process Overview

1. Relay reads voting power providers from on-chain network config.
2. For each provider:
    - external range `chainId` -> query external gRPC service
    - non-external `chainId` -> query EVM provider
3. Provider queries run in parallel with shared limit `10`.
4. Relay aggregates provider outputs into validator voting power.

Derivation is fail-closed:

- any provider fetch error fails derivation for that epoch
- external provider referenced on-chain but missing in local config fails derivation

## External Provider Identity

External provider lookup uses:

1. on-chain `CrossChainAddress.ChainId` (must be in reserved external range)
2. provider ID encoded in `CrossChainAddress.Address`

Provider ID is the first `10` bytes of the provider address (`20` hex chars).  
Local relay config maps provider ID to gRPC endpoint and transport/auth settings.

## gRPC Contract

External services must implement:

- `votingpower.v1.VotingPowerProviderService/GetVotingPowersAt`

See:

- `votingpower/proto/v1/votingpower.proto`
- `docs/votingpower/v1/doc.md`

Input:

- `timestamp` (`uint64`)

Output rows:

- `operator` (hex EVM address)
- `voting_power` (decimal string, non-negative integer)

Relay behavior for response parsing:

- empty list is valid
- duplicate operators in one response are merged by sum
- output is sorted by operator address for determinism
- invalid operator or invalid/negative voting power fails request

## Relay Configuration

Configure external mappings in relay config:

- `external-voting-power-providers`

Fields:

- `id` (required): provider ID (`10` bytes hex, `0x` optional)
- `url` (required): gRPC target
- `secure` (optional, default `false`): TLS enabled
- `ca-cert-file` (optional): CA PEM file
- `server-name` (optional): TLS server name override
- `headers` (optional): outbound gRPC metadata
- `timeout` (optional, default `5s`): dial/request timeout

Example:

```yaml
external-voting-power-providers:
    - id: "0x11223344556677889900"
      url: "dns:///beacon-vp:50051"
      secure: false
      # ca-cert-file: "/path/to/ca.pem"
      # server-name: "beacon-vp.internal"
      # timeout: 5s
      # headers:
      #   authorization: "Bearer <token>"
```

See:

- `example.config.yaml`

## Add / Remove Flow

To add an external provider:

1. Run external gRPC service implementing `GetVotingPowersAt`.
2. Add local relay mapping in `external-voting-power-providers`.
3. Register provider on-chain in `ValSetDriver.addVotingPowerProvider((chainId, addr))`:
    - `chainId` in `4_000_000_000..4_100_000_000`
    - `addr` with provider ID in first `10` bytes

To remove provider:

- call `ValSetDriver.removeVotingPowerProvider((chainId, addr))`

Configuration changes apply by epoch, not mid-epoch.

## Operational Notes

- duplicate provider IDs in local config are rejected at relay startup
- relay establishes gRPC connections on startup and fails startup if provider connection is not ready
- external request failures are not retried by relay
- transport is insecure by default (`secure: false`)

## CLI Usage

Utility commands can load external provider mappings from:

- repeatable `--external-voting-power-provider` flag in format:
    - `id=<id>,url=<url>[,secure=<bool>][,ca-cert-file=<path>][,server-name=<name>][,timeout=<duration>][,headers=<k:v|k2:v2>]`

Example:

```bash
./relay_utils network info \
  --chains http://127.0.0.1:8545 \
  --driver.address 0x1234... \
  --driver.chainid 1 \
  --external-voting-power-provider "id=0x11223344556677889900,url=dns:///vp:50051,secure=true,ca-cert-file=/etc/ca.pem,server-name=vp.internal,timeout=5s,headers=authorization:BearerX|x-request-id:abc"
```

See:

- `docs/cli/utils/utils_network_info.md`
- `docs/cli/utils/utils_operator_info.md`
````

## File: docs/core/keys_and_quorum.md

````markdown
# Keys and Quorum

## Description

The Symbiotic Relay supports a flexible key management system where each validator can have multiple cryptographic keys, each serving different purposes. This enables fine-grained control over signing operations, aggregation capabilities, and quorum requirements for different use cases.

**See also**:

- [`ValidatorKey`](./types.md#validatorkey) for key structure
- [`KeyTag`](./types.md#keytag) for key tag encoding
- [`NetworkConfig`](./types.md#networkconfig) for quorum threshold configuration

## Multiple Keys per Validator

Each validator in the system can possess multiple cryptographic keys, where each key is identified by a unique [`KeyTag`](./types.md#keytag). This design enables:

- **Separation of Concerns**: Different keys can be used for different purposes (e.g., consensus signing, light operations, heavy operations)
- **Flexible Quorum Configuration**: Each key tag can have its own quorum threshold, allowing different security levels for different operations
- **Key Mapping**: External keys (e.g., from other consensus systems) can be mapped to aggregation-enabled keys, enabling interoperability

### Key Structure

A validator's keys are stored in the `Keys` field of the [`Validator`](./types.md#validator) structure:

```go
type Validator struct {
    Operator    common.Address
    VotingPower VotingPower
    IsActive    bool
    Keys        []ValidatorKey  // Multiple keys per validator
    Vaults      []ValidatorVault
}

type ValidatorKey struct {
    Tag     KeyTag              // Unique identifier (KeyType + Key ID)
    Payload CompactPublicKey    // Public key bytes
}
```

Each key is uniquely identified by its [`KeyTag`](./types.md#keytag), which encodes both the key type (upper 4 bits) and a key ID (lower 4 bits), allowing up to 16 keys per key type per validator.

## Supported Key Types

The system supports multiple key types, each with different capabilities:

| Key Type                | Value | Listing Enabled | Signing Enabled | Aggregation Enabled | Description                                                              |
| ----------------------- | ----- | --------------- | --------------- | ------------------- | ------------------------------------------------------------------------ |
| `KeyTypeBlsBn254`       | 0     | ✅ Yes          | ✅ Yes          | ✅ Yes              | BLS signatures on BN254 curve. Supports efficient signature aggregation. |
| `KeyTypeEcdsaSecp256k1` | 1     | ✅ Yes          | ✅ Yes          | ❌ No               | ECDSA signatures on secp256k1 curve. Standard Ethereum signing.          |
| `KeyTypeBls12381Bn254`  | 2     | ✅ Yes          | ✅ Yes          | ❌ No               | BLS signatures on BLS12-381/BN254. Signing only, no aggregation.         |
| `unknown`               | any   | ✅ Yes          | ❌ No           | ❌ No               | Any unknown key type can be just listed.                                 |
| `KeyTypeInvalid`        | 255   | ❌ No           | ❌ No           | ❌ No               | Invalid key type.                                                        |

### Key Type Properties

**Listing Enabled**: All valid key types (except `KeyTypeInvalid`) can be registered and listed in the validator set. This means validators can have keys of these types associated with them.

**Signing Enabled**: Keys with signing enabled can be used to sign messages.

**Aggregation Enabled**: Currently, only `KeyTypeBlsBn254` supports signature aggregation. This means:

- Individual signatures from BLS BN254 keys can be aggregated into a single proof
- Aggregated proofs can be verified efficiently on-chain using a single pairing check
- Non-signers are explicitly tracked in the aggregation proof

## Quorum Thresholds

The system supports multiple quorum thresholds, where each threshold is associated with a specific [`KeyTag`](./types.md#keytag). This allows different security requirements for different operations.

### Configuration

Quorum thresholds are configured in [`NetworkConfig`](./types.md#networkconfig) via the `QuorumThresholds` field:

```go
type QuorumThreshold struct {
    KeyTag          KeyTag              // Key tag this threshold applies to
    QuorumThreshold QuorumThresholdPct  // Threshold as percentage (0-10^18)
}

type NetworkConfig struct {
    // ... other fields ...
    QuorumThresholds []QuorumThreshold  // Multiple thresholds per key tag
    RequiredKeyTags  []KeyTag           // Key tags validators must have
    RequiredHeaderKeyTag KeyTag          // Key tag for valset header commitments
}
```

### Threshold Calculation

Quorum thresholds are specified as percentages using a scale where `10^18` represents 100%. The absolute quorum threshold for a given key tag is calculated as:

```
absoluteThreshold = (totalVotingPower × thresholdPercentage) / 10^18 + 1
```

The `+1` ensures rounding up, so the threshold is always at least the specified percentage.

### Multiple Thresholds per Key Tag

For aggregation-enabled keys (BLS BN254), you can configure multiple quorum thresholds by using different key IDs within the same key type. For example:

- `KeyTag 0x00` (BLS BN254, ID 0): 66% threshold for heavy operations
- `KeyTag 0x01` (BLS BN254, ID 1): 51% threshold for light operations
- `KeyTag 0x02` (BLS BN254, ID 2): 80% threshold for critical operations

Each threshold is independent and applies only to signature requests using that specific key tag.

## Use Cases

### Multiple Use Cases with Different Thresholds

A common pattern is to configure multiple keys for the same validator with different quorum thresholds, each optimized for different use cases:

**Example: Heavy vs. Light Thresholds**

```yaml
NetworkConfig:
    QuorumThresholds:
        - KeyTag: 0x00 # BLS BN254, ID 0 - Heavy operations
          QuorumThreshold: 800000000000000000 # 80% threshold
        - KeyTag: 0x01 # BLS BN254, ID 1 - Light operations
          QuorumThreshold: 510000000000000000 # 51% threshold
    RequiredKeyTags: [0x00, 0x01]
```

**Use Cases:**

- **Heavy Threshold (80%)**: Used for critical operations requiring high security, such as:
    - Large value transfers
    - Protocol upgrades
    - Security-sensitive operations
- **Light Threshold (51%)**: Used for routine operations requiring lower latency, such as:
    - Frequent state updates
    - Low-value transactions
    - High-throughput operations

This allows the same validator set to support both high-security and high-throughput use cases simultaneously.

### Mapping External Keys to Aggregation Keys

Another powerful use case is mapping external keys (e.g., from other blockchain networks or consensus systems) to aggregation-enabled keys in the relay system.

**Example: External Consensus Key Mapping**

```yaml
Validator:
    Operator: 0x1234...
    Keys:
        - Tag: 0x10 # ECDSA secp256k1, ID 0 - External consensus key
          Payload: <external_consensus_public_key>
        - Tag: 0x00 # BLS BN254, ID 0 - Aggregation key (mapped)
          Payload: <bls_bn254_public_key>
```

**How It Works:**

1. The validator registers their external consensus key (e.g., ECDSA secp256k1) with ID 0
2. The same validator also registers a BLS BN254 aggregation key with ID 0
3. The system treats both keys as belonging to the same validator (same operator address)
4. When a signature request is made with the BLS BN254 key tag, the validator uses their aggregation key
5. The aggregation key enables the validator to participate in efficient signature aggregation

**Benefits:**

- **Interoperability**: Existing consensus systems can integrate with the relay without changing their key infrastructure
- **Efficiency**: External keys can be mapped to aggregation-enabled keys, enabling efficient on-chain verification
- **Flexibility**: Validators can maintain their existing key management while gaining aggregation capabilities

**Real-World Scenario:**
A validator running a PoS blockchain with ECDSA consensus keys wants to participate in the relay network. They:

1. Keep their existing ECDSA keys for their primary blockchain
2. Generate additional BLS BN254 keys for relay participation
3. Register both key types under the same operator address
4. Use ECDSA keys for their blockchain operations
5. Use BLS BN254 keys for relay aggregation operations

This mapping allows arbitrary key sets (that may not natively support aggregation) to be "turned into" aggregatable sets by associating them with BLS BN254 keys.

## Key Tag Structure

A [`KeyTag`](./types.md#keytag) is an 8-bit value encoding both the key type and key ID:

```
KeyTag = (KeyType << 4) | KeyID
```

- **Upper 4 bits (bits 4-7)**: Key type (0-15, currently 0-2 used)
- **Lower 4 bits (bits 0-3)**: Key ID (0-15, allows 16 keys per type)

**Examples:**

- `0x00` = BLS BN254, ID 0
- `0x01` = BLS BN254, ID 1
- `0x10` = ECDSA secp256k1, ID 0
- `0x11` = ECDSA secp256k1, ID 1
- `0x20` = BLS12381 BN254, ID 0

## References

- [`Types`](./types.md) for complete type definitions
- [`Signature Aggregation`](./signature_aggregation.md) for how aggregation works
- [`Valset Commitment`](./valset_commitment.md) for how keys are used in commitments
````

## File: docs/core/sign_message.md

````markdown
# Sign Message API

## Description

The Sign Message API allows client applications to request cryptographic signatures from the validator network. Each node has its own client application that calls the SignMessage API on that node. When all client applications call their respective nodes with the same message, key tag (see [`KeyTag`](./types.md#keytag)), and epoch, the nodes coordinate to produce an aggregation proof (see [`AggregationProof`](./types.md#aggregationproof)) that can be verified on-chain using settlement contracts.

### Process Overview

1. **API Request**: Each client application calls the SignMessage API endpoint on its respective node with:
    - The message to be signed
    - The key tag (see [`KeyTag`](./types.md#keytag)) specifying which validator keys should sign
    - The required epoch (or current epoch if not specified)

2. **Request Distribution**: Each node receives a SignMessage API call from its own client application. For the aggregation to work correctly, all client applications must call their nodes with exactly the same message, key tag, and epoch. This ensures all nodes generate the same request ID and coordinate on the same signature request.

3. **Signature Request Creation**: Each node creates a signature request (see [`SignatureRequest`](./types.md#signaturerequest)) internally. The request ID is deterministically calculated from the message hash, key tag, and epoch, ensuring all nodes generate the same request ID for identical inputs.

4. **Signature Aggregation**: The nodes follow the signature aggregation process (see [Signature Aggregation](./signature_aggregation.md)):
    - Signers sign the message
    - Signatures are collected via P2P
    - When quorum is reached, aggregators generate an aggregation proof

5. **Proof Retrieval**: Each client application can retrieve the aggregation proof from its own node using the GetAggregationProof API endpoint, providing the request ID returned from the SignMessage call.

6. **On-Chain Verification**: Any client application can verify the aggregation proof on-chain using settlement contracts. The settlement contract's `VerifyQuorumSigAt` function verifies:
    - The aggregation proof is valid (BN254 Simple pairing check)
    - The signers meet the quorum threshold
    - The proof corresponds to the specified epoch and message

### Key Features

- **Deterministic Request IDs**: Identical messages, key tags, and epochs produce the same request ID across all nodes, enabling coordination
- **Quorum-Based Signing**: Signatures are only aggregated when sufficient validator voting power has signed
- **On-Chain Verifiable**: Aggregation proofs can be verified on-chain using settlement contracts, enabling trustless verification
- **Multi-Node Coordination**: All nodes process the same request, ensuring consistent aggregation across the network
- **BN254 Simple**: Aggregation proofs use BN254 Simple aggregation for efficient on-chain verification

### Diagram

```mermaid
sequenceDiagram
    participant Client1 as Client App 1
    participant Node1 as Node 1
    participant Client2 as Client App 2
    participant Node2 as Node 2
    participant Client3 as Client App 3
    participant Node3 as Node 3
    participant Client4 as Client App 4
    participant Node4 as Node 4
    participant Settlement as Settlement Contract

    Note over Client1,Client4: SignMessage API call<br/>(same message, keyTag, epoch)

    par Client 1 -> Node 1
        Client1->>Node1: SignMessage(message, keyTag, epoch)
        Node1->>Node1: Create signature request<br/>(same requestID for same data)
        Node1-->>Client1: requestID, epoch
    and Client 2 -> Node 2
        Client2->>Node2: SignMessage(message, keyTag, epoch)
        Node2->>Node2: Create signature request<br/>(same requestID for same data)
        Node2-->>Client2: requestID, epoch
    and Client 3 -> Node 3
        Client3->>Node3: SignMessage(message, keyTag, epoch)
        Node3->>Node3: Create signature request<br/>(same requestID for same data)
        Node3-->>Client3: requestID, epoch
    and Client 4 -> Node 4
        Client4->>Node4: SignMessage(message, keyTag, epoch)
        Node4->>Node4: Create signature request<br/>(same requestID for same data)
        Node4-->>Client4: requestID, epoch
    end

    Note over Node1,Node4: Signature aggregation process<br/>(see Signature Aggregation flow)

    par Client 1 polls Node 1
        loop Poll until proof available
            Client1->>Node1: GetAggregationProof(requestID)
            alt Proof not ready
                Node1-->>Client1: Not found / Not ready
            else Proof ready
                Node1-->>Client1: AggregationProof
            end
        end
    and Client 2 polls Node 2
        loop Poll until proof available
            Client2->>Node2: GetAggregationProof(requestID)
            alt Proof not ready
                Node2-->>Client2: Not found / Not ready
            else Proof ready
                Node2-->>Client2: AggregationProof
            end
        end
    and Client 3 polls Node 3
        loop Poll until proof available
            Client3->>Node3: GetAggregationProof(requestID)
            alt Proof not ready
                Node3-->>Client3: Not found / Not ready
            else Proof ready
                Node3-->>Client3: AggregationProof
            end
        end
    and Client 4 polls Node 4
        loop Poll until proof available
            Client4->>Node4: GetAggregationProof(requestID)
            alt Proof not ready
                Node4-->>Client4: Not found / Not ready
            else Proof ready
                Node4-->>Client4: AggregationProof
            end
        end
    end

    Note over Client1,Client4: Proof received

    Client1->>Settlement: VerifyQuorumSigAt(<br/>message, keyTag, epoch,<br/>threshold, proof)
    Note over Settlement: Verify aggregation proof<br/>(BN254 Simple pairing check)
    Settlement->>Settlement: Check quorum threshold
    Settlement->>Settlement: Verify proof validity
    Settlement-->>Client1: Verification result

    Note over Client1: Proof verified on-chain
```
````

## File: docs/core/signature_aggregation.md

````markdown
# Aggregation

## Description

The aggregation process generates aggregation proofs (see [`AggregationProof`](./types.md#aggregationproof)) from individual validator signatures (see [`Signature`](./types.md#signature)) when a quorum threshold is reached. This process enables the network to produce a single cryptographic proof representing the collective agreement of validators, which can be efficiently verified on-chain.

### Process Overview

1. **Signature Request Reception**: Each node receives a signature request (see [`SignatureRequest`](./types.md#signaturerequest)) (e.g., when a new validator set is derived). The request contains the message to be signed, the required key tag (see [`KeyTag`](./types.md#keytag)), and the epoch.

2. **Individual Signing**: Each node that is a signer for the requested key tag signs the message using their private key. The signature is then broadcast to other nodes via P2P network.

3. **Signature Collection**: Nodes receive signatures from other validators via P2P. Each signature is validated (verifying the signature against the validator's public key) and stored in the local database. The system tracks which validators have signed using a signature map.

4. **Quorum Check**: Aggregator nodes continuously monitor the signature map. When a new signature is processed, aggregators check if the total voting power of signers has reached the quorum threshold defined in the validator set.

5. **Aggregation Proof Generation**: Once quorum is reached, aggregator nodes generate an aggregation proof. For BN254 Simple aggregation:
    - All individual signatures are aggregated into a single G1 point
    - All signer public keys are aggregated into a single G2 point
    - Non-signer validators are identified and encoded
    - Validator data (keys, voting powers) is encoded
    - The proof is assembled containing: aggregated signature (G1), aggregated public key (G2), validators data, and non-signer indices

6. **Proof Broadcast**: The generated aggregation proof is broadcast via P2P network to all nodes, allowing them to verify and use the proof.

### Key Features

- **Quorum-Based**: Aggregation only occurs when sufficient voting power has signed, ensuring security and consensus
- **BLS Signature Aggregation**: Uses BLS (Boneh-Lynn-Shacham) signatures on BN254 curve, allowing efficient aggregation of multiple signatures into a single proof
- **Deterministic**: All aggregators produce the same proof from the same set of signatures, ensuring consistency across the network
- **Efficient Verification**: The aggregated proof can be verified on-chain with a single pairing check, regardless of the number of signers
- **Non-Signer Tracking**: The proof explicitly tracks which validators did not sign, allowing the verifier to calculate the effective signing voting power

### Diagram (BN254 Simple)

```mermaid
sequenceDiagram
    participant Node1 as Node 1<br/>(Signer)
    participant Node2 as Node 2<br/>(Signer)
    participant Node3 as Node 3<br/>(Signer + Aggregator)
    participant Node4 as Node 4<br/>(Signer)
    participant P2P as P2P Network

    Note over Node1,Node4: Signature request received

    par Node 1 signs
        Node1->>Node1: Sign message with<br/>private key
        Node1->>P2P: Broadcast signature
    and Node 2 signs
        Node2->>Node2: Sign message with<br/>private key
        Node2->>P2P: Broadcast signature
    and Node 3 signs
        Node3->>Node3: Sign message with<br/>private key
        Node3->>P2P: Broadcast signature
    and Node 4 signs
        Node4->>Node4: Sign message with<br/>private key
        Node4->>P2P: Broadcast signature
    end

    Note over P2P: Signatures distributed via P2P

    par Node 1 receives signatures
        P2P->>Node1: Receive signatures<br/>from other nodes
        Node1->>Node1: Verify signatures
    and Node 2 receives signatures
        P2P->>Node2: Receive signatures<br/>from other nodes
        Node2->>Node2: Verify signatures
    and Node 3 receives signatures
        P2P->>Node3: Receive signatures<br/>from other nodes
        Node3->>Node3: Verify signatures
        Node3->>Node3: Check quorum threshold
    and Node 4 receives signatures
        P2P->>Node4: Receive signatures<br/>from other nodes
        Node4->>Node4: Verify signatures
    end

    Note over Node3: Quorum reached
    Note over Node3: Aggregate signatures<br/>(BN254 Simple)
    Node3->>Node3: Aggregate G1 signatures
    Node3->>Node3: Aggregate G2 public keys
    Node3->>Node3: Encode validators data
    Node3->>Node3: Identify non-signers
    Node3->>Node3: Assemble aggregation proof
    Node3->>P2P: Broadcast aggregation proof

    P2P->>Node1: Receive aggregation proof
    P2P->>Node2: Receive aggregation proof
    P2P->>Node3: Receive aggregation proof
    P2P->>Node4: Receive aggregation proof

    Note over Node1,Node4: All nodes have aggregation proof
```
````

## File: docs/core/types.md

````markdown
# Core Types Reference

The document contains abstract core types definitions with fields size and their underlying types.

_For golang specific types definition visit: https://github.com/symbioticfi/relay/tree/dev/symbiotic/entity_

## Structures

### NetworkConfig

| Field                     | Type                                          | Size(b)  | Description                                                            |
| ------------------------- | --------------------------------------------- | -------- | ---------------------------------------------------------------------- |
| `NumAggregators`          | `uint208`                                     | 26       | Number of aggregators assigned per epoch                               |
| `NumCommitters`           | `uint208`                                     | 26       | Number of committers assigned per epoch                                |
| `CommitterSlotDuration`   | `uint48`                                      | 6        | Duration of each committer's time slot in seconds                      |
| `VotingPowerProviders`    | `[]`[`CrossChainAddress`](#crosschainaddress) | variable | List of VotingPowerProvider contract addresses across different chains |
| `KeysProvider`            | [`CrossChainAddress`](#crosschainaddress)     | 28       | KeyRegistry contract address for retrieving validator keys             |
| `Settlements`             | `[]`[`CrossChainAddress`](#crosschainaddress) | variable | List of Settlement contract addresses where valsets are committed      |
| `MaxVotingPower`          | `uint256`                                     | 32       | Maximum voting power cap per validator (0 = no cap)                    |
| `MinInclusionVotingPower` | `uint256`                                     | 32       | Minimum voting power required for validator inclusion                  |
| `MaxValidatorsCount`      | `uint208`                                     | 26       | Maximum number of validators (0 = no limit)                            |
| `RequiredKeyTags`         | `[]`[`KeyTag`](#keytag)                       | variable | List of key tags required for validators                               |
| `QuorumThresholds`        | `[]`[`QuorumThreshold`](#quorumthreshold)     | variable | Quorum threshold configurations per key tag                            |
| `RequiredHeaderKeyTag`    | [`KeyTag`](#keytag)                           | 1        | Key tag required for signing valset header commitments                 |
| `VerificationType`        | [`VerificationType`](#verificationtype)       | 4        | Type of verification (BN254 Simple or BN254 ZK)                        |

### CrossChainAddress

| Field     | Type      | Size(b) | Description                                                                                                                                                                     |
| --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ChainId` | `uint64`  | 8       | Chain ID where the contract is deployed. For voting power providers, IDs in reserved range `4_000_000_000..4_100_000_000` mean external provider routing via local relay config |
| `Address` | `address` | 20      | Contract address on the specified chain                                                                                                                                         |

### QuorumThreshold

| Field             | Type      | Size(b) | Description                             |
| ----------------- | --------- | ------- | --------------------------------------- |
| `KeyTag`          | `KeyTag`  | 8       | Chain ID where the contract is deployed |
| `QuorumThreshold` | `uint248` | 31      | Contract address on the specified chain |

### ValidatorSet

| Field               | Type                                        | Size(b)  | Description                                                                   |
| ------------------- | ------------------------------------------- | -------- | ----------------------------------------------------------------------------- |
| `Version`           | `uint8`                                     | 1        | Validator set version                                                         |
| `RequiredKeyTag`    | [`KeyTag`](#keytag)                         | 1        | Key tag required to commit the next valset                                    |
| `Epoch`             | `uint48`                                    | 6        | Epoch number for this validator set                                           |
| `CaptureTimestamp`  | `uint48`                                    | 6        | Timestamp when the validator set was captured                                 |
| `QuorumThreshold`   | `uint256`                                   | 32       | Absolute quorum threshold required to commit the next valset (not percentage) |
| `Validators`        | `[]`[`Validator`](#validator)               | variable | List of validators in the set                                                 |
| `Status`            | [`ValidatorSetStatus`](#validatorsetstatus) | 1        | Current status (Derived, Aggregated, Committed, Missed)                       |
| `AggregatorIndices` | `[]uint32`                                  | variable | Indices of validators assigned as aggregators (off-chain)                     |
| `CommitterIndices`  | `[]uint32`                                  | variable | Indices of validators assigned as committers (off-chain)                      |

**Note: Check [`ValidatorsSszMRoot`](#validatorssszmroot) to see limitations applied to validators size**

### ValidatorSetHeader

| Field                | Type                | Size(b) | Description                                                                                             |
| -------------------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| `Version`            | `uint8`             | 1       | Validator set version                                                                                   |
| `RequiredKeyTag`     | [`KeyTag`](#keytag) | 1       | Key tag required for signing                                                                            |
| `Epoch`              | `uint48`            | 6       | Epoch number                                                                                            |
| `CaptureTimestamp`   | `uint48`            | 8       | Timestamp when validator set was captured                                                               |
| `QuorumThreshold`    | `uint256`           | 32      | Absolute quorum threshold                                                                               |
| `TotalVotingPower`   | `uint256`           | 32      | Total voting power of active validators                                                                 |
| `ValidatorsSszMRoot` | `bytes32`           | 32      | Merkle root of validators tree (SSZ encoding, see details: [`ValidatorsSszMRoot`](#validatorssszmroot)) |

### Validator

| Field         | Type                                    | Size(b)  | Description                                                |
| ------------- | --------------------------------------- | -------- | ---------------------------------------------------------- |
| `Operator`    | `address`                               | 20       | Operator address                                           |
| `VotingPower` | `uint256`                               | 32       | Total voting power (sum of all vaults)                     |
| `IsActive`    | `bool`                                  | 1        | Whether the validator is active                            |
| `Keys`        | `[]`[`ValidatorKey`](#validatorkey)     | variable | List of cryptographic keys associated with this validator  |
| `Vaults`      | `[]`[`ValidatorVault`](#validatorvault) | variable | List of vaults contributing voting power to this validator |

**Note: Check [`ValidatorsSszMRoot`](#validatorssszmroot) to see limitations applied to vaults, keys size**

#### ValidatorKey

| Field     | Type                | Size(b)  | Description                                         |
| --------- | ------------------- | -------- | --------------------------------------------------- |
| `Tag`     | [`KeyTag`](#keytag) | 1        | Key tag identifying the key type and ID             |
| `Payload` | `[]byte`            | variable | Compact public key representation (on-chain format) |

#### ValidatorVault

| Field         | Type      | Size(b) | Description                            |
| ------------- | --------- | ------- | -------------------------------------- |
| `ChainID`     | `uint64`  | 8       | Chain ID where the vault is deployed   |
| `Vault`       | `address` | 20      | Vault contract address                 |
| `VotingPower` | `uint256` | 32      | Voting power contributed by this vault |

### SignatureRequest

| Field           | Type                | Size(b)  | Description                                         |
| --------------- | ------------------- | -------- | --------------------------------------------------- |
| `KeyTag`        | [`KeyTag`](#keytag) | 1        | Key tag specifying which validator keys should sign |
| `RequiredEpoch` | `uint48`            | 6        | Epoch in which the signature is required            |
| `Message`       | `[]byte`            | variable | Raw message bytes to be signed                      |

### Signature

| Field         | Type                | Size(b)  | Description                                                      |
| ------------- | ------------------- | -------- | ---------------------------------------------------------------- |
| `MessageHash` | `[]byte`            | variable | Hash of the message (scheme depends on [`KeyTag`](#keytag))      |
| `KeyTag`      | [`KeyTag`](#keytag) | 1        | Key tag used for validation                                      |
| `Epoch`       | `uint48`            | 6        | Epoch for validation                                             |
| `PublicKey`   | `[]byte`            | variable | Public key of the signer (format depends on [`KeyTag`](#keytag)) |
| `Signature`   | `[]byte`            | variable | Raw signature bytes (format depends on [`KeyTag`](#keytag))      |

### AggregationProof

| Field         | Type                | Size(b)  | Description                                                                             |
| ------------- | ------------------- | -------- | --------------------------------------------------------------------------------------- |
| `MessageHash` | `[]byte`            | variable | Hash of the message (scheme depends on [`KeyTag`](#keytag))                             |
| `KeyTag`      | [`KeyTag`](#keytag) | 1        | Key tag used for validation                                                             |
| `Epoch`       | `uint48`            | 6        | Epoch for validation                                                                    |
| `Proof`       | `[]byte`            | variable | Raw aggregation proof bytes (format depends on [`VerificationType`](#verificationtype)) |

## Enums / unions

### KeyType

| Name                    | Value | Description                         |
| ----------------------- | ----- | ----------------------------------- |
| `KeyTypeBlsBn254`       | 0     | BLS signatures on BN254 curve       |
| `KeyTypeEcdsaSecp256k1` | 1     | ECDSA signatures on secp256k1 curve |
| `KeyTypeBls12381Bn254`  | 2     | BLS signatures on BLS12-381/BN254   |
| `KeyTypeInvalid`        | 255   | Invalid key type                    |

Underlying type: `uint8` (in fact used only 4 bits, except `KeyTypeInvalid`)

### KeyTag

| Field       | Bits     | Description                          |
| ----------- | -------- | ------------------------------------ |
| _`KeyType`_ | `[0..4]` | [`KeyType`](#keytype) (upper 4 bits) |
| _`Key ID`_  | `[5..8]` | Key ID (lower 4 bits)                |

Underlying type: `uint8`

### VerificationType

| Name                          | Value | Description                                                                                                          |
| ----------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------- |
| `VerificationTypeBn254ZK`     | 0     | Zero-knowledge proof based verification for BLS signatures on BN254 (used for privacy-preserving or batched proofs). |
| `VerificationTypeBn254Simple` | 1     | BLS signature aggregation/verification on the BN254 curve (supports fast aggregation, single pairing verification).  |
| `VerificationTypeUnknown`     | 255   | Unknown or unsupported verification type                                                                             |

Underlying type: `uint32`

### ValidatorSetStatus

| Name                           | Value | Description                                                                                |
| ------------------------------ | ----- | ------------------------------------------------------------------------------------------ |
| `ValidatorSetStatusDerived`    | 0     | The validator set has been derived from on-chain data but not yet aggregated or committed. |
| `ValidatorSetStatusAggregated` | 1     | The aggregation proof for the validator set has been created but not yet committed.        |
| `ValidatorSetStatusCommitted`  | 2     | The validator set has been successfully committed on-chain.                                |
| `ValidatorSetStatusMissed`     | 3     | The validator set commitment was missed (e.g., not committed in time).                     |

Underlying type: `uint8`

## ValidatorsSszMRoot

The `ValidatorsSszMRoot` is a 32-byte Merkle root hash computed from the SSZ (Simple Serialize) encoding of the validator set. It provides a compact cryptographic commitment to the entire validator set structure.

**Construction:**

The root is computed by:

1. Converting the [`ValidatorSet`](#validatorset) to SSZ format (`SszValidatorSet`)
2. Computing the SSZ hash tree root using Merkleization

**SSZ Structure:**

The hash tree root is computed from the `SszValidators` structure, which contains only the validators list (Version is stored separately in [`ValidatorSetHeader`](#validatorsetheader) and is not included in the SSZ root):

```
SszValidators
└── Validators: []SszValidator (max 1,048,576)
    └── SszValidator
        ├── Operator: address (20 bytes)
        ├── VotingPower: uint256 (32 bytes)
        ├── IsActive: bool (1 byte)
        ├── Keys: []SszKey (max 128)
        │   └── SszKey
        │       ├── Tag: uint8 (1 byte)
        │       └── PayloadHash: bytes32 (32 bytes) - Keccak256 hash of Payload
        └── Vaults: []SszVault (max 1024)
            └── SszVault
                ├── ChainId: uint64 (8 bytes)
                ├── Vault: address (20 bytes)
                └── VotingPower: uint256 (32 bytes)
```

**Key Points:**

- Validator keys store `PayloadHash` (Keccak256 hash of the key payload) rather than the full payload in the SSZ structure
- Validators must be sorted by operator address (ascending) before encoding
- The SSZ encoding uses Merkleization with mix-in for variable-length lists

**Limitations:**

| Element              | Maximum Count | Description                             |
| -------------------- | ------------- | --------------------------------------- |
| Validators           | 1,048,576     | Maximum number of validators in the set |
| Keys per Validator   | 128           | Maximum number of keys per validator    |
| Vaults per Validator | 1,024         | Maximum number of vaults per validator  |

**Merkleization:**

- Uses SSZ Merkleization algorithm with mix-in for list lengths
- Tree heights: Validators list (20 levels), Keys list (7 levels), Vaults list (10 levels)
- The final root is a 32-byte hash representing the entire validator set structure

**Reference Implementation:**

- Golang: [`relay/symbiotic/usecase/ssz/ssz.go`](https://github.com/symbioticfi/relay/tree/dev/symbiotic/usecase/ssz/ssz.go)
- Typescript: [`relay-stats-ts/src/encoding.ts`](https://github.com/symbioticfi/relay-stats-ts/blob/main/src/encoding.ts)
````

## File: docs/core/valset_commitment.md

````markdown
# Valset Commitment

## Description

The valset commitment process commits derived validator sets (see [`ValidatorSet`](./types.md#validatorset)) to settlement contracts on multiple chains, enabling cross-chain verification of validator set state. Each commitment includes a cryptographic proof (see [`AggregationProof`](./types.md#aggregationproof)) that verifies against the previous committed valset, ensuring continuity and security across epochs.

### Process Overview

1. **Valset Derivation**: A new validator set is derived for an epoch (see [Valset Derivation](./valset_derivation.md)). This process aggregates voting powers from multiple chains and forms the validator set according to network configuration.

2. **Header and Extra Data Generation**: Once a valset is derived:
    - The valset header (see [`ValidatorSetHeader`](./types.md#validatorsetheader)) is generated, containing epoch, quorum threshold, total voting power, and validators Merkle root
    - Extra data is generated using BN254 Simple aggregation, which aggregates the public keys of all validators for the required key tags
    - Commitment data is created as EIP712 typed data, combining the header hash and extra data hash

3. **Commitment Signing**: Signers from the previous epoch's validator set sign the commitment data. This creates a signature request (see [`SignatureRequest`](./types.md#signaturerequest)) that triggers the aggregation process (see [Signature Aggregation](./signature_aggregation.md)).

4. **Aggregation Proof Generation**: Once quorum is reached, an aggregation proof is generated using BN254 Simple aggregation, proving that sufficient validators from the previous epoch signed the commitment.

5. **Commitment to Settlement Contracts**: Committer nodes commit the valset to all configured settlement contracts:
    - Verifies that the previous epoch's valset is already committed on the settlement contract
    - Ensures consecutive epoch commitment (new epoch = last committed epoch + 1)
    - Submits the valset header, extra data, and aggregation proof to the settlement contract
    - The settlement contract verifies the aggregation proof against the previous committed valset

6. **Cross-Chain Verification**: Settlement contracts on different chains independently verify the same proof, ensuring consistency across all chains. Each contract maintains its own chain of committed valsets, with each new commitment verified against the previous one.

### Key Features

- **Sequential Commitment**: Each valset commitment must be consecutive (epoch N can only be committed after epoch N-1 is committed)
- **Proof Verification**: The aggregation proof is verified on-chain against the previous committed valset, ensuring cryptographic continuity
- **Multi-Chain Support**: The same valset is committed to multiple settlement contracts on different chains, enabling cross-chain state verification
- **BN254 Simple**: Both extra data (aggregated public keys) and aggregation proofs use BN254 Simple aggregation for efficient on-chain verification
- **Deterministic**: All committers produce the same commitment data, ensuring consistency across the network

> **Note**: The first valset header and extra data in settlement contracts must be set through the trusted genesis functionality. This establishes the initial state that all subsequent commitments will verify against.

### Diagram

```mermaid
sequenceDiagram
    participant Deriver as Valset Deriver
    participant Aggregator as BN254 Simple<br/>Aggregator
    participant Signers as Signers<br/>(Previous Epoch)
    participant Committer as Committer Node
    participant Settlement1 as Settlement Contract<br/>(Chain 1)
    participant Settlement2 as Settlement Contract<br/>(Chain 2)

    Note over Deriver: Valset derived<br/>(see Valset Derivation flow)

    Deriver->>Deriver: Generate valset header
    Deriver->>Aggregator: GenerateExtraData(valset, keyTags)
    Note over Aggregator: Aggregate public keys<br/>(BN254 Simple)
    Aggregator-->>Deriver: ExtraData (aggregated keys)

    Deriver->>Deriver: Create commitment data<br/>(EIP712: headerHash + extraDataHash)

    Note over Signers: Sign commitment data<br/>(see Signature Aggregation flow)

    Note over Aggregator: Generate aggregation proof<br/>(see Signature Aggregation flow)<br/>BN254 Simple

    Note over Committer: Aggregation proof received

    par Commit to Chain 1
        Committer->>Settlement1: GetLastCommittedHeaderEpoch()
        Settlement1-->>Committer: lastCommittedEpoch (N-1)

        alt Previous epoch committed
            Committer->>Settlement1: CommitValSetHeader(<br/>header, extraData, proof)
            Note over Settlement1: Verify proof against<br/>previous valset (epoch N-1)
            Settlement1->>Settlement1: Verify aggregation proof<br/>(BN254 Simple pairing check)
            Settlement1->>Settlement1: Check epoch = N-1 + 1
            Settlement1-->>Committer: Valset committed (epoch N)
        else Previous epoch not committed
            Note over Committer: Wait for previous epoch<br/>to be committed
        end
    and Commit to Chain 2
        Committer->>Settlement2: GetLastCommittedHeaderEpoch()
        Settlement2-->>Committer: lastCommittedEpoch (N-1)

        alt Previous epoch committed
            Committer->>Settlement2: CommitValSetHeader(<br/>header, extraData, proof)
            Note over Settlement2: Verify proof against<br/>previous valset (epoch N-1)
            Settlement2->>Settlement2: Verify aggregation proof<br/>(BN254 Simple pairing check)
            Settlement2->>Settlement2: Check epoch = N-1 + 1
            Settlement2-->>Committer: Valset committed (epoch N)
        else Previous epoch not committed
            Note over Committer: Wait for previous epoch<br/>to be committed
        end
    end

    Note over Settlement1,Settlement2: Valset committed on both chains<br/>Verified against previous valset
```
````

## File: docs/core/valset_derivation.md

````markdown
# Validator Set Derivation

## Description

The valset derivation process is responsible for computing and storing validator sets (see [`ValidatorSet`](./types.md#validatorset)) when new epochs occur in the ValSetDriver contract. This process ensures that the validator set accurately reflects the voting power distribution across multiple chains at a specific point in time.

### Process Overview

1. **Epoch Detection**: The system continuously polls the ValSetDriver contract to detect when a new epoch occurs. All contract calls use finalized blocks to ensure data consistency and prevent reorgs.

2. **Configuration Retrieval**: When a new epoch is detected, the system retrieves:
    - The epoch start timestamp
    - Network configuration (see [`NetworkConfig`](./types.md#networkconfig)) including:
        - VotingPowerProvider contract addresses (deployed on multiple chains)
        - External voting power providers (`chainId` in reserved range `4_000_000_000..4_100_000_000`, resolved by local relay config)
        - KeyRegistry contract address
        - Validator set formation rules (min/max voting power, validator limits, etc.)

3. **Cross-Chain Voting Power Aggregation**: The system queries voting powers from all configured providers in parallel. Providers with `chainId` in reserved external range `4_000_000_000..4_100_000_000` are queried through configured external gRPC services; all other providers are queried through EVM contracts. For external providers, provider ID is read from the first 10 bytes of provider address and resolved via local relay config. All queries use finalized on-chain state for config/timestamp inputs. The derivation is fail-closed: any provider error fails the epoch.

4. **Key Retrieval**: The system fetches operator keys from the KeyRegistry contract at the epoch timestamp, again using finalized blocks.

5. **Validator Set Formation**: The deriver combines voting powers and keys to form validators according to the network configuration rules:
    - Filters validators by minimum voting power thresholds
    - Applies maximum voting power caps if configured
    - Limits the total number of validators if specified
    - Sorts validators by voting power

6. **Quorum and Role Assignment**: The system calculates the quorum threshold and deterministically assigns aggregator and committer roles pseudo-randomly based on the validator set hash.

### Key Features

- **Multi-Chain Support**: VotingPowerProviders can be deployed on different chains, with voting powers aggregated across all chains
- **Deterministic Derivation**: The validator set is deterministically derived from on-chain data from finalized state, ensuring all nodes derive the same set
- **Configuration-Driven**: Validator set formation follows rules defined in the network configuration, allowing for flexible governance

### Diagram

```mermaid
sequenceDiagram
    participant ValSetDriver as ValSetDriver Contract<br/>(Driver Chain)
    participant Deriver as Valset Deriver
    participant VPP1 as VotingPowerProvider<br/>(Chain 1)
    participant VPP2 as VotingPowerProvider<br/>(Chain 2)
    participant KeyRegistry as KeyRegistry Contract
    participant DB as Local Database

    Note over ValSetDriver: New epoch occurs
    ValSetDriver->>ValSetDriver: Epoch transition event

    loop Polling for new epochs
        Deriver->>ValSetDriver: GetCurrentEpoch()<br/>(finalized block)
        ValSetDriver-->>Deriver: currentEpoch

        alt New epoch detected
            Deriver->>ValSetDriver: GetEpochStart(epoch)<br/>(finalized block)
            ValSetDriver-->>Deriver: epochStartTimestamp

            Deriver->>ValSetDriver: GetConfig(epochStartTimestamp, epoch)<br/>(finalized block)
            ValSetDriver-->>Deriver: NetworkConfig<br/>Includes:<br/>- VotingPowerProvider addresses<br/>- KeyRegistry address<br/>- Validator set formation rules

            Note over Deriver,VPP2: Query voting powers from all chains<br/>(waiting for finality)

            par Query Chain 1
                Deriver->>VPP1: GetVotingPowersAt(timestamp)<br/>(finalized block)
                VPP1-->>Deriver: OperatorVotingPower[]
            and Query Chain 2
                Deriver->>VPP2: GetVotingPowersAt(timestamp)<br/>(finalized block)
                VPP2-->>Deriver: OperatorVotingPower[]
            end

            Deriver->>KeyRegistry: GetKeys(timestamp)<br/>(finalized block)
            KeyRegistry-->>Deriver: OperatorWithKeys[]

            Note over Deriver: Form validators from<br/>voting powers + keys<br/>(Ruled by config)

            Deriver->>Deriver: Calculate quorum threshold
            Deriver->>Deriver: Assign aggregator/committer indices

            Deriver->>DB: SaveNetworkConfig(epoch, config)
            Deriver->>DB: SaveValidatorSet(epoch, valset)

            Note over DB: Valset stored in local DB
        end
    end
```
````

## File: docs/votingpower/v1/doc.md

```markdown
# Protocol Documentation

<a name="top"></a>

## Table of Contents

- [v1/votingpower.proto](#v1_votingpower-proto)
    - [GetVotingPowersAtRequest](#votingpower-v1-GetVotingPowersAtRequest)
    - [GetVotingPowersAtResponse](#votingpower-v1-GetVotingPowersAtResponse)
    - [OperatorVotingPower](#votingpower-v1-OperatorVotingPower)
    - [VotingPowerProviderService](#votingpower-v1-VotingPowerProviderService)

- [Scalar Value Types](#scalar-value-types)

<a name="v1_votingpower-proto"></a>

<p align="right"><a href="#top">Top</a></p>

## v1/votingpower.proto

<a name="votingpower-v1-GetVotingPowersAtRequest"></a>

### GetVotingPowersAtRequest

| Field     | Type              | Label | Description                |
| --------- | ----------------- | ----- | -------------------------- |
| timestamp | [uint64](#uint64) |       | Unix timestamp in seconds. |

<a name="votingpower-v1-GetVotingPowersAtResponse"></a>

### GetVotingPowersAtResponse

| Field         | Type                                                       | Label    | Description |
| ------------- | ---------------------------------------------------------- | -------- | ----------- |
| voting_powers | [OperatorVotingPower](#votingpower-v1-OperatorVotingPower) | repeated |             |

<a name="votingpower-v1-OperatorVotingPower"></a>

### OperatorVotingPower

| Field        | Type              | Label | Description                     |
| ------------ | ----------------- | ----- | ------------------------------- |
| operator     | [string](#string) |       | Operator address as hex string. |
| voting_power | [string](#string) |       | Decimal string voting power.    |

<a name="votingpower-v1-VotingPowerProviderService"></a>

### VotingPowerProviderService

VotingPowerProviderService is implemented by external voting power providers.

| Method Name       | Request Type                                                         | Response Type                                                          | Description                                                                   |
| ----------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| GetVotingPowersAt | [GetVotingPowersAtRequest](#votingpower-v1-GetVotingPowersAtRequest) | [GetVotingPowersAtResponse](#votingpower-v1-GetVotingPowersAtResponse) | GetVotingPowersAt returns voting power for operators at a specific timestamp. |

## Scalar Value Types

| .proto Type                    | Notes                                                                                                                                           | C++    | Java       | Python      | Go      | C#         | PHP            | Ruby                           |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ---------- | ----------- | ------- | ---------- | -------------- | ------------------------------ |
| <a name="double" /> double     |                                                                                                                                                 | double | double     | float       | float64 | double     | float          | Float                          |
| <a name="float" /> float       |                                                                                                                                                 | float  | float      | float       | float32 | float      | float          | Float                          |
| <a name="int32" /> int32       | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="int64" /> int64       | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="uint32" /> uint32     | Uses variable-length encoding.                                                                                                                  | uint32 | int        | int/long    | uint32  | uint       | integer        | Bignum or Fixnum (as required) |
| <a name="uint64" /> uint64     | Uses variable-length encoding.                                                                                                                  | uint64 | long       | int/long    | uint64  | ulong      | integer/string | Bignum or Fixnum (as required) |
| <a name="sint32" /> sint32     | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.                            | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="sint64" /> sint64     | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.                            | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="fixed32" /> fixed32   | Always four bytes. More efficient than uint32 if values are often greater than 2^28.                                                            | uint32 | int        | int         | uint32  | uint       | integer        | Bignum or Fixnum (as required) |
| <a name="fixed64" /> fixed64   | Always eight bytes. More efficient than uint64 if values are often greater than 2^56.                                                           | uint64 | long       | int/long    | uint64  | ulong      | integer/string | Bignum                         |
| <a name="sfixed32" /> sfixed32 | Always four bytes.                                                                                                                              | int32  | int        | int         | int32   | int        | integer        | Bignum or Fixnum (as required) |
| <a name="sfixed64" /> sfixed64 | Always eight bytes.                                                                                                                             | int64  | long       | int/long    | int64   | long       | integer/string | Bignum                         |
| <a name="bool" /> bool         |                                                                                                                                                 | bool   | boolean    | boolean     | bool    | bool       | boolean        | TrueClass/FalseClass           |
| <a name="string" /> string     | A string must always contain UTF-8 encoded or 7-bit ASCII text.                                                                                 | string | String     | str/unicode | string  | string     | string         | String (UTF-8)                 |
| <a name="bytes" /> bytes       | May contain any arbitrary sequence of bytes.                                                                                                    | string | ByteString | str         | []byte  | ByteString | string         | String (ASCII-8BIT)            |
```

## File: docs/votingpower/v1/index.html

```html
<!DOCTYPE html>

<html>
    <head>
        <title>Protocol Documentation</title>
        <meta charset="UTF-8" />
        <link
            rel="stylesheet"
            type="text/css"
            href="https://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic"
        />
        <style>
            body {
                width: 60em;
                margin: 1em auto;
                color: #222;
                font-family: "Ubuntu", sans-serif;
                padding-bottom: 4em;
            }

            h1 {
                font-weight: normal;
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
            }

            h2 {
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
                margin: 1.5em 0;
            }

            h3 {
                font-weight: normal;
                border-bottom: 1px solid #aaa;
                padding-bottom: 0.5ex;
            }

            a {
                text-decoration: none;
                color: #567e25;
            }

            table {
                width: 100%;
                font-size: 80%;
                border-collapse: collapse;
            }

            thead {
                font-weight: 700;
                background-color: #dcdcdc;
            }

            tbody tr:nth-child(even) {
                background-color: #fbfbfb;
            }

            td {
                border: 1px solid #ccc;
                padding: 0.5ex 2ex;
            }

            td p {
                text-indent: 1em;
                margin: 0;
            }

            td p:nth-child(1) {
                text-indent: 0;
            }

            .field-table td:nth-child(1) {
                width: 10em;
            }
            .field-table td:nth-child(2) {
                width: 10em;
            }
            .field-table td:nth-child(3) {
                width: 6em;
            }
            .field-table td:nth-child(4) {
                width: auto;
            }

            .extension-table td:nth-child(1) {
                width: 10em;
            }
            .extension-table td:nth-child(2) {
                width: 10em;
            }
            .extension-table td:nth-child(3) {
                width: 10em;
            }
            .extension-table td:nth-child(4) {
                width: 5em;
            }
            .extension-table td:nth-child(5) {
                width: auto;
            }

            .enum-table td:nth-child(1) {
                width: 10em;
            }
            .enum-table td:nth-child(2) {
                width: 10em;
            }
            .enum-table td:nth-child(3) {
                width: auto;
            }

            .scalar-value-types-table tr {
                height: 3em;
            }

            #toc-container ul {
                list-style-type: none;
                padding-left: 1em;
                line-height: 180%;
                margin: 0;
            }
            #toc > li > a {
                font-weight: bold;
            }

            .file-heading {
                width: 100%;
                display: table;
                border-bottom: 1px solid #aaa;
                margin: 4em 0 1.5em 0;
            }
            .file-heading h2 {
                border: none;
                display: table-cell;
            }
            .file-heading a {
                text-align: right;
                display: table-cell;
            }

            .badge {
                width: 1.6em;
                height: 1.6em;
                display: inline-block;

                line-height: 1.6em;
                text-align: center;
                font-weight: bold;
                font-size: 60%;

                color: #89ba48;
                background-color: #dff0c8;

                margin: 0.5ex 1em 0.5ex -1em;
                border: 1px solid #fbfbfb;
                border-radius: 1ex;
            }
        </style>

        <link rel="stylesheet" type="text/css" href="stylesheet.css" />
    </head>

    <body>
        <h1 id="title">Protocol Documentation</h1>

        <h2>Table of Contents</h2>

        <div id="toc-container">
            <ul id="toc">
                <li>
                    <a href="#v1%2fvotingpower.proto">v1/votingpower.proto</a>
                    <ul>
                        <li>
                            <a href="#votingpower.v1.GetVotingPowersAtRequest"
                                ><span class="badge">M</span>GetVotingPowersAtRequest</a
                            >
                        </li>

                        <li>
                            <a href="#votingpower.v1.GetVotingPowersAtResponse"
                                ><span class="badge">M</span>GetVotingPowersAtResponse</a
                            >
                        </li>

                        <li>
                            <a href="#votingpower.v1.OperatorVotingPower"
                                ><span class="badge">M</span>OperatorVotingPower</a
                            >
                        </li>

                        <li>
                            <a href="#votingpower.v1.VotingPowerProviderService"
                                ><span class="badge">S</span>VotingPowerProviderService</a
                            >
                        </li>
                    </ul>
                </li>

                <li><a href="#scalar-value-types">Scalar Value Types</a></li>
            </ul>
        </div>

        <div class="file-heading">
            <h2 id="v1/votingpower.proto">v1/votingpower.proto</h2>
            <a href="#title">Top</a>
        </div>
        <p></p>

        <h3 id="votingpower.v1.GetVotingPowersAtRequest">GetVotingPowersAtRequest</h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>timestamp</td>
                    <td><a href="#uint64">uint64</a></td>
                    <td></td>
                    <td><p>Unix timestamp in seconds.</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="votingpower.v1.GetVotingPowersAtResponse">GetVotingPowersAtResponse</h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>voting_powers</td>
                    <td><a href="#votingpower.v1.OperatorVotingPower">OperatorVotingPower</a></td>
                    <td>repeated</td>
                    <td><p></p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="votingpower.v1.OperatorVotingPower">OperatorVotingPower</h3>
        <p></p>

        <table class="field-table">
            <thead>
                <tr>
                    <td>Field</td>
                    <td>Type</td>
                    <td>Label</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>operator</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Operator address as hex string.</p></td>
                </tr>

                <tr>
                    <td>voting_power</td>
                    <td><a href="#string">string</a></td>
                    <td></td>
                    <td><p>Decimal string voting power.</p></td>
                </tr>
            </tbody>
        </table>

        <h3 id="votingpower.v1.VotingPowerProviderService">VotingPowerProviderService</h3>
        <p>VotingPowerProviderService is implemented by external voting power providers.</p>
        <table class="enum-table">
            <thead>
                <tr>
                    <td>Method Name</td>
                    <td>Request Type</td>
                    <td>Response Type</td>
                    <td>Description</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>GetVotingPowersAt</td>
                    <td>
                        <a href="#votingpower.v1.GetVotingPowersAtRequest"
                            >GetVotingPowersAtRequest</a
                        >
                    </td>
                    <td>
                        <a href="#votingpower.v1.GetVotingPowersAtResponse"
                            >GetVotingPowersAtResponse</a
                        >
                    </td>
                    <td>
                        <p>
                            GetVotingPowersAt returns voting power for operators at a specific
                            timestamp.
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>

        <h2 id="scalar-value-types">Scalar Value Types</h2>
        <table class="scalar-value-types-table">
            <thead>
                <tr>
                    <td>.proto Type</td>
                    <td>Notes</td>
                    <td>C++</td>
                    <td>Java</td>
                    <td>Python</td>
                    <td>Go</td>
                    <td>C#</td>
                    <td>PHP</td>
                    <td>Ruby</td>
                </tr>
            </thead>
            <tbody>
                <tr id="double">
                    <td>double</td>
                    <td></td>
                    <td>double</td>
                    <td>double</td>
                    <td>float</td>
                    <td>float64</td>
                    <td>double</td>
                    <td>float</td>
                    <td>Float</td>
                </tr>

                <tr id="float">
                    <td>float</td>
                    <td></td>
                    <td>float</td>
                    <td>float</td>
                    <td>float</td>
                    <td>float32</td>
                    <td>float</td>
                    <td>float</td>
                    <td>Float</td>
                </tr>

                <tr id="int32">
                    <td>int32</td>
                    <td>
                        Uses variable-length encoding. Inefficient for encoding negative numbers –
                        if your field is likely to have negative values, use sint32 instead.
                    </td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="int64">
                    <td>int64</td>
                    <td>
                        Uses variable-length encoding. Inefficient for encoding negative numbers –
                        if your field is likely to have negative values, use sint64 instead.
                    </td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="uint32">
                    <td>uint32</td>
                    <td>Uses variable-length encoding.</td>
                    <td>uint32</td>
                    <td>int</td>
                    <td>int/long</td>
                    <td>uint32</td>
                    <td>uint</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="uint64">
                    <td>uint64</td>
                    <td>Uses variable-length encoding.</td>
                    <td>uint64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>uint64</td>
                    <td>ulong</td>
                    <td>integer/string</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sint32">
                    <td>sint32</td>
                    <td>
                        Uses variable-length encoding. Signed int value. These more efficiently
                        encode negative numbers than regular int32s.
                    </td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sint64">
                    <td>sint64</td>
                    <td>
                        Uses variable-length encoding. Signed int value. These more efficiently
                        encode negative numbers than regular int64s.
                    </td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="fixed32">
                    <td>fixed32</td>
                    <td>
                        Always four bytes. More efficient than uint32 if values are often greater
                        than 2^28.
                    </td>
                    <td>uint32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>uint32</td>
                    <td>uint</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="fixed64">
                    <td>fixed64</td>
                    <td>
                        Always eight bytes. More efficient than uint64 if values are often greater
                        than 2^56.
                    </td>
                    <td>uint64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>uint64</td>
                    <td>ulong</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="sfixed32">
                    <td>sfixed32</td>
                    <td>Always four bytes.</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>int</td>
                    <td>int32</td>
                    <td>int</td>
                    <td>integer</td>
                    <td>Bignum or Fixnum (as required)</td>
                </tr>

                <tr id="sfixed64">
                    <td>sfixed64</td>
                    <td>Always eight bytes.</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>int/long</td>
                    <td>int64</td>
                    <td>long</td>
                    <td>integer/string</td>
                    <td>Bignum</td>
                </tr>

                <tr id="bool">
                    <td>bool</td>
                    <td></td>
                    <td>bool</td>
                    <td>boolean</td>
                    <td>boolean</td>
                    <td>bool</td>
                    <td>bool</td>
                    <td>boolean</td>
                    <td>TrueClass/FalseClass</td>
                </tr>

                <tr id="string">
                    <td>string</td>
                    <td>A string must always contain UTF-8 encoded or 7-bit ASCII text.</td>
                    <td>string</td>
                    <td>String</td>
                    <td>str/unicode</td>
                    <td>string</td>
                    <td>string</td>
                    <td>string</td>
                    <td>String (UTF-8)</td>
                </tr>

                <tr id="bytes">
                    <td>bytes</td>
                    <td>May contain any arbitrary sequence of bytes.</td>
                    <td>string</td>
                    <td>ByteString</td>
                    <td>str</td>
                    <td>[]byte</td>
                    <td>ByteString</td>
                    <td>string</td>
                    <td>String (ASCII-8BIT)</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>
```

## File: docs/votingpower/v1/votingpower.swagger.json

```json
{
    "swagger": "2.0",
    "info": {
        "title": "v1/votingpower.proto",
        "version": "version not set"
    },
    "tags": [
        {
            "name": "VotingPowerProviderService"
        }
    ],
    "consumes": ["application/json"],
    "produces": ["application/json"],
    "paths": {},
    "definitions": {
        "Any": {
            "type": "object",
            "properties": {
                "@type": {
                    "type": "string"
                }
            },
            "additionalProperties": {}
        },
        "Status": {
            "type": "object",
            "properties": {
                "code": {
                    "type": "integer",
                    "format": "int32"
                },
                "message": {
                    "type": "string"
                },
                "details": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "$ref": "#/definitions/Any"
                    }
                }
            }
        }
    }
}
```

## File: e2e/scripts/deploy.sh

```bash
#!/bin/sh
set -e

ANVIL_RPC_URL=${ANVIL_RPC_URL:-http://anvil:8545}
SETTLEMENT_RPC_URL=${SETTLEMENT_RPC_URL:-http://anvil-settlement:8546}
MULTICALL_ADDRESS=0x05f32b3cc3888453ff71b01135b34ff8e41263f2
MULTICALL_BALANCE_HEX=0xde0b6b3a7640000 # 1 ether

echo "Waiting for anvil to be ready..."
until cast client --rpc-url "$ANVIL_RPC_URL" > /dev/null 2>&1; do sleep 1; done
until cast client --rpc-url "$SETTLEMENT_RPC_URL" > /dev/null 2>&1; do sleep 1; done


echo "Deploying Multicall3 contracts..."
cast rpc --rpc-url "$ANVIL_RPC_URL" anvil_setBalance "$MULTICALL_ADDRESS" "$MULTICALL_BALANCE_HEX"
cast rpc --rpc-url "$ANVIL_RPC_URL" anvil_setNonce "$MULTICALL_ADDRESS" 0x0
cast publish 0xf90f538085174876e800830f42408080b90f00608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c00331ca0edce47092c0f398cebf3ffc267f05c8e7076e3b89445e0fe50f6332273d4569ba01b0b9d000e19b24c5869b0fc3b22b0d6fa47cd63316875cbbd577d76e6fde086 --rpc-url "$ANVIL_RPC_URL"
cast rpc --rpc-url "$SETTLEMENT_RPC_URL" anvil_setBalance "$MULTICALL_ADDRESS" "$MULTICALL_BALANCE_HEX"
cast rpc --rpc-url "$SETTLEMENT_RPC_URL" anvil_setNonce "$MULTICALL_ADDRESS" 0x0
cast publish 0xf90f538085174876e800830f42408080b90f00608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c00331ca0edce47092c0f398cebf3ffc267f05c8e7076e3b89445e0fe50f6332273d4569ba01b0b9d000e19b24c5869b0fc3b22b0d6fa47cd63316875cbbd577d76e6fde086 --rpc-url "$SETTLEMENT_RPC_URL"

if [ "${VERIFICATION_TYPE}" = "0" ]; then
  forge build circuits/
fi

echo "Deploying contracts..."
./node_modules/@symbioticfi/relay-contracts/script/relay-deploy.sh script/MyRelayDeploy.sol script/my-relay-deploy.toml --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -vvvvv

echo 'Waiting for deployment completion...'
until [ -f /deploy-data/deployment-completed.json ]; do sleep 2; done

echo "Setting interval mining..."
cast rpc --rpc-url "$ANVIL_RPC_URL" evm_setIntervalMining 1
cast rpc --rpc-url "$SETTLEMENT_RPC_URL" evm_setIntervalMining 1

echo "Mine a single block to finalize the deployment..."
cast rpc --rpc-url "$ANVIL_RPC_URL" evm_mine
cast rpc --rpc-url "$SETTLEMENT_RPC_URL" evm_mine

echo "Deployment completed successfully!"

# Create deployment completion marker
echo "$(date): Deployment completed successfully" > /deploy-data/deployment-complete.marker
echo "Deployment completion marker created"
```

## File: e2e/scripts/deployer.Dockerfile

```dockerfile
FROM ghcr.io/foundry-rs/foundry:v1.4.3

USER root

# Install Python (needed by relay deployment helper scripts) together with tomli fallback.
RUN set -eux; \
    if command -v apt-get >/dev/null 2>&1; then \
        apt-get update; \
        DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
            python3 \
            python3-venv \
            python3-pip; \
        rm -rf /var/lib/apt/lists/*; \
    elif command -v apk >/dev/null 2>&1; then \
        apk add --no-cache \
            python3 \
            py3-virtualenv \
            py3-pip; \
    else \
        echo "Unable to determine package manager for Python installation." >&2; \
        exit 1; \
    fi; \
    python3 -m pip install --no-cache-dir tomli; \
    python3 --version

USER foundry
```

## File: e2e/scripts/generate_network.sh

```bash
#!/bin/bash

# Symbiotic Network Infrastructure Generator
# This script generates a Docker Compose setup for blockchain infrastructure
# (anvil chains, deployer, genesis-generator) with configurable parameters
#
# Environment Variables:
#   OPERATORS        - Number of operators (default: 4, max: 999)
#   COMMITERS        - Number of commiters (default: 1)
#   AGGREGATORS      - Number of aggregators (default: 1)
#   VERIFICATION_TYPE - Verification type: 0=BLS-BN254-ZK, 1=BLS-BN254-SIMPLE (default: 1)
#   EPOCH_TIME       - Time for new epochs in relay network (default: 30)
#   BLOCK_TIME       - Block time in seconds for anvil interval mining (default: 1)
#   FINALITY_BLOCKS  - Number of blocks for finality (default: 1)
#
# Example usage:
#   OPERATORS=6 COMMITERS=2 AGGREGATORS=1 VERIFICATION_TYPE=0 EPOCH_TIME=32 BLOCK_TIME=2 ./generate_network.sh

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# Default values
DEFAULT_OPERATORS=4
DEFAULT_COMMITERS=1
DEFAULT_AGGREGATORS=1
DEFAULT_VERIFICATION_TYPE=1  # BLS-BN254-SIMPLE
DEFAULT_EPOCH_TIME=30
DEFAULT_BLOCK_TIME=1
DEFAULT_FINALITY_BLOCKS=2
MAX_OPERATORS=999
DEFAULT_COMMITTER_SLOT_DURATION=10


print_status() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_header() {
    echo -e "${BLUE}================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}================================${NC}"
}


validate_number() {
    local num=$1
    local name=$2
    if ! [[ "$num" =~ ^[0-9]+$ ]] || [ "$num" -lt 1 ]; then
        print_error "$name must be a positive integer"
        exit 1
    fi
}

validate_verification_type() {
    local type=$1
    local name=$2
    if ! [[ "$type" =~ ^[0-1]$ ]]; then
        print_error "$name must be 0 (BLS-BN254-ZK) or 1 (BLS-BN254-SIMPLE)"
        exit 1
    fi
}

get_config_from_env() {
    echo
    print_header "Symbiotic Network Configuration"
    echo

    # Read from environment variables with defaults
    operators=${OPERATORS:-$DEFAULT_OPERATORS}
    commiters=${COMMITERS:-$DEFAULT_COMMITERS}
    aggregators=${AGGREGATORS:-$DEFAULT_AGGREGATORS}
    verification_type=${VERIFICATION_TYPE:-$DEFAULT_VERIFICATION_TYPE}
    epoch_size=${EPOCH_TIME:-$DEFAULT_EPOCH_TIME}
    block_time=${BLOCK_TIME:-$DEFAULT_BLOCK_TIME}
    finality_blocks=${FINALITY_BLOCKS:-$DEFAULT_FINALITY_BLOCKS}
    committer_slot_duration=${COMMITTER_SLOT_DURATION:-$DEFAULT_COMMITTER_SLOT_DURATION}

    # Validate inputs
    validate_number "$operators" "Number of operators (OPERATORS env var)"
    validate_number "$commiters" "Number of commiters (COMMITERS env var)"
    validate_number "$aggregators" "Number of aggregators (AGGREGATORS env var)"
    validate_verification_type "$verification_type" "Verification type (VERIFICATION_TYPE env var)"
    validate_number "$epoch_size" "Epoch size (EPOCH_TIME env var)"
    validate_number "$block_time" "Block time (BLOCK_TIME env var)"
    validate_number "$finality_blocks" "Finality blocks (FINALITY_BLOCKS env var)"
    validate_number "$committer_slot_duration" "Committer slot duration (COMMITTER_SLOT_DURATION env var)"

    # Validate that commiters + aggregators <= operators
    total_special_roles=$((commiters + aggregators))
    if [ "$total_special_roles" -gt "$operators" ]; then
        print_error "Total commiters ($commiters) + aggregators ($aggregators) cannot exceed total operators ($operators)"
        exit 1
    fi

    if [ "$operators" -gt $MAX_OPERATORS ]; then
        print_error "Maximum $MAX_OPERATORS operators supported. Requested: $operators"
        exit 1
    fi

    # Convert verification type to description
    local verification_desc
    case $verification_type in
        0) verification_desc="BLS-BN254-ZK" ;;
        1) verification_desc="BLS-BN254-SIMPLE" ;;
    esac

    print_status "Configuration (from environment variables):"
    print_status "  Operators: $operators (OPERATORS=${OPERATORS:-default})"
    print_status "  Committers: $commiters (COMMITERS=${COMMITERS:-default})"
    print_status "  Aggregators: $aggregators (AGGREGATORS=${AGGREGATORS:-default})"
    print_status "  Regular signers: $((operators - total_special_roles))"
    print_status "  Verification type: $verification_type ($verification_desc) (VERIFICATION_TYPE=${VERIFICATION_TYPE:-default})"
    print_status "  Epoch size: $epoch_size slots (EPOCH_TIME=${EPOCH_TIME:-default})"
    print_status "  Block time: $block_time seconds (BLOCK_TIME=${BLOCK_TIME:-default})"
    print_status "  Finality blocks: $finality_blocks (FINALITY_BLOCKS=${FINALITY_BLOCKS:-default})"
    print_status "  Committer slot duration: $committer_slot_duration seconds (COMMITTER_SLOT_DURATION=${COMMITTER_SLOT_DURATION:-default})"
    print_status "  Storage type: ${STORAGE_TYPE:-default (bbolt)} (STORAGE_TYPE=${STORAGE_TYPE:-default})"
}

# Function to generate Docker Compose file
generate_docker_compose() {
    local operators=$1
    local commiters=$2
    local aggregators=$3
    local verification_type=$4
    local epoch_size=$5
    local block_time=$6
    local finality_blocks=$7
    local committer_slot_duration=$8

    local network_dir="temp-network"

    if [ -d "$network_dir" ]; then
        print_status "Cleaning up existing $network_dir directory..."
        rm -rf "$network_dir"
    fi

    mkdir -p "$network_dir/deploy-data"
    # Ensure deploy-data directory is writable for Docker containers
    chmod 777 "$network_dir/deploy-data"

    # Create cache and broadcast directories with proper permissions
    print_status "Creating out, cache and broadcast directories..."
    mkdir -p "$network_dir/out" "$network_dir/cache" "$network_dir/broadcast"
    chmod 777 "$network_dir/out" "$network_dir/cache" "$network_dir/broadcast"

    local deploy_config_src="contracts/script/my-relay-deploy.toml"
    local deploy_config_dst="$network_dir/my-relay-deploy.toml"
    if [ ! -f "$deploy_config_src" ]; then
        print_error "Deployment config not found at $deploy_config_src"
        exit 1
    fi
    print_status "Copying deployment config to $deploy_config_dst"
    cp "$deploy_config_src" "$deploy_config_dst"

    for i in $(seq 1 $operators); do
        local storage_dir="$network_dir/data-$(printf "%02d" $i)"
        mkdir -p "$storage_dir"
        # Make sure the directory is writable
        chmod 777 "$storage_dir"
    done

    local anvil_port=8545
    local anvil_settlement_port=8546
    local relay_start_port=8081
    local sum_start_port=9091

    # Calculate timestamp as current unix timestamp + 5 seconds
    local timestamp=$(($(date +%s) + 5))

    cat > "$network_dir/docker-compose.yml" << EOF
services:
  # Main Anvil local Ethereum network (Chain ID: 31337)
  anvil:
    image: ghcr.io/foundry-rs/foundry:v1.4.3
    container_name: symbiotic-anvil
    entrypoint: ["anvil"]
    command: "--port 8545 --chain-id 31337 --timestamp $timestamp --auto-impersonate --slots-in-an-epoch $finality_blocks --accounts 10 --balance 10000 --gas-limit 30000000"
    environment:
      - ANVIL_IP_ADDR=0.0.0.0
    ports:
      - "8545:8545"
    networks:
      - symbiotic-network
    healthcheck:
      test: ["CMD", "cast", "client", "--rpc-url", "http://localhost:8545"]
      interval: 2s
      timeout: 1s
      retries: 10

  # Settlement Anvil local Ethereum network (Chain ID: 31338)
  anvil-settlement:
    image: ghcr.io/foundry-rs/foundry:v1.4.3
    container_name: symbiotic-anvil-settlement
    entrypoint: ["anvil"]
    command: "--port 8546 --chain-id 31338 --timestamp $timestamp --auto-impersonate --slots-in-an-epoch $finality_blocks --accounts 10 --balance 10000 --gas-limit 30000000"
    environment:
      - ANVIL_IP_ADDR=0.0.0.0
    ports:
      - "8546:8546"
    networks:
      - symbiotic-network
    healthcheck:
      test: ["CMD", "cast", "client", "--rpc-url", "http://localhost:8546"]
      interval: 2s
      timeout: 1s
      retries: 10

  # Contract deployment service for main chain
  deployer:
    build:
      context: ..
      dockerfile: scripts/deployer.Dockerfile
    image: symbiotic-deployer
    container_name: symbiotic-deployer
    user: "1000:1000"
    volumes:
      - ../contracts/:/app
      - ../scripts:/app/deploy-scripts
      - ../temp-network:/app/temp-network
      - ./cache:/app/cache
      - ./broadcast:/app/broadcast
      - ./out:/app/out
      - ./deploy-data:/deploy-data
      - ./my-relay-deploy.toml:/my-relay-deploy.toml
    working_dir: /app
    command: ./deploy-scripts/deploy.sh
    depends_on:
      anvil:
        condition: service_healthy
      anvil-settlement:
        condition: service_healthy
    networks:
      - symbiotic-network
    environment:
      - OPERATOR_COUNT=$operators
      - VERIFICATION_TYPE=$verification_type
      - BLOCK_TIME=$block_time
      - EPOCH_TIME=$epoch_size
      - FOUNDRY_CACHE_PATH=/tmp/.foundry-cache
      - NUM_AGGREGATORS=$aggregators
      - NUM_COMMITTERS=$commiters
      - COMMITTER_SLOT_DURATION=$committer_slot_duration

  # Genesis generation service
  genesis-generator:
    image: relay_sidecar:dev
    container_name: symbiotic-genesis-generator
    volumes:
      - ../:/workspace
      - ./deploy-data:/deploy-data
    working_dir: /workspace
    command: ./scripts/genesis-generator.sh
    depends_on:
      deployer:
        condition: service_completed_successfully
    networks:
      - symbiotic-network

EOF

    local committer_count=0
    local aggregator_count=0
    local signer_count=0

    # Calculate symb private key properly
    # ECDSA secp256k1 private keys must be 32 bytes (64 hex chars) and within range [1, n-1]
    # where n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
    BASE_PRIVATE_KEY=1000000000000000000

    for i in $(seq 1 $operators); do
        local port=$((relay_start_port + i - 1))
        local storage_dir="data-$(printf "%02d" $i)"
        local key_index=$((i - 1))

        SYMB_PRIVATE_KEY_DECIMAL=$(($BASE_PRIVATE_KEY + $key_index))
        SYMB_SECONDARY_PRIVATE_KEY_DECIMAL=$(($BASE_PRIVATE_KEY + $key_index + 10000))
        SYMB_PRIVATE_KEY_HEX=$(printf "%064x" $SYMB_PRIVATE_KEY_DECIMAL)
        SYMB_SECONDARY_PRIVATE_KEY_HEX=$(printf "%064x" $SYMB_SECONDARY_PRIVATE_KEY_DECIMAL)
        SYMB_BLS12381_PRIVATE_KEY_DECIMAL=$(($BASE_PRIVATE_KEY + $key_index + 20000))
        SYMB_BLS12381_PRIVATE_KEY_HEX=$(printf "%064x" $SYMB_BLS12381_PRIVATE_KEY_DECIMAL)

        # Validate ECDSA secp256k1 private key range (must be between 1 and n-1)
        # Maximum valid key: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140
        if [ $SYMB_PRIVATE_KEY_DECIMAL -eq 0 ]; then
            echo "ERROR: Generated private key is zero (invalid for ECDSA)"
            exit 1
        fi

        # Set circuits directory parameter based on verification type
        if [ "$verification_type" = "0" ]; then
            circuits_param="/app/circuits"
        else
            circuits_param=""
        fi

        cat >> "$network_dir/docker-compose.yml" << EOF

  # Relay sidecar $i
  relay-sidecar-$i:
    image: relay_sidecar:dev
    container_name: symbiotic-relay-$i
    command:
      - sh
      - -c
      - "chmod 777 /app/$storage_dir /deploy-data 2>/dev/null || true && /workspace/scripts/sidecar-start.sh symb/0/15/0x$SYMB_PRIVATE_KEY_HEX,symb/0/11/0x$SYMB_SECONDARY_PRIVATE_KEY_HEX,symb/2/1/0x$SYMB_BLS12381_PRIVATE_KEY_HEX,symb/1/0/0x$SYMB_PRIVATE_KEY_HEX,evm/1/31337/0x$SYMB_PRIVATE_KEY_HEX,evm/1/31338/0x$SYMB_PRIVATE_KEY_HEX,p2p/1/1/$SYMB_PRIVATE_KEY_HEX /app/$storage_dir $circuits_param"
    ports:
      - "$port:8080"
    volumes:
      - ../:/workspace
      - ./$storage_dir:/app/$storage_dir
      - ./deploy-data:/deploy-data
EOF

        # Add circuits volume only if verification type is 0
        if [ "$verification_type" = "0" ]; then
            cat >> "$network_dir/docker-compose.yml" << EOF
      - ./circuits:/app/circuits
EOF
        fi

        cat >> "$network_dir/docker-compose.yml" << EOF
    depends_on:
      genesis-generator:
        condition: service_completed_successfully
    networks:
      - symbiotic-network
    restart: unless-stopped
    environment:
      - MAX_VALIDATORS=10
      - STORAGE_TYPE=${STORAGE_TYPE:-}
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/healthz"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

EOF
    done

    # Extra relay for testing (not part of validator set)
    local extra_idx=$((operators + 1))
    local extra_port=$((relay_start_port + operators))
    local extra_storage_dir="data-$(printf "%02d" $extra_idx)"
    local extra_key_decimal=$((BASE_PRIVATE_KEY + operators))
    local extra_secondary_key_decimal=$((BASE_PRIVATE_KEY + operators + 10000))
    local extra_bls12381_key_decimal=$((BASE_PRIVATE_KEY + operators + 20000))
    local extra_key_hex=$(printf "%064x" $extra_key_decimal)
    local extra_secondary_key_hex=$(printf "%064x" $extra_secondary_key_decimal)
    local extra_bls12381_key_hex=$(printf "%064x" $extra_bls12381_key_decimal)

    mkdir -p "$network_dir/$extra_storage_dir"
    chmod 777 "$network_dir/$extra_storage_dir"

    cat >> "$network_dir/docker-compose.yml" << EOF

  # Extra relay (not in validator set, for testing)
  relay-sidecar-extra:
    image: relay_sidecar:dev
    container_name: symbiotic-relay-extra
    command:
      - sh
      - -c
      - "chmod 777 /app/$extra_storage_dir /deploy-data 2>/dev/null || true && /workspace/scripts/sidecar-start.sh symb/0/15/0x$extra_key_hex,symb/0/11/0x$extra_secondary_key_hex,symb/2/1/0x$extra_bls12381_key_hex,symb/1/0/0x$extra_key_hex,evm/1/31337/0x$extra_key_hex,evm/1/31338/0x$extra_key_hex,p2p/1/1/$extra_key_hex /app/$extra_storage_dir $circuits_param"
    ports:
      - "$extra_port:8080"
    volumes:
      - ../:/workspace
      - ./$extra_storage_dir:/app/$extra_storage_dir
      - ./deploy-data:/deploy-data
EOF

    if [ "$verification_type" = "0" ]; then
        cat >> "$network_dir/docker-compose.yml" << EOF
      - ./circuits:/app/circuits
EOF
    fi

    cat >> "$network_dir/docker-compose.yml" << EOF
    depends_on:
      genesis-generator:
        condition: service_completed_successfully
    networks:
      - symbiotic-network
    restart: unless-stopped
    environment:
      - MAX_VALIDATORS=10
      - STORAGE_TYPE=${STORAGE_TYPE:-}
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/healthz"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

EOF

    cat >> "$network_dir/docker-compose.yml" << EOF

networks:
  symbiotic-network:
    driver: bridge

EOF
}


# Main execution
main() {
    print_header "Symbiotic Network Generator"

    # Check if required tools are available
    if ! command -v docker &> /dev/null; then
        print_error "Docker is not installed or not in PATH"
        exit 1
    fi

    if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
        print_error "Docker Compose is not installed or not in PATH"
        exit 1
    fi

    get_config_from_env


    print_status "Generating Docker Compose configuration..."
    print_status "Creating $operators new operator accounts..."
    generate_docker_compose "$operators" "$commiters" "$aggregators" "$verification_type" "$epoch_size" "$block_time" "$finality_blocks" "$committer_slot_duration"
}

main "$@"
```

## File: e2e/scripts/genesis-generator.sh

```bash
#!/bin/sh

echo 'Waiting for deployment completion...'
until [ -f /deploy-data/deployment-complete.marker ]; do sleep 2; done

DRIVER_ADDRESS=0x43C27243F96591892976FFf886511807B65a33d5

MAX_RETRIES=50
RETRY_DELAY=2
attempt=1

while [ $attempt -le $MAX_RETRIES ]; do
    echo "Attempt $attempt of $MAX_RETRIES: Generating network genesis..."

    if /app/relay_utils network \
            --chains http://anvil:8545,http://anvil-settlement:8546 \
            --driver.address "$DRIVER_ADDRESS" \
            --driver.chainid 31337 \
          generate-genesis \
            --commit \
            --secret-keys 31337:0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80,31338:0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80; then
        echo 'Genesis generation completed successfully!'

        # Create genesis completion marker
        echo "$(date): Genesis generation completed successfully" > /deploy-data/genesis-complete.marker
        echo "Genesis completion marker created"

        echo "Waiting few seconds before exiting..."
        sleep 5

        exit 0
    else
        echo "Genesis generation failed on attempt $attempt"
        if [ $attempt -lt $MAX_RETRIES ]; then
            echo "Waiting $RETRY_DELAY seconds before retry..."
            sleep $RETRY_DELAY
        else
            echo "All $MAX_RETRIES attempts failed. Exiting with error."
            exit 1
        fi
        attempt=$((attempt + 1))
    fi
done
```

## File: e2e/scripts/sidecar-start.sh

```bash
#!/bin/sh

DRIVER_ADDRESS=0x43C27243F96591892976FFf886511807B65a33d5

cat > /tmp/sidecar.yaml << EOFCONFIG
# Logging
log:
  level: "debug"
  mode: "json"

# API Server Configuration
api:
  listen: ":8080"
  http-gateway: true

# Metrics Configuration
metrics:
  pprof: true

# Driver Contract
driver:
  chain-id: 31337
  address: "$DRIVER_ADDRESS"

# P2P Configuration
p2p:
  listen: "/ip4/0.0.0.0/tcp/8880"
  bootnodes:
    - /dns4/relay-sidecar-1/tcp/8880/p2p/16Uiu2HAmFUiPYAJ7bE88Q8d7Kznrw5ifrje2e5QFyt7uFPk2G3iR
  dht-mode: "server"
  mdns: true

# EVM Configuration
evm:
  chains:
    - "http://anvil:8545"
    - "http://anvil-settlement:8546"
  max-calls: 30

# Retention config
retention:
  valset-epochs: 1000
  signature-epochs: 1000
  proof-epochs: 1000

sync:
  enabled: true
  period: 5s
  timeout: 1m
  epochs: 1000

pruner:
  enabled: true
  interval: 1m

tracing:
  enabled: false
  endpoint: "jaeger:4317"
  sample-rate: 1.0

EOFCONFIG

if [ -n "$STORAGE_TYPE" ]; then
  echo "storage-type: \"$STORAGE_TYPE\"" >> /tmp/sidecar.yaml
fi

# Ensure environment variables are explicitly preserved
export MAX_VALIDATORS="${MAX_VALIDATORS:-}"

# Handle optional circuits directory parameter
if [ -n "$3" ] && [ -d "$3" ]; then
    echo "Using circuits directory: $3"
    echo "Starting relay_sidecar with MAX_VALIDATORS=$MAX_VALIDATORS"
    exec /app/relay_sidecar --config /tmp/sidecar.yaml --secret-keys "$1" --storage-dir "$2" --circuits-dir "$3"
else
    echo "No circuits directory provided or directory doesn't exist, running without circuits"
    echo "Starting relay_sidecar with MAX_VALIDATORS=$MAX_VALIDATORS"
    exec /app/relay_sidecar --config /tmp/sidecar.yaml --secret-keys "$1" --storage-dir "$2"
fi
```

## File: e2e/tests/evm/abi/IOptInService.abi.json

```json
[
    {
        "type": "function",
        "name": "WHERE_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "WHO_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "increaseNonce",
        "inputs": [
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "isOptedIn",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOptedInAt",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "nonces",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "optIn",
        "inputs": [
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "optIn",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "deadline",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "signature",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "optOut",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "deadline",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "signature",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "optOut",
        "inputs": [
            {
                "name": "where",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "IncreaseNonce",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "OptIn",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "OptOut",
        "inputs": [
            {
                "name": "who",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "where",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "AlreadyOptedIn",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ExpiredSignature",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidSignature",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotOptedIn",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotWhereEntity",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotWho",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OptOutCooldown",
        "inputs": []
    }
]
```

## File: e2e/tests/evm/abi/MockERC20.abi.json

```json
[
    {
        "type": "constructor",
        "inputs": [
            {
                "name": "name",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "symbol",
                "type": "string",
                "internalType": "string"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "allowance",
        "inputs": [
            {
                "name": "owner",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "spender",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "approve",
        "inputs": [
            {
                "name": "spender",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "value",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "balanceOf",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "decimals",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "name",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "string",
                "internalType": "string"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "symbol",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "string",
                "internalType": "string"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "totalSupply",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "transfer",
        "inputs": [
            {
                "name": "to",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "value",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "transferFrom",
        "inputs": [
            {
                "name": "from",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "to",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "value",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "Approval",
        "inputs": [
            {
                "name": "owner",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "spender",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "value",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Transfer",
        "inputs": [
            {
                "name": "from",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "to",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "value",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "ERC20InsufficientAllowance",
        "inputs": [
            {
                "name": "spender",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "allowance",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "needed",
                "type": "uint256",
                "internalType": "uint256"
            }
        ]
    },
    {
        "type": "error",
        "name": "ERC20InsufficientBalance",
        "inputs": [
            {
                "name": "sender",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "balance",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "needed",
                "type": "uint256",
                "internalType": "uint256"
            }
        ]
    },
    {
        "type": "error",
        "name": "ERC20InvalidApprover",
        "inputs": [
            {
                "name": "approver",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "ERC20InvalidReceiver",
        "inputs": [
            {
                "name": "receiver",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "ERC20InvalidSender",
        "inputs": [
            {
                "name": "sender",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "ERC20InvalidSpender",
        "inputs": [
            {
                "name": "spender",
                "type": "address",
                "internalType": "address"
            }
        ]
    }
]
```

## File: e2e/tests/evm/abi/OpNetVaultAutoDeployLogic.abi.json

```json
[
    {
        "type": "function",
        "name": "_validateConfig",
        "inputs": [
            {
                "name": "config",
                "type": "tuple",
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getAutoDeployConfig",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getAutoDeployedVault",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getDelegatorParams",
        "inputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            },
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorNetworkSpecificDelegatorParams",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "defaultAdminRoleHolder",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "hook",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "hookSetRoleHolder",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSlasherParams",
        "inputs": [
            {
                "name": "isBurnerHook",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSlasherParams",
        "inputs": [
            {
                "name": "config",
                "type": "tuple",
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVaultParams",
        "inputs": [
            {
                "name": "config",
                "type": "tuple",
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVaultParams",
        "inputs": [
            {
                "name": "params",
                "type": "tuple",
                "internalType": "struct IVault.InitParams",
                "components": [
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "depositWhitelist",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isDepositLimit",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "depositLimit",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "defaultAdminRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositWhitelistSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositorWhitelistRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "isDepositLimitSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositLimitSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVaultTokenizedParams",
        "inputs": [
            {
                "name": "baseParams",
                "type": "tuple",
                "internalType": "struct IVault.InitParams",
                "components": [
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "depositWhitelist",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isDepositLimit",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "depositLimit",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "defaultAdminRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositWhitelistSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositorWhitelistRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "isDepositLimitSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "depositLimitSetRoleHolder",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            },
            {
                "name": "name",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "symbol",
                "type": "string",
                "internalType": "string"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVetoSlasherParams",
        "inputs": [
            {
                "name": "isBurnerHook",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "vetoDuration",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "resolverSetEpochsDelay",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isAutoDeployEnabled",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSetMaxNetworkLimitHookEnabled",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "SetAutoDeployConfig",
        "inputs": [
            {
                "name": "config",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IOpNetVaultAutoDeploy.AutoDeployConfig",
                "components": [
                    {
                        "name": "epochDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "collateral",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "burner",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "withSlasher",
                        "type": "bool",
                        "internalType": "bool"
                    },
                    {
                        "name": "isBurnerHook",
                        "type": "bool",
                        "internalType": "bool"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetAutoDeployStatus",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetSetMaxNetworkLimitHookStatus",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "OpNetVaultAutoDeploy_InvalidBurnerHook",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OpNetVaultAutoDeploy_InvalidCollateral",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OpNetVaultAutoDeploy_InvalidEpochDuration",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OpNetVaultAutoDeploy_InvalidWithSlasher",
        "inputs": []
    }
]
```

## File: e2e/tests/evm/abi/Vault.abi.json

```json
[
    {
        "type": "constructor",
        "inputs": [
            {
                "name": "delegatorFactory",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "slasherFactory",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vaultFactory",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "DEFAULT_ADMIN_ROLE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "DELEGATOR_FACTORY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "DEPOSITOR_WHITELIST_ROLE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "DEPOSIT_LIMIT_SET_ROLE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "DEPOSIT_WHITELIST_SET_ROLE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "FACTORY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "IS_DEPOSIT_LIMIT_SET_ROLE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SLASHER_FACTORY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeBalanceOf",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeBalanceOfAt",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hints",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeShares",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeSharesAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeSharesOf",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeSharesOfAt",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeStake",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "activeStakeAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "burner",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "claim",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimBatch",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "epochs",
                "type": "uint256[]",
                "internalType": "uint256[]"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "collateral",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "currentEpoch",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "currentEpochStart",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "delegator",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "deposit",
        "inputs": [
            {
                "name": "onBehalfOf",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "depositedAmount",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "mintedShares",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "depositLimit",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "depositWhitelist",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "epochAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "epochDuration",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "epochDurationInit",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRoleAdmin",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "grantRole",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "hasRole",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "initialize",
        "inputs": [
            {
                "name": "initialVersion",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "owner_",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "isDelegatorInitialized",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isDepositLimit",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isDepositorWhitelisted",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "value",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isInitialized",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSlasherInitialized",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isWithdrawalsClaimed",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "value",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "migrate",
        "inputs": [
            {
                "name": "newVersion",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "nextEpochStart",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "onSlash",
        "inputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "captureTimestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "slashedAmount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "owner",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "previousEpochStart",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "redeem",
        "inputs": [
            {
                "name": "claimer",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "shares",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "withdrawnAssets",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "mintedShares",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "renounceOwnership",
        "inputs": [],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "renounceRole",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "callerConfirmation",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "revokeRole",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setDelegator",
        "inputs": [
            {
                "name": "delegator_",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setDepositLimit",
        "inputs": [
            {
                "name": "limit",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setDepositWhitelist",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setDepositorWhitelistStatus",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "status",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setIsDepositLimit",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setSlasher",
        "inputs": [
            {
                "name": "slasher_",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "slashableBalanceOf",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "slasher",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "staticDelegateCall",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "supportsInterface",
        "inputs": [
            {
                "name": "interfaceId",
                "type": "bytes4",
                "internalType": "bytes4"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "totalStake",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "transferOwnership",
        "inputs": [
            {
                "name": "newOwner",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "version",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint64",
                "internalType": "uint64"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "withdraw",
        "inputs": [
            {
                "name": "claimer",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "burnedShares",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "mintedShares",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "withdrawalShares",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "withdrawalSharesOf",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "withdrawals",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "withdrawalsOf",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "Claim",
        "inputs": [
            {
                "name": "claimer",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "recipient",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "epoch",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "ClaimBatch",
        "inputs": [
            {
                "name": "claimer",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "recipient",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "epochs",
                "type": "uint256[]",
                "indexed": false,
                "internalType": "uint256[]"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Deposit",
        "inputs": [
            {
                "name": "depositor",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "onBehalfOf",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "shares",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Initialized",
        "inputs": [
            {
                "name": "version",
                "type": "uint64",
                "indexed": false,
                "internalType": "uint64"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "OnSlash",
        "inputs": [
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "captureTimestamp",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            },
            {
                "name": "slashedAmount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "OwnershipTransferred",
        "inputs": [
            {
                "name": "previousOwner",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "newOwner",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RoleAdminChanged",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            },
            {
                "name": "previousAdminRole",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            },
            {
                "name": "newAdminRole",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RoleGranted",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            },
            {
                "name": "account",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "sender",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RoleRevoked",
        "inputs": [
            {
                "name": "role",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            },
            {
                "name": "account",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "sender",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetDelegator",
        "inputs": [
            {
                "name": "delegator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetDepositLimit",
        "inputs": [
            {
                "name": "limit",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetDepositWhitelist",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetDepositorWhitelistStatus",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "status",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetIsDepositLimit",
        "inputs": [
            {
                "name": "status",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetSlasher",
        "inputs": [
            {
                "name": "slasher",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Withdraw",
        "inputs": [
            {
                "name": "withdrawer",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "claimer",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "burnedShares",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "mintedShares",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "AccessControlBadConfirmation",
        "inputs": []
    },
    {
        "type": "error",
        "name": "AccessControlUnauthorizedAccount",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "neededRole",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ]
    },
    {
        "type": "error",
        "name": "AddressEmptyCode",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "AddressInsufficientBalance",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "AlreadyClaimed",
        "inputs": []
    },
    {
        "type": "error",
        "name": "AlreadyInitialized",
        "inputs": []
    },
    {
        "type": "error",
        "name": "AlreadySet",
        "inputs": []
    },
    {
        "type": "error",
        "name": "CheckpointUnorderedInsertion",
        "inputs": []
    },
    {
        "type": "error",
        "name": "DelegatorAlreadyInitialized",
        "inputs": []
    },
    {
        "type": "error",
        "name": "DepositLimitReached",
        "inputs": []
    },
    {
        "type": "error",
        "name": "FailedInnerCall",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InsufficientClaim",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InsufficientDeposit",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InsufficientRedemption",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InsufficientWithdrawal",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidAccount",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidCaptureEpoch",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidClaimer",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidCollateral",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidDelegator",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidEpoch",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidEpochDuration",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidInitialization",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidLengthEpochs",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidOnBehalfOf",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidRecipient",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidSlasher",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "MathOverflowedMulDiv",
        "inputs": []
    },
    {
        "type": "error",
        "name": "MissingRoles",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NoPreviousEpoch",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotDelegator",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotFactory",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitialized",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitializing",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotSlasher",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotWhitelistedDepositor",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OwnableInvalidOwner",
        "inputs": [
            {
                "name": "owner",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "OwnableUnauthorizedAccount",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "ReentrancyGuardReentrantCall",
        "inputs": []
    },
    {
        "type": "error",
        "name": "SafeCastOverflowedUintDowncast",
        "inputs": [
            {
                "name": "bits",
                "type": "uint8",
                "internalType": "uint8"
            },
            {
                "name": "value",
                "type": "uint256",
                "internalType": "uint256"
            }
        ]
    },
    {
        "type": "error",
        "name": "SafeERC20FailedOperation",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "SlasherAlreadyInitialized",
        "inputs": []
    },
    {
        "type": "error",
        "name": "TooMuchRedeem",
        "inputs": []
    },
    {
        "type": "error",
        "name": "TooMuchWithdraw",
        "inputs": []
    }
]
```

## File: e2e/tests/evm/gen/mockERC20.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// MockERC20MetaData contains all meta data concerning the MockERC20 contract.
var MockERC20MetaData = &bind.MetaData{
	ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ERC20InsufficientAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"allowance\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"needed\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC20InsufficientBalance\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"balance\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"needed\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidSpender\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}]}]",
}
⋮----
// MockERC20ABI is the input ABI used to generate the binding from.
// Deprecated: Use MockERC20MetaData.ABI instead.
var MockERC20ABI = MockERC20MetaData.ABI
⋮----
// MockERC20 is an auto generated Go binding around an Ethereum contract.
type MockERC20 struct {
	MockERC20Caller     // Read-only binding to the contract
	MockERC20Transactor // Write-only binding to the contract
	MockERC20Filterer   // Log filterer for contract events
}
⋮----
MockERC20Caller     // Read-only binding to the contract
MockERC20Transactor // Write-only binding to the contract
MockERC20Filterer   // Log filterer for contract events
⋮----
// MockERC20Caller is an auto generated read-only Go binding around an Ethereum contract.
type MockERC20Caller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// MockERC20Transactor is an auto generated write-only Go binding around an Ethereum contract.
type MockERC20Transactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// MockERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
type MockERC20Filterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// MockERC20Session is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type MockERC20Session struct {
	Contract     *MockERC20        // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *MockERC20        // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// MockERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type MockERC20CallerSession struct {
	Contract *MockERC20Caller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts    // Call options to use throughout this session
}
⋮----
Contract *MockERC20Caller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts    // Call options to use throughout this session
⋮----
// MockERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type MockERC20TransactorSession struct {
	Contract     *MockERC20Transactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts    // Transaction auth options to use throughout this session
}
⋮----
Contract     *MockERC20Transactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts    // Transaction auth options to use throughout this session
⋮----
// MockERC20Raw is an auto generated low-level Go binding around an Ethereum contract.
type MockERC20Raw struct {
	Contract *MockERC20 // Generic contract binding to access the raw methods on
}
⋮----
Contract *MockERC20 // Generic contract binding to access the raw methods on
⋮----
// MockERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type MockERC20CallerRaw struct {
	Contract *MockERC20Caller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *MockERC20Caller // Generic read-only contract binding to access the raw methods on
⋮----
// MockERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type MockERC20TransactorRaw struct {
	Contract *MockERC20Transactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *MockERC20Transactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewMockERC20 creates a new instance of MockERC20, bound to a specific deployed contract.
func NewMockERC20(address common.Address, backend bind.ContractBackend) (*MockERC20, error)
⋮----
// NewMockERC20Caller creates a new read-only instance of MockERC20, bound to a specific deployed contract.
func NewMockERC20Caller(address common.Address, caller bind.ContractCaller) (*MockERC20Caller, error)
⋮----
// NewMockERC20Transactor creates a new write-only instance of MockERC20, bound to a specific deployed contract.
func NewMockERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*MockERC20Transactor, error)
⋮----
// NewMockERC20Filterer creates a new log filterer instance of MockERC20, bound to a specific deployed contract.
func NewMockERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*MockERC20Filterer, error)
⋮----
// bindMockERC20 binds a generic wrapper to an already deployed contract.
func bindMockERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_MockERC20 *MockERC20Raw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_MockERC20 *MockERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_MockERC20 *MockERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e.
//
// Solidity: function allowance(address owner, address spender) view returns(uint256)
func (_MockERC20 *MockERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error)
⋮----
var out []interface{}
⋮----
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
⋮----
// Solidity: function balanceOf(address account) view returns(uint256)
func (_MockERC20 *MockERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error)
⋮----
// Decimals is a free data retrieval call binding the contract method 0x313ce567.
⋮----
// Solidity: function decimals() view returns(uint8)
func (_MockERC20 *MockERC20Caller) Decimals(opts *bind.CallOpts) (uint8, error)
⋮----
// Name is a free data retrieval call binding the contract method 0x06fdde03.
⋮----
// Solidity: function name() view returns(string)
func (_MockERC20 *MockERC20Caller) Name(opts *bind.CallOpts) (string, error)
⋮----
// Symbol is a free data retrieval call binding the contract method 0x95d89b41.
⋮----
// Solidity: function symbol() view returns(string)
func (_MockERC20 *MockERC20Caller) Symbol(opts *bind.CallOpts) (string, error)
⋮----
// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd.
⋮----
// Solidity: function totalSupply() view returns(uint256)
func (_MockERC20 *MockERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error)
⋮----
// Approve is a paid mutator transaction binding the contract method 0x095ea7b3.
⋮----
// Solidity: function approve(address spender, uint256 value) returns(bool)
func (_MockERC20 *MockERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error)
⋮----
// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb.
⋮----
// Solidity: function transfer(address to, uint256 value) returns(bool)
⋮----
// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd.
⋮----
// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool)
func (_MockERC20 *MockERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error)
⋮----
// MockERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the MockERC20 contract.
type MockERC20ApprovalIterator struct {
	Event *MockERC20Approval // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *MockERC20Approval // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *MockERC20ApprovalIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *MockERC20ApprovalIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *MockERC20ApprovalIterator) Close() error
⋮----
// MockERC20Approval represents a Approval event raised by the MockERC20 contract.
type MockERC20Approval struct {
	Owner   common.Address
	Spender common.Address
	Value   *big.Int
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
⋮----
// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value)
func (_MockERC20 *MockERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*MockERC20ApprovalIterator, error)
⋮----
var ownerRule []interface{}
⋮----
var spenderRule []interface{}
⋮----
// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
⋮----
func (_MockERC20 *MockERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *MockERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
⋮----
func (_MockERC20 *MockERC20Filterer) ParseApproval(log types.Log) (*MockERC20Approval, error)
⋮----
// MockERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the MockERC20 contract.
type MockERC20TransferIterator struct {
	Event *MockERC20Transfer // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *MockERC20Transfer // Event containing the contract specifics and raw log
⋮----
// MockERC20Transfer represents a Transfer event raised by the MockERC20 contract.
type MockERC20Transfer struct {
	From  common.Address
	To    common.Address
	Value *big.Int
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
Raw   types.Log // Blockchain specific contextual infos
⋮----
// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
⋮----
// Solidity: event Transfer(address indexed from, address indexed to, uint256 value)
func (_MockERC20 *MockERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MockERC20TransferIterator, error)
⋮----
var fromRule []interface{}
⋮----
var toRule []interface{}
⋮----
// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
⋮----
func (_MockERC20 *MockERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *MockERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error)
⋮----
// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
⋮----
func (_MockERC20 *MockERC20Filterer) ParseTransfer(log types.Log) (*MockERC20Transfer, error)
```

## File: e2e/tests/evm/gen/opNetVaultAutoDeployLogic.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// IOpNetVaultAutoDeployAutoDeployConfig is an auto generated low-level Go binding around an user-defined struct.
type IOpNetVaultAutoDeployAutoDeployConfig struct {
	EpochDuration *big.Int
	Collateral    common.Address
	Burner        common.Address
	WithSlasher   bool
	IsBurnerHook  bool
}
⋮----
// IVaultInitParams is an auto generated low-level Go binding around an user-defined struct.
type IVaultInitParams struct {
	Collateral                    common.Address
	Burner                        common.Address
	EpochDuration                 *big.Int
	DepositWhitelist              bool
	IsDepositLimit                bool
	DepositLimit                  *big.Int
	DefaultAdminRoleHolder        common.Address
	DepositWhitelistSetRoleHolder common.Address
	DepositorWhitelistRoleHolder  common.Address
	IsDepositLimitSetRoleHolder   common.Address
	DepositLimitSetRoleHolder     common.Address
}
⋮----
// OpNetVaultAutoDeployLogicMetaData contains all meta data concerning the OpNetVaultAutoDeployLogic contract.
var OpNetVaultAutoDeployLogicMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"_validateConfig\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"outputs\":[],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAutoDeployConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAutoDeployedVault\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getDelegatorParams\",\"inputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorNetworkSpecificDelegatorParams\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"defaultAdminRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"hook\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"hookSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSlasherParams\",\"inputs\":[{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSlasherParams\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVaultParams\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVaultParams\",\"inputs\":[{\"name\":\"params\",\"type\":\"tuple\",\"internalType\":\"structIVault.InitParams\",\"components\":[{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"depositWhitelist\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDepositLimit\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"depositLimit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"defaultAdminRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositWhitelistSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositorWhitelistRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isDepositLimitSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositLimitSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVaultTokenizedParams\",\"inputs\":[{\"name\":\"baseParams\",\"type\":\"tuple\",\"internalType\":\"structIVault.InitParams\",\"components\":[{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"depositWhitelist\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDepositLimit\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"depositLimit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"defaultAdminRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositWhitelistSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositorWhitelistRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"isDepositLimitSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"depositLimitSetRoleHolder\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVetoSlasherParams\",\"inputs\":[{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"vetoDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"resolverSetEpochsDelay\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isAutoDeployEnabled\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSetMaxNetworkLimitHookEnabled\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"SetAutoDeployConfig\",\"inputs\":[{\"name\":\"config\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIOpNetVaultAutoDeploy.AutoDeployConfig\",\"components\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"collateral\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"burner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"withSlasher\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isBurnerHook\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetAutoDeployStatus\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetSetMaxNetworkLimitHookStatus\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"OpNetVaultAutoDeploy_InvalidBurnerHook\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OpNetVaultAutoDeploy_InvalidCollateral\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OpNetVaultAutoDeploy_InvalidEpochDuration\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OpNetVaultAutoDeploy_InvalidWithSlasher\",\"inputs\":[]}]",
}
⋮----
// OpNetVaultAutoDeployLogicABI is the input ABI used to generate the binding from.
// Deprecated: Use OpNetVaultAutoDeployLogicMetaData.ABI instead.
var OpNetVaultAutoDeployLogicABI = OpNetVaultAutoDeployLogicMetaData.ABI
⋮----
// OpNetVaultAutoDeployLogic is an auto generated Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogic struct {
	OpNetVaultAutoDeployLogicCaller     // Read-only binding to the contract
	OpNetVaultAutoDeployLogicTransactor // Write-only binding to the contract
	OpNetVaultAutoDeployLogicFilterer   // Log filterer for contract events
}
⋮----
OpNetVaultAutoDeployLogicCaller     // Read-only binding to the contract
OpNetVaultAutoDeployLogicTransactor // Write-only binding to the contract
OpNetVaultAutoDeployLogicFilterer   // Log filterer for contract events
⋮----
// OpNetVaultAutoDeployLogicCaller is an auto generated read-only Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogicCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// OpNetVaultAutoDeployLogicTransactor is an auto generated write-only Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogicTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OpNetVaultAutoDeployLogicFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type OpNetVaultAutoDeployLogicFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OpNetVaultAutoDeployLogicSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type OpNetVaultAutoDeployLogicSession struct {
	Contract     *OpNetVaultAutoDeployLogic // Generic contract binding to set the session for
	CallOpts     bind.CallOpts              // Call options to use throughout this session
	TransactOpts bind.TransactOpts          // Transaction auth options to use throughout this session
}
⋮----
Contract     *OpNetVaultAutoDeployLogic // Generic contract binding to set the session for
CallOpts     bind.CallOpts              // Call options to use throughout this session
TransactOpts bind.TransactOpts          // Transaction auth options to use throughout this session
⋮----
// OpNetVaultAutoDeployLogicCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type OpNetVaultAutoDeployLogicCallerSession struct {
	Contract *OpNetVaultAutoDeployLogicCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts                    // Call options to use throughout this session
}
⋮----
Contract *OpNetVaultAutoDeployLogicCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts                    // Call options to use throughout this session
⋮----
// OpNetVaultAutoDeployLogicTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type OpNetVaultAutoDeployLogicTransactorSession struct {
	Contract     *OpNetVaultAutoDeployLogicTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts                    // Transaction auth options to use throughout this session
}
⋮----
Contract     *OpNetVaultAutoDeployLogicTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts                    // Transaction auth options to use throughout this session
⋮----
// OpNetVaultAutoDeployLogicRaw is an auto generated low-level Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogicRaw struct {
	Contract *OpNetVaultAutoDeployLogic // Generic contract binding to access the raw methods on
}
⋮----
Contract *OpNetVaultAutoDeployLogic // Generic contract binding to access the raw methods on
⋮----
// OpNetVaultAutoDeployLogicCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogicCallerRaw struct {
	Contract *OpNetVaultAutoDeployLogicCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *OpNetVaultAutoDeployLogicCaller // Generic read-only contract binding to access the raw methods on
⋮----
// OpNetVaultAutoDeployLogicTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type OpNetVaultAutoDeployLogicTransactorRaw struct {
	Contract *OpNetVaultAutoDeployLogicTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *OpNetVaultAutoDeployLogicTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewOpNetVaultAutoDeployLogic creates a new instance of OpNetVaultAutoDeployLogic, bound to a specific deployed contract.
func NewOpNetVaultAutoDeployLogic(address common.Address, backend bind.ContractBackend) (*OpNetVaultAutoDeployLogic, error)
⋮----
// NewOpNetVaultAutoDeployLogicCaller creates a new read-only instance of OpNetVaultAutoDeployLogic, bound to a specific deployed contract.
func NewOpNetVaultAutoDeployLogicCaller(address common.Address, caller bind.ContractCaller) (*OpNetVaultAutoDeployLogicCaller, error)
⋮----
// NewOpNetVaultAutoDeployLogicTransactor creates a new write-only instance of OpNetVaultAutoDeployLogic, bound to a specific deployed contract.
func NewOpNetVaultAutoDeployLogicTransactor(address common.Address, transactor bind.ContractTransactor) (*OpNetVaultAutoDeployLogicTransactor, error)
⋮----
// NewOpNetVaultAutoDeployLogicFilterer creates a new log filterer instance of OpNetVaultAutoDeployLogic, bound to a specific deployed contract.
func NewOpNetVaultAutoDeployLogicFilterer(address common.Address, filterer bind.ContractFilterer) (*OpNetVaultAutoDeployLogicFilterer, error)
⋮----
// bindOpNetVaultAutoDeployLogic binds a generic wrapper to an already deployed contract.
func bindOpNetVaultAutoDeployLogic(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// ValidateConfig is a free data retrieval call binding the contract method 0x97c1ad57.
//
// Solidity: function _validateConfig((uint48,address,address,bool,bool) config) view returns()
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) ValidateConfig(opts *bind.CallOpts, config IOpNetVaultAutoDeployAutoDeployConfig) error
⋮----
var out []interface{}
⋮----
// GetAutoDeployConfig is a free data retrieval call binding the contract method 0xa149c987.
⋮----
// Solidity: function getAutoDeployConfig() view returns((uint48,address,address,bool,bool))
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetAutoDeployConfig(opts *bind.CallOpts) (IOpNetVaultAutoDeployAutoDeployConfig, error)
⋮----
// GetAutoDeployedVault is a free data retrieval call binding the contract method 0x2b2fd015.
⋮----
// Solidity: function getAutoDeployedVault(address operator) view returns(address)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetAutoDeployedVault(opts *bind.CallOpts, operator common.Address) (common.Address, error)
⋮----
// GetDelegatorParams is a free data retrieval call binding the contract method 0x4c0098f2.
⋮----
// Solidity: function getDelegatorParams((uint48,address,address,bool,bool) , address operator) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetDelegatorParams(opts *bind.CallOpts, arg0 IOpNetVaultAutoDeployAutoDeployConfig, operator common.Address) (uint64, []byte, error)
⋮----
// GetOperatorNetworkSpecificDelegatorParams is a free data retrieval call binding the contract method 0xb21fe3ed.
⋮----
// Solidity: function getOperatorNetworkSpecificDelegatorParams(address operator, address defaultAdminRoleHolder, address hook, address hookSetRoleHolder) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetOperatorNetworkSpecificDelegatorParams(opts *bind.CallOpts, operator common.Address, defaultAdminRoleHolder common.Address, hook common.Address, hookSetRoleHolder common.Address) (uint64, []byte, error)
⋮----
// GetSlasherParams is a free data retrieval call binding the contract method 0x2b45a2f9.
⋮----
// Solidity: function getSlasherParams(bool isBurnerHook) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetSlasherParams(opts *bind.CallOpts, isBurnerHook bool) (uint64, []byte, error)
⋮----
// GetSlasherParams0 is a free data retrieval call binding the contract method 0xac296ec2.
⋮----
// Solidity: function getSlasherParams((uint48,address,address,bool,bool) config) view returns(bool, uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetSlasherParams0(opts *bind.CallOpts, config IOpNetVaultAutoDeployAutoDeployConfig) (bool, uint64, []byte, error)
⋮----
// GetVaultParams is a free data retrieval call binding the contract method 0xea8ea5c7.
⋮----
// Solidity: function getVaultParams((uint48,address,address,bool,bool) config) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetVaultParams(opts *bind.CallOpts, config IOpNetVaultAutoDeployAutoDeployConfig) (uint64, []byte, error)
⋮----
// GetVaultParams0 is a free data retrieval call binding the contract method 0x168432da.
⋮----
// Solidity: function getVaultParams((address,address,uint48,bool,bool,uint256,address,address,address,address,address) params) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetVaultParams0(opts *bind.CallOpts, params IVaultInitParams) (uint64, []byte, error)
⋮----
// GetVaultTokenizedParams is a free data retrieval call binding the contract method 0x49b6cfc6.
⋮----
// Solidity: function getVaultTokenizedParams((address,address,uint48,bool,bool,uint256,address,address,address,address,address) baseParams, string name, string symbol) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetVaultTokenizedParams(opts *bind.CallOpts, baseParams IVaultInitParams, name string, symbol string) (uint64, []byte, error)
⋮----
// GetVetoSlasherParams is a free data retrieval call binding the contract method 0xae500700.
⋮----
// Solidity: function getVetoSlasherParams(bool isBurnerHook, uint48 vetoDuration, uint256 resolverSetEpochsDelay) view returns(uint64, bytes)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) GetVetoSlasherParams(opts *bind.CallOpts, isBurnerHook bool, vetoDuration *big.Int, resolverSetEpochsDelay *big.Int) (uint64, []byte, error)
⋮----
// IsAutoDeployEnabled is a free data retrieval call binding the contract method 0xdeb018dc.
⋮----
// Solidity: function isAutoDeployEnabled() view returns(bool)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) IsAutoDeployEnabled(opts *bind.CallOpts) (bool, error)
⋮----
// IsSetMaxNetworkLimitHookEnabled is a free data retrieval call binding the contract method 0xe77b136d.
⋮----
// Solidity: function isSetMaxNetworkLimitHookEnabled() view returns(bool)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicCaller) IsSetMaxNetworkLimitHookEnabled(opts *bind.CallOpts) (bool, error)
⋮----
// OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator is returned from FilterSetAutoDeployConfig and is used to iterate over the raw logs and unpacked data for SetAutoDeployConfig events raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator struct {
	Event *OpNetVaultAutoDeployLogicSetAutoDeployConfig // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OpNetVaultAutoDeployLogicSetAutoDeployConfig // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator) Close() error
⋮----
// OpNetVaultAutoDeployLogicSetAutoDeployConfig represents a SetAutoDeployConfig event raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetAutoDeployConfig struct {
	Config IOpNetVaultAutoDeployAutoDeployConfig
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
Raw    types.Log // Blockchain specific contextual infos
⋮----
// FilterSetAutoDeployConfig is a free log retrieval operation binding the contract event 0x77e47da1f6025186b00adae5351f623eba1ab5151f7d15bc44c6a39be86e6c05.
⋮----
// Solidity: event SetAutoDeployConfig((uint48,address,address,bool,bool) config)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) FilterSetAutoDeployConfig(opts *bind.FilterOpts) (*OpNetVaultAutoDeployLogicSetAutoDeployConfigIterator, error)
⋮----
// WatchSetAutoDeployConfig is a free log subscription operation binding the contract event 0x77e47da1f6025186b00adae5351f623eba1ab5151f7d15bc44c6a39be86e6c05.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) WatchSetAutoDeployConfig(opts *bind.WatchOpts, sink chan<- *OpNetVaultAutoDeployLogicSetAutoDeployConfig) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseSetAutoDeployConfig is a log parse operation binding the contract event 0x77e47da1f6025186b00adae5351f623eba1ab5151f7d15bc44c6a39be86e6c05.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) ParseSetAutoDeployConfig(log types.Log) (*OpNetVaultAutoDeployLogicSetAutoDeployConfig, error)
⋮----
// OpNetVaultAutoDeployLogicSetAutoDeployStatusIterator is returned from FilterSetAutoDeployStatus and is used to iterate over the raw logs and unpacked data for SetAutoDeployStatus events raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetAutoDeployStatusIterator struct {
	Event *OpNetVaultAutoDeployLogicSetAutoDeployStatus // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OpNetVaultAutoDeployLogicSetAutoDeployStatus // Event containing the contract specifics and raw log
⋮----
// OpNetVaultAutoDeployLogicSetAutoDeployStatus represents a SetAutoDeployStatus event raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetAutoDeployStatus struct {
	Status bool
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetAutoDeployStatus is a free log retrieval operation binding the contract event 0x8951c46d8957e007c4f4222e768ee8e59bb367b6c72569e92e337a5b194bf04d.
⋮----
// Solidity: event SetAutoDeployStatus(bool status)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) FilterSetAutoDeployStatus(opts *bind.FilterOpts) (*OpNetVaultAutoDeployLogicSetAutoDeployStatusIterator, error)
⋮----
// WatchSetAutoDeployStatus is a free log subscription operation binding the contract event 0x8951c46d8957e007c4f4222e768ee8e59bb367b6c72569e92e337a5b194bf04d.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) WatchSetAutoDeployStatus(opts *bind.WatchOpts, sink chan<- *OpNetVaultAutoDeployLogicSetAutoDeployStatus) (event.Subscription, error)
⋮----
// ParseSetAutoDeployStatus is a log parse operation binding the contract event 0x8951c46d8957e007c4f4222e768ee8e59bb367b6c72569e92e337a5b194bf04d.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) ParseSetAutoDeployStatus(log types.Log) (*OpNetVaultAutoDeployLogicSetAutoDeployStatus, error)
⋮----
// OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatusIterator is returned from FilterSetSetMaxNetworkLimitHookStatus and is used to iterate over the raw logs and unpacked data for SetSetMaxNetworkLimitHookStatus events raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatusIterator struct {
	Event *OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus // Event containing the contract specifics and raw log
⋮----
// OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus represents a SetSetMaxNetworkLimitHookStatus event raised by the OpNetVaultAutoDeployLogic contract.
type OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus struct {
	Status bool
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetSetMaxNetworkLimitHookStatus is a free log retrieval operation binding the contract event 0x8bd71bb92871c7cb65d4ba7554dadeb02abcf4d9e99aff8367714c5a15bd019c.
⋮----
// Solidity: event SetSetMaxNetworkLimitHookStatus(bool status)
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) FilterSetSetMaxNetworkLimitHookStatus(opts *bind.FilterOpts) (*OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatusIterator, error)
⋮----
// WatchSetSetMaxNetworkLimitHookStatus is a free log subscription operation binding the contract event 0x8bd71bb92871c7cb65d4ba7554dadeb02abcf4d9e99aff8367714c5a15bd019c.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) WatchSetSetMaxNetworkLimitHookStatus(opts *bind.WatchOpts, sink chan<- *OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus) (event.Subscription, error)
⋮----
// ParseSetSetMaxNetworkLimitHookStatus is a log parse operation binding the contract event 0x8bd71bb92871c7cb65d4ba7554dadeb02abcf4d9e99aff8367714c5a15bd019c.
⋮----
func (_OpNetVaultAutoDeployLogic *OpNetVaultAutoDeployLogicFilterer) ParseSetSetMaxNetworkLimitHookStatus(log types.Log) (*OpNetVaultAutoDeployLogicSetSetMaxNetworkLimitHookStatus, error)
```

## File: e2e/tests/evm/gen/optInService.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// OptInServiceMetaData contains all meta data concerning the OptInService contract.
var OptInServiceMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"WHERE_REGISTRY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"WHO_REGISTRY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"increaseNonce\",\"inputs\":[{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isOptedIn\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOptedInAt\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optIn\",\"inputs\":[{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"optIn\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"deadline\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"optOut\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"deadline\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"optOut\",\"inputs\":[{\"name\":\"where\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"IncreaseNonce\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OptIn\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OptOut\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"where\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyOptedIn\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpiredSignature\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignature\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotOptedIn\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotWhereEntity\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotWho\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OptOutCooldown\",\"inputs\":[]}]",
}
⋮----
// OptInServiceABI is the input ABI used to generate the binding from.
// Deprecated: Use OptInServiceMetaData.ABI instead.
var OptInServiceABI = OptInServiceMetaData.ABI
⋮----
// OptInService is an auto generated Go binding around an Ethereum contract.
type OptInService struct {
	OptInServiceCaller     // Read-only binding to the contract
	OptInServiceTransactor // Write-only binding to the contract
	OptInServiceFilterer   // Log filterer for contract events
}
⋮----
OptInServiceCaller     // Read-only binding to the contract
OptInServiceTransactor // Write-only binding to the contract
OptInServiceFilterer   // Log filterer for contract events
⋮----
// OptInServiceCaller is an auto generated read-only Go binding around an Ethereum contract.
type OptInServiceCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// OptInServiceTransactor is an auto generated write-only Go binding around an Ethereum contract.
type OptInServiceTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OptInServiceFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type OptInServiceFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OptInServiceSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type OptInServiceSession struct {
	Contract     *OptInService     // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *OptInService     // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// OptInServiceCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type OptInServiceCallerSession struct {
	Contract *OptInServiceCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts       // Call options to use throughout this session
}
⋮----
Contract *OptInServiceCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts       // Call options to use throughout this session
⋮----
// OptInServiceTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type OptInServiceTransactorSession struct {
	Contract     *OptInServiceTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts       // Transaction auth options to use throughout this session
}
⋮----
Contract     *OptInServiceTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts       // Transaction auth options to use throughout this session
⋮----
// OptInServiceRaw is an auto generated low-level Go binding around an Ethereum contract.
type OptInServiceRaw struct {
	Contract *OptInService // Generic contract binding to access the raw methods on
}
⋮----
Contract *OptInService // Generic contract binding to access the raw methods on
⋮----
// OptInServiceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type OptInServiceCallerRaw struct {
	Contract *OptInServiceCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *OptInServiceCaller // Generic read-only contract binding to access the raw methods on
⋮----
// OptInServiceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type OptInServiceTransactorRaw struct {
	Contract *OptInServiceTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *OptInServiceTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewOptInService creates a new instance of OptInService, bound to a specific deployed contract.
func NewOptInService(address common.Address, backend bind.ContractBackend) (*OptInService, error)
⋮----
// NewOptInServiceCaller creates a new read-only instance of OptInService, bound to a specific deployed contract.
func NewOptInServiceCaller(address common.Address, caller bind.ContractCaller) (*OptInServiceCaller, error)
⋮----
// NewOptInServiceTransactor creates a new write-only instance of OptInService, bound to a specific deployed contract.
func NewOptInServiceTransactor(address common.Address, transactor bind.ContractTransactor) (*OptInServiceTransactor, error)
⋮----
// NewOptInServiceFilterer creates a new log filterer instance of OptInService, bound to a specific deployed contract.
func NewOptInServiceFilterer(address common.Address, filterer bind.ContractFilterer) (*OptInServiceFilterer, error)
⋮----
// bindOptInService binds a generic wrapper to an already deployed contract.
func bindOptInService(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_OptInService *OptInServiceRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_OptInService *OptInServiceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_OptInService *OptInServiceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// WHEREREGISTRY is a free data retrieval call binding the contract method 0x6d0fae4a.
//
// Solidity: function WHERE_REGISTRY() view returns(address)
func (_OptInService *OptInServiceCaller) WHEREREGISTRY(opts *bind.CallOpts) (common.Address, error)
⋮----
var out []interface{}
⋮----
// WHOREGISTRY is a free data retrieval call binding the contract method 0xc4b5d62c.
⋮----
// Solidity: function WHO_REGISTRY() view returns(address)
func (_OptInService *OptInServiceCaller) WHOREGISTRY(opts *bind.CallOpts) (common.Address, error)
⋮----
// IsOptedIn is a free data retrieval call binding the contract method 0x220d32d4.
⋮----
// Solidity: function isOptedIn(address who, address where) view returns(bool)
func (_OptInService *OptInServiceCaller) IsOptedIn(opts *bind.CallOpts, who common.Address, where common.Address) (bool, error)
⋮----
// IsOptedInAt is a free data retrieval call binding the contract method 0x530e1d43.
⋮----
// Solidity: function isOptedInAt(address who, address where, uint48 timestamp, bytes hint) view returns(bool)
func (_OptInService *OptInServiceCaller) IsOptedInAt(opts *bind.CallOpts, who common.Address, where common.Address, timestamp *big.Int, hint []byte) (bool, error)
⋮----
// Nonces is a free data retrieval call binding the contract method 0x9333fbda.
⋮----
// Solidity: function nonces(address who, address where) view returns(uint256)
func (_OptInService *OptInServiceCaller) Nonces(opts *bind.CallOpts, who common.Address, where common.Address) (*big.Int, error)
⋮----
// IncreaseNonce is a paid mutator transaction binding the contract method 0x8247a97c.
⋮----
// Solidity: function increaseNonce(address where) returns()
func (_OptInService *OptInServiceTransactor) IncreaseNonce(opts *bind.TransactOpts, where common.Address) (*types.Transaction, error)
⋮----
// OptIn is a paid mutator transaction binding the contract method 0xb1138ad1.
⋮----
// Solidity: function optIn(address where) returns()
func (_OptInService *OptInServiceTransactor) OptIn(opts *bind.TransactOpts, where common.Address) (*types.Transaction, error)
⋮----
// OptIn0 is a paid mutator transaction binding the contract method 0xced44ba7.
⋮----
// Solidity: function optIn(address who, address where, uint48 deadline, bytes signature) returns()
func (_OptInService *OptInServiceTransactor) OptIn0(opts *bind.TransactOpts, who common.Address, where common.Address, deadline *big.Int, signature []byte) (*types.Transaction, error)
⋮----
// OptOut is a paid mutator transaction binding the contract method 0x93f79bc3.
⋮----
// Solidity: function optOut(address who, address where, uint48 deadline, bytes signature) returns()
func (_OptInService *OptInServiceTransactor) OptOut(opts *bind.TransactOpts, who common.Address, where common.Address, deadline *big.Int, signature []byte) (*types.Transaction, error)
⋮----
// OptOut0 is a paid mutator transaction binding the contract method 0xd4610483.
⋮----
// Solidity: function optOut(address where) returns()
func (_OptInService *OptInServiceTransactor) OptOut0(opts *bind.TransactOpts, where common.Address) (*types.Transaction, error)
⋮----
// OptInServiceIncreaseNonceIterator is returned from FilterIncreaseNonce and is used to iterate over the raw logs and unpacked data for IncreaseNonce events raised by the OptInService contract.
type OptInServiceIncreaseNonceIterator struct {
	Event *OptInServiceIncreaseNonce // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OptInServiceIncreaseNonce // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *OptInServiceIncreaseNonceIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *OptInServiceIncreaseNonceIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *OptInServiceIncreaseNonceIterator) Close() error
⋮----
// OptInServiceIncreaseNonce represents a IncreaseNonce event raised by the OptInService contract.
type OptInServiceIncreaseNonce struct {
	Who   common.Address
	Where common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
Raw   types.Log // Blockchain specific contextual infos
⋮----
// FilterIncreaseNonce is a free log retrieval operation binding the contract event 0x8ed32926585579e6191b145240df788165f4957e1135f30a00e08ee8feb9d680.
⋮----
// Solidity: event IncreaseNonce(address indexed who, address indexed where)
func (_OptInService *OptInServiceFilterer) FilterIncreaseNonce(opts *bind.FilterOpts, who []common.Address, where []common.Address) (*OptInServiceIncreaseNonceIterator, error)
⋮----
var whoRule []interface{}
⋮----
var whereRule []interface{}
⋮----
// WatchIncreaseNonce is a free log subscription operation binding the contract event 0x8ed32926585579e6191b145240df788165f4957e1135f30a00e08ee8feb9d680.
⋮----
func (_OptInService *OptInServiceFilterer) WatchIncreaseNonce(opts *bind.WatchOpts, sink chan<- *OptInServiceIncreaseNonce, who []common.Address, where []common.Address) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseIncreaseNonce is a log parse operation binding the contract event 0x8ed32926585579e6191b145240df788165f4957e1135f30a00e08ee8feb9d680.
⋮----
func (_OptInService *OptInServiceFilterer) ParseIncreaseNonce(log types.Log) (*OptInServiceIncreaseNonce, error)
⋮----
// OptInServiceOptInIterator is returned from FilterOptIn and is used to iterate over the raw logs and unpacked data for OptIn events raised by the OptInService contract.
type OptInServiceOptInIterator struct {
	Event *OptInServiceOptIn // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OptInServiceOptIn // Event containing the contract specifics and raw log
⋮----
// OptInServiceOptIn represents a OptIn event raised by the OptInService contract.
type OptInServiceOptIn struct {
	Who   common.Address
	Where common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
// FilterOptIn is a free log retrieval operation binding the contract event 0x9b730d5b907ee509de729817a2bb37e404418ba569b3a50f36192372f973cb41.
⋮----
// Solidity: event OptIn(address indexed who, address indexed where)
func (_OptInService *OptInServiceFilterer) FilterOptIn(opts *bind.FilterOpts, who []common.Address, where []common.Address) (*OptInServiceOptInIterator, error)
⋮----
// WatchOptIn is a free log subscription operation binding the contract event 0x9b730d5b907ee509de729817a2bb37e404418ba569b3a50f36192372f973cb41.
⋮----
func (_OptInService *OptInServiceFilterer) WatchOptIn(opts *bind.WatchOpts, sink chan<- *OptInServiceOptIn, who []common.Address, where []common.Address) (event.Subscription, error)
⋮----
// ParseOptIn is a log parse operation binding the contract event 0x9b730d5b907ee509de729817a2bb37e404418ba569b3a50f36192372f973cb41.
⋮----
func (_OptInService *OptInServiceFilterer) ParseOptIn(log types.Log) (*OptInServiceOptIn, error)
⋮----
// OptInServiceOptOutIterator is returned from FilterOptOut and is used to iterate over the raw logs and unpacked data for OptOut events raised by the OptInService contract.
type OptInServiceOptOutIterator struct {
	Event *OptInServiceOptOut // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OptInServiceOptOut // Event containing the contract specifics and raw log
⋮----
// OptInServiceOptOut represents a OptOut event raised by the OptInService contract.
type OptInServiceOptOut struct {
	Who   common.Address
	Where common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
// FilterOptOut is a free log retrieval operation binding the contract event 0x1629cd9ad365627cf8408d19c50224af8f3213c1a18ae48062d92e22bddf7de5.
⋮----
// Solidity: event OptOut(address indexed who, address indexed where)
func (_OptInService *OptInServiceFilterer) FilterOptOut(opts *bind.FilterOpts, who []common.Address, where []common.Address) (*OptInServiceOptOutIterator, error)
⋮----
// WatchOptOut is a free log subscription operation binding the contract event 0x1629cd9ad365627cf8408d19c50224af8f3213c1a18ae48062d92e22bddf7de5.
⋮----
func (_OptInService *OptInServiceFilterer) WatchOptOut(opts *bind.WatchOpts, sink chan<- *OptInServiceOptOut, who []common.Address, where []common.Address) (event.Subscription, error)
⋮----
// ParseOptOut is a log parse operation binding the contract event 0x1629cd9ad365627cf8408d19c50224af8f3213c1a18ae48062d92e22bddf7de5.
⋮----
func (_OptInService *OptInServiceFilterer) ParseOptOut(log types.Log) (*OptInServiceOptOut, error)
```

## File: e2e/tests/evm/gen/vault.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// VaultMetaData contains all meta data concerning the Vault contract.
var VaultMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"delegatorFactory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"slasherFactory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"vaultFactory\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DELEGATOR_FACTORY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEPOSITOR_WHITELIST_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEPOSIT_LIMIT_SET_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEPOSIT_WHITELIST_SET_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"FACTORY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"IS_DEPOSIT_LIMIT_SET_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SLASHER_FACTORY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeBalanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeBalanceOfAt\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hints\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeShares\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeSharesAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeSharesOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeSharesOfAt\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeStake\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"activeStakeAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"burner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claim\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"claimBatch\",\"inputs\":[{\"name\":\"recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"epochs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"outputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"collateral\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentEpoch\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"currentEpochStart\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"delegator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"onBehalfOf\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"depositedAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"mintedShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositWhitelist\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"epochAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"epochDuration\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"epochDurationInit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"initialVersion\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"owner_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isDelegatorInitialized\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isDepositLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isDepositorWhitelisted\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isInitialized\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSlasherInitialized\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isWithdrawalsClaimed\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"value\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"migrate\",\"inputs\":[{\"name\":\"newVersion\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"nextEpochStart\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"onSlash\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"slashedAmount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"previousEpochStart\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"redeem\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"shares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"withdrawnAssets\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"mintedShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setDelegator\",\"inputs\":[{\"name\":\"delegator_\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setDepositLimit\",\"inputs\":[{\"name\":\"limit\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setDepositWhitelist\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setDepositorWhitelistStatus\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsDepositLimit\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setSlasher\",\"inputs\":[{\"name\":\"slasher_\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"slashableBalanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"slasher\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"staticDelegateCall\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalStake\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdraw\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"burnedShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"mintedShares\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"withdrawalShares\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawalSharesOf\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawals\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawalsOf\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Claim\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"epoch\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ClaimBatch\",\"inputs\":[{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"epochs\",\"type\":\"uint256[]\",\"indexed\":false,\"internalType\":\"uint256[]\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"depositor\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"onBehalfOf\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"shares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OnSlash\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"},{\"name\":\"slashedAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetDelegator\",\"inputs\":[{\"name\":\"delegator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetDepositLimit\",\"inputs\":[{\"name\":\"limit\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetDepositWhitelist\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetDepositorWhitelistStatus\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"status\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetIsDepositLimit\",\"inputs\":[{\"name\":\"status\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetSlasher\",\"inputs\":[{\"name\":\"slasher\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Withdraw\",\"inputs\":[{\"name\":\"withdrawer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"claimer\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"burnedShares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"mintedShares\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AddressInsufficientBalance\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AlreadyClaimed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AlreadyInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AlreadySet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CheckpointUnorderedInsertion\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DelegatorAlreadyInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DepositLimitReached\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedInnerCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientClaim\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientDeposit\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientRedemption\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientWithdrawal\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidAccount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCaptureEpoch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidClaimer\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCollateral\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDelegator\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEpoch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidEpochDuration\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidLengthEpochs\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidOnBehalfOf\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRecipient\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSlasher\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidTimestamp\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MathOverflowedMulDiv\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MissingRoles\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoPreviousEpoch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotDelegator\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotFactory\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotSlasher\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotWhitelistedDepositor\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeCastOverflowedUintDowncast\",\"inputs\":[{\"name\":\"bits\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"SafeERC20FailedOperation\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"SlasherAlreadyInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TooMuchRedeem\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TooMuchWithdraw\",\"inputs\":[]}]",
}
⋮----
// VaultABI is the input ABI used to generate the binding from.
// Deprecated: Use VaultMetaData.ABI instead.
var VaultABI = VaultMetaData.ABI
⋮----
// Vault is an auto generated Go binding around an Ethereum contract.
type Vault struct {
	VaultCaller     // Read-only binding to the contract
	VaultTransactor // Write-only binding to the contract
	VaultFilterer   // Log filterer for contract events
}
⋮----
VaultCaller     // Read-only binding to the contract
VaultTransactor // Write-only binding to the contract
VaultFilterer   // Log filterer for contract events
⋮----
// VaultCaller is an auto generated read-only Go binding around an Ethereum contract.
type VaultCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// VaultTransactor is an auto generated write-only Go binding around an Ethereum contract.
type VaultTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// VaultFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type VaultFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// VaultSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type VaultSession struct {
	Contract     *Vault            // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *Vault            // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// VaultCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type VaultCallerSession struct {
	Contract *VaultCaller  // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts // Call options to use throughout this session
}
⋮----
Contract *VaultCaller  // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
⋮----
// VaultTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type VaultTransactorSession struct {
	Contract     *VaultTransactor  // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *VaultTransactor  // Generic contract transactor binding to set the session for
⋮----
// VaultRaw is an auto generated low-level Go binding around an Ethereum contract.
type VaultRaw struct {
	Contract *Vault // Generic contract binding to access the raw methods on
}
⋮----
Contract *Vault // Generic contract binding to access the raw methods on
⋮----
// VaultCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type VaultCallerRaw struct {
	Contract *VaultCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *VaultCaller // Generic read-only contract binding to access the raw methods on
⋮----
// VaultTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type VaultTransactorRaw struct {
	Contract *VaultTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *VaultTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewVault creates a new instance of Vault, bound to a specific deployed contract.
func NewVault(address common.Address, backend bind.ContractBackend) (*Vault, error)
⋮----
// NewVaultCaller creates a new read-only instance of Vault, bound to a specific deployed contract.
func NewVaultCaller(address common.Address, caller bind.ContractCaller) (*VaultCaller, error)
⋮----
// NewVaultTransactor creates a new write-only instance of Vault, bound to a specific deployed contract.
func NewVaultTransactor(address common.Address, transactor bind.ContractTransactor) (*VaultTransactor, error)
⋮----
// NewVaultFilterer creates a new log filterer instance of Vault, bound to a specific deployed contract.
func NewVaultFilterer(address common.Address, filterer bind.ContractFilterer) (*VaultFilterer, error)
⋮----
// bindVault binds a generic wrapper to an already deployed contract.
func bindVault(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Vault *VaultRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Vault *VaultRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_Vault *VaultRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf.
//
// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32)
func (_Vault *VaultCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error)
⋮----
var out []interface{}
⋮----
// DELEGATORFACTORY is a free data retrieval call binding the contract method 0x6da3e06d.
⋮----
// Solidity: function DELEGATOR_FACTORY() view returns(address)
func (_Vault *VaultCaller) DELEGATORFACTORY(opts *bind.CallOpts) (common.Address, error)
⋮----
// DEPOSITORWHITELISTROLE is a free data retrieval call binding the contract method 0x1b66c9e1.
⋮----
// Solidity: function DEPOSITOR_WHITELIST_ROLE() view returns(bytes32)
func (_Vault *VaultCaller) DEPOSITORWHITELISTROLE(opts *bind.CallOpts) ([32]byte, error)
⋮----
// DEPOSITLIMITSETROLE is a free data retrieval call binding the contract method 0xa21a1df9.
⋮----
// Solidity: function DEPOSIT_LIMIT_SET_ROLE() view returns(bytes32)
func (_Vault *VaultCaller) DEPOSITLIMITSETROLE(opts *bind.CallOpts) ([32]byte, error)
⋮----
// DEPOSITWHITELISTSETROLE is a free data retrieval call binding the contract method 0xdb388715.
⋮----
// Solidity: function DEPOSIT_WHITELIST_SET_ROLE() view returns(bytes32)
func (_Vault *VaultCaller) DEPOSITWHITELISTSETROLE(opts *bind.CallOpts) ([32]byte, error)
⋮----
// FACTORY is a free data retrieval call binding the contract method 0x2dd31000.
⋮----
// Solidity: function FACTORY() view returns(address)
func (_Vault *VaultCaller) FACTORY(opts *bind.CallOpts) (common.Address, error)
⋮----
// ISDEPOSITLIMITSETROLE is a free data retrieval call binding the contract method 0x1415519b.
⋮----
// Solidity: function IS_DEPOSIT_LIMIT_SET_ROLE() view returns(bytes32)
func (_Vault *VaultCaller) ISDEPOSITLIMITSETROLE(opts *bind.CallOpts) ([32]byte, error)
⋮----
// SLASHERFACTORY is a free data retrieval call binding the contract method 0x87df0788.
⋮----
// Solidity: function SLASHER_FACTORY() view returns(address)
func (_Vault *VaultCaller) SLASHERFACTORY(opts *bind.CallOpts) (common.Address, error)
⋮----
// ActiveBalanceOf is a free data retrieval call binding the contract method 0x59f769a9.
⋮----
// Solidity: function activeBalanceOf(address account) view returns(uint256)
func (_Vault *VaultCaller) ActiveBalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error)
⋮----
// ActiveBalanceOfAt is a free data retrieval call binding the contract method 0xefb559d6.
⋮----
// Solidity: function activeBalanceOfAt(address account, uint48 timestamp, bytes hints) view returns(uint256)
func (_Vault *VaultCaller) ActiveBalanceOfAt(opts *bind.CallOpts, account common.Address, timestamp *big.Int, hints []byte) (*big.Int, error)
⋮----
// ActiveShares is a free data retrieval call binding the contract method 0xbfefcd7b.
⋮----
// Solidity: function activeShares() view returns(uint256)
func (_Vault *VaultCaller) ActiveShares(opts *bind.CallOpts) (*big.Int, error)
⋮----
// ActiveSharesAt is a free data retrieval call binding the contract method 0x50f22068.
⋮----
// Solidity: function activeSharesAt(uint48 timestamp, bytes hint) view returns(uint256)
func (_Vault *VaultCaller) ActiveSharesAt(opts *bind.CallOpts, timestamp *big.Int, hint []byte) (*big.Int, error)
⋮----
// ActiveSharesOf is a free data retrieval call binding the contract method 0x9d66201b.
⋮----
// Solidity: function activeSharesOf(address account) view returns(uint256)
func (_Vault *VaultCaller) ActiveSharesOf(opts *bind.CallOpts, account common.Address) (*big.Int, error)
⋮----
// ActiveSharesOfAt is a free data retrieval call binding the contract method 0x2d73c69c.
⋮----
// Solidity: function activeSharesOfAt(address account, uint48 timestamp, bytes hint) view returns(uint256)
func (_Vault *VaultCaller) ActiveSharesOfAt(opts *bind.CallOpts, account common.Address, timestamp *big.Int, hint []byte) (*big.Int, error)
⋮----
// ActiveStake is a free data retrieval call binding the contract method 0xbd49c35f.
⋮----
// Solidity: function activeStake() view returns(uint256)
func (_Vault *VaultCaller) ActiveStake(opts *bind.CallOpts) (*big.Int, error)
⋮----
// ActiveStakeAt is a free data retrieval call binding the contract method 0x810da75d.
⋮----
// Solidity: function activeStakeAt(uint48 timestamp, bytes hint) view returns(uint256)
func (_Vault *VaultCaller) ActiveStakeAt(opts *bind.CallOpts, timestamp *big.Int, hint []byte) (*big.Int, error)
⋮----
// Burner is a free data retrieval call binding the contract method 0x27810b6e.
⋮----
// Solidity: function burner() view returns(address)
func (_Vault *VaultCaller) Burner(opts *bind.CallOpts) (common.Address, error)
⋮----
// Collateral is a free data retrieval call binding the contract method 0xd8dfeb45.
⋮----
// Solidity: function collateral() view returns(address)
func (_Vault *VaultCaller) Collateral(opts *bind.CallOpts) (common.Address, error)
⋮----
// CurrentEpoch is a free data retrieval call binding the contract method 0x76671808.
⋮----
// Solidity: function currentEpoch() view returns(uint256)
func (_Vault *VaultCaller) CurrentEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
// CurrentEpochStart is a free data retrieval call binding the contract method 0x61a8c8c4.
⋮----
// Solidity: function currentEpochStart() view returns(uint48)
func (_Vault *VaultCaller) CurrentEpochStart(opts *bind.CallOpts) (*big.Int, error)
⋮----
// Delegator is a free data retrieval call binding the contract method 0xce9b7930.
⋮----
// Solidity: function delegator() view returns(address)
func (_Vault *VaultCaller) Delegator(opts *bind.CallOpts) (common.Address, error)
⋮----
// DepositLimit is a free data retrieval call binding the contract method 0xecf70858.
⋮----
// Solidity: function depositLimit() view returns(uint256)
func (_Vault *VaultCaller) DepositLimit(opts *bind.CallOpts) (*big.Int, error)
⋮----
// DepositWhitelist is a free data retrieval call binding the contract method 0x48d3b775.
⋮----
// Solidity: function depositWhitelist() view returns(bool)
func (_Vault *VaultCaller) DepositWhitelist(opts *bind.CallOpts) (bool, error)
⋮----
// EpochAt is a free data retrieval call binding the contract method 0x7953b33b.
⋮----
// Solidity: function epochAt(uint48 timestamp) view returns(uint256)
func (_Vault *VaultCaller) EpochAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// EpochDuration is a free data retrieval call binding the contract method 0x4ff0876a.
⋮----
// Solidity: function epochDuration() view returns(uint48)
func (_Vault *VaultCaller) EpochDuration(opts *bind.CallOpts) (*big.Int, error)
⋮----
// EpochDurationInit is a free data retrieval call binding the contract method 0x46361671.
⋮----
// Solidity: function epochDurationInit() view returns(uint48)
func (_Vault *VaultCaller) EpochDurationInit(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3.
⋮----
// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32)
func (_Vault *VaultCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error)
⋮----
// HasRole is a free data retrieval call binding the contract method 0x91d14854.
⋮----
// Solidity: function hasRole(bytes32 role, address account) view returns(bool)
func (_Vault *VaultCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error)
⋮----
// IsDelegatorInitialized is a free data retrieval call binding the contract method 0x50861adc.
⋮----
// Solidity: function isDelegatorInitialized() view returns(bool)
func (_Vault *VaultCaller) IsDelegatorInitialized(opts *bind.CallOpts) (bool, error)
⋮----
// IsDepositLimit is a free data retrieval call binding the contract method 0xa1b12202.
⋮----
// Solidity: function isDepositLimit() view returns(bool)
func (_Vault *VaultCaller) IsDepositLimit(opts *bind.CallOpts) (bool, error)
⋮----
// IsDepositorWhitelisted is a free data retrieval call binding the contract method 0x794b15b7.
⋮----
// Solidity: function isDepositorWhitelisted(address account) view returns(bool value)
func (_Vault *VaultCaller) IsDepositorWhitelisted(opts *bind.CallOpts, account common.Address) (bool, error)
⋮----
// IsInitialized is a free data retrieval call binding the contract method 0x392e53cd.
⋮----
// Solidity: function isInitialized() view returns(bool)
func (_Vault *VaultCaller) IsInitialized(opts *bind.CallOpts) (bool, error)
⋮----
// IsSlasherInitialized is a free data retrieval call binding the contract method 0x6ec1e3f8.
⋮----
// Solidity: function isSlasherInitialized() view returns(bool)
func (_Vault *VaultCaller) IsSlasherInitialized(opts *bind.CallOpts) (bool, error)
⋮----
// IsWithdrawalsClaimed is a free data retrieval call binding the contract method 0xa5d03223.
⋮----
// Solidity: function isWithdrawalsClaimed(uint256 epoch, address account) view returns(bool value)
func (_Vault *VaultCaller) IsWithdrawalsClaimed(opts *bind.CallOpts, epoch *big.Int, account common.Address) (bool, error)
⋮----
// NextEpochStart is a free data retrieval call binding the contract method 0x73790ab3.
⋮----
// Solidity: function nextEpochStart() view returns(uint48)
func (_Vault *VaultCaller) NextEpochStart(opts *bind.CallOpts) (*big.Int, error)
⋮----
// Owner is a free data retrieval call binding the contract method 0x8da5cb5b.
⋮----
// Solidity: function owner() view returns(address)
func (_Vault *VaultCaller) Owner(opts *bind.CallOpts) (common.Address, error)
⋮----
// PreviousEpochStart is a free data retrieval call binding the contract method 0x281f5752.
⋮----
// Solidity: function previousEpochStart() view returns(uint48)
func (_Vault *VaultCaller) PreviousEpochStart(opts *bind.CallOpts) (*big.Int, error)
⋮----
// SlashableBalanceOf is a free data retrieval call binding the contract method 0xc31e8dd7.
⋮----
// Solidity: function slashableBalanceOf(address account) view returns(uint256)
func (_Vault *VaultCaller) SlashableBalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error)
⋮----
// Slasher is a free data retrieval call binding the contract method 0xb1344271.
⋮----
// Solidity: function slasher() view returns(address)
func (_Vault *VaultCaller) Slasher(opts *bind.CallOpts) (common.Address, error)
⋮----
// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7.
⋮----
// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool)
func (_Vault *VaultCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
⋮----
// TotalStake is a free data retrieval call binding the contract method 0x8b0e9f3f.
⋮----
// Solidity: function totalStake() view returns(uint256)
func (_Vault *VaultCaller) TotalStake(opts *bind.CallOpts) (*big.Int, error)
⋮----
// Version is a free data retrieval call binding the contract method 0x54fd4d50.
⋮----
// Solidity: function version() view returns(uint64)
func (_Vault *VaultCaller) Version(opts *bind.CallOpts) (uint64, error)
⋮----
// WithdrawalShares is a free data retrieval call binding the contract method 0xafba70ad.
⋮----
// Solidity: function withdrawalShares(uint256 epoch) view returns(uint256 amount)
func (_Vault *VaultCaller) WithdrawalShares(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// WithdrawalSharesOf is a free data retrieval call binding the contract method 0xa3b54172.
⋮----
// Solidity: function withdrawalSharesOf(uint256 epoch, address account) view returns(uint256 amount)
func (_Vault *VaultCaller) WithdrawalSharesOf(opts *bind.CallOpts, epoch *big.Int, account common.Address) (*big.Int, error)
⋮----
// Withdrawals is a free data retrieval call binding the contract method 0x5cc07076.
⋮----
// Solidity: function withdrawals(uint256 epoch) view returns(uint256 amount)
func (_Vault *VaultCaller) Withdrawals(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// WithdrawalsOf is a free data retrieval call binding the contract method 0xf5e7ee0f.
⋮----
// Solidity: function withdrawalsOf(uint256 epoch, address account) view returns(uint256)
func (_Vault *VaultCaller) WithdrawalsOf(opts *bind.CallOpts, epoch *big.Int, account common.Address) (*big.Int, error)
⋮----
// Claim is a paid mutator transaction binding the contract method 0xaad3ec96.
⋮----
// Solidity: function claim(address recipient, uint256 epoch) returns(uint256 amount)
func (_Vault *VaultTransactor) Claim(opts *bind.TransactOpts, recipient common.Address, epoch *big.Int) (*types.Transaction, error)
⋮----
// ClaimBatch is a paid mutator transaction binding the contract method 0x7c04c80a.
⋮----
// Solidity: function claimBatch(address recipient, uint256[] epochs) returns(uint256 amount)
func (_Vault *VaultTransactor) ClaimBatch(opts *bind.TransactOpts, recipient common.Address, epochs []*big.Int) (*types.Transaction, error)
⋮----
// Deposit is a paid mutator transaction binding the contract method 0x47e7ef24.
⋮----
// Solidity: function deposit(address onBehalfOf, uint256 amount) returns(uint256 depositedAmount, uint256 mintedShares)
func (_Vault *VaultTransactor) Deposit(opts *bind.TransactOpts, onBehalfOf common.Address, amount *big.Int) (*types.Transaction, error)
⋮----
// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d.
⋮----
// Solidity: function grantRole(bytes32 role, address account) returns()
func (_Vault *VaultTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error)
⋮----
// Initialize is a paid mutator transaction binding the contract method 0x57ec83cc.
⋮----
// Solidity: function initialize(uint64 initialVersion, address owner_, bytes data) returns()
func (_Vault *VaultTransactor) Initialize(opts *bind.TransactOpts, initialVersion uint64, owner_ common.Address, data []byte) (*types.Transaction, error)
⋮----
// Migrate is a paid mutator transaction binding the contract method 0x2abe3048.
⋮----
// Solidity: function migrate(uint64 newVersion, bytes data) returns()
func (_Vault *VaultTransactor) Migrate(opts *bind.TransactOpts, newVersion uint64, data []byte) (*types.Transaction, error)
⋮----
// OnSlash is a paid mutator transaction binding the contract method 0x7278e31c.
⋮----
// Solidity: function onSlash(uint256 amount, uint48 captureTimestamp) returns(uint256 slashedAmount)
func (_Vault *VaultTransactor) OnSlash(opts *bind.TransactOpts, amount *big.Int, captureTimestamp *big.Int) (*types.Transaction, error)
⋮----
// Redeem is a paid mutator transaction binding the contract method 0x1e9a6950.
⋮----
// Solidity: function redeem(address claimer, uint256 shares) returns(uint256 withdrawnAssets, uint256 mintedShares)
func (_Vault *VaultTransactor) Redeem(opts *bind.TransactOpts, claimer common.Address, shares *big.Int) (*types.Transaction, error)
⋮----
// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6.
⋮----
// Solidity: function renounceOwnership() returns()
func (_Vault *VaultTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe.
⋮----
// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns()
func (_Vault *VaultTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error)
⋮----
// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f.
⋮----
// Solidity: function revokeRole(bytes32 role, address account) returns()
func (_Vault *VaultTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error)
⋮----
// SetDelegator is a paid mutator transaction binding the contract method 0x83cd9cc3.
⋮----
// Solidity: function setDelegator(address delegator_) returns()
func (_Vault *VaultTransactor) SetDelegator(opts *bind.TransactOpts, delegator_ common.Address) (*types.Transaction, error)
⋮----
// SetDepositLimit is a paid mutator transaction binding the contract method 0xbdc8144b.
⋮----
// Solidity: function setDepositLimit(uint256 limit) returns()
func (_Vault *VaultTransactor) SetDepositLimit(opts *bind.TransactOpts, limit *big.Int) (*types.Transaction, error)
⋮----
// SetDepositWhitelist is a paid mutator transaction binding the contract method 0x4105a7dd.
⋮----
// Solidity: function setDepositWhitelist(bool status) returns()
func (_Vault *VaultTransactor) SetDepositWhitelist(opts *bind.TransactOpts, status bool) (*types.Transaction, error)
⋮----
// SetDepositorWhitelistStatus is a paid mutator transaction binding the contract method 0xa2861466.
⋮----
// Solidity: function setDepositorWhitelistStatus(address account, bool status) returns()
func (_Vault *VaultTransactor) SetDepositorWhitelistStatus(opts *bind.TransactOpts, account common.Address, status bool) (*types.Transaction, error)
⋮----
// SetIsDepositLimit is a paid mutator transaction binding the contract method 0x5346e34f.
⋮----
// Solidity: function setIsDepositLimit(bool status) returns()
func (_Vault *VaultTransactor) SetIsDepositLimit(opts *bind.TransactOpts, status bool) (*types.Transaction, error)
⋮----
// SetSlasher is a paid mutator transaction binding the contract method 0xaabc2496.
⋮----
// Solidity: function setSlasher(address slasher_) returns()
func (_Vault *VaultTransactor) SetSlasher(opts *bind.TransactOpts, slasher_ common.Address) (*types.Transaction, error)
⋮----
// StaticDelegateCall is a paid mutator transaction binding the contract method 0x9f86fd85.
⋮----
// Solidity: function staticDelegateCall(address target, bytes data) returns()
func (_Vault *VaultTransactor) StaticDelegateCall(opts *bind.TransactOpts, target common.Address, data []byte) (*types.Transaction, error)
⋮----
// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b.
⋮----
// Solidity: function transferOwnership(address newOwner) returns()
func (_Vault *VaultTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error)
⋮----
// Withdraw is a paid mutator transaction binding the contract method 0xf3fef3a3.
⋮----
// Solidity: function withdraw(address claimer, uint256 amount) returns(uint256 burnedShares, uint256 mintedShares)
func (_Vault *VaultTransactor) Withdraw(opts *bind.TransactOpts, claimer common.Address, amount *big.Int) (*types.Transaction, error)
⋮----
// VaultClaimIterator is returned from FilterClaim and is used to iterate over the raw logs and unpacked data for Claim events raised by the Vault contract.
type VaultClaimIterator struct {
	Event *VaultClaim // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultClaim // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *VaultClaimIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *VaultClaimIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *VaultClaimIterator) Close() error
⋮----
// VaultClaim represents a Claim event raised by the Vault contract.
type VaultClaim struct {
	Claimer   common.Address
	Recipient common.Address
	Epoch     *big.Int
	Amount    *big.Int
	Raw       types.Log // Blockchain specific contextual infos
}
⋮----
Raw       types.Log // Blockchain specific contextual infos
⋮----
// FilterClaim is a free log retrieval operation binding the contract event 0x865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e94645.
⋮----
// Solidity: event Claim(address indexed claimer, address indexed recipient, uint256 epoch, uint256 amount)
func (_Vault *VaultFilterer) FilterClaim(opts *bind.FilterOpts, claimer []common.Address, recipient []common.Address) (*VaultClaimIterator, error)
⋮----
var claimerRule []interface{}
⋮----
var recipientRule []interface{}
⋮----
// WatchClaim is a free log subscription operation binding the contract event 0x865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e94645.
⋮----
func (_Vault *VaultFilterer) WatchClaim(opts *bind.WatchOpts, sink chan<- *VaultClaim, claimer []common.Address, recipient []common.Address) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseClaim is a log parse operation binding the contract event 0x865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e94645.
⋮----
func (_Vault *VaultFilterer) ParseClaim(log types.Log) (*VaultClaim, error)
⋮----
// VaultClaimBatchIterator is returned from FilterClaimBatch and is used to iterate over the raw logs and unpacked data for ClaimBatch events raised by the Vault contract.
type VaultClaimBatchIterator struct {
	Event *VaultClaimBatch // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultClaimBatch // Event containing the contract specifics and raw log
⋮----
// VaultClaimBatch represents a ClaimBatch event raised by the Vault contract.
type VaultClaimBatch struct {
	Claimer   common.Address
	Recipient common.Address
	Epochs    []*big.Int
	Amount    *big.Int
	Raw       types.Log // Blockchain specific contextual infos
}
⋮----
// FilterClaimBatch is a free log retrieval operation binding the contract event 0x326b6aff1cd2fb1c8234de4f9dcfb9047c5c36eb9ef2eb34af5121e969a75d27.
⋮----
// Solidity: event ClaimBatch(address indexed claimer, address indexed recipient, uint256[] epochs, uint256 amount)
func (_Vault *VaultFilterer) FilterClaimBatch(opts *bind.FilterOpts, claimer []common.Address, recipient []common.Address) (*VaultClaimBatchIterator, error)
⋮----
// WatchClaimBatch is a free log subscription operation binding the contract event 0x326b6aff1cd2fb1c8234de4f9dcfb9047c5c36eb9ef2eb34af5121e969a75d27.
⋮----
func (_Vault *VaultFilterer) WatchClaimBatch(opts *bind.WatchOpts, sink chan<- *VaultClaimBatch, claimer []common.Address, recipient []common.Address) (event.Subscription, error)
⋮----
// ParseClaimBatch is a log parse operation binding the contract event 0x326b6aff1cd2fb1c8234de4f9dcfb9047c5c36eb9ef2eb34af5121e969a75d27.
⋮----
func (_Vault *VaultFilterer) ParseClaimBatch(log types.Log) (*VaultClaimBatch, error)
⋮----
// VaultDepositIterator is returned from FilterDeposit and is used to iterate over the raw logs and unpacked data for Deposit events raised by the Vault contract.
type VaultDepositIterator struct {
	Event *VaultDeposit // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultDeposit // Event containing the contract specifics and raw log
⋮----
// VaultDeposit represents a Deposit event raised by the Vault contract.
type VaultDeposit struct {
	Depositor  common.Address
	OnBehalfOf common.Address
	Amount     *big.Int
	Shares     *big.Int
	Raw        types.Log // Blockchain specific contextual infos
}
⋮----
Raw        types.Log // Blockchain specific contextual infos
⋮----
// FilterDeposit is a free log retrieval operation binding the contract event 0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7.
⋮----
// Solidity: event Deposit(address indexed depositor, address indexed onBehalfOf, uint256 amount, uint256 shares)
func (_Vault *VaultFilterer) FilterDeposit(opts *bind.FilterOpts, depositor []common.Address, onBehalfOf []common.Address) (*VaultDepositIterator, error)
⋮----
var depositorRule []interface{}
⋮----
var onBehalfOfRule []interface{}
⋮----
// WatchDeposit is a free log subscription operation binding the contract event 0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7.
⋮----
func (_Vault *VaultFilterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *VaultDeposit, depositor []common.Address, onBehalfOf []common.Address) (event.Subscription, error)
⋮----
// ParseDeposit is a log parse operation binding the contract event 0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7.
⋮----
func (_Vault *VaultFilterer) ParseDeposit(log types.Log) (*VaultDeposit, error)
⋮----
// VaultInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Vault contract.
type VaultInitializedIterator struct {
	Event *VaultInitialized // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultInitialized // Event containing the contract specifics and raw log
⋮----
// VaultInitialized represents a Initialized event raised by the Vault contract.
type VaultInitialized struct {
	Version uint64
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
// Solidity: event Initialized(uint64 version)
func (_Vault *VaultFilterer) FilterInitialized(opts *bind.FilterOpts) (*VaultInitializedIterator, error)
⋮----
// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_Vault *VaultFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *VaultInitialized) (event.Subscription, error)
⋮----
// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_Vault *VaultFilterer) ParseInitialized(log types.Log) (*VaultInitialized, error)
⋮----
// VaultOnSlashIterator is returned from FilterOnSlash and is used to iterate over the raw logs and unpacked data for OnSlash events raised by the Vault contract.
type VaultOnSlashIterator struct {
	Event *VaultOnSlash // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultOnSlash // Event containing the contract specifics and raw log
⋮----
// VaultOnSlash represents a OnSlash event raised by the Vault contract.
type VaultOnSlash struct {
	Amount           *big.Int
	CaptureTimestamp *big.Int
	SlashedAmount    *big.Int
	Raw              types.Log // Blockchain specific contextual infos
}
⋮----
Raw              types.Log // Blockchain specific contextual infos
⋮----
// FilterOnSlash is a free log retrieval operation binding the contract event 0xf9d090c096f71cd1659861a9ce5b6f384bceb4e2fa4e4a19edf6489a9b8d56c7.
⋮----
// Solidity: event OnSlash(uint256 amount, uint48 captureTimestamp, uint256 slashedAmount)
func (_Vault *VaultFilterer) FilterOnSlash(opts *bind.FilterOpts) (*VaultOnSlashIterator, error)
⋮----
// WatchOnSlash is a free log subscription operation binding the contract event 0xf9d090c096f71cd1659861a9ce5b6f384bceb4e2fa4e4a19edf6489a9b8d56c7.
⋮----
func (_Vault *VaultFilterer) WatchOnSlash(opts *bind.WatchOpts, sink chan<- *VaultOnSlash) (event.Subscription, error)
⋮----
// ParseOnSlash is a log parse operation binding the contract event 0xf9d090c096f71cd1659861a9ce5b6f384bceb4e2fa4e4a19edf6489a9b8d56c7.
⋮----
func (_Vault *VaultFilterer) ParseOnSlash(log types.Log) (*VaultOnSlash, error)
⋮----
// VaultOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Vault contract.
type VaultOwnershipTransferredIterator struct {
	Event *VaultOwnershipTransferred // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultOwnershipTransferred // Event containing the contract specifics and raw log
⋮----
// VaultOwnershipTransferred represents a OwnershipTransferred event raised by the Vault contract.
type VaultOwnershipTransferred struct {
	PreviousOwner common.Address
	NewOwner      common.Address
	Raw           types.Log // Blockchain specific contextual infos
}
⋮----
Raw           types.Log // Blockchain specific contextual infos
⋮----
// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
⋮----
// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
func (_Vault *VaultFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*VaultOwnershipTransferredIterator, error)
⋮----
var previousOwnerRule []interface{}
⋮----
var newOwnerRule []interface{}
⋮----
// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
⋮----
func (_Vault *VaultFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VaultOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error)
⋮----
// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0.
⋮----
func (_Vault *VaultFilterer) ParseOwnershipTransferred(log types.Log) (*VaultOwnershipTransferred, error)
⋮----
// VaultRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the Vault contract.
type VaultRoleAdminChangedIterator struct {
	Event *VaultRoleAdminChanged // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultRoleAdminChanged // Event containing the contract specifics and raw log
⋮----
// VaultRoleAdminChanged represents a RoleAdminChanged event raised by the Vault contract.
type VaultRoleAdminChanged struct {
	Role              [32]byte
	PreviousAdminRole [32]byte
	NewAdminRole      [32]byte
	Raw               types.Log // Blockchain specific contextual infos
}
⋮----
Raw               types.Log // Blockchain specific contextual infos
⋮----
// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff.
⋮----
// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole)
func (_Vault *VaultFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*VaultRoleAdminChangedIterator, error)
⋮----
var roleRule []interface{}
⋮----
var previousAdminRoleRule []interface{}
⋮----
var newAdminRoleRule []interface{}
⋮----
// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff.
⋮----
func (_Vault *VaultFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *VaultRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error)
⋮----
// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff.
⋮----
func (_Vault *VaultFilterer) ParseRoleAdminChanged(log types.Log) (*VaultRoleAdminChanged, error)
⋮----
// VaultRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the Vault contract.
type VaultRoleGrantedIterator struct {
	Event *VaultRoleGranted // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultRoleGranted // Event containing the contract specifics and raw log
⋮----
// VaultRoleGranted represents a RoleGranted event raised by the Vault contract.
type VaultRoleGranted struct {
	Role    [32]byte
	Account common.Address
	Sender  common.Address
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d.
⋮----
// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender)
func (_Vault *VaultFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*VaultRoleGrantedIterator, error)
⋮----
var accountRule []interface{}
⋮----
var senderRule []interface{}
⋮----
// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d.
⋮----
func (_Vault *VaultFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *VaultRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error)
⋮----
// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d.
⋮----
func (_Vault *VaultFilterer) ParseRoleGranted(log types.Log) (*VaultRoleGranted, error)
⋮----
// VaultRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the Vault contract.
type VaultRoleRevokedIterator struct {
	Event *VaultRoleRevoked // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultRoleRevoked // Event containing the contract specifics and raw log
⋮----
// VaultRoleRevoked represents a RoleRevoked event raised by the Vault contract.
type VaultRoleRevoked struct {
	Role    [32]byte
	Account common.Address
	Sender  common.Address
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b.
⋮----
// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender)
func (_Vault *VaultFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*VaultRoleRevokedIterator, error)
⋮----
// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b.
⋮----
func (_Vault *VaultFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *VaultRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error)
⋮----
// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b.
⋮----
func (_Vault *VaultFilterer) ParseRoleRevoked(log types.Log) (*VaultRoleRevoked, error)
⋮----
// VaultSetDelegatorIterator is returned from FilterSetDelegator and is used to iterate over the raw logs and unpacked data for SetDelegator events raised by the Vault contract.
type VaultSetDelegatorIterator struct {
	Event *VaultSetDelegator // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetDelegator // Event containing the contract specifics and raw log
⋮----
// VaultSetDelegator represents a SetDelegator event raised by the Vault contract.
type VaultSetDelegator struct {
	Delegator common.Address
	Raw       types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetDelegator is a free log retrieval operation binding the contract event 0xdb2160616f776a37b24808115554e79439bf26cccbbd4438190cc6d28e80ecd1.
⋮----
// Solidity: event SetDelegator(address indexed delegator)
func (_Vault *VaultFilterer) FilterSetDelegator(opts *bind.FilterOpts, delegator []common.Address) (*VaultSetDelegatorIterator, error)
⋮----
var delegatorRule []interface{}
⋮----
// WatchSetDelegator is a free log subscription operation binding the contract event 0xdb2160616f776a37b24808115554e79439bf26cccbbd4438190cc6d28e80ecd1.
⋮----
func (_Vault *VaultFilterer) WatchSetDelegator(opts *bind.WatchOpts, sink chan<- *VaultSetDelegator, delegator []common.Address) (event.Subscription, error)
⋮----
// ParseSetDelegator is a log parse operation binding the contract event 0xdb2160616f776a37b24808115554e79439bf26cccbbd4438190cc6d28e80ecd1.
⋮----
func (_Vault *VaultFilterer) ParseSetDelegator(log types.Log) (*VaultSetDelegator, error)
⋮----
// VaultSetDepositLimitIterator is returned from FilterSetDepositLimit and is used to iterate over the raw logs and unpacked data for SetDepositLimit events raised by the Vault contract.
type VaultSetDepositLimitIterator struct {
	Event *VaultSetDepositLimit // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetDepositLimit // Event containing the contract specifics and raw log
⋮----
// VaultSetDepositLimit represents a SetDepositLimit event raised by the Vault contract.
type VaultSetDepositLimit struct {
	Limit *big.Int
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
Raw   types.Log // Blockchain specific contextual infos
⋮----
// FilterSetDepositLimit is a free log retrieval operation binding the contract event 0x854df3eb95564502c8bc871ebdd15310ee26270f955f6c6bd8cea68e75045bc0.
⋮----
// Solidity: event SetDepositLimit(uint256 limit)
func (_Vault *VaultFilterer) FilterSetDepositLimit(opts *bind.FilterOpts) (*VaultSetDepositLimitIterator, error)
⋮----
// WatchSetDepositLimit is a free log subscription operation binding the contract event 0x854df3eb95564502c8bc871ebdd15310ee26270f955f6c6bd8cea68e75045bc0.
⋮----
func (_Vault *VaultFilterer) WatchSetDepositLimit(opts *bind.WatchOpts, sink chan<- *VaultSetDepositLimit) (event.Subscription, error)
⋮----
// ParseSetDepositLimit is a log parse operation binding the contract event 0x854df3eb95564502c8bc871ebdd15310ee26270f955f6c6bd8cea68e75045bc0.
⋮----
func (_Vault *VaultFilterer) ParseSetDepositLimit(log types.Log) (*VaultSetDepositLimit, error)
⋮----
// VaultSetDepositWhitelistIterator is returned from FilterSetDepositWhitelist and is used to iterate over the raw logs and unpacked data for SetDepositWhitelist events raised by the Vault contract.
type VaultSetDepositWhitelistIterator struct {
	Event *VaultSetDepositWhitelist // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetDepositWhitelist // Event containing the contract specifics and raw log
⋮----
// VaultSetDepositWhitelist represents a SetDepositWhitelist event raised by the Vault contract.
type VaultSetDepositWhitelist struct {
	Status bool
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
Raw    types.Log // Blockchain specific contextual infos
⋮----
// FilterSetDepositWhitelist is a free log retrieval operation binding the contract event 0x3e12b7b36c75ac9609a3f58609b331210428e1a85909132638955ba0301eec33.
⋮----
// Solidity: event SetDepositWhitelist(bool status)
func (_Vault *VaultFilterer) FilterSetDepositWhitelist(opts *bind.FilterOpts) (*VaultSetDepositWhitelistIterator, error)
⋮----
// WatchSetDepositWhitelist is a free log subscription operation binding the contract event 0x3e12b7b36c75ac9609a3f58609b331210428e1a85909132638955ba0301eec33.
⋮----
func (_Vault *VaultFilterer) WatchSetDepositWhitelist(opts *bind.WatchOpts, sink chan<- *VaultSetDepositWhitelist) (event.Subscription, error)
⋮----
// ParseSetDepositWhitelist is a log parse operation binding the contract event 0x3e12b7b36c75ac9609a3f58609b331210428e1a85909132638955ba0301eec33.
⋮----
func (_Vault *VaultFilterer) ParseSetDepositWhitelist(log types.Log) (*VaultSetDepositWhitelist, error)
⋮----
// VaultSetDepositorWhitelistStatusIterator is returned from FilterSetDepositorWhitelistStatus and is used to iterate over the raw logs and unpacked data for SetDepositorWhitelistStatus events raised by the Vault contract.
type VaultSetDepositorWhitelistStatusIterator struct {
	Event *VaultSetDepositorWhitelistStatus // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetDepositorWhitelistStatus // Event containing the contract specifics and raw log
⋮----
// VaultSetDepositorWhitelistStatus represents a SetDepositorWhitelistStatus event raised by the Vault contract.
type VaultSetDepositorWhitelistStatus struct {
	Account common.Address
	Status  bool
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetDepositorWhitelistStatus is a free log retrieval operation binding the contract event 0xf991b1ecfb5115cbb36a2b2e2240c058406d2acc2fcc6e9e2dc99d845ff70a62.
⋮----
// Solidity: event SetDepositorWhitelistStatus(address indexed account, bool status)
func (_Vault *VaultFilterer) FilterSetDepositorWhitelistStatus(opts *bind.FilterOpts, account []common.Address) (*VaultSetDepositorWhitelistStatusIterator, error)
⋮----
// WatchSetDepositorWhitelistStatus is a free log subscription operation binding the contract event 0xf991b1ecfb5115cbb36a2b2e2240c058406d2acc2fcc6e9e2dc99d845ff70a62.
⋮----
func (_Vault *VaultFilterer) WatchSetDepositorWhitelistStatus(opts *bind.WatchOpts, sink chan<- *VaultSetDepositorWhitelistStatus, account []common.Address) (event.Subscription, error)
⋮----
// ParseSetDepositorWhitelistStatus is a log parse operation binding the contract event 0xf991b1ecfb5115cbb36a2b2e2240c058406d2acc2fcc6e9e2dc99d845ff70a62.
⋮----
func (_Vault *VaultFilterer) ParseSetDepositorWhitelistStatus(log types.Log) (*VaultSetDepositorWhitelistStatus, error)
⋮----
// VaultSetIsDepositLimitIterator is returned from FilterSetIsDepositLimit and is used to iterate over the raw logs and unpacked data for SetIsDepositLimit events raised by the Vault contract.
type VaultSetIsDepositLimitIterator struct {
	Event *VaultSetIsDepositLimit // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetIsDepositLimit // Event containing the contract specifics and raw log
⋮----
// VaultSetIsDepositLimit represents a SetIsDepositLimit event raised by the Vault contract.
type VaultSetIsDepositLimit struct {
	Status bool
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetIsDepositLimit is a free log retrieval operation binding the contract event 0xfa7a25a0b611d4ba3c0ea990e90dc23d484a5dd7a1be4733fef2946ba74530c6.
⋮----
// Solidity: event SetIsDepositLimit(bool status)
func (_Vault *VaultFilterer) FilterSetIsDepositLimit(opts *bind.FilterOpts) (*VaultSetIsDepositLimitIterator, error)
⋮----
// WatchSetIsDepositLimit is a free log subscription operation binding the contract event 0xfa7a25a0b611d4ba3c0ea990e90dc23d484a5dd7a1be4733fef2946ba74530c6.
⋮----
func (_Vault *VaultFilterer) WatchSetIsDepositLimit(opts *bind.WatchOpts, sink chan<- *VaultSetIsDepositLimit) (event.Subscription, error)
⋮----
// ParseSetIsDepositLimit is a log parse operation binding the contract event 0xfa7a25a0b611d4ba3c0ea990e90dc23d484a5dd7a1be4733fef2946ba74530c6.
⋮----
func (_Vault *VaultFilterer) ParseSetIsDepositLimit(log types.Log) (*VaultSetIsDepositLimit, error)
⋮----
// VaultSetSlasherIterator is returned from FilterSetSlasher and is used to iterate over the raw logs and unpacked data for SetSlasher events raised by the Vault contract.
type VaultSetSlasherIterator struct {
	Event *VaultSetSlasher // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultSetSlasher // Event containing the contract specifics and raw log
⋮----
// VaultSetSlasher represents a SetSlasher event raised by the Vault contract.
type VaultSetSlasher struct {
	Slasher common.Address
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetSlasher is a free log retrieval operation binding the contract event 0xe7e4c932e03abddfe20f83af42c33627e816115c7ec2b168441f65dc14bfc3ba.
⋮----
// Solidity: event SetSlasher(address indexed slasher)
func (_Vault *VaultFilterer) FilterSetSlasher(opts *bind.FilterOpts, slasher []common.Address) (*VaultSetSlasherIterator, error)
⋮----
var slasherRule []interface{}
⋮----
// WatchSetSlasher is a free log subscription operation binding the contract event 0xe7e4c932e03abddfe20f83af42c33627e816115c7ec2b168441f65dc14bfc3ba.
⋮----
func (_Vault *VaultFilterer) WatchSetSlasher(opts *bind.WatchOpts, sink chan<- *VaultSetSlasher, slasher []common.Address) (event.Subscription, error)
⋮----
// ParseSetSlasher is a log parse operation binding the contract event 0xe7e4c932e03abddfe20f83af42c33627e816115c7ec2b168441f65dc14bfc3ba.
⋮----
func (_Vault *VaultFilterer) ParseSetSlasher(log types.Log) (*VaultSetSlasher, error)
⋮----
// VaultWithdrawIterator is returned from FilterWithdraw and is used to iterate over the raw logs and unpacked data for Withdraw events raised by the Vault contract.
type VaultWithdrawIterator struct {
	Event *VaultWithdraw // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VaultWithdraw // Event containing the contract specifics and raw log
⋮----
// VaultWithdraw represents a Withdraw event raised by the Vault contract.
type VaultWithdraw struct {
	Withdrawer   common.Address
	Claimer      common.Address
	Amount       *big.Int
	BurnedShares *big.Int
	MintedShares *big.Int
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
Raw          types.Log // Blockchain specific contextual infos
⋮----
// FilterWithdraw is a free log retrieval operation binding the contract event 0xebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f.
⋮----
// Solidity: event Withdraw(address indexed withdrawer, address indexed claimer, uint256 amount, uint256 burnedShares, uint256 mintedShares)
func (_Vault *VaultFilterer) FilterWithdraw(opts *bind.FilterOpts, withdrawer []common.Address, claimer []common.Address) (*VaultWithdrawIterator, error)
⋮----
var withdrawerRule []interface{}
⋮----
// WatchWithdraw is a free log subscription operation binding the contract event 0xebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f.
⋮----
func (_Vault *VaultFilterer) WatchWithdraw(opts *bind.WatchOpts, sink chan<- *VaultWithdraw, withdrawer []common.Address, claimer []common.Address) (event.Subscription, error)
⋮----
// ParseWithdraw is a log parse operation binding the contract event 0xebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f.
⋮----
func (_Vault *VaultFilterer) ParseWithdraw(log types.Log) (*VaultWithdraw, error)
```

## File: e2e/tests/evm/client.go

```go
package evm
⋮----
import (
	"context"
	"encoding/hex"
	"log/slog"
	"math/big"
	"regexp"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/e2e/tests/evm/gen"
	drivergen "github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"encoding/hex"
"log/slog"
"math/big"
"regexp"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/e2e/tests/evm/gen"
drivergen "github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type Config struct {
	ChainURL   string
	PrivateKey symbiotic.PrivateKey
}
⋮----
type Client struct {
	client  *ethclient.Client
	cfg     Config
	chainID *big.Int
}
⋮----
func NewClient(t *testing.T, cfg Config) *Client
⋮----
func (e *Client) Close()
⋮----
func (e *Client) TransferMockToken(ctx context.Context, tokenAddress, to common.Address, amount *big.Int) (symbiotic.TxResult, error)
⋮----
func (e *Client) ApproveMockToken(ctx context.Context, tokenAddress, vault common.Address, amount *big.Int) (symbiotic.TxResult, error)
⋮----
func (e *Client) VaultDeposit(ctx context.Context, vaultAddress, tokenAddress common.Address, amount *big.Int) (symbiotic.TxResult, error)
⋮----
func (e *Client) OptIn(ctx context.Context, optInServiceAddr, networkAddress common.Address) (symbiotic.TxResult, error)
⋮----
func (e *Client) GetAutoDeployVault(ctx context.Context, autoDeployVaultAddress, operator common.Address) (common.Address, error)
⋮----
func (e *Client) IsAutoDeployEnabled(ctx context.Context, autoDeployVaultAddress common.Address) (bool, error)
⋮----
func (e *Client) AddVotingPowerProvider(
	ctx context.Context,
	driverAddress common.Address,
	providerChainID uint64,
	providerAddress common.Address,
) (symbiotic.TxResult, error)
⋮----
func (e *Client) RemoveVotingPowerProvider(
	ctx context.Context,
	driverAddress common.Address,
	providerChainID uint64,
	providerAddress common.Address,
) (symbiotic.TxResult, error)
⋮----
func (e *Client) doTransaction(ctx context.Context, f func(opts *bind.TransactOpts) (*types.Transaction, error)) (symbiotic.TxResult, error)
⋮----
var customErrRegExp = regexp.MustCompile(`0x[0-9a-fA-F]{8}`)
⋮----
func (e *Client) formatEVMError(err error) error
⋮----
type jsonError interface {
		Error() string
		ErrorData() interface{}
var errData jsonError
⋮----
func findErrorBySelector(errSelector string) (abi.Error, bool)
```

## File: e2e/tests/api_test.go

```go
package tests
⋮----
import (
	"context"
	"fmt"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"context"
"fmt"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
const driverChainID = 31337
⋮----
// ContractExpectedData holds expected values derived from smart contracts
type ContractExpectedData struct {
	CurrentEpoch         symbiotic.Epoch
	EpochStartTime       symbiotic.Timestamp
	CurrentEpochDuration uint64
	ValidatorSet         symbiotic.ValidatorSet
	NetworkConfig        symbiotic.NetworkConfig
	IsEpochCommitted     bool
}
⋮----
// getExpectedDataFromContracts retrieves expected values directly from smart contracts
func getExpectedDataFromContracts(t *testing.T, relayContracts RelayContractsData) *ContractExpectedData
⋮----
// Check if current epoch is committed
⋮----
// validateValidatorSetAgainstExpected compares API response with expected contract data
func validateValidatorSetAgainstExpected(t *testing.T, apiResponse *apiv1.GetValidatorSetResponse, expected *ContractExpectedData)
⋮----
// TestRelayAPIConnectivity tests that all relay servers are accessible via gRPC
func TestRelayAPIConnectivity(t *testing.T)
⋮----
// TestValidatorSetAPI tests the GetValidatorSet API endpoint
func TestValidatorSetAPI(t *testing.T)
⋮----
const retryAttempts = 4
⋮----
func TestAPIsSequence(t *testing.T)
⋮----
func testListenSignaturesAPI(t *testing.T)
⋮----
func testListenProofsAPI(t *testing.T)
⋮----
func testListenValidatorSetAPI(t *testing.T)
⋮----
func testGetSignaturesByEpochAPI(t *testing.T)
⋮----
// Verify request_id field is present in each signature
⋮----
func testGetAggregationProofsByEpochAPI(t *testing.T)
⋮----
// Verify request_id field is present in each proof
⋮----
func testGetValidatorByKeyAPI(t *testing.T)
⋮----
func testGetSignatureRequestIDsByEpochAPI(t *testing.T)
⋮----
// Verify each request ID is a valid hex hash
⋮----
func testGetSignatureRequestsByEpochAPI(t *testing.T)
⋮----
// Verify each signature request has valid fields
⋮----
// Verify request ID
⋮----
// Verify key tag
⋮----
// Verify message
⋮----
// Verify required epoch matches the requested epoch
⋮----
func testGetSignatureRequestAPI(t *testing.T)
⋮----
// First, get current epoch
⋮----
// Get signature request IDs for current epoch
⋮----
// Get the first signature request by ID
⋮----
// Verify request ID is included and matches
⋮----
// Verify other fields are populated
⋮----
func testGetLocalValidatorAPI(t *testing.T)
```

## File: e2e/tests/epoch_test.go

```go
package tests
⋮----
import (
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// TestEpochProgression tests that epochs progress correctly over time
func TestEpochProgression(t *testing.T)
⋮----
func waitForNextCommitment(t *testing.T, evmClient *evm.Client)
⋮----
// ensure the current epoch gets committed, timeout after 2x epoch time and error if still not committed
⋮----
func waitForCommitmentInEpoch(t *testing.T, evmClient *evm.Client, epochTime uint64, waitForEpoch symbiotic.Epoch)
⋮----
// start watching for any new epochs being committed, will keep timeout to 5x the epoch duration
```

## File: e2e/tests/external_voting_power_provider_test.go

```go
package tests
⋮----
import (
	"context"
	"encoding/hex"
	"fmt"
	"math/big"
	"strings"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	evmtest "github.com/symbioticfi/relay/e2e/tests/evm"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	votingpowerclient "github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"context"
"encoding/hex"
"fmt"
"math/big"
"strings"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
evmtest "github.com/symbioticfi/relay/e2e/tests/evm"
"github.com/symbioticfi/relay/symbiotic/client/evm"
votingpowerclient "github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
const externalVotingPowerBonus = int64(100)
const externalVotingPowerChainID = votingpowerclient.ExternalVotingPowerChainIDMin
const maxEpochTransitionsToWait = 2
⋮----
var externalProviderID = [10]byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00}
⋮----
func TestExternalVotingPowerProvider_AddsBonusForExistingOperators(t *testing.T)
⋮----
func providerIDToHex(id [10]byte) string
⋮----
func providerAddressFromID(id [10]byte) common.Address
⋮----
var addr common.Address
⋮----
func cleanupExternalVotingPowerProviders(
	ctx context.Context,
	evmClient *evm.Client,
	adminEVM *evmtest.Client,
	driverAddress common.Address,
) error
⋮----
func ensureExternalProviderAbsent(
	ctx context.Context,
	evmClient *evm.Client,
	externalProvider symbiotic.CrossChainAddress,
	currentEpoch symbiotic.Epoch,
) error
```

## File: e2e/tests/genesis_test.go

```go
package tests
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// TestGenesisDone tests that the genesis validator set header has been committed
func TestGenesisDone(t *testing.T)
⋮----
// TestContractData tests that the data in the contract matches expected values
func TestContractData(t *testing.T)
```

## File: e2e/tests/http_gateway_test.go

```go
package tests
⋮----
import (
	"bufio"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"google.golang.org/protobuf/encoding/protojson"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
)
⋮----
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"testing"
"time"
⋮----
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protojson"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
⋮----
// httpGatewayBaseURL constructs the base URL for HTTP gateway requests
func httpGatewayBaseURL(t *testing.T) string
⋮----
// TestHTTPGateway_GetCurrentEpoch tests the HTTP gateway GET endpoint for current epoch
func TestHTTPGateway_GetCurrentEpoch(t *testing.T)
⋮----
// Get expected data from gRPC API
⋮----
// Make HTTP request
⋮----
// Verify HTTP status
⋮----
// Verify Content-Type
⋮----
// Parse response using protobuf JSON unmarshaler
⋮----
var httpResult apiv1.GetCurrentEpochResponse
⋮----
// Verify response matches gRPC data
⋮----
// TestHTTPGateway_GetValidatorSet tests the HTTP gateway GET endpoint for validator set
func TestHTTPGateway_GetValidatorSet(t *testing.T)
⋮----
var httpResult apiv1.GetValidatorSetResponse
⋮----
// TestHTTPGateway_StreamProofs tests the HTTP gateway streaming endpoint for proofs
func TestHTTPGateway_StreamProofs(t *testing.T)
⋮----
// Make HTTP streaming request
⋮----
// Verify SSE Content-Type
⋮----
// Verify SSE headers
⋮----
// Read streaming responses with timeout
⋮----
// Channel to signal when we've read enough messages
⋮----
// Skip empty lines
⋮----
// Parse SSE format: "data: {...}"
⋮----
// Parse the wrapper to extract the result field
var wrapper struct {
					Result json.RawMessage `json:"result"`
				}
⋮----
// Use protojson to unmarshal the result field
var sseMessage apiv1.ListenProofsResponse
⋮----
// Verify message structure (log warnings instead of failing in goroutine)
⋮----
// Wait for messages or timeout
⋮----
// Successfully received messages
⋮----
// Timeout - this is OK if no proofs were generated during test
⋮----
// Check for scanner errors
⋮----
// Only fail if we didn't receive any messages
⋮----
// TestHTTPGateway_StreamSignatures tests the HTTP gateway streaming endpoint for signatures
func TestHTTPGateway_StreamSignatures(t *testing.T)
⋮----
// Verify HTTP status and headers
⋮----
// Read a few messages to verify streaming
⋮----
var sseMessage apiv1.ListenSignaturesResponse
```

## File: e2e/tests/metadata_test.go

```go
package tests
⋮----
import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
)
⋮----
"context"
"fmt"
"testing"
"time"
⋮----
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
⋮----
// TestGetValidatorSetMetadata tests the GetValidatorSetMetadata API endpoint
// and verifies that the request id can be used to retrieve the proof of a committed valset
func TestGetValidatorSetMetadata(t *testing.T)
⋮----
// Get last committed epochs to find a committed epoch ≥1 for testing
// We need committed epochs because that's when proofs and signatures are available
var committedEpoch uint64
const maxRetries = 10
const retryDelay = 10 * time.Second
⋮----
// Find the minimum committed epoch across all chains that is ≥1
⋮----
// Test 1: Get metadata for committed epoch (should work and have proofs/signatures)
⋮----
// Validate response structure
⋮----
// ExtraData can be empty, so we don't require it to be non-empty
⋮----
// Test 2: Use the request id to get signature request
⋮----
// Validate the signature request
⋮----
// Test 3: Get aggregation proof (should exist for committed epochs)
⋮----
// For committed epochs, aggregation proof should be available
⋮----
// Test 4: Get signatures for the request id (should exist for committed epochs)
⋮----
// For committed epochs, signatures should be available
⋮----
// Validate signatures structure
⋮----
// Test 5: Get metadata without specifying epoch (should use current epoch)
⋮----
// Test 6: Try to get metadata for a future epoch (should fail)
⋮----
// Get current epoch to determine what would be a future epoch
⋮----
// TestGetLastAllCommitted tests the GetLastAllCommitted API endpoint
// and validates whether it returns proper epoch info for the contracts
func TestGetLastAllCommitted(t *testing.T)
⋮----
// Get expected data from contracts to validate against
⋮----
// Test the GetLastAllCommitted API
⋮----
// Get current epoch for validation
⋮----
// Validate that we have epoch info for all settlement chains in the network config
⋮----
// Validate that the epoch is reasonable (not 0 and not way in the future)
⋮----
// Validate start time is reasonable (not zero and not in the future)
⋮----
// Test individual GetLastCommitted for each chain to ensure consistency
⋮----
// Compare with the result from GetLastAllCommitted
⋮----
// Test edge case: query for non-existent chain
```

## File: e2e/tests/operator_test.go

```go
package tests
⋮----
import (
	"bytes"
	"context"
	"math/big"
	"strings"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	ethCrypto "github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	testEth "github.com/symbioticfi/relay/e2e/tests/evm"
	key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"bytes"
"context"
"math/big"
"strings"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
testEth "github.com/symbioticfi/relay/e2e/tests/evm"
key_registerer "github.com/symbioticfi/relay/internal/usecase/key-registerer"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
func TestAddAndRemoveOperator(t *testing.T)
⋮----
func checkOperatorProducesSignatures(t *testing.T, opData operatorData)
⋮----
func waitOperatorIncludedIntoValset(t *testing.T, opData operatorData, expectedCount int)
⋮----
func getValset(t *testing.T, opEVMClient *evm.Client) symbiotic.ValidatorSet
⋮----
func unregisterOperator(t *testing.T, opData operatorData)
⋮----
func registerOperator(t *testing.T, opData operatorData)
⋮----
if err != nil && !strings.Contains(err.Error(), "custom error 0xdcdeaba3") { // already opted in
⋮----
func initVault(t *testing.T, opData operatorData)
⋮----
func createTestEVM(t *testing.T, chainURL string, privateKey crypto.PrivateKey) *testEth.Client
⋮----
func getOperatorData(t *testing.T, operatorNumber int64) operatorData
⋮----
// Matches generate_network.sh: BASE_PRIVATE_KEY + operators
// BASE_PRIVATE_KEY = 1000000000000000000
⋮----
// Derive Ethereum address from private key
⋮----
type operatorData struct {
	number                 int
	privateKey             crypto.PrivateKey
	address                common.Address
	blsPrivateKey          crypto.PrivateKey
	blsPrivateKeySecondary crypto.PrivateKey
	bls12381PrivateKey     crypto.PrivateKey
}
⋮----
// createExtraOperator creates an operator using the extra relay's private key.
// The extra relay is not part of the validator set and uses a deterministic key
// based on the formula: BASE_PRIVATE_KEY + operators (matching generate_network.sh).
func createExtraOperator(t *testing.T) operatorData
⋮----
func fundOperator(
	ctx context.Context,
	pk crypto.PrivateKey,
	chainURL string,
	opAddr symbiotic.CrossChainAddress,
	amountWei *big.Int, // Amount in wei (e.g., 1 ether = 1e18 wei)
) (symbiotic.TxResult, error)
⋮----
amountWei *big.Int, // Amount in wei (e.g., 1 ether = 1e18 wei)
⋮----
Gas:      21000, // Standard gas limit for ETH transfer
⋮----
// Wait for transaction to be mined
```

## File: e2e/tests/settlement_test.go

```go
package tests
⋮----
import (
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	"github.com/symbioticfi/relay/symbiotic/entity"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
"github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
// TestRemoveSettlement verifies the settlement lifecycle management:
// 1. Removes a settlement from the network configuration
// 2. Waits for the next epoch and confirms removal took effect (2 → 1 settlement)
// 3. Re-adds the settlement back to the configuration
// 4. Sets genesis for the re-added settlement chain
// 5. Waits for another epoch and confirms both settlements are active and committed (1 → 2 settlements)
//
// This test validates that the relay network can dynamically handle settlement chain
// configuration changes across epoch boundaries and properly commits validator sets
// to all active settlement chains.
func TestRemoveAndAddSettlement(t *testing.T)
⋮----
var currentEpoch entity.Epoch
var currentConfig entity.NetworkConfig
⋮----
var oneSettlementConfig entity.NetworkConfig
⋮----
// Query the last committed epoch on the unmodified settlement to handle edge cases
// where the addition happens slightly delayed and oneSettlementEpoch+1 might've been committed
⋮----
var nextMetadata *apiv1.GetValidatorSetMetadataResponse
⋮----
// Get config for the genesis epoch
```

## File: e2e/tests/sidecar.yaml

```yaml
# E2E Test Sidecar Configuration

# Logging
log:
    level: "debug"
    mode: "json"

# API Server Configuration
api:
    listen: ":8080"
    verbose-logging: false
    http-gateway: true

# Metrics Configuration
metrics:
    pprof: false

# Driver Contract (address is set via command-line flag in tests)
driver:
    chain-id: 31337

# P2P Configuration
p2p:
    listen: "/ip4/0.0.0.0/tcp/8880"
    bootnodes:
        - /dns4/relay-sidecar-1/tcp/8880/p2p/16Uiu2HAmFUiPYAJ7bE88Q8d7Kznrw5ifrje2e5QFyt7uFPk2G3iR
    dht-mode: "server"
    mdns: true

# EVM Configuration
evm:
    chains:
        - "http://anvil:8545"
        - "http://anvil-settlement:8546"
    max-calls: 30

sync:
    enabled: true
    period: 5s
    timeout: 1m
    epochs: 1000

# Retention config
retention:
    valset-epochs: 1000
    signature-epochs: 1000
    proof-epochs: 1000

pruner:
    enabled: true

    interval: 1m
```

## File: e2e/tests/sign_test.go

```go
package tests
⋮----
import (
	"bytes"
	"context"
	"crypto/rand"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	cryptoModule "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"bytes"
"context"
"crypto/rand"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/crypto"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
cryptoModule "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
const (
	defaultECDSAKeyTag    = 16
	secondaryBLSKeyTag    = 11
	defaultBLS12381KeyTag = 33
)
⋮----
// TestNonHeaderKeySignature tests signing with different non-header key types
func TestNonHeaderKeySignature(t *testing.T)
⋮----
var resp *apiv1.SignMessageResponse
// retry sign call 3 times as it can get transaction conflict
⋮----
// wait for signatures
⋮----
// expect all n signatures for ECDSA and BLS12381 (non agg)
⋮----
// need at least 2/3 signatures for BLS, signers skip signing is proof is already generated so we may not get all n sigs
⋮----
// verify signatures based on key type
⋮----
// ECDSA signature verification using ethereum crypto
⋮----
// the contract stores 32 bytes padded address for ecdsa addrs,
// so stripping first 12 bytes to get to the address
⋮----
// Create public key from stored payload
⋮----
// Verify signature using BLS verification
⋮----
// check for proof
var proof *apiv1.GetAggregationProofResponse
⋮----
// if it's ZK proof, poll for the proof to be generated for the epoch duration
```

## File: e2e/tests/sync_test.go

```go
package tests
⋮----
import (
	"context"
	"net/http"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"context"
"net/http"
"os"
"strconv"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
// testPrivateKeyHex is the well-known Hardhat/Anvil test account #0 private key
// from /e2e/contracts/network-scripts/deploy.sh
const testPrivateKeyHex = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
⋮----
// TestAggregatorSignatureSync tests that aggregators can sync missed signatures
// and generate proofs even when they were offline during signature collection.
//
// Test scenario:
// 1. Get current epoch from EVM client
// 2. Stop all aggregators before signatures are generated
// 3. Wait for next epoch to trigger signature generation by signers
// 4. Verify signers have generated signatures
// 5. Start aggregators back up
// 6. Verify aggregators sync missed signatures and generate proofs
func TestAggregatorSignatureSync(t *testing.T)
⋮----
// Load deployment data to get contract addresses and environment info
⋮----
// Identify aggregators
⋮----
var aggregatorIndexes []int
⋮----
// Step 1: Get current epoch from EVM client
⋮----
// Step 2: Stop all aggregator containers
⋮----
// Step 3: Wait for next epoch to trigger signature generation
// During this time, signers will generate signatures but aggregators are offline
⋮----
// Step 4: Verify signers have generated signatures
⋮----
// Step 5: Start aggregators back up
⋮----
// Step 6: Verify aggregators have synced and generated proofs
⋮----
// Wait for aggregator to be healthy
⋮----
func TestAggregatorProofSync(t *testing.T)
⋮----
// Identify only signers
⋮----
// Step 2: Stop signer container
⋮----
// Step 3: Wait for next epoch to trigger proof generation
⋮----
var metadataResp *apiv1.GetValidatorSetMetadataResponse
⋮----
// Step 5: Start signer back up
⋮----
func waitForErrorIsNil(ctx context.Context, timeout time.Duration, f func() error) error
⋮----
// waitForHealthy polls a health endpoint until it returns 200 or timeout occurs
func waitForHealthy(ctx context.Context, healthURL string, timeout time.Duration) error
⋮----
// createEVMClient creates an EVM client for interacting with the blockchain
func createEVMClient(t *testing.T, deploymentData RelayContractsData) *evm.Client
⋮----
func getFunderPrivateKey(t *testing.T) crypto.PrivateKey
⋮----
func createEVMClientWithEVMKey(t *testing.T, deploymentData RelayContractsData, privateKey crypto.PrivateKey) *evm.Client
⋮----
// waitForEpoch waits until the specified epoch is reached
func waitForEpoch(ctx context.Context, client *evm.Client, targetEpoch symbiotic.Epoch, timeout time.Duration) error
⋮----
// Continue trying on error, but log it
⋮----
func waitEpochTimeout() time.Duration
```

## File: e2e/tests/types_test.go

```go
package tests
⋮----
import (
	"context"
	"encoding/hex"
	"fmt"
	"math/big"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/kelseyhightower/envconfig"
	"github.com/pelletier/go-toml/v2"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"

	apiv1 "github.com/symbioticfi/relay/api/client/v1"
	votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"encoding/hex"
"fmt"
"math/big"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/kelseyhightower/envconfig"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
⋮----
apiv1 "github.com/symbioticfi/relay/api/client/v1"
votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
var (
	settlementChains = []string{
		"http://localhost:8545", // Main anvil chain
		"http://localhost:8546", // Settlement anvil chain
	}
)
⋮----
"http://localhost:8545", // Main anvil chain
"http://localhost:8546", // Settlement anvil chain
⋮----
// ContractAddress represents a contract address with chain ID
type ContractAddress struct {
	Addr    string `json:"addr"`
	ChainId uint64 `json:"chainId"`
}
⋮----
// ChainAddresses holds all contract addresses for a chain
type ChainAddresses struct {
	KeyRegistry                 string `json:"key_registry,omitempty"`
	VaultFactory                string `json:"vault_factory"`
	DelegatorFactory            string `json:"delegator_factory"`
	SlasherFactory              string `json:"slasher_factory"`
	NetworkRegistry             string `json:"network_registry"`
	OperatorRegistry            string `json:"operator_registry"`
	OperatorMetadataService     string `json:"operator_metadata_service"`
	NetworkMetadataService      string `json:"network_metadata_service"`
	NetworkMiddlewareService    string `json:"network_middleware_service"`
	OperatorVaultOptInService   string `json:"operator_vault_opt_in_service"`
	OperatorNetworkOptInService string `json:"operator_network_opt_in_service"`
	VaultConfigurator           string `json:"vault_configurator"`
	Network                     string `json:"network"`
	StakingToken                string `json:"staking_token,omitempty"`
	VotingPowerProvider         string `json:"voting_power_provider,omitempty"`
	Settlement                  string `json:"settlement"`
	SumTask                     string `json:"sum_task"`
	ValSetDriver                string `json:"val_set_driver,omitempty"`
}
⋮----
// ChainConfig holds configuration for a specific chain
type ChainConfig struct {
	ChainID     uint64         `json:"chain_id"`
	EndpointURL string         `json:"endpoint_url"`
	Addresses   ChainAddresses `json:"addresses"`
}
⋮----
// NetworkConfig holds the network-level configuration
type NetworkConfig struct {
	NetworkID           uint64   `json:"network_id"`
	EndpointURL         string   `json:"endpoint_url"`
	KeyRegistry         uint64   `json:"key_registry"`
	VotingPowerProvider []uint64 `json:"voting_power_provider"`
	Settlement          []uint64 `json:"settlement"`
	ValSetDriver        uint64   `json:"val_set_driver"`
}
⋮----
// RelayContractsData represents the structure from relay_contracts.json
type RelayContractsData struct {
	Driver ContractAddress `json:"driver"`

	// Parsed chains from TOML
	MainChain       ChainConfig   `json:"main_chain"`
	SettlementChain ChainConfig   `json:"settlement_chain"`
	Network         NetworkConfig `json:"network"`

	Env EnvInfo `json:"-"`
}
⋮----
// Parsed chains from TOML
⋮----
type EnvInfo struct {
	Operators        int64  `default:"4" split_words:"true"`
	Commiters        int64  `default:"1" split_words:"true"`
	Aggregators      int64  `default:"1" split_words:"true"`
	EpochTime        uint64 `default:"30" split_words:"true"`
	VerificationType uint32 `default:"1" split_words:"true"`
}
⋮----
type RelaySidecarConfig struct {
	ContainerName  string
	RequiredSymKey crypto.PrivateKey
}
⋮----
func (i EnvInfo) GetSidecarConfigs() []RelaySidecarConfig
⋮----
const basePrivateKey = 1000000000000000000
⋮----
// GetDriverAddress returns the driver address as a string for backward compatibility
func (d RelayContractsData) GetDriverAddress() string
⋮----
// tomlDeploymentData represents the structure of my-relay-deploy.toml
type tomlDeploymentData struct {
	Chain31337 tomlChainData   `toml:"31337"`
	Chain31338 tomlChainData   `toml:"31338"`
	Network    tomlNetworkData `toml:"1234567890"`
}
⋮----
type tomlChainData struct {
	EndpointURL string        `toml:"endpoint_url"`
	Address     tomlAddresses `toml:"address"`
}
⋮----
type tomlAddresses struct {
	KeyRegistry                 string `toml:"key_registry"`
	VaultFactory                string `toml:"vault_factory"`
	DelegatorFactory            string `toml:"delegator_factory"`
	SlasherFactory              string `toml:"slasher_factory"`
	NetworkRegistry             string `toml:"network_registry"`
	OperatorRegistry            string `toml:"operator_registry"`
	OperatorMetadataService     string `toml:"operator_metadata_service"`
	NetworkMetadataService      string `toml:"network_metadata_service"`
	NetworkMiddlewareService    string `toml:"network_middleware_service"`
	OperatorVaultOptInService   string `toml:"operator_vault_opt_in_service"`
	OperatorNetworkOptInService string `toml:"operator_network_opt_in_service"`
	VaultConfigurator           string `toml:"vault_configurator"`
	Network                     string `toml:"network"`
	StakingToken                string `toml:"staking_token"`
	VotingPowerProvider         string `toml:"voting_power_provider"`
	Settlement                  string `toml:"settlement"`
	SumTask                     string `toml:"sum_task"`
	ValSetDriver                string `toml:"val_set_driver"`
}
⋮----
type tomlNetworkData struct {
	EndpointURL         string   `toml:"endpoint_url"`
	KeyRegistry         uint64   `toml:"keyRegistry"`
	VotingPowerProvider []uint64 `toml:"votingPowerProvider"`
	Settlement          []uint64 `toml:"settlement"`
	ValSetDriver        uint64   `toml:"valSetDriver"`
}
⋮----
func loadDeploymentData(t *testing.T) RelayContractsData
⋮----
// Read TOML file from temp-network directory
⋮----
// Parse TOML
var deployData tomlDeploymentData
⋮----
// Extract driver address from chain 31337
⋮----
// testMockKeyProvider is a mock key provider for testing
type testMockKeyProvider struct{}
⋮----
func (m *testMockKeyProvider) GetPrivateKey(_ symbiotic.KeyTag) (crypto.PrivateKey, error)
⋮----
func (m *testMockKeyProvider) GetPrivateKeyByAlias(_ string) (crypto.PrivateKey, error)
⋮----
func (m *testMockKeyProvider) GetPrivateKeyByNamespaceTypeId(_ string, _ symbiotic.KeyType, _ int) (crypto.PrivateKey, error)
⋮----
func (m *testMockKeyProvider) HasKey(_ symbiotic.KeyTag) (bool, error)
⋮----
func (m *testMockKeyProvider) HasKeyByAlias(_ string) (bool, error)
⋮----
func (m *testMockKeyProvider) HasKeyByNamespaceTypeId(_ string, _ symbiotic.KeyType, _ int) (bool, error)
⋮----
func getContainerPort(i int) int
⋮----
func getGRPCClient(t *testing.T, index int) *apiv1.SymbioticClient
⋮----
func getHealthEndpoint(i int) string
⋮----
type bonusVotingPowerServer struct {
	votingpowerv1.UnimplementedVotingPowerProviderServiceServer

	operators   []common.Address
	votingPower int64
}
⋮----
func (s *bonusVotingPowerServer) GetVotingPowersAt(
	_ context.Context,
	_ *votingpowerv1.GetVotingPowersAtRequest,
) (*votingpowerv1.GetVotingPowersAtResponse, error)
⋮----
func startBonusVotingPowerServer(t *testing.T, operators []common.Address, votingPower int64) string
⋮----
func startContainer(ctx context.Context, container string) error
⋮----
func stopContainer(ctx context.Context, container string) error
```

## File: e2e/README.md

````markdown
# E2E Testing Guide

This directory contains end-to-end tests for the Symbiotic Relay project. The tests run against a local blockchain network with configurable relay operators, commiters, and aggregators.

## Prerequisites

- Docker and Docker Compose
- Go 1.26+
- Node.js and npm (for smart contract compilation)
- Foundry (forge) for contract building

## Quick Start

1. **Setup the test environment:**

    ```bash
    ./setup.sh
    ```

2. **Start the network:**

    ```bash
    cd temp-network
    docker compose up -d
    cd ..
    ```

3. **Run the tests:**
    ```bash
    cd tests
    go test -v
    ```

## Configuration

You can customize the test environment by setting environment variables before running `setup.sh`. All variables have sensible defaults.

### Environment Variables

| Variable            | Default | Description                                               |
| ------------------- | ------- | --------------------------------------------------------- |
| `OPERATORS`         | `4`     | Number of relay operators (max: 999)                      |
| `COMMITERS`         | `1`     | Number of commiter nodes                                  |
| `AGGREGATORS`       | `1`     | Number of aggregator nodes                                |
| `VERIFICATION_TYPE` | `1`     | Verification type: `0`=BLS-BN254-ZK, `1`=BLS-BN254-SIMPLE |
| `EPOCH_TIME`        | `30`    | Time for new epochs in relay network (seconds)            |
| `BLOCK_TIME`        | `1`     | Block time in seconds for anvil interval mining           |
| `FINALITY_BLOCKS`   | `2`     | Number of blocks for finality                             |

### Example with Custom Configuration

```bash
# Set custom configuration
export OPERATORS=6
export COMMITERS=2
export AGGREGATORS=1
export VERIFICATION_TYPE=0
export EPOCH_TIME=32
export BLOCK_TIME=2

# Run setup
./setup.sh

# Start network
cd temp-network
docker compose up -d
cd ..

# Run tests
cd tests
go test -v
```

## Contract Information

The tests use smart contracts from the Symbiotic protocol:

- **Repository**: https://github.com/symbioticfi/symbiotic-super-sum

The commit hash can be updated in `setup.sh` if needed for testing against different contract versions.
````

## File: e2e/setup.sh

```bash
#!/bin/bash

set -eo pipefail

# Configuration

# Contracts commit hash to use
CONTRACTS_COMMIT="1a804aea49da44ea7c7490fa07a8f7b2a9ce36a8"

# Circuits commit
CIRCUITS_COMMIT="e2e-branch"

# -----------------------------------------

echo "Building Relay Docker image for e2e tests..."
# go to root of repo
cd ..
make image TAG=dev
# get back into e2e
cd e2e

# Check if temp-network directory exists and clean up any running containers
if [ -d "temp-network" ]; then
    echo "Found existing temp-network directory. Attempting to clean up running containers..."
    cd temp-network
    if ! docker compose down; then
        echo "WARNING: Failed to run 'docker compose down' in temp-network directory."
        echo "Please manually clean up the temp-network directory and any running containers before proceeding."
        echo "You can try: cd temp-network && docker compose down --remove-orphans && cd .. && rm -rf temp-network"
        exit 1
    fi
    cd ..
    echo "Successfully cleaned up existing containers."
fi

echo "Setting up Symbiotic contracts..."
if [ ! -d "contracts" ]; then
    echo "Cloning Symbiotic contracts repository..."
    git clone https://github.com/symbioticfi/symbiotic-super-sum contracts
else
    echo "Contracts directory already exists, skipping clone..."
fi
cd contracts
git fetch origin
git checkout $CONTRACTS_COMMIT

echo "Installing dependencies..."
npm install
echo "Building contracts..."
forge build

cd ..

# Pass through all environment variables to generate_network.sh with defaults
export OPERATORS=${OPERATORS}
export COMMITERS=${COMMITERS}
export AGGREGATORS=${AGGREGATORS}
export VERIFICATION_TYPE=${VERIFICATION_TYPE}
export EPOCH_TIME=${EPOCH_TIME}
export BLOCK_TIME=${BLOCK_TIME}
export FINALITY_BLOCKS=${FINALITY_BLOCKS}
export COMMITTER_SLOT_DURATION=${COMMITTER_SLOT_DURATION}
export STORAGE_TYPE=${STORAGE_TYPE}

# Call the generate network script
./scripts/generate_network.sh

# If verification type is 0, clone the circuit keys repository
if [ "${VERIFICATION_TYPE}" = "0" ]; then
    echo "Verification type is 0, cloning circuit keys repository..."
    if [ ! -d "temp-network/circuits" ]; then
        echo "Cloning circuit keys repository (shallow clone of specific commit)..."
        # Create circuits directory in temp-network
        mkdir -p temp-network/circuits
        cd temp-network/circuits

        # Initialize empty git repo and add remote
        git init
        git remote add origin https://github.com/symbioticfi/relay-bn254-example-circuit-keys

        # Fetch only the specific commit (shallow) with parallel jobs for speed
        git fetch --depth 1 --jobs=4 origin $CIRCUITS_COMMIT
        git checkout FETCH_HEAD

        # Remove git metadata to keep only the files
        rm -rf .git

        cd ../..
        echo "Circuit keys cloned successfully to temp-network/circuits/"
    else
        echo "Circuits directory already exists in temp-network, skipping clone..."
    fi

    echo "Copying circuits to contracts directory and building..."
    cp -r temp-network/circuits contracts/circuits
    cd contracts
    echo "Building circuits with Forge..."
    forge build circuits/
else
    echo "Verification type is not 0, skipping circuit keys clone..."
fi



echo "Setup complete! Network configuration generated in temp-network/ directory."
```

## File: hack/codegen/generate-client-types.go

```go
package main
⋮----
// generate-client-types is a tool to parse the generated protobuf file and create a client types file
// that exports types for client usage, including enums, requests, responses, and data types.
⋮----
import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"regexp"
	"sort"
	"strings"
)
⋮----
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"regexp"
"sort"
"strings"
⋮----
const clientTemplate = `// Code generated by generate-client-types. DO NOT EDIT.
package v1

import (
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
)

// Exported types for client usage

%s
`
⋮----
type TypeInfo struct {
	Name      string
	Category  string
	IsEnum    bool
	Constants []string
}
⋮----
func main()
⋮----
// Parse the generated protobuf file
⋮----
// Generate the client file content
⋮----
// Write to client file
⋮----
func parseGeneratedFile(filename string) ([]TypeInfo, error)
⋮----
// Read the file content
⋮----
// Parse using AST
⋮----
var types []TypeInfo
⋮----
// Walk the AST to find type declarations
⋮----
// Skip internal/private types
⋮----
// Determine type category and if it's an enum
⋮----
// Check if it's an enum (int32 type)
⋮----
func isExportedType(typeName string) bool
⋮----
// Skip internal protobuf types and unexported types
⋮----
func categorizeStruct(typeName string) string
⋮----
return "response" // ErrorResponse goes with responses
⋮----
func findEnumConstants(content, enumName string) []string
⋮----
var constants []string
⋮----
// Use regex to find enum constants
⋮----
func generateClientContent(types []TypeInfo) string
⋮----
var sections []string
⋮----
// Group types by category
⋮----
// Sort each category
⋮----
// Generate enums section
⋮----
// Generate enum constants
⋮----
// Generate request types section
⋮----
// Generate response types section
⋮----
// Generate data types section
⋮----
func hasEnumConstants(enums []TypeInfo) bool
```

## File: hack/docgen/generate-cli-docs.go

```go
package main
⋮----
import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra/doc"
	relay "github.com/symbioticfi/relay/cmd/relay/root"
	utils "github.com/symbioticfi/relay/cmd/utils/root"
)
⋮----
"fmt"
"log"
"os"
"path/filepath"
"strings"
⋮----
"github.com/spf13/cobra/doc"
relay "github.com/symbioticfi/relay/cmd/relay/root"
utils "github.com/symbioticfi/relay/cmd/utils/root"
⋮----
func main()
⋮----
// The default header looks like `Argocd app get`. The leading capital letter is off-putting.
// This header overrides the default. It's better visually and for search results.
⋮----
filename = filename[:len(filename)-3] // Drop the '.md'
⋮----
// Create docs/cli directory
⋮----
// Disable auto-generated timestamp line
```

## File: internal/client/p2p/proto/v1/message_grpc.pb.go

```go
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc             (unknown)
// source: v1/message.proto
⋮----
package v1
⋮----
import (
	context "context"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
)
⋮----
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
⋮----
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
⋮----
const (
	SymbioticP2PService_WantSignatures_FullMethodName        = "/internal.client.p2p.proto.v1.SymbioticP2PService/WantSignatures"
	SymbioticP2PService_WantAggregationProofs_FullMethodName = "/internal.client.p2p.proto.v1.SymbioticP2PService/WantAggregationProofs"
)
⋮----
// SymbioticP2PServiceClient is the client API for SymbioticP2PService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SymbioticP2PServiceClient interface {
	WantSignatures(ctx context.Context, in *WantSignaturesRequest, opts ...grpc.CallOption) (*WantSignaturesResponse, error)
	WantAggregationProofs(ctx context.Context, in *WantAggregationProofsRequest, opts ...grpc.CallOption) (*WantAggregationProofsResponse, error)
}
⋮----
type symbioticP2PServiceClient struct {
	cc grpc.ClientConnInterface
}
⋮----
func NewSymbioticP2PServiceClient(cc grpc.ClientConnInterface) SymbioticP2PServiceClient
⋮----
func (c *symbioticP2PServiceClient) WantSignatures(ctx context.Context, in *WantSignaturesRequest, opts ...grpc.CallOption) (*WantSignaturesResponse, error)
⋮----
func (c *symbioticP2PServiceClient) WantAggregationProofs(ctx context.Context, in *WantAggregationProofsRequest, opts ...grpc.CallOption) (*WantAggregationProofsResponse, error)
⋮----
// SymbioticP2PServiceServer is the server API for SymbioticP2PService service.
// All implementations must embed UnimplementedSymbioticP2PServiceServer
// for forward compatibility.
type SymbioticP2PServiceServer interface {
	WantSignatures(context.Context, *WantSignaturesRequest) (*WantSignaturesResponse, error)
	WantAggregationProofs(context.Context, *WantAggregationProofsRequest) (*WantAggregationProofsResponse, error)
	mustEmbedUnimplementedSymbioticP2PServiceServer()
}
⋮----
// UnimplementedSymbioticP2PServiceServer must be embedded to have
// forward compatible implementations.
⋮----
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedSymbioticP2PServiceServer struct{}
⋮----
func (UnimplementedSymbioticP2PServiceServer) mustEmbedUnimplementedSymbioticP2PServiceServer()
func (UnimplementedSymbioticP2PServiceServer) testEmbeddedByValue()
⋮----
// UnsafeSymbioticP2PServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SymbioticP2PServiceServer will
// result in compilation errors.
type UnsafeSymbioticP2PServiceServer interface {
	mustEmbedUnimplementedSymbioticP2PServiceServer()
}
⋮----
func RegisterSymbioticP2PServiceServer(s grpc.ServiceRegistrar, srv SymbioticP2PServiceServer)
⋮----
// If the following call pancis, it indicates UnimplementedSymbioticP2PServiceServer was
// embedded by pointer and is nil.  This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
⋮----
func _SymbioticP2PService_WantSignatures_Handler(srv interface
⋮----
func _SymbioticP2PService_WantAggregationProofs_Handler(srv interface
⋮----
// SymbioticP2PService_ServiceDesc is the grpc.ServiceDesc for SymbioticP2PService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var SymbioticP2PService_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "internal.client.p2p.proto.v1.SymbioticP2PService",
	HandlerType: (*SymbioticP2PServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "WantSignatures",
			Handler:    _SymbioticP2PService_WantSignatures_Handler,
		},
		{
			MethodName: "WantAggregationProofs",
			Handler:    _SymbioticP2PService_WantAggregationProofs_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "v1/message.proto",
}
```

## File: internal/client/p2p/proto/v1/message.pb.go

```go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.36.6
// 	protoc        (unknown)
// source: v1/message.proto
⋮----
package v1
⋮----
import (
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
	unsafe "unsafe"
)
⋮----
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
⋮----
const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
⋮----
// Verify that this generated code is sufficiently up-to-date.
⋮----
// Verify that runtime/protoimpl is sufficiently up-to-date.
⋮----
// AggregationProof represents the aggregated signatures message
type AggregationProof struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	KeyTag        uint32                 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	Epoch         uint64                 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	MessageHash   []byte                 `protobuf:"bytes,4,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	Proof         []byte                 `protobuf:"bytes,5,opt,name=proof,proto3" json:"proof,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
func (x *AggregationProof) Reset()
⋮----
func (x *AggregationProof) String() string
⋮----
func (*AggregationProof) ProtoMessage()
⋮----
func (x *AggregationProof) ProtoReflect() protoreflect.Message
⋮----
// Deprecated: Use AggregationProof.ProtoReflect.Descriptor instead.
func (*AggregationProof) Descriptor() ([]byte, []int)
⋮----
func (x *AggregationProof) GetKeyTag() uint32
⋮----
func (x *AggregationProof) GetEpoch() uint64
⋮----
func (x *AggregationProof) GetMessageHash() []byte
⋮----
func (x *AggregationProof) GetProof() []byte
⋮----
// P2PMessage represents a peer-to-peer message wrapper
type P2PMessage struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Sender        string                 `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"`
	Timestamp     int64                  `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
	Data          []byte                 `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
	TraceContext  map[string]string      `protobuf:"bytes,4,rep,name=trace_context,json=traceContext,proto3" json:"trace_context,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use P2PMessage.ProtoReflect.Descriptor instead.
⋮----
func (x *P2PMessage) GetSender() string
⋮----
func (x *P2PMessage) GetTimestamp() int64
⋮----
func (x *P2PMessage) GetData() []byte
⋮----
func (x *P2PMessage) GetTraceContext() map[string]string
⋮----
type WantSignaturesRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Map of request id to bitmap of wanted validator indices
	WantSignatures map[string][]byte `protobuf:"bytes,1,rep,name=want_signatures,json=wantSignatures,proto3" json:"want_signatures,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash, value: roaring bitmap bytes
	unknownFields  protoimpl.UnknownFields
	sizeCache      protoimpl.SizeCache
}
⋮----
// Map of request id to bitmap of wanted validator indices
WantSignatures map[string][]byte `protobuf:"bytes,1,rep,name=want_signatures,json=wantSignatures,proto3" json:"want_signatures,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash, value: roaring bitmap bytes
⋮----
// Deprecated: Use WantSignaturesRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *WantSignaturesRequest) GetWantSignatures() map[string][]byte
⋮----
type WantSignaturesResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Map of request id to list of validator signatures
	Signatures    map[string]*ValidatorSignatureList `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Map of request id to list of validator signatures
Signatures    map[string]*ValidatorSignatureList `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash
⋮----
// Deprecated: Use WantSignaturesResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *WantSignaturesResponse) GetSignatures() map[string]*ValidatorSignatureList
⋮----
// ValidatorSignatureList contains a list of validator signatures for a specific request
type ValidatorSignatureList struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Signatures    []*ValidatorSignature  `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorSignatureList.ProtoReflect.Descriptor instead.
⋮----
// ValidatorSignature pairs a signature with its validator index
type ValidatorSignature struct {
	state          protoimpl.MessageState `protogen:"open.v1"`
	ValidatorIndex uint32                 `protobuf:"varint,1,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"`
	Signature      *Signature             `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
	unknownFields  protoimpl.UnknownFields
	sizeCache      protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorSignature.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorSignature) GetValidatorIndex() uint32
⋮----
func (x *ValidatorSignature) GetSignature() *Signature
⋮----
// Signature represents extended signature data
type Signature struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	MessageHash   []byte                 `protobuf:"bytes,1,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	KeyTag        uint32                 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	Epoch         uint64                 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	Signature     []byte                 `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"`
	PublicKey     []byte                 `protobuf:"bytes,5,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
⋮----
func (x *Signature) GetPublicKey() []byte
⋮----
type WantAggregationProofsRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of request ids for which aggregation proofs are needed
	RequestIds    []string `protobuf:"bytes,1,rep,name=request_ids,json=requestIds,proto3" json:"request_ids,omitempty"` // hex strings of common.Hash
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// List of request ids for which aggregation proofs are needed
RequestIds    []string `protobuf:"bytes,1,rep,name=request_ids,json=requestIds,proto3" json:"request_ids,omitempty"` // hex strings of common.Hash
⋮----
// Deprecated: Use WantAggregationProofsRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *WantAggregationProofsRequest) GetRequestIds() []string
⋮----
type WantAggregationProofsResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Map of request ids to aggregation proof
	Proofs        map[string]*AggregationProof `protobuf:"bytes,1,rep,name=proofs,proto3" json:"proofs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Map of request ids to aggregation proof
Proofs        map[string]*AggregationProof `protobuf:"bytes,1,rep,name=proofs,proto3" json:"proofs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // key: hex string of common.Hash
⋮----
// Deprecated: Use WantAggregationProofsResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *WantAggregationProofsResponse) GetProofs() map[string]*AggregationProof
⋮----
var File_v1_message_proto protoreflect.FileDescriptor
⋮----
const file_v1_message_proto_rawDesc = "" +
	"\n" +
	"\x10v1/message.proto\x12\x1cinternal.client.p2p.proto.v1\"z\n" +
	"\x10AggregationProof\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12!\n" +
	"\fmessage_hash\x18\x04 \x01(\fR\vmessageHash\x12\x14\n" +
	"\x05proof\x18\x05 \x01(\fR\x05proof\"\xf8\x01\n" +
	"\n" +
	"P2PMessage\x12\x16\n" +
	"\x06sender\x18\x01 \x01(\tR\x06sender\x12\x1c\n" +
	"\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x12\x12\n" +
	"\x04data\x18\x03 \x01(\fR\x04data\x12_\n" +
	"\rtrace_context\x18\x04 \x03(\v2:.internal.client.p2p.proto.v1.P2PMessage.TraceContextEntryR\ftraceContext\x1a?\n" +
	"\x11TraceContextEntry\x12\x10\n" +
	"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
	"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xcc\x01\n" +
	"\x15WantSignaturesRequest\x12p\n" +
	"\x0fwant_signatures\x18\x01 \x03(\v2G.internal.client.p2p.proto.v1.WantSignaturesRequest.WantSignaturesEntryR\x0ewantSignatures\x1aA\n" +
	"\x13WantSignaturesEntry\x12\x10\n" +
	"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
	"\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"\xf3\x01\n" +
	"\x16WantSignaturesResponse\x12d\n" +
	"\n" +
	"signatures\x18\x02 \x03(\v2D.internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntryR\n" +
	"signatures\x1as\n" +
	"\x0fSignaturesEntry\x12\x10\n" +
	"\x03key\x18\x01 \x01(\tR\x03key\x12J\n" +
	"\x05value\x18\x02 \x01(\v24.internal.client.p2p.proto.v1.ValidatorSignatureListR\x05value:\x028\x01\"j\n" +
	"\x16ValidatorSignatureList\x12P\n" +
	"\n" +
	"signatures\x18\x01 \x03(\v20.internal.client.p2p.proto.v1.ValidatorSignatureR\n" +
	"signatures\"\x84\x01\n" +
	"\x12ValidatorSignature\x12'\n" +
	"\x0fvalidator_index\x18\x01 \x01(\rR\x0evalidatorIndex\x12E\n" +
	"\tsignature\x18\x02 \x01(\v2'.internal.client.p2p.proto.v1.SignatureR\tsignature\"\x9a\x01\n" +
	"\tSignature\x12!\n" +
	"\fmessage_hash\x18\x01 \x01(\fR\vmessageHash\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12\x1c\n" +
	"\tsignature\x18\x04 \x01(\fR\tsignature\x12\x1d\n" +
	"\n" +
	"public_key\x18\x05 \x01(\fR\tpublicKey\"?\n" +
	"\x1cWantAggregationProofsRequest\x12\x1f\n" +
	"\vrequest_ids\x18\x01 \x03(\tR\n" +
	"requestIds\"\xeb\x01\n" +
	"\x1dWantAggregationProofsResponse\x12_\n" +
	"\x06proofs\x18\x01 \x03(\v2G.internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntryR\x06proofs\x1ai\n" +
	"\vProofsEntry\x12\x10\n" +
	"\x03key\x18\x01 \x01(\tR\x03key\x12D\n" +
	"\x05value\x18\x02 \x01(\v2..internal.client.p2p.proto.v1.AggregationProofR\x05value:\x028\x012\xa5\x02\n" +
	"\x13SymbioticP2PService\x12{\n" +
	"\x0eWantSignatures\x123.internal.client.p2p.proto.v1.WantSignaturesRequest\x1a4.internal.client.p2p.proto.v1.WantSignaturesResponse\x12\x90\x01\n" +
	"\x15WantAggregationProofs\x12:.internal.client.p2p.proto.v1.WantAggregationProofsRequest\x1a;.internal.client.p2p.proto.v1.WantAggregationProofsResponseB\x80\x02\n" +
	" com.internal.client.p2p.proto.v1B\fMessageProtoP\x01Z9github.com/symbioticfi/relay/internal/client/p2p/proto/v1\xa2\x02\x04ICPP\xaa\x02\x1cInternal.Client.P2p.Proto.V1\xca\x02\x1cInternal\\Client\\P2p\\Proto\\V1\xe2\x02(Internal\\Client\\P2p\\Proto\\V1\\GPBMetadata\xea\x02 Internal::Client::P2p::Proto::V1b\x06proto3"
⋮----
var (
	file_v1_message_proto_rawDescOnce sync.Once
	file_v1_message_proto_rawDescData []byte
)
⋮----
func file_v1_message_proto_rawDescGZIP() []byte
⋮----
var file_v1_message_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_v1_message_proto_goTypes = []any{
	(*AggregationProof)(nil),              // 0: internal.client.p2p.proto.v1.AggregationProof
	(*P2PMessage)(nil),                    // 1: internal.client.p2p.proto.v1.P2PMessage
	(*WantSignaturesRequest)(nil),         // 2: internal.client.p2p.proto.v1.WantSignaturesRequest
	(*WantSignaturesResponse)(nil),        // 3: internal.client.p2p.proto.v1.WantSignaturesResponse
	(*ValidatorSignatureList)(nil),        // 4: internal.client.p2p.proto.v1.ValidatorSignatureList
	(*ValidatorSignature)(nil),            // 5: internal.client.p2p.proto.v1.ValidatorSignature
	(*Signature)(nil),                     // 6: internal.client.p2p.proto.v1.Signature
	(*WantAggregationProofsRequest)(nil),  // 7: internal.client.p2p.proto.v1.WantAggregationProofsRequest
	(*WantAggregationProofsResponse)(nil), // 8: internal.client.p2p.proto.v1.WantAggregationProofsResponse
	nil,                                   // 9: internal.client.p2p.proto.v1.P2PMessage.TraceContextEntry
	nil,                                   // 10: internal.client.p2p.proto.v1.WantSignaturesRequest.WantSignaturesEntry
	nil,                                   // 11: internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry
	nil,                                   // 12: internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry
}
⋮----
(*AggregationProof)(nil),              // 0: internal.client.p2p.proto.v1.AggregationProof
(*P2PMessage)(nil),                    // 1: internal.client.p2p.proto.v1.P2PMessage
(*WantSignaturesRequest)(nil),         // 2: internal.client.p2p.proto.v1.WantSignaturesRequest
(*WantSignaturesResponse)(nil),        // 3: internal.client.p2p.proto.v1.WantSignaturesResponse
(*ValidatorSignatureList)(nil),        // 4: internal.client.p2p.proto.v1.ValidatorSignatureList
(*ValidatorSignature)(nil),            // 5: internal.client.p2p.proto.v1.ValidatorSignature
(*Signature)(nil),                     // 6: internal.client.p2p.proto.v1.Signature
(*WantAggregationProofsRequest)(nil),  // 7: internal.client.p2p.proto.v1.WantAggregationProofsRequest
(*WantAggregationProofsResponse)(nil), // 8: internal.client.p2p.proto.v1.WantAggregationProofsResponse
nil,                                   // 9: internal.client.p2p.proto.v1.P2PMessage.TraceContextEntry
nil,                                   // 10: internal.client.p2p.proto.v1.WantSignaturesRequest.WantSignaturesEntry
nil,                                   // 11: internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry
nil,                                   // 12: internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry
⋮----
var file_v1_message_proto_depIdxs = []int32{
	9,  // 0: internal.client.p2p.proto.v1.P2PMessage.trace_context:type_name -> internal.client.p2p.proto.v1.P2PMessage.TraceContextEntry
	10, // 1: internal.client.p2p.proto.v1.WantSignaturesRequest.want_signatures:type_name -> internal.client.p2p.proto.v1.WantSignaturesRequest.WantSignaturesEntry
	11, // 2: internal.client.p2p.proto.v1.WantSignaturesResponse.signatures:type_name -> internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry
	5,  // 3: internal.client.p2p.proto.v1.ValidatorSignatureList.signatures:type_name -> internal.client.p2p.proto.v1.ValidatorSignature
	6,  // 4: internal.client.p2p.proto.v1.ValidatorSignature.signature:type_name -> internal.client.p2p.proto.v1.Signature
	12, // 5: internal.client.p2p.proto.v1.WantAggregationProofsResponse.proofs:type_name -> internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry
	4,  // 6: internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry.value:type_name -> internal.client.p2p.proto.v1.ValidatorSignatureList
	0,  // 7: internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry.value:type_name -> internal.client.p2p.proto.v1.AggregationProof
	2,  // 8: internal.client.p2p.proto.v1.SymbioticP2PService.WantSignatures:input_type -> internal.client.p2p.proto.v1.WantSignaturesRequest
	7,  // 9: internal.client.p2p.proto.v1.SymbioticP2PService.WantAggregationProofs:input_type -> internal.client.p2p.proto.v1.WantAggregationProofsRequest
	3,  // 10: internal.client.p2p.proto.v1.SymbioticP2PService.WantSignatures:output_type -> internal.client.p2p.proto.v1.WantSignaturesResponse
	8,  // 11: internal.client.p2p.proto.v1.SymbioticP2PService.WantAggregationProofs:output_type -> internal.client.p2p.proto.v1.WantAggregationProofsResponse
	10, // [10:12] is the sub-list for method output_type
	8,  // [8:10] is the sub-list for method input_type
	8,  // [8:8] is the sub-list for extension type_name
	8,  // [8:8] is the sub-list for extension extendee
	0,  // [0:8] is the sub-list for field type_name
}
⋮----
9,  // 0: internal.client.p2p.proto.v1.P2PMessage.trace_context:type_name -> internal.client.p2p.proto.v1.P2PMessage.TraceContextEntry
10, // 1: internal.client.p2p.proto.v1.WantSignaturesRequest.want_signatures:type_name -> internal.client.p2p.proto.v1.WantSignaturesRequest.WantSignaturesEntry
11, // 2: internal.client.p2p.proto.v1.WantSignaturesResponse.signatures:type_name -> internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry
5,  // 3: internal.client.p2p.proto.v1.ValidatorSignatureList.signatures:type_name -> internal.client.p2p.proto.v1.ValidatorSignature
6,  // 4: internal.client.p2p.proto.v1.ValidatorSignature.signature:type_name -> internal.client.p2p.proto.v1.Signature
12, // 5: internal.client.p2p.proto.v1.WantAggregationProofsResponse.proofs:type_name -> internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry
4,  // 6: internal.client.p2p.proto.v1.WantSignaturesResponse.SignaturesEntry.value:type_name -> internal.client.p2p.proto.v1.ValidatorSignatureList
0,  // 7: internal.client.p2p.proto.v1.WantAggregationProofsResponse.ProofsEntry.value:type_name -> internal.client.p2p.proto.v1.AggregationProof
2,  // 8: internal.client.p2p.proto.v1.SymbioticP2PService.WantSignatures:input_type -> internal.client.p2p.proto.v1.WantSignaturesRequest
7,  // 9: internal.client.p2p.proto.v1.SymbioticP2PService.WantAggregationProofs:input_type -> internal.client.p2p.proto.v1.WantAggregationProofsRequest
3,  // 10: internal.client.p2p.proto.v1.SymbioticP2PService.WantSignatures:output_type -> internal.client.p2p.proto.v1.WantSignaturesResponse
8,  // 11: internal.client.p2p.proto.v1.SymbioticP2PService.WantAggregationProofs:output_type -> internal.client.p2p.proto.v1.WantAggregationProofsResponse
10, // [10:12] is the sub-list for method output_type
8,  // [8:10] is the sub-list for method input_type
8,  // [8:8] is the sub-list for extension type_name
8,  // [8:8] is the sub-list for extension extendee
0,  // [0:8] is the sub-list for field type_name
⋮----
func init()
func file_v1_message_proto_init()
⋮----
type x struct{}
```

## File: internal/client/p2p/proto/v1/message.proto

```protobuf
syntax = "proto3";

package internal.client.p2p.proto.v1;

option go_package = "github.com/symbioticfi/relay/internal/client/p2p/proto/v1";

// AggregationProof represents the aggregated signatures message
message AggregationProof {
  uint32 key_tag = 2;
  uint64 epoch = 3;
  bytes message_hash = 4;
  bytes proof = 5;
}

// P2PMessage represents a peer-to-peer message wrapper
message P2PMessage {
  string sender = 1;
  int64 timestamp = 2;
  bytes data = 3;
  map<string, string> trace_context = 4;
}

service SymbioticP2PService {
  rpc WantSignatures(WantSignaturesRequest) returns (WantSignaturesResponse);
  rpc WantAggregationProofs(WantAggregationProofsRequest) returns (WantAggregationProofsResponse);

}

message WantSignaturesRequest {
  // Map of request id to bitmap of wanted validator indices
  map<string, bytes> want_signatures = 1;  // key: hex string of common.Hash, value: roaring bitmap bytes
}

message WantSignaturesResponse {
  // Map of request id to list of validator signatures
  map<string, ValidatorSignatureList> signatures = 2;  // key: hex string of common.Hash
}


// ValidatorSignatureList contains a list of validator signatures for a specific request
message ValidatorSignatureList {
  repeated ValidatorSignature signatures = 1;
}

// ValidatorSignature pairs a signature with its validator index
message ValidatorSignature {
  uint32 validator_index = 1;
  Signature signature = 2;
}

// Signature represents extended signature data
message Signature {
  bytes message_hash = 1;
  uint32 key_tag = 2;
  uint64 epoch = 3;
  bytes signature = 4;
  bytes public_key = 5;
}

message WantAggregationProofsRequest {
  // List of request ids for which aggregation proofs are needed
  repeated string request_ids = 1;  // hex strings of common.Hash
}

message WantAggregationProofsResponse {
  // Map of request ids to aggregation proof
  map<string, AggregationProof> proofs = 1;  // key: hex string of common.Hash
}
```

## File: internal/client/p2p/broadcast_signature_aggregated_message.go

```go
package p2p
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/go-errors/errors"
	"google.golang.org/protobuf/proto"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/protobuf/proto"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (s *Service) BroadcastSignatureAggregatedMessage(ctx context.Context, msg symbiotic.AggregationProof) error
```

## File: internal/client/p2p/broadcast_signature_generated_message.go

```go
package p2p
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/go-errors/errors"
	"google.golang.org/protobuf/proto"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/protobuf/proto"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (s *Service) BroadcastSignatureGeneratedMessage(ctx context.Context, msg symbiotic.Signature) error
```

## File: internal/client/p2p/discovery_integration_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func TestDiscoveryService_Start_WithDHTEnabled_InitializesDHT(t *testing.T)
⋮----
func TestDiscoveryService_Start_WithDHTDisabled_SkipsDHT(t *testing.T)
⋮----
func TestDiscoveryService_Start_WhenAlreadyStarted_ReturnsError(t *testing.T)
⋮----
func TestDiscoveryService_initDHT_WithClientMode_Success(t *testing.T)
⋮----
func TestDiscoveryService_initDHT_WithBootstrapPeers_ParsesPeers(t *testing.T)
⋮----
func TestDiscoveryService_initMDNS_WhenDisabled_ReturnsNil(t *testing.T)
⋮----
func TestDiscoveryService_initMDNS_WhenEnabled_InitializesMDNS(t *testing.T)
⋮----
func TestDiscoveryService_Close_WithDHTAndMDNS_ClosesAll(t *testing.T)
⋮----
func TestDiscoveryService_HandlePeerFound_ConnectsToPeer(t *testing.T)
⋮----
func TestDiscoveryService_Advertise_WithValidRdiscov_SuccessOrExpectedError(t *testing.T)
⋮----
func TestDiscoveryService_Advertise_WithZeroTTL_CallsAdvertise(t *testing.T)
⋮----
func TestDiscoveryService_GetDiscoveryClient_WhenInitialized_ReturnsClient(t *testing.T)
```

## File: internal/client/p2p/discovery_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/libp2p/go-libp2p"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/multiformats/go-multiaddr"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func createMockHost(t *testing.T) host.Host
⋮----
func TestDiscoveryService_determineDHTMode_Client(t *testing.T)
⋮----
func TestDiscoveryService_determineDHTMode_Server(t *testing.T)
⋮----
func TestDiscoveryService_determineDHTMode_Auto(t *testing.T)
⋮----
func TestDiscoveryService_determineDHTMode_Empty(t *testing.T)
⋮----
func TestDiscoveryService_determineDHTMode_Invalid(t *testing.T)
⋮----
func TestDiscoveryService_parseBootstrapPeers_EmptyList(t *testing.T)
⋮----
func TestDiscoveryService_parseBootstrapPeers_ValidPeer(t *testing.T)
⋮----
func TestDiscoveryService_parseBootstrapPeers_InvalidPeer(t *testing.T)
⋮----
func TestDiscoveryService_parseBootstrapPeers_SkipsSelfPeer(t *testing.T)
⋮----
func TestDiscoveryService_parseBootstrapPeers_MultiplePeers(t *testing.T)
⋮----
func TestDiscoveryService_GetDiscoveryClient_WhenNotInitialized_ReturnsNil(t *testing.T)
⋮----
func TestNewDiscoveryService_WithValidHost_Success(t *testing.T)
⋮----
func TestNewDiscoveryService_WithNilHost_ReturnsError(t *testing.T)
⋮----
func TestDiscoveryService_Advertise_WhenRdiscovIsNil_ReturnsError(t *testing.T)
⋮----
func TestDiscoveryService_connectToPeer_AlreadyConnected_ReturnsNil(t *testing.T)
⋮----
func TestDiscoveryService_connectToPeer_NotConnected_ConnectsToPeer(t *testing.T)
⋮----
func TestDiscoveryService_connectToPeer_WithTimeout_ReturnsError(t *testing.T)
⋮----
func TestDiscoveryService_Close_WhenNotStarted_ReturnsNil(t *testing.T)
```

## File: internal/client/p2p/discovery.go

```go
package p2p
⋮----
import (
	"context"
	"log/slog"
	"sync"
	"time"

	"github.com/go-errors/errors"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	"github.com/libp2p/go-libp2p/core/discovery"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/p2p/discovery/mdns"
	drouting "github.com/libp2p/go-libp2p/p2p/discovery/routing"
)
⋮----
"context"
"log/slog"
"sync"
"time"
⋮----
"github.com/go-errors/errors"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/discovery"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/discovery/mdns"
drouting "github.com/libp2p/go-libp2p/p2p/discovery/routing"
⋮----
// DiscoveryService implements peer discovery functionality allowing both DHT and mDNS.
type DiscoveryService struct {
	cfg  Config
	host host.Host

	dht     *dht.IpfsDHT
	mdns    mdns.Service
	rdiscov *drouting.RoutingDiscovery

	mu                sync.RWMutex
	started           bool
	ctx               context.Context
	cancel            context.CancelFunc
	lastAdvertisement time.Time

	bootstrapPeers []peer.AddrInfo
}
⋮----
// DiscoverySvc represents the peer discovery service interface.
type DiscoverySvc interface {
	Start(ctx context.Context) error
	Close(ctx context.Context) error
	GetDiscoveryClient(ctx context.Context) *drouting.RoutingDiscovery
}
⋮----
const ProtocolPrefix = "/symbiotic"
⋮----
// NewDiscoveryService creates a new discovery service.
func NewDiscoveryService(cfg Config) (*DiscoveryService, error)
⋮----
func (s *DiscoveryService) initDHT(ctx context.Context) error
⋮----
func (s *DiscoveryService) determineDHTMode(ctx context.Context) dht.ModeOpt
⋮----
func (s *DiscoveryService) parseBootstrapPeers(ctx context.Context) ([]peer.AddrInfo, error)
⋮----
func (s *DiscoveryService) initMDNS(ctx context.Context) error
⋮----
func (s *DiscoveryService) Start(ctx context.Context) error
⋮----
func (s *DiscoveryService) maintainConnections(ctx context.Context)
⋮----
func (s *DiscoveryService) Close(ctx context.Context) error
⋮----
func (s *DiscoveryService) GetDiscoveryClient(ctx context.Context) *drouting.RoutingDiscovery
⋮----
func (s *DiscoveryService) Advertise(ctx context.Context, topic string) error
⋮----
// HandlePeerFound processes a newly discovered mDNS peer and attempts to connect.
func (s *DiscoveryService) HandlePeerFound(peerInfo peer.AddrInfo)
⋮----
// linter suggests to use separate context
⋮----
// Attempt to connect to the discovered peer
⋮----
func (s *DiscoveryService) connectToPeer(ctx context.Context, peerInfo peer.AddrInfo) error
```

## File: internal/client/p2p/p2p_broadcast_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"testing"
⋮----
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func TestService_ID_ReturnsHostID(t *testing.T)
⋮----
func TestService_Broadcast_TopicNotFound_ReturnsError(t *testing.T)
⋮----
func TestService_AddPeer_SkipsSelfConnection(t *testing.T)
⋮----
func TestService_AddPeer_ConnectsToValidPeer(t *testing.T)
```

## File: internal/client/p2p/p2p_grpc_handler.go

```go
package p2p
⋮----
import (
	"context"

	"github.com/go-errors/errors"

	p2pv1 "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
⋮----
p2pv1 "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
⋮----
// syncRequestHandler defines the interface for handling both signature and aggregation proof requests
type syncRequestHandler interface {
	HandleWantSignaturesRequest(ctx context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
	HandleWantAggregationProofsRequest(ctx context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
}
⋮----
type GRPCHandler struct {
	p2pv1.UnimplementedSymbioticP2PServiceServer

	syncHandler syncRequestHandler
}
⋮----
func NewP2PHandler(syncHandler syncRequestHandler) *GRPCHandler
⋮----
// WantSignatures handles incoming signature requests from peers
func (h *GRPCHandler) WantSignatures(ctx context.Context, req *p2pv1.WantSignaturesRequest) (*p2pv1.WantSignaturesResponse, error)
⋮----
// WantAggregationProofs handles incoming aggregation proof requests from peers
func (h *GRPCHandler) WantAggregationProofs(ctx context.Context, req *p2pv1.WantAggregationProofsRequest) (*p2pv1.WantAggregationProofsResponse, error)
```

## File: internal/client/p2p/p2p_grpc_send_want_aggregation_proofs_request_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/peerstore"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestSendWantAggregationProofsRequest_HappyPath(t *testing.T)
⋮----
type mockAggregationProofHandler struct {
	expectedRequest  entity.WantAggregationProofsRequest
	responseToReturn entity.WantAggregationProofsResponse
	wasCalled        bool
	receivedRequest  entity.WantAggregationProofsRequest
}
⋮----
func (m *mockAggregationProofHandler) HandleWantSignaturesRequest(_ context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
⋮----
func (m *mockAggregationProofHandler) HandleWantAggregationProofsRequest(_ context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
```

## File: internal/client/p2p/p2p_grpc_send_want_aggregation_proofs_request.go

```go
package p2p
⋮----
import (
	"context"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/samber/lo"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/samber/lo"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// SendWantAggregationProofsRequest sends a synchronous aggregation proof request to a peer
func (s *Service) SendWantAggregationProofsRequest(ctx context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
⋮----
// Convert entity request to protobuf
⋮----
// Select a peer for the request
⋮----
// Send request to the selected peer
⋮----
// sendAggregationProofRequestToPeer sends a gRPC aggregation proof request to a specific peer
func (s *Service) sendAggregationProofRequestToPeer(ctx context.Context, peerID peer.ID, req *prototypes.WantAggregationProofsRequest) (*prototypes.WantAggregationProofsResponse, error)
⋮----
// Create gRPC connection over libp2p stream
⋮----
// Create gRPC client and send request
⋮----
// entityToProtoAggregationProofRequest converts entity.WantAggregationProofsRequest to protobuf
func entityToProtoAggregationProofRequest(req entity.WantAggregationProofsRequest) *prototypes.WantAggregationProofsRequest
⋮----
// protoToEntityAggregationProofResponse converts protobuf WantAggregationProofsResponse to entity
func protoToEntityAggregationProofResponse(resp *prototypes.WantAggregationProofsResponse) entity.WantAggregationProofsResponse
⋮----
// Convert aggregation proof
⋮----
// protoToEntityAggregationProofRequest converts protobuf WantAggregationProofsRequest to entity
func protoToEntityAggregationProofRequest(req *prototypes.WantAggregationProofsRequest) entity.WantAggregationProofsRequest
⋮----
// entityToProtoAggregationProofResponse converts entity WantAggregationProofsResponse to protobuf
func entityToProtoAggregationProofResponse(resp entity.WantAggregationProofsResponse) *prototypes.WantAggregationProofsResponse
```

## File: internal/client/p2p/p2p_grpc_send_want_signatures_request_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/peerstore"
	"github.com/stretchr/testify/require"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/stretchr/testify/require"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestSendWantSignaturesRequest_HappyPath(t *testing.T)
⋮----
// Setup two libp2p hosts (peer1 as client, peer2 as server)
⋮----
// Manually connect the peers by adding addresses to peerstore
⋮----
// Actually connect the peers
⋮----
// Create test data for the request
⋮----
// Create signature bitmaps (requesting signatures from validators 0, 2, 5)
⋮----
// Create expected response data
⋮----
// Setup mock sync request handler for the server
⋮----
// Create server P2P service using NewService constructor
⋮----
SkipMessageSign: true, // Skip message signing for tests
⋮----
// Start the gRPC server
⋮----
// Stop server
⋮----
// Create client P2P service using NewService constructor
⋮----
Handler:     NewP2PHandler(mockHandler), // Not used for client but required
⋮----
// Execute the test: send want signatures request
⋮----
// Verify the response
⋮----
// Verify signatures for testHash1
⋮----
// Find and verify first signature
var foundSig1, foundSig2 *entity.ValidatorSignature
⋮----
// Verify signatures for testHash2
⋮----
// Verify that the mock handler was called with the correct request
⋮----
// mockSyncRequestHandler implements syncRequestHandler for testing
type mockSyncRequestHandler struct {
	expectedRequest  entity.WantSignaturesRequest
	responseToReturn entity.WantSignaturesResponse
	wasCalled        bool
	receivedRequest  entity.WantSignaturesRequest
}
⋮----
func (m *mockSyncRequestHandler) HandleWantSignaturesRequest(_ context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
⋮----
func (m *mockSyncRequestHandler) HandleWantAggregationProofsRequest(_ context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
⋮----
// Return empty response for tests that don't need aggregation proof functionality
```

## File: internal/client/p2p/p2p_grpc_send_want_signatures_request.go

```go
package p2p
⋮----
import (
	"context"
	"log/slog"
	"math/rand/v2"
	"net"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	gostream "github.com/libp2p/go-libp2p-gostream"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/protocol"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"go.opentelemetry.io/otel/trace"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"log/slog"
"math/rand/v2"
"net"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
gostream "github.com/libp2p/go-libp2p-gostream"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
const grpcProtocolTag protocol.ID = "/relay/v1/grpc"
⋮----
// SendWantSignaturesRequest sends a synchronous signature request to a peer
func (s *Service) SendWantSignaturesRequest(ctx context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
⋮----
// Convert entity request to protobuf
⋮----
// Select a peer for the request
⋮----
// Send request to the selected peer
⋮----
// Convert protobuf response to entity
⋮----
// sendRequestToPeer sends a gRPC request to a specific peer
func (s *Service) sendRequestToPeer(ctx context.Context, peerID peer.ID, req *prototypes.WantSignaturesRequest) (*prototypes.WantSignaturesResponse, error)
⋮----
// Create gRPC connection over libp2p stream
⋮----
// Create gRPC client and send request
⋮----
// createGRPCConnection creates a gRPC connection to a peer over libp2p
func (s *Service) createGRPCConnection(ctx context.Context, peerID peer.ID) (*grpc.ClientConn, error)
⋮----
// Attach tracing interceptors whenever we have a valid span context so trace headers propagate
⋮----
// entityToProtoRequest converts entity.WantSignaturesRequest to protobuf
func entityToProtoRequest(req entity.WantSignaturesRequest) (*prototypes.WantSignaturesRequest, error)
⋮----
// Serialize roaring bitmap to bytes
⋮----
// protoToEntityResponse converts protobuf WantSignaturesResponse to entity
func protoToEntityResponse(ctx context.Context, resp *prototypes.WantSignaturesResponse) entity.WantSignaturesResponse
⋮----
// Convert validator signatures
var validatorSigs []entity.ValidatorSignature
⋮----
// selectPeerForSync selects a single peer for synchronous signature requests
func (s *Service) selectPeerForSync() (peer.ID, error)
⋮----
//nolint:gosec // G404: non-cryptographic random selection
⋮----
// protoToEntityRequest converts protobuf WantSignaturesRequest to entity
func protoToEntityRequest(req *prototypes.WantSignaturesRequest) (entity.WantSignaturesRequest, error)
⋮----
// Deserialize roaring bitmap from bytes
⋮----
// entityToProtoResponse converts entity WantSignaturesResponse to protobuf
func entityToProtoResponse(resp entity.WantSignaturesResponse) *prototypes.WantSignaturesResponse
```

## File: internal/client/p2p/p2p_grpc_test.go

```go
package p2p
⋮----
import (
	"context"
	"net"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
	"github.com/libp2p/go-libp2p"
	gostream "github.com/libp2p/go-libp2p-gostream"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/peerstore"
	"github.com/libp2p/go-libp2p/core/protocol"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	v2 "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"net"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
"github.com/libp2p/go-libp2p"
gostream "github.com/libp2p/go-libp2p-gostream"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
⋮----
v2 "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestP2P_GRPC(t *testing.T)
⋮----
var tag protocol.ID = "/testp2pgrpc"
⋮----
type myHandler struct {
	v2.UnimplementedSymbioticP2PServiceServer
}
⋮----
func (m myHandler) WantSignatures(ctx context.Context, request *v2.WantSignaturesRequest) (*v2.WantSignaturesResponse, error)
⋮----
func (m myHandler) HandleWantSignaturesRequest(ctx context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
⋮----
func (m myHandler) HandleWantAggregationProofsRequest(ctx context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
```

## File: internal/client/p2p/p2p_handle_message_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/libp2p/go-libp2p"
	pubsub "github.com/libp2p/go-libp2p-pubsub"
	pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
	"github.com/libp2p/go-libp2p/core/crypto"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/p2p/security/noise"
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
	"github.com/samber/lo"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"google.golang.org/grpc"

	p2pEntity "github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/libp2p/go-libp2p"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"google.golang.org/grpc"
⋮----
p2pEntity "github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
// TestService_IntegrationSuccessful tests full P2P communication between two services
func TestService_IntegrationSuccessful(t *testing.T)
⋮----
// Create two libp2p hosts
⋮----
// Connect the peers
⋮----
time.Sleep(100 * time.Millisecond) // Small delay to ensure the gossip protocol is set up
⋮----
// Wait for connection to establish
⋮----
// Set up message listener on service2
var receivedMsg p2pEntity.P2PMessage[symbiotic.Signature]
⋮----
// Prepare test message
⋮----
// Publish until service2 receives, retrying every 500ms. A publish into an
// empty gossipsub mesh (which can happen on slow CI before GRAFT lands)
// is silently dropped — retrying papers over that race without needing to
// reach into gossipsub internals.
⋮----
// TestService_IntegrationFailedSignature tests P2P communication with a message that fails signature verification
func TestService_IntegrationFailedSignature(t *testing.T)
⋮----
// Publish until the rejection arrives (or test ctx expires) — see comment
// on broadcastUntilReceived in TestService_IntegrationSuccessful.
⋮----
var rejectEvt *pubsub_pb.TraceEvent
⋮----
func createTestService(t *testing.T, skipMessageSigning bool, tracer pubsub.EventTracer) *Service
⋮----
type rejectTracer struct {
	rejectCh chan *pubsub_pb.TraceEvent
}
⋮----
func (rt *rejectTracer) Trace(evt *pubsub_pb.TraceEvent)
⋮----
// mockMetrics implements the metrics interface for testing
type mockMetrics struct{}
⋮----
func (m *mockMetrics) UnaryServerInterceptor() grpc.UnaryServerInterceptor
⋮----
func (m *mockMetrics) StreamServerInterceptor() grpc.StreamServerInterceptor
⋮----
func (m *mockMetrics) ObserveP2PBroadcastDuration(topic, status string, d time.Duration)
func (m *mockMetrics) ObserveP2PPeerMessageSent(messageType, status string)
⋮----
func TestService_AggregatedProofIntegrationSuccessful(t *testing.T)
⋮----
var receivedMsg p2pEntity.P2PMessage[symbiotic.AggregationProof]
⋮----
// broadcastUntilReceived publishes via `publish` repeatedly (every 500ms) until
// `done` closes or `ctx` expires. A publish into an empty gossipsub mesh
// returns nil but delivers nothing; retrying papers over that race instead of
// reaching into the mesh state from the test.
func broadcastUntilReceived(ctx context.Context, t *testing.T, done <-chan struct
```

## File: internal/client/p2p/p2p_handle_message_unit_test.go

```go
package p2p
⋮----
import (
	"fmt"
	"testing"

	pubsub "github.com/libp2p/go-libp2p-pubsub"
	pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"google.golang.org/protobuf/proto"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
)
⋮----
"fmt"
"testing"
⋮----
pubsub "github.com/libp2p/go-libp2p-pubsub"
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
⋮----
func TestHandleSignatureReadyMessage_WithOversizedPublicKey_ReturnsError(t *testing.T)
⋮----
func TestHandleSignatureReadyMessage_WithOversizedSignature_ReturnsError(t *testing.T)
⋮----
func TestHandleSignatureReadyMessage_WithOversizedMessageHash_ReturnsError(t *testing.T)
⋮----
func TestHandleSignatureReadyMessage_WithInvalidPublicKey_ReturnsError(t *testing.T)
⋮----
func TestHandleAggregatedProofReadyMessage_WithOversizedMessageHash_ReturnsError(t *testing.T)
⋮----
func TestHandleAggregatedProofReadyMessage_WithOversizedProof_ReturnsError(t *testing.T)
⋮----
func TestUnmarshalMessage_WithInvalidP2PMessage_ReturnsError(t *testing.T)
⋮----
var signature prototypes.Signature
⋮----
func TestUnmarshalMessage_WithInvalidInnerMessage_ReturnsError(t *testing.T)
⋮----
func TestExtractSenderInfo_WithInvalidPeerID_ReturnsError(t *testing.T)
```

## File: internal/client/p2p/p2p_handle_message.go

```go
package p2p
⋮----
import (
	"github.com/go-errors/errors"
	pubsub "github.com/libp2p/go-libp2p-pubsub"
	"google.golang.org/protobuf/proto"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	p2pEntity "github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"github.com/go-errors/errors"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"google.golang.org/protobuf/proto"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
p2pEntity "github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func (s *Service) handleSignatureReadyMessage(pubSubMsg *pubsub.Message) error
⋮----
var signature prototypes.Signature
⋮----
// Validate the signature message
⋮----
func (s *Service) handleAggregatedProofReadyMessage(pubSubMsg *pubsub.Message) error
⋮----
var signaturesAggregated prototypes.AggregationProof
⋮----
// Validate the signaturesAggregated message
⋮----
// The Simple format is the smaller of the two; the ZK verifier enforces
// its own larger minimum at parse time. Use the Simple floor here as a
// cheap defence against obviously-bogus messages before they reach the
// scheme-specific decoder.
⋮----
func extractSenderInfo(pubSubMsg *pubsub.Message) (p2pEntity.SenderInfo, error)
⋮----
// try to extract public key from sender peer.ID
⋮----
func unmarshalMessage(msg *pubsub.Message, v proto.Message) (*prototypes.P2PMessage, error)
⋮----
var message prototypes.P2PMessage
```

## File: internal/client/p2p/p2p_sync_peer_state_test.go

```go
package p2p
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/peerstore"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/stretchr/testify/require"
⋮----
func TestSelectPeerForSync_SkipsCooledDownPeersWhenPossible(t *testing.T)
⋮----
func TestSelectPeerForSync_FallsBackWhenAllPeersAreCooledDown(t *testing.T)
⋮----
func TestMarkPeerSyncFailure_IncreasesCooldown(t *testing.T)
⋮----
func TestNextSyncPeerCooldown_UsesConfiguredBackoffAndCap(t *testing.T)
⋮----
func TestMarkPeerSyncSuccess_ClearsFailureState(t *testing.T)
⋮----
func newServiceWithConnectedPeers(t *testing.T, peerCount int, now time.Time) (*Service, []peer.ID, func())
```

## File: internal/client/p2p/p2p_sync_peer_state.go

```go
package p2p
⋮----
import (
	"math"
	"time"

	"github.com/libp2p/go-libp2p/core/peer"
)
⋮----
"math"
"time"
⋮----
"github.com/libp2p/go-libp2p/core/peer"
⋮----
type peerSyncFailure struct {
	consecutiveFailures int
	cooldownUntil       time.Time
}
⋮----
func (s *Service) currentTime() time.Time
⋮----
func (s *Service) getEligibleSyncPeers(peers []peer.ID) []peer.ID
⋮----
func (s *Service) markPeerSyncFailure(peerID peer.ID)
⋮----
func (s *Service) markPeerSyncSuccess(peerID peer.ID)
⋮----
func (s *Service) nextSyncPeerCooldown(failureCount int) time.Duration
```

## File: internal/client/p2p/p2p_test.go

```go
package p2p
⋮----
import (
	"testing"
	"time"

	"github.com/libp2p/go-libp2p"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"testing"
"time"
⋮----
"github.com/libp2p/go-libp2p"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func TestConfig_Validate_Success(t *testing.T)
⋮----
func TestConfig_Validate_MissingHost(t *testing.T)
⋮----
func TestConfig_Validate_MissingMetrics(t *testing.T)
⋮----
func TestConfig_Validate_MissingHandler(t *testing.T)
⋮----
func TestDefaultDiscoveryConfig_ReturnsValidConfig(t *testing.T)
⋮----
func TestDefaultSyncPeerBackoffConfig_ReturnsValidConfig(t *testing.T)
⋮----
func TestConfig_Validate_InvalidSyncPeerBackoff(t *testing.T)
```

## File: internal/client/p2p/p2p.go

```go
package p2p
⋮----
import (
	"context"
	"log/slog"
	"sync"
	"time"

	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	gostream "github.com/libp2p/go-libp2p-gostream"
	pubsub "github.com/libp2p/go-libp2p-pubsub"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/multiformats/go-multiaddr"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/proto"

	prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
	p2pEntity "github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/server"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"sync"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
gostream "github.com/libp2p/go-libp2p-gostream"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
⋮----
prototypes "github.com/symbioticfi/relay/internal/client/p2p/proto/v1"
p2pEntity "github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/server"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	topicPrefix = "/relay/v1"

	topicSignatureReady = topicPrefix + "/signature/ready"
	topicAggProofReady  = topicPrefix + "/proof/ready"

	maxP2PMessageSize = 1<<20 + 1024 // 1 MiB + 1 KiB for overhead
	maxPubKeySize     = 144          // BLS12381 pubkey is 144 bytes
	maxSignatureSize  = 96
	maxMsgHashSize    = 64
	maxProofSize      = 1 << 20

	// defaultPublishTimeout is used when Config.PublishTimeout is zero.
	defaultPublishTimeout = 10 * time.Second
)
⋮----
maxP2PMessageSize = 1<<20 + 1024 // 1 MiB + 1 KiB for overhead
maxPubKeySize     = 144          // BLS12381 pubkey is 144 bytes
⋮----
// defaultPublishTimeout is used when Config.PublishTimeout is zero.
⋮----
type metrics interface {
	ObserveP2PBroadcastDuration(topic, status string, d time.Duration)
	ObserveP2PPeerMessageSent(messageType, status string)
	UnaryServerInterceptor() grpc.UnaryServerInterceptor
	StreamServerInterceptor() grpc.StreamServerInterceptor
}
⋮----
type SyncPeerBackoffConfig struct {
	MinBackoff time.Duration `mapstructure:"min-backoff"`
	Base       float64       `mapstructure:"base"`
	MaxBackoff time.Duration `mapstructure:"max-backoff"`
}
⋮----
func DefaultSyncPeerBackoffConfig() SyncPeerBackoffConfig
⋮----
func normalizeSyncPeerBackoffConfig(cfg SyncPeerBackoffConfig) SyncPeerBackoffConfig
⋮----
// DiscoveryConfig contains discovery protocol configuration
type DiscoveryConfig struct {
	// EnableMDNS specifies whether mDNS discovery is enabled.
	EnableMDNS bool
	// MDNSServiceName is the mDNS service name.
	MDNSServiceName string

	// DHTMode specifies the DHT mode.
	DHTMode string
	// BootstrapPeers is the list of bootstrap peers in multiaddr format.
	BootstrapPeers []string
	// AdvertiseTTL is the advertise time-to-live duration.
	AdvertiseTTL time.Duration
	// AdvertiseServiceName is the advertise service name.
	AdvertiseServiceName string
	// AdvertiseInterval is the interval between advertisements.
	AdvertiseInterval time.Duration
	// ConnectionTimeout is the timeout for peer connections.
	ConnectionTimeout time.Duration
	// MaxDHTReconnectPeerCount is the maximum number of DHT reconnect peers.
	MaxDHTReconnectPeerCount int
	// DHTPeerDiscoveryInterval is the interval for DHT peer discovery. Should be smaller than AdvertiseInterval.
	DHTPeerDiscoveryInterval time.Duration
	// DHTRoutingTableRefreshInterval is the interval for DHT routing table refresh. Should be greater than DHTPeerDiscoveryInterval.
	DHTRoutingTableRefreshInterval time.Duration
}
⋮----
// EnableMDNS specifies whether mDNS discovery is enabled.
⋮----
// MDNSServiceName is the mDNS service name.
⋮----
// DHTMode specifies the DHT mode.
⋮----
// BootstrapPeers is the list of bootstrap peers in multiaddr format.
⋮----
// AdvertiseTTL is the advertise time-to-live duration.
⋮----
// AdvertiseServiceName is the advertise service name.
⋮----
// AdvertiseInterval is the interval between advertisements.
⋮----
// ConnectionTimeout is the timeout for peer connections.
⋮----
// MaxDHTReconnectPeerCount is the maximum number of DHT reconnect peers.
⋮----
// DHTPeerDiscoveryInterval is the interval for DHT peer discovery. Should be smaller than AdvertiseInterval.
⋮----
// DHTRoutingTableRefreshInterval is the interval for DHT routing table refresh. Should be greater than DHTPeerDiscoveryInterval.
⋮----
func DefaultDiscoveryConfig() DiscoveryConfig
⋮----
AdvertiseTTL:                   3 * time.Hour, // max allowed value in kdht package
⋮----
DHTRoutingTableRefreshInterval: 10 * time.Minute, // same as kdht package default
⋮----
type Config struct {
	Host            host.Host `validate:"required"`
	SkipMessageSign bool
	Metrics         metrics         `validate:"required"`
	Discovery       DiscoveryConfig `validate:"required"`
	SyncPeerBackoff SyncPeerBackoffConfig
	EventTracer     pubsub.EventTracer
	Handler         prototypes.SymbioticP2PServiceServer `validate:"required"`
	// PublishTimeout caps how long pubsub.Topic.Publish may block on a single
	// broadcast. Zero falls back to defaultPublishTimeout.
	PublishTimeout time.Duration
}
⋮----
// PublishTimeout caps how long pubsub.Topic.Publish may block on a single
// broadcast. Zero falls back to defaultPublishTimeout.
⋮----
func (c Config) withDefaults() Config
⋮----
func (c Config) Validate() error
⋮----
// Service handles peer-to-peer communication and signature aggregation
type Service struct {
	ctx                         context.Context
	host                        host.Host
	signatureReceivedHandler    *signals.Signal[p2pEntity.P2PMessage[symbiotic.Signature]]
	signaturesAggregatedHandler *signals.Signal[p2pEntity.P2PMessage[symbiotic.AggregationProof]]
	metrics                     metrics
	topicsMap                   map[string]*pubsub.Topic
	p2pGRPCHandler              prototypes.SymbioticP2PServiceServer
	publishTimeout              time.Duration
	syncPeerBackoff             SyncPeerBackoffConfig
	peerSyncMu                  sync.RWMutex
	peerSyncState               map[peer.ID]peerSyncFailure
	now                         func() time.Time
}
⋮----
// NewService creates a new P2P service with the given configuration
func NewService(ctx context.Context, cfg Config, signalCfg signals.Config) (*Service, error)
⋮----
func (s *Service) listenForMessages(ctx context.Context, sub *pubsub.Subscription, topic *pubsub.Topic, handler func(msg *pubsub.Message) error)
⋮----
func (s *Service) StartSignatureMessageListener(mh func(ctx context.Context, msg p2pEntity.P2PMessage[symbiotic.Signature]) error) error
⋮----
func (s *Service) StartSignaturesAggregatedMessageListener(mh func(ctx context.Context, msg p2pEntity.P2PMessage[symbiotic.AggregationProof]) error) error
⋮----
func (s *Service) addPeer(pi peer.AddrInfo) error
⋮----
// broadcast sends a message to all connected peers
func (s *Service) broadcast(ctx context.Context, topicName string, data []byte) error
⋮----
// Inject trace context if the span context is valid so downstream nodes can link traces
⋮----
// Marshal and send the message
⋮----
// Close gracefully stops the service
func (s *Service) Close() error
⋮----
func (s *Service) Listen(n network.Network, multiaddr multiaddr.Multiaddr)
⋮----
func (s *Service) ListenClose(n network.Network, multiaddr multiaddr.Multiaddr)
⋮----
func (s *Service) Connected(n network.Network, conn network.Conn)
⋮----
func (s *Service) Disconnected(n network.Network, conn network.Conn)
⋮----
func (s *Service) ID() string
⋮----
func (s *Service) StartGRPCServer(ctx context.Context) error
⋮----
//nolint:contextcheck // the context comes from th stream
⋮----
// Wait for context cancellation or server error
```

## File: internal/client/repository/badger/proto/v1/badger.pb.go

```go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.36.6
// 	protoc        (unknown)
// source: v1/badger.proto
⋮----
package v1
⋮----
import (
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
	unsafe "unsafe"
)
⋮----
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
⋮----
const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
⋮----
// Verify that this generated code is sufficiently up-to-date.
⋮----
// Verify that runtime/protoimpl is sufficiently up-to-date.
⋮----
type Validator struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Operator      []byte                 `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"`
	VotingPower   string                 `protobuf:"bytes,2,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
	IsActive      bool                   `protobuf:"varint,3,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
	ActiveIndex   uint32                 `protobuf:"varint,4,opt,name=active_index,json=activeIndex,proto3" json:"active_index,omitempty"`
	Keys          []*ValidatorKey        `protobuf:"bytes,5,rep,name=keys,proto3" json:"keys,omitempty"`
	Vaults        []*ValidatorVault      `protobuf:"bytes,6,rep,name=vaults,proto3" json:"vaults,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
func (x *Validator) Reset()
⋮----
func (x *Validator) String() string
⋮----
func (*Validator) ProtoMessage()
⋮----
func (x *Validator) ProtoReflect() protoreflect.Message
⋮----
// Deprecated: Use Validator.ProtoReflect.Descriptor instead.
func (*Validator) Descriptor() ([]byte, []int)
⋮----
func (x *Validator) GetOperator() []byte
⋮----
func (x *Validator) GetVotingPower() string
⋮----
func (x *Validator) GetIsActive() bool
⋮----
func (x *Validator) GetActiveIndex() uint32
⋮----
func (x *Validator) GetKeys() []*ValidatorKey
⋮----
func (x *Validator) GetVaults() []*ValidatorVault
⋮----
type ValidatorKey struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Tag           uint32                 `protobuf:"varint,1,opt,name=tag,proto3" json:"tag,omitempty"`
	Payload       []byte                 `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorKey.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorKey) GetTag() uint32
⋮----
func (x *ValidatorKey) GetPayload() []byte
⋮----
type ValidatorVault struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	ChainId       uint64                 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
	Vault         []byte                 `protobuf:"bytes,2,opt,name=vault,proto3" json:"vault,omitempty"`
	VotingPower   string                 `protobuf:"bytes,3,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorVault.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorVault) GetChainId() uint64
⋮----
func (x *ValidatorVault) GetVault() []byte
⋮----
type ValidatorSetHeader struct {
	state              protoimpl.MessageState `protogen:"open.v1"`
	Version            uint32                 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	RequiredKeyTag     uint32                 `protobuf:"varint,2,opt,name=required_key_tag,json=requiredKeyTag,proto3" json:"required_key_tag,omitempty"`
	Epoch              uint64                 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	CaptureTimestamp   uint64                 `protobuf:"varint,4,opt,name=capture_timestamp,json=captureTimestamp,proto3" json:"capture_timestamp,omitempty"`
	QuorumThreshold    string                 `protobuf:"bytes,5,opt,name=quorum_threshold,json=quorumThreshold,proto3" json:"quorum_threshold,omitempty"`
	TotalVotingPower   string                 `protobuf:"bytes,6,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"`
	ValidatorsSszMroot []byte                 `protobuf:"bytes,7,opt,name=validators_ssz_mroot,json=validatorsSszMroot,proto3" json:"validators_ssz_mroot,omitempty"`
	AggregatorIndices  []byte                 `protobuf:"bytes,8,opt,name=aggregator_indices,json=aggregatorIndices,proto3" json:"aggregator_indices,omitempty"`
	CommitterIndices   []byte                 `protobuf:"bytes,9,opt,name=committer_indices,json=committerIndices,proto3" json:"committer_indices,omitempty"`
	unknownFields      protoimpl.UnknownFields
	sizeCache          protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorSetHeader.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorSetHeader) GetVersion() uint32
⋮----
func (x *ValidatorSetHeader) GetRequiredKeyTag() uint32
⋮----
func (x *ValidatorSetHeader) GetEpoch() uint64
⋮----
func (x *ValidatorSetHeader) GetCaptureTimestamp() uint64
⋮----
func (x *ValidatorSetHeader) GetQuorumThreshold() string
⋮----
func (x *ValidatorSetHeader) GetTotalVotingPower() string
⋮----
func (x *ValidatorSetHeader) GetValidatorsSszMroot() []byte
⋮----
func (x *ValidatorSetHeader) GetAggregatorIndices() []byte
⋮----
func (x *ValidatorSetHeader) GetCommitterIndices() []byte
⋮----
type ValidatorSetMetadata struct {
	state          protoimpl.MessageState `protogen:"open.v1"`
	RequestId      []byte                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	Epoch          uint64                 `protobuf:"varint,2,opt,name=epoch,proto3" json:"epoch,omitempty"`
	ExtraData      []*ExtraData           `protobuf:"bytes,3,rep,name=extra_data,json=extraData,proto3" json:"extra_data,omitempty"`
	CommitmentData []byte                 `protobuf:"bytes,4,opt,name=commitment_data,json=commitmentData,proto3" json:"commitment_data,omitempty"`
	unknownFields  protoimpl.UnknownFields
	sizeCache      protoimpl.SizeCache
}
⋮----
// Deprecated: Use ValidatorSetMetadata.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorSetMetadata) GetRequestId() []byte
⋮----
func (x *ValidatorSetMetadata) GetExtraData() []*ExtraData
⋮----
func (x *ValidatorSetMetadata) GetCommitmentData() []byte
⋮----
type ExtraData struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Key           []byte                 `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
	Value         []byte                 `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use ExtraData.ProtoReflect.Descriptor instead.
⋮----
func (x *ExtraData) GetKey() []byte
⋮----
func (x *ExtraData) GetValue() []byte
⋮----
type AggregationProof struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	MessageHash   []byte                 `protobuf:"bytes,1,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	KeyTag        uint32                 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	Epoch         uint64                 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	Proof         []byte                 `protobuf:"bytes,4,opt,name=proof,proto3" json:"proof,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use AggregationProof.ProtoReflect.Descriptor instead.
⋮----
func (x *AggregationProof) GetMessageHash() []byte
⋮----
func (x *AggregationProof) GetKeyTag() uint32
⋮----
func (x *AggregationProof) GetProof() []byte
⋮----
type Signature struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	MessageHash   []byte                 `protobuf:"bytes,1,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	KeyTag        uint32                 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	Epoch         uint64                 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	Signature     []byte                 `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"`
	RawPublicKey  []byte                 `protobuf:"bytes,5,opt,name=raw_public_key,json=rawPublicKey,proto3" json:"raw_public_key,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
⋮----
func (x *Signature) GetSignature() []byte
⋮----
func (x *Signature) GetRawPublicKey() []byte
⋮----
type SignatureRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	KeyTag        uint32                 `protobuf:"varint,1,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	RequiredEpoch uint64                 `protobuf:"varint,2,opt,name=required_epoch,json=requiredEpoch,proto3" json:"required_epoch,omitempty"`
	Message       []byte                 `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use SignatureRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *SignatureRequest) GetRequiredEpoch() uint64
⋮----
func (x *SignatureRequest) GetMessage() []byte
⋮----
type SignatureMap struct {
	state                  protoimpl.MessageState `protogen:"open.v1"`
	RequestId              []byte                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	Epoch                  uint64                 `protobuf:"varint,2,opt,name=epoch,proto3" json:"epoch,omitempty"`
	SignedValidatorsBitmap []byte                 `protobuf:"bytes,3,opt,name=signed_validators_bitmap,json=signedValidatorsBitmap,proto3" json:"signed_validators_bitmap,omitempty"`
	CurrentVotingPower     string                 `protobuf:"bytes,4,opt,name=current_voting_power,json=currentVotingPower,proto3" json:"current_voting_power,omitempty"`
	TotalValidators        uint32                 `protobuf:"varint,5,opt,name=total_validators,json=totalValidators,proto3" json:"total_validators,omitempty"`
	unknownFields          protoimpl.UnknownFields
	sizeCache              protoimpl.SizeCache
}
⋮----
// Deprecated: Use SignatureMap.ProtoReflect.Descriptor instead.
⋮----
func (x *SignatureMap) GetSignedValidatorsBitmap() []byte
⋮----
func (x *SignatureMap) GetCurrentVotingPower() string
⋮----
func (x *SignatureMap) GetTotalValidators() uint32
⋮----
type NetworkConfig struct {
	state                   protoimpl.MessageState `protogen:"open.v1"`
	VotingPowerProviders    []*CrossChainAddress   `protobuf:"bytes,1,rep,name=voting_power_providers,json=votingPowerProviders,proto3" json:"voting_power_providers,omitempty"`
	KeysProvider            *CrossChainAddress     `protobuf:"bytes,2,opt,name=keys_provider,json=keysProvider,proto3" json:"keys_provider,omitempty"`
	Settlements             []*CrossChainAddress   `protobuf:"bytes,3,rep,name=settlements,proto3" json:"settlements,omitempty"`
	VerificationType        uint32                 `protobuf:"varint,4,opt,name=verification_type,json=verificationType,proto3" json:"verification_type,omitempty"`
	MaxVotingPower          string                 `protobuf:"bytes,5,opt,name=max_voting_power,json=maxVotingPower,proto3" json:"max_voting_power,omitempty"`
	MinInclusionVotingPower string                 `protobuf:"bytes,6,opt,name=min_inclusion_voting_power,json=minInclusionVotingPower,proto3" json:"min_inclusion_voting_power,omitempty"`
	MaxValidatorsCount      string                 `protobuf:"bytes,7,opt,name=max_validators_count,json=maxValidatorsCount,proto3" json:"max_validators_count,omitempty"`
	RequiredKeyTags         []uint32               `protobuf:"varint,8,rep,packed,name=required_key_tags,json=requiredKeyTags,proto3" json:"required_key_tags,omitempty"`
	RequiredHeaderKeyTag    uint32                 `protobuf:"varint,9,opt,name=required_header_key_tag,json=requiredHeaderKeyTag,proto3" json:"required_header_key_tag,omitempty"`
	QuorumThresholds        []*QuorumThreshold     `protobuf:"bytes,10,rep,name=quorum_thresholds,json=quorumThresholds,proto3" json:"quorum_thresholds,omitempty"`
	NumCommitters           uint64                 `protobuf:"varint,11,opt,name=num_committers,json=numCommitters,proto3" json:"num_committers,omitempty"`
	NumAggregators          uint64                 `protobuf:"varint,12,opt,name=num_aggregators,json=numAggregators,proto3" json:"num_aggregators,omitempty"`
	CommitterSlotDuration   uint64                 `protobuf:"varint,13,opt,name=committer_slot_duration,json=committerSlotDuration,proto3" json:"committer_slot_duration,omitempty"`
	EpochDuration           uint64                 `protobuf:"varint,14,opt,name=epoch_duration,json=epochDuration,proto3" json:"epoch_duration,omitempty"`
	unknownFields           protoimpl.UnknownFields
	sizeCache               protoimpl.SizeCache
}
⋮----
// Deprecated: Use NetworkConfig.ProtoReflect.Descriptor instead.
⋮----
func (x *NetworkConfig) GetVotingPowerProviders() []*CrossChainAddress
⋮----
func (x *NetworkConfig) GetKeysProvider() *CrossChainAddress
⋮----
func (x *NetworkConfig) GetSettlements() []*CrossChainAddress
⋮----
func (x *NetworkConfig) GetVerificationType() uint32
⋮----
func (x *NetworkConfig) GetMaxVotingPower() string
⋮----
func (x *NetworkConfig) GetMinInclusionVotingPower() string
⋮----
func (x *NetworkConfig) GetMaxValidatorsCount() string
⋮----
func (x *NetworkConfig) GetRequiredKeyTags() []uint32
⋮----
func (x *NetworkConfig) GetRequiredHeaderKeyTag() uint32
⋮----
func (x *NetworkConfig) GetQuorumThresholds() []*QuorumThreshold
⋮----
func (x *NetworkConfig) GetNumCommitters() uint64
⋮----
func (x *NetworkConfig) GetNumAggregators() uint64
⋮----
func (x *NetworkConfig) GetCommitterSlotDuration() uint64
⋮----
func (x *NetworkConfig) GetEpochDuration() uint64
⋮----
type CrossChainAddress struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Address       []byte                 `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
	ChainId       uint64                 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use CrossChainAddress.ProtoReflect.Descriptor instead.
⋮----
func (x *CrossChainAddress) GetAddress() []byte
⋮----
type QuorumThreshold struct {
	state           protoimpl.MessageState `protogen:"open.v1"`
	KeyTag          uint32                 `protobuf:"varint,1,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	QuorumThreshold string                 `protobuf:"bytes,2,opt,name=quorum_threshold,json=quorumThreshold,proto3" json:"quorum_threshold,omitempty"`
	unknownFields   protoimpl.UnknownFields
	sizeCache       protoimpl.SizeCache
}
⋮----
// Deprecated: Use QuorumThreshold.ProtoReflect.Descriptor instead.
⋮----
var File_v1_badger_proto protoreflect.FileDescriptor
⋮----
const file_v1_badger_proto_rawDesc = "" +
	"\n" +
	"\x0fv1/badger.proto\x12*internal.client.repository.badger.proto.v1\"\xac\x02\n" +
	"\tValidator\x12\x1a\n" +
	"\boperator\x18\x01 \x01(\fR\boperator\x12!\n" +
	"\fvoting_power\x18\x02 \x01(\tR\vvotingPower\x12\x1b\n" +
	"\tis_active\x18\x03 \x01(\bR\bisActive\x12!\n" +
	"\factive_index\x18\x04 \x01(\rR\vactiveIndex\x12L\n" +
	"\x04keys\x18\x05 \x03(\v28.internal.client.repository.badger.proto.v1.ValidatorKeyR\x04keys\x12R\n" +
	"\x06vaults\x18\x06 \x03(\v2:.internal.client.repository.badger.proto.v1.ValidatorVaultR\x06vaults\":\n" +
	"\fValidatorKey\x12\x10\n" +
	"\x03tag\x18\x01 \x01(\rR\x03tag\x12\x18\n" +
	"\apayload\x18\x02 \x01(\fR\apayload\"d\n" +
	"\x0eValidatorVault\x12\x19\n" +
	"\bchain_id\x18\x01 \x01(\x04R\achainId\x12\x14\n" +
	"\x05vault\x18\x02 \x01(\fR\x05vault\x12!\n" +
	"\fvoting_power\x18\x03 \x01(\tR\vvotingPower\"\x82\x03\n" +
	"\x12ValidatorSetHeader\x12\x18\n" +
	"\aversion\x18\x01 \x01(\rR\aversion\x12(\n" +
	"\x10required_key_tag\x18\x02 \x01(\rR\x0erequiredKeyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12+\n" +
	"\x11capture_timestamp\x18\x04 \x01(\x04R\x10captureTimestamp\x12)\n" +
	"\x10quorum_threshold\x18\x05 \x01(\tR\x0fquorumThreshold\x12,\n" +
	"\x12total_voting_power\x18\x06 \x01(\tR\x10totalVotingPower\x120\n" +
	"\x14validators_ssz_mroot\x18\a \x01(\fR\x12validatorsSszMroot\x12-\n" +
	"\x12aggregator_indices\x18\b \x01(\fR\x11aggregatorIndices\x12+\n" +
	"\x11committer_indices\x18\t \x01(\fR\x10committerIndices\"\xca\x01\n" +
	"\x14ValidatorSetMetadata\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\fR\trequestId\x12\x14\n" +
	"\x05epoch\x18\x02 \x01(\x04R\x05epoch\x12T\n" +
	"\n" +
	"extra_data\x18\x03 \x03(\v25.internal.client.repository.badger.proto.v1.ExtraDataR\textraData\x12'\n" +
	"\x0fcommitment_data\x18\x04 \x01(\fR\x0ecommitmentData\"3\n" +
	"\tExtraData\x12\x10\n" +
	"\x03key\x18\x01 \x01(\fR\x03key\x12\x14\n" +
	"\x05value\x18\x02 \x01(\fR\x05value\"z\n" +
	"\x10AggregationProof\x12!\n" +
	"\fmessage_hash\x18\x01 \x01(\fR\vmessageHash\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12\x14\n" +
	"\x05proof\x18\x04 \x01(\fR\x05proof\"\xa1\x01\n" +
	"\tSignature\x12!\n" +
	"\fmessage_hash\x18\x01 \x01(\fR\vmessageHash\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12\x1c\n" +
	"\tsignature\x18\x04 \x01(\fR\tsignature\x12$\n" +
	"\x0eraw_public_key\x18\x05 \x01(\fR\frawPublicKey\"l\n" +
	"\x10SignatureRequest\x12\x17\n" +
	"\akey_tag\x18\x01 \x01(\rR\x06keyTag\x12%\n" +
	"\x0erequired_epoch\x18\x02 \x01(\x04R\rrequiredEpoch\x12\x18\n" +
	"\amessage\x18\x03 \x01(\fR\amessage\"\xda\x01\n" +
	"\fSignatureMap\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\fR\trequestId\x12\x14\n" +
	"\x05epoch\x18\x02 \x01(\x04R\x05epoch\x128\n" +
	"\x18signed_validators_bitmap\x18\x03 \x01(\fR\x16signedValidatorsBitmap\x120\n" +
	"\x14current_voting_power\x18\x04 \x01(\tR\x12currentVotingPower\x12)\n" +
	"\x10total_validators\x18\x05 \x01(\rR\x0ftotalValidators\"\x8b\a\n" +
	"\rNetworkConfig\x12s\n" +
	"\x16voting_power_providers\x18\x01 \x03(\v2=.internal.client.repository.badger.proto.v1.CrossChainAddressR\x14votingPowerProviders\x12b\n" +
	"\rkeys_provider\x18\x02 \x01(\v2=.internal.client.repository.badger.proto.v1.CrossChainAddressR\fkeysProvider\x12_\n" +
	"\vsettlements\x18\x03 \x03(\v2=.internal.client.repository.badger.proto.v1.CrossChainAddressR\vsettlements\x12+\n" +
	"\x11verification_type\x18\x04 \x01(\rR\x10verificationType\x12(\n" +
	"\x10max_voting_power\x18\x05 \x01(\tR\x0emaxVotingPower\x12;\n" +
	"\x1amin_inclusion_voting_power\x18\x06 \x01(\tR\x17minInclusionVotingPower\x120\n" +
	"\x14max_validators_count\x18\a \x01(\tR\x12maxValidatorsCount\x12*\n" +
	"\x11required_key_tags\x18\b \x03(\rR\x0frequiredKeyTags\x125\n" +
	"\x17required_header_key_tag\x18\t \x01(\rR\x14requiredHeaderKeyTag\x12h\n" +
	"\x11quorum_thresholds\x18\n" +
	" \x03(\v2;.internal.client.repository.badger.proto.v1.QuorumThresholdR\x10quorumThresholds\x12%\n" +
	"\x0enum_committers\x18\v \x01(\x04R\rnumCommitters\x12'\n" +
	"\x0fnum_aggregators\x18\f \x01(\x04R\x0enumAggregators\x126\n" +
	"\x17committer_slot_duration\x18\r \x01(\x04R\x15committerSlotDuration\x12%\n" +
	"\x0eepoch_duration\x18\x0e \x01(\x04R\repochDuration\"H\n" +
	"\x11CrossChainAddress\x12\x18\n" +
	"\aaddress\x18\x01 \x01(\fR\aaddress\x12\x19\n" +
	"\bchain_id\x18\x02 \x01(\x04R\achainId\"U\n" +
	"\x0fQuorumThreshold\x12\x17\n" +
	"\akey_tag\x18\x01 \x01(\rR\x06keyTag\x12)\n" +
	"\x10quorum_threshold\x18\x02 \x01(\tR\x0fquorumThresholdB\xd5\x02\n" +
	".com.internal.client.repository.badger.proto.v1B\vBadgerProtoP\x01ZGgithub.com/symbioticfi/relay/internal/client/repository/badger/proto/v1\xa2\x02\x05ICRBP\xaa\x02*Internal.Client.Repository.Badger.Proto.V1\xca\x02*Internal\\Client\\Repository\\Badger\\Proto\\V1\xe2\x026Internal\\Client\\Repository\\Badger\\Proto\\V1\\GPBMetadata\xea\x02/Internal::Client::Repository::Badger::Proto::V1b\x06proto3"
⋮----
var (
	file_v1_badger_proto_rawDescOnce sync.Once
	file_v1_badger_proto_rawDescData []byte
)
⋮----
func file_v1_badger_proto_rawDescGZIP() []byte
⋮----
var file_v1_badger_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_v1_badger_proto_goTypes = []any{
	(*Validator)(nil),            // 0: internal.client.repository.badger.proto.v1.Validator
	(*ValidatorKey)(nil),         // 1: internal.client.repository.badger.proto.v1.ValidatorKey
	(*ValidatorVault)(nil),       // 2: internal.client.repository.badger.proto.v1.ValidatorVault
	(*ValidatorSetHeader)(nil),   // 3: internal.client.repository.badger.proto.v1.ValidatorSetHeader
	(*ValidatorSetMetadata)(nil), // 4: internal.client.repository.badger.proto.v1.ValidatorSetMetadata
	(*ExtraData)(nil),            // 5: internal.client.repository.badger.proto.v1.ExtraData
	(*AggregationProof)(nil),     // 6: internal.client.repository.badger.proto.v1.AggregationProof
	(*Signature)(nil),            // 7: internal.client.repository.badger.proto.v1.Signature
	(*SignatureRequest)(nil),     // 8: internal.client.repository.badger.proto.v1.SignatureRequest
	(*SignatureMap)(nil),         // 9: internal.client.repository.badger.proto.v1.SignatureMap
	(*NetworkConfig)(nil),        // 10: internal.client.repository.badger.proto.v1.NetworkConfig
	(*CrossChainAddress)(nil),    // 11: internal.client.repository.badger.proto.v1.CrossChainAddress
	(*QuorumThreshold)(nil),      // 12: internal.client.repository.badger.proto.v1.QuorumThreshold
}
⋮----
(*Validator)(nil),            // 0: internal.client.repository.badger.proto.v1.Validator
(*ValidatorKey)(nil),         // 1: internal.client.repository.badger.proto.v1.ValidatorKey
(*ValidatorVault)(nil),       // 2: internal.client.repository.badger.proto.v1.ValidatorVault
(*ValidatorSetHeader)(nil),   // 3: internal.client.repository.badger.proto.v1.ValidatorSetHeader
(*ValidatorSetMetadata)(nil), // 4: internal.client.repository.badger.proto.v1.ValidatorSetMetadata
(*ExtraData)(nil),            // 5: internal.client.repository.badger.proto.v1.ExtraData
(*AggregationProof)(nil),     // 6: internal.client.repository.badger.proto.v1.AggregationProof
(*Signature)(nil),            // 7: internal.client.repository.badger.proto.v1.Signature
(*SignatureRequest)(nil),     // 8: internal.client.repository.badger.proto.v1.SignatureRequest
(*SignatureMap)(nil),         // 9: internal.client.repository.badger.proto.v1.SignatureMap
(*NetworkConfig)(nil),        // 10: internal.client.repository.badger.proto.v1.NetworkConfig
(*CrossChainAddress)(nil),    // 11: internal.client.repository.badger.proto.v1.CrossChainAddress
(*QuorumThreshold)(nil),      // 12: internal.client.repository.badger.proto.v1.QuorumThreshold
⋮----
var file_v1_badger_proto_depIdxs = []int32{
	1,  // 0: internal.client.repository.badger.proto.v1.Validator.keys:type_name -> internal.client.repository.badger.proto.v1.ValidatorKey
	2,  // 1: internal.client.repository.badger.proto.v1.Validator.vaults:type_name -> internal.client.repository.badger.proto.v1.ValidatorVault
	5,  // 2: internal.client.repository.badger.proto.v1.ValidatorSetMetadata.extra_data:type_name -> internal.client.repository.badger.proto.v1.ExtraData
	11, // 3: internal.client.repository.badger.proto.v1.NetworkConfig.voting_power_providers:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
	11, // 4: internal.client.repository.badger.proto.v1.NetworkConfig.keys_provider:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
	11, // 5: internal.client.repository.badger.proto.v1.NetworkConfig.settlements:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
	12, // 6: internal.client.repository.badger.proto.v1.NetworkConfig.quorum_thresholds:type_name -> internal.client.repository.badger.proto.v1.QuorumThreshold
	7,  // [7:7] is the sub-list for method output_type
	7,  // [7:7] is the sub-list for method input_type
	7,  // [7:7] is the sub-list for extension type_name
	7,  // [7:7] is the sub-list for extension extendee
	0,  // [0:7] is the sub-list for field type_name
}
⋮----
1,  // 0: internal.client.repository.badger.proto.v1.Validator.keys:type_name -> internal.client.repository.badger.proto.v1.ValidatorKey
2,  // 1: internal.client.repository.badger.proto.v1.Validator.vaults:type_name -> internal.client.repository.badger.proto.v1.ValidatorVault
5,  // 2: internal.client.repository.badger.proto.v1.ValidatorSetMetadata.extra_data:type_name -> internal.client.repository.badger.proto.v1.ExtraData
11, // 3: internal.client.repository.badger.proto.v1.NetworkConfig.voting_power_providers:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
11, // 4: internal.client.repository.badger.proto.v1.NetworkConfig.keys_provider:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
11, // 5: internal.client.repository.badger.proto.v1.NetworkConfig.settlements:type_name -> internal.client.repository.badger.proto.v1.CrossChainAddress
12, // 6: internal.client.repository.badger.proto.v1.NetworkConfig.quorum_thresholds:type_name -> internal.client.repository.badger.proto.v1.QuorumThreshold
7,  // [7:7] is the sub-list for method output_type
7,  // [7:7] is the sub-list for method input_type
7,  // [7:7] is the sub-list for extension type_name
7,  // [7:7] is the sub-list for extension extendee
0,  // [0:7] is the sub-list for field type_name
⋮----
func init()
func file_v1_badger_proto_init()
⋮----
type x struct{}
```

## File: internal/client/repository/badger/proto/v1/badger.proto

```protobuf
syntax = "proto3";

package internal.client.repository.badger.proto.v1;

option go_package = "github.com/symbioticfi/relay/internal/client/repository/badger/proto/v1";

message Validator {
  bytes operator = 1;
  string voting_power = 2;
  bool is_active = 3;
  uint32 active_index = 4;
  repeated ValidatorKey keys = 5;
  repeated ValidatorVault vaults = 6;
}

message ValidatorKey {
  uint32 tag = 1;
  bytes payload = 2;
}

message ValidatorVault {
  uint64 chain_id = 1;
  bytes vault = 2;
  string voting_power = 3;
}

message ValidatorSetHeader {
  uint32 version = 1;
  uint32 required_key_tag = 2;
  uint64 epoch = 3;
  uint64 capture_timestamp = 4;
  string quorum_threshold = 5;
  string total_voting_power = 6;
  bytes validators_ssz_mroot = 7;
  bytes aggregator_indices = 8;
  bytes committer_indices = 9;
}

message ValidatorSetMetadata {
  bytes request_id = 1;
  uint64 epoch = 2;
  repeated ExtraData extra_data = 3;
  bytes commitment_data = 4;
}

message ExtraData {
  bytes key = 1;
  bytes value = 2;
}

message AggregationProof {
  bytes message_hash = 1;
  uint32 key_tag = 2;
  uint64 epoch = 3;
  bytes proof = 4;
}

message Signature {
  bytes message_hash = 1;
  uint32 key_tag = 2;
  uint64 epoch = 3;
  bytes signature = 4;
  bytes raw_public_key = 5;
}

message SignatureRequest {
  uint32 key_tag = 1;
  uint64 required_epoch = 2;
  bytes message = 3;
}

message SignatureMap {
  bytes request_id = 1;
  uint64 epoch = 2;
  bytes signed_validators_bitmap = 3;
  string current_voting_power = 4;
  uint32 total_validators = 5;
}

message NetworkConfig {
  repeated CrossChainAddress voting_power_providers = 1;
  CrossChainAddress keys_provider = 2;
  repeated CrossChainAddress settlements = 3;
  uint32 verification_type = 4;
  string max_voting_power = 5;
  string min_inclusion_voting_power = 6;
  string max_validators_count = 7;
  repeated uint32 required_key_tags = 8;
  uint32 required_header_key_tag = 9;
  repeated QuorumThreshold quorum_thresholds = 10;
  uint64 num_committers = 11;
  uint64 num_aggregators = 12;
  uint64 committer_slot_duration = 13;
  uint64 epoch_duration = 14;
}

message CrossChainAddress {
  bytes address = 1;
  uint64 chain_id = 2;
}

message QuorumThreshold {
  uint32 key_tag = 1;
  string quorum_threshold = 2;
}
```

## File: internal/client/repository/badger/badger_repository_add_proof.go

```go
package badger
⋮----
import (
	"context"

	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) SaveProof(ctx context.Context, aggregationProof symbiotic.AggregationProof) error
```

## File: internal/client/repository/badger/badger_repository_add_signature.go

```go
package badger
⋮----
import (
	"context"
	"log/slog"

	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) SaveSignature(ctx context.Context, signature symbiotic.Signature, validator symbiotic.Validator, activeIndex uint32) error
```

## File: internal/client/repository/badger/badger_repository_aggregation_proof_pending_test.go

```go
package badger
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestBadgerRepository_SaveAggregationProofPending(t *testing.T)
⋮----
func TestBadgerRepository_RemoveAggregationProofPending(t *testing.T)
⋮----
// First save
⋮----
// Then remove
⋮----
// Try to remove again should fail
⋮----
// Save multiple entries
⋮----
// Remove one specific entry
⋮----
// Verify others still exist by trying to save them again (should fail)
⋮----
// But the removed one should be gone - we can save it again
⋮----
func TestBadgerRepository_GetSignatureRequestsWithoutAggregationProof(t *testing.T)
⋮----
// Create multiple signature requests
var requests []symbiotic.Signature
⋮----
// Save signature request
⋮----
// Get first page (limit 3)
⋮----
// Get second page using last hash from first page
⋮----
require.Len(t, secondPage, 2) // Remaining 2 requests
⋮----
// Verify no overlap between pages
⋮----
// Verify all original requests are found across both pages
⋮----
// Create one valid signature request
⋮----
// Create a pending aggregation proof marker without corresponding signature request
⋮----
// Should only return the valid request, skipping the orphan
⋮----
// Query epoch1 should only return req1
⋮----
// Query epoch2 should only return req2
⋮----
func TestBadgerRepository_AggregationProofPendingIntegration(t *testing.T)
⋮----
// Now it should appear in pending list
⋮----
// Remove from pending
⋮----
// Should no longer appear in pending list
```

## File: internal/client/repository/badger/badger_repository_aggregation_proof_test.go

```go
package badger
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestBadgerRepository_AggregationProof(t *testing.T)
⋮----
func TestKeyAggregationProofPendingBinaryFormat(t *testing.T)
⋮----
func TestBadgerRepository_GetAggregationProofsByEpoch(t *testing.T)
⋮----
func randomAggregationProof(t *testing.T) symbiotic.AggregationProof
```

## File: internal/client/repository/badger/badger_repository_aggregation_proof.go

```go
package badger
⋮----
import (
	"bytes"
	"context"
	"fmt"
	"log/slog"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"fmt"
"log/slog"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func keyAggregationProof(requestID common.Hash) []byte
⋮----
const aggregationProofPendingPrefix = "aggregation_proof_pending:"
⋮----
func keyAggregationProofPending(epoch symbiotic.Epoch, requestID common.Hash) []byte
⋮----
func keyAggregationProofPendingEpochPrefix(epoch symbiotic.Epoch) []byte
⋮----
func (r *Repository) saveAggregationProof(ctx context.Context, requestID common.Hash, ap symbiotic.AggregationProof) error
⋮----
func (r *Repository) writeAggregationProof(ctx context.Context, requestID common.Hash, ap symbiotic.AggregationProof) error
⋮----
func (r *Repository) GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
⋮----
var ap symbiotic.AggregationProof
⋮----
// GetAggregationProofsByEpoch returns one page of aggregation proofs for the
// given epoch, paginated via opaque cursor `from` (32-byte requestID raw).
// Iterates the request_id_epoch index (sorted by requestID within epoch);
// nextFrom == nil signals the last page.
func (r *Repository) GetAggregationProofsByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]symbiotic.AggregationProof, []byte, error)
⋮----
var (
		proofs   []symbiotic.AggregationProof
		lastID   common.Hash
		moreLeft bool
	)
⋮----
opts.PrefetchValues = false // index entries are key-only; the proof value comes from a separate Get.
⋮----
func getAggregationProofByEpochFromItem(txn *badger.Txn, it *badger.Iterator) (symbiotic.AggregationProof, error)
⋮----
var (
	aggregationProofToBytes = codec.AggregationProofToBytes
	bytesToAggregationProof = codec.BytesToAggregationProof
)
⋮----
func (r *Repository) saveAggregationProofPending(ctx context.Context, requestID common.Hash, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) removeAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) RemoveAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch symbiotic.Epoch, limit int, lastHash common.Hash) ([]symbiotic.SignatureRequestWithID, error)
⋮----
var requests []symbiotic.SignatureRequestWithID
⋮----
// Iterate through pending aggregation proof markers
⋮----
opts.PrefetchValues = false // We don't need the values, just the keys
⋮----
// Subsequent pages: seek to the record after lastHash
⋮----
// If we're seeking from a specific hash and positioned exactly on that key, skip it (already returned in previous page)
⋮----
// Stop if we've reached the limit
⋮----
// Get the actual signature request
⋮----
// This shouldn't happen - pending marker exists but signature request doesn't
// Skip this entry and continue
```

## File: internal/client/repository/badger/badger_repository_network_config_test.go

```go
package badger
⋮----
import (
	"math/big"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestBadgerRepository_NetworkConfig(t *testing.T)
⋮----
func randomNetworkConfig(t *testing.T) symbiotic.NetworkConfig
```

## File: internal/client/repository/badger/badger_repository_network_config.go

```go
package badger
⋮----
import (
	"context"

	"github.com/dgraph-io/badger/v4"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const networkConfigPrefix = "network_config:"
⋮----
func keyNetworkConfig(epoch symbiotic.Epoch) []byte
⋮----
func (r *Repository) SaveConfig(ctx context.Context, config symbiotic.NetworkConfig, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
⋮----
var config symbiotic.NetworkConfig
⋮----
var (
	networkConfigToBytes = codec.NetworkConfigToBytes
	bytesToNetworkConfig = codec.BytesToNetworkConfig
)
```

## File: internal/client/repository/badger/badger_repository_next_valset_data_test.go

```go
package badger
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_SaveNextValsetData_HappyPath(t *testing.T)
⋮----
// Save the data
⋮----
// Verify data was saved by reading it back
// Verify previous validator set was saved
⋮----
// Verify next validator set was saved
⋮----
// Verify previous config was saved
⋮----
// Verify next config was saved
⋮----
// Verify signature request was saved
⋮----
func TestRepository_SaveNextValsetData_IgnoresExistingMappings(t *testing.T)
⋮----
// Remove pending entry so the second save only hits the mapping duplication path.
⋮----
func newTestNextValsetData(t *testing.T) entity.NextValsetData
```

## File: internal/client/repository/badger/badger_repository_next_valset_data.go

```go
package badger
⋮----
import (
	"context"

	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
func (r *Repository) SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error
⋮----
// Save previous validator set and config
⋮----
// Save next validator set and config
⋮----
// save pending proof commit here
// we store pending commit request for all nodes and not just current commiters because
// if committers of this epoch fail then commiters for next epoch should still try to commit old proofs
```

## File: internal/client/repository/badger/badger_repository_proof_commits_test.go

```go
package badger
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestBadgerRepository_SaveProofCommitPending(t *testing.T)
⋮----
func TestBadgerRepository_RemoveProofCommitPending(t *testing.T)
⋮----
// First save
⋮----
// Then remove
⋮----
// Try to remove again should fail
⋮----
// Save multiple entries
⋮----
// Remove one specific entry
⋮----
// Verify others still exist by trying to save them again (should fail)
⋮----
// But the removed one should be gone - we can save it again
⋮----
func TestBadgerRepository_GetPendingProofCommitsSinceEpoch(t *testing.T)
⋮----
// Save commits in different epochs
⋮----
// Get commits since epoch 100
⋮----
// Should return commits for epochs 100 and 150, not 50
⋮----
// Create commits with same epoch but different hashes to test hash sorting
⋮----
// Save in reverse order to test sorting
⋮----
// Verify epoch ordering (ascending)
⋮----
// Verify hash ordering within same epoch
⋮----
// Create multiple commits
⋮----
// Test limit = 3
⋮----
// Test limit = 0 (should return all)
⋮----
// Test limit > available (should return all available)
⋮----
// Query from epoch 701 should return epochs 701 and 702
⋮----
// This test verifies that the function handles malformed keys in the database
// We can't directly insert malformed keys through the public API, but the function
// should be robust against them. This test mainly verifies no panic occurs.
```

## File: internal/client/repository/badger/badger_repository_proof_commits.go

```go
package badger
⋮----
import (
	"bytes"
	"context"
	"math/big"
	"sort"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"math/big"
"sort"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	aggregationProofCommitPrefix = "aggregation_proof_commit:"
)
⋮----
func keyAggregationProofCommited(epoch symbiotic.Epoch) []byte
⋮----
func (r *Repository) saveProofCommitPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) removeProofCommitPending(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
// Check if exists before removing
⋮----
func (r *Repository) GetPendingProofCommitsSinceEpoch(ctx context.Context, epoch symbiotic.Epoch, limit int) ([]symbiotic.ProofCommitKey, error)
⋮----
var requests []symbiotic.ProofCommitKey
⋮----
// Step 1: Collect all keys with their parsed epochs and hashes
var keys []symbiotic.ProofCommitKey
⋮----
// Use broader prefix to capture all epochs
// Key format: "aggregation_proof_commit:epoch:hash"
⋮----
// Iterate through all aggregation proof commit keys
⋮----
continue // Skip invalid keys
⋮----
// Parse the epoch
⋮----
// Skip if this epoch is less than our target epoch
⋮----
continue // Skip invalid request IDs
⋮----
return nil // No keys found
⋮----
// Step 2: Sort keys by epoch (ascending) and then by hash for deterministic ordering
⋮----
// Step 3: limit response
```

## File: internal/client/repository/badger/badger_repository_proto_test.go

```go
package badger
⋮----
import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestValidatorProtoConversion(t *testing.T)
⋮----
func TestValidatorProtoConversion_EmptyArrays(t *testing.T)
⋮----
func TestNetworkConfigProtoConversion(t *testing.T)
⋮----
func TestValidatorSetHeaderProtoConversion(t *testing.T)
⋮----
func TestValidatorSetMetadataProtoConversion(t *testing.T)
⋮----
func TestSignatureMapProtoConversion(t *testing.T)
⋮----
func TestSignatureProtoConversion(t *testing.T)
⋮----
KeyTag:      symbiotic.KeyTag(4), // 4 is BLS (upper nibble = 0)
⋮----
KeyTag:      symbiotic.KeyTag(16), // 16 is ECDSA (upper nibble = 1)
⋮----
func TestSignatureRequestProtoConversion(t *testing.T)
⋮----
func TestAggregationProofProtoConversion(t *testing.T)
⋮----
func TestBigIntEdgeCases(t *testing.T)
```

## File: internal/client/repository/badger/badger_repository_prune_test.go

```go
package badger
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestRepository_PruneAllEntityTypes(t *testing.T)
⋮----
// Setup: Create all entities for the epoch
⋮----
// 1. Create and save validator set
⋮----
Payload: randomBytes(t, 96), // CompactPublicKey as bytes
⋮----
// 2. Save network config
⋮----
// 3. Save signature request and compute requestID
⋮----
// Compute requestID for signatures
⋮----
// 4. Save proof commit pending
⋮----
// 5. Save signature request
⋮----
// 6. Save signature
⋮----
// 7. Save signature map
⋮----
// 8. Save aggregation proof
⋮----
// Verify entities exist before pruning
⋮----
// Check validator set
⋮----
// Check network config
⋮----
// Check signature request
⋮----
// Check signature
⋮----
// Check signature map
⋮----
// Check aggregation proof
⋮----
// Execute: Prune all entity types for the epoch
⋮----
// Prune in reverse dependency order
⋮----
// Verify: All entities should be deleted
⋮----
// Check validator set deleted
⋮----
// Check network config deleted
⋮----
// Check signature request deleted
⋮----
// Check signature deleted
⋮----
// Check signature map deleted
⋮----
// Check aggregation proof deleted
⋮----
func TestRepository_PruneEntityTypes_Separately(t *testing.T)
⋮----
// Setup: Create minimal entities for testing
⋮----
// 1. Create validator set
⋮----
// 3. Create signature and proof entities
⋮----
// Test: Prune only signatures, verify proofs and valsets remain
⋮----
// Signatures should be deleted
⋮----
// Proofs should still exist
⋮----
// Validator sets should still exist
⋮----
// Test: Prune proofs, verify valsets remain
⋮----
// Proofs should be deleted
⋮----
// Test: Prune valsets last
⋮----
// Validator sets should be deleted
⋮----
func TestRepository_PruneAggregationProof_IndexCleanup(t *testing.T)
⋮----
// Create aggregation proofs for three epochs
⋮----
// Create signature to get requestID
⋮----
// Save aggregation proof
⋮----
// Verify all proofs exist before pruning
⋮----
// Prune the middle epoch (101)
⋮----
// Direct get should fail
⋮----
// Clean up indices (since no signatures exist in this test, indices should be deleted)
⋮----
// Verify GetAggregationProofsByEpoch returns empty for pruned epoch
⋮----
// Verify GetAggregationProofsByEpoch still works for non-pruned epochs
⋮----
// First epoch should still have its proof
⋮----
// Last epoch should still have its proof
⋮----
func TestRepository_PruneRequestIDEpochIndices_DifferentRetentionSettings(t *testing.T)
⋮----
// Create signature and proof for the same epoch
⋮----
// Save signature request and signature
⋮----
// Verify index exists
⋮----
// Scenario 1: Delete only proof, index should remain (signature still exists)
⋮----
// Try to clean up indices
⋮----
// Index should still exist because signatures are still there
⋮----
// Scenario 2: Now delete signatures, index should be removed
⋮----
// Try to clean up indices again
⋮----
// Now index should be gone
⋮----
func TestRepository_PruneRequestIDEpochIndices_SignaturesDeletedFirst(t *testing.T)
⋮----
// Scenario 1: Delete only signatures, index should remain (proof still exists)
⋮----
// Index should still exist because proof is still there
⋮----
// Scenario 2: Now delete proof, index should be removed
```

## File: internal/client/repository/badger/badger_repository_prune.go

```go
package badger
⋮----
import (
	"context"
	"log/slog"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) PruneValsetEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *Repository) PruneProofEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *Repository) PruneSignatureEntitiesForEpoch(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *Repository) pruneProofCommits(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) pruneNetworkConfigs(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) pruneValidatorSets(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
it.Close() // Close before opening another iterator
⋮----
func (r *Repository) getRequestIDsByEpoch(ctx context.Context, epoch symbiotic.Epoch) ([]common.Hash, error)
⋮----
var requestIDs []common.Hash
⋮----
func (r *Repository) pruneSignatureEntities(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) pruneAggregationProof(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
// PruneRequestIDEpochIndices removes the request ID epoch indices for the given epoch.
// This should be called AFTER both PruneProofEntities and PruneSignatureEntitiesForEpoch
// to ensure that the index is only deleted when both the aggregation proof and signatures
// have been removed. This handles cases where proof and signature retention settings differ.
func (r *Repository) PruneRequestIDEpochIndices(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
// deleteRequestIDEpochIndex deletes the request ID epoch index entry if both
// the aggregation proof and signatures have been pruned for the given requestID.
func (r *Repository) deleteRequestIDEpochIndex(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
// Check if aggregation proof still exists
⋮----
// Proof still exists, don't delete the index
⋮----
// Check if signatures still exist
⋮----
// Signatures still exist, don't delete the index
⋮----
// Both proof and signatures are gone, safe to delete the index
```

## File: internal/client/repository/badger/badger_repository_signature_map_test.go

```go
package badger
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
// randomRequestID generates a valid request id for testing
func randomRequestID(t *testing.T) common.Hash
⋮----
// randomSignatureMap creates a SignatureMap with test data
func randomSignatureMap(t *testing.T, requestID common.Hash) entity.SignatureMap
⋮----
// assertSignatureMapsEqual performs deep equality check on SignatureMaps
func assertSignatureMapsEqual(t *testing.T, expected, actual entity.SignatureMap)
⋮----
func TestBadgerRepository_SignatureMap(t *testing.T)
⋮----
// Verify data was saved correctly
⋮----
// Save initial signature map
⋮----
// Update with modified data
⋮----
// Verify updated data
⋮----
// Save two different signature maps
⋮----
// Retrieve first signature map
⋮----
// Retrieve second signature map
⋮----
// Create multiple signature maps
⋮----
// Verify all can be retrieved correctly
⋮----
func TestSignatureMapSerialization(t *testing.T)
⋮----
// Serialize
⋮----
// Deserialize
⋮----
// Verify round-trip preservation
⋮----
// Create SignatureMap with large big.Int values
⋮----
Epoch:                  18446744073709551615, // Max uint64
⋮----
// Serialize and deserialize
⋮----
// Test roaring bitmap with specific indexes
bitmap := entity.NewBitmapOf(0) // Only validator at index 0 is present
⋮----
// Verify bitmap contains expected validator index
⋮----
func TestSignatureMapTransactions(t *testing.T)
⋮----
// Update within transaction
⋮----
// Get within same transaction - should work
⋮----
// Verify data persisted after transaction
⋮----
// Transaction that will rollback due to error
⋮----
// Verify data exists within transaction
⋮----
// Return error to trigger rollback
⋮----
// Verify data was not persisted due to rollback
⋮----
// Setup existing data
⋮----
// Read existing data
⋮----
// Write new data
⋮----
// Read newly written data within same transaction
⋮----
// Verify both datasets exist after transaction
⋮----
func TestSignatureMapKeyGeneration(t *testing.T)
⋮----
func TestSignatureMapEdgeCases(t *testing.T)
⋮----
RequestID:              common.Hash{}, // Zero hash
⋮----
// Test single validator scenario
⋮----
SignedValidatorsBitmap: entity.NewBitmapOf(0), // Single validator at index 0
⋮----
// Create signature map with many validators
⋮----
// Add even indexes (50 validators present out of 100)
```

## File: internal/client/repository/badger/badger_repository_signature_map.go

```go
package badger
⋮----
import (
	"context"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"context"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
⋮----
func keySignatureMap(requestID common.Hash) []byte
⋮----
func (r *Repository) updateSignatureMap(ctx context.Context, vm entity.SignatureMap) error
⋮----
func (r *Repository) GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
⋮----
var vm entity.SignatureMap
⋮----
// Create a new read-only transaction
⋮----
var err error
⋮----
func (r *Repository) getSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
⋮----
var (
	signatureMapToBytes = codec.SignatureMapToBytes
	bytesToSignatureMap = codec.BytesToSignatureMap
)
```

## File: internal/client/repository/badger/badger_repository_signature_request_test.go

```go
package badger
⋮----
import (
	"bytes"
	"sort"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"sort"
"strconv"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// signatureRequestID computes the RequestID for a SignatureRequest
func signatureRequestID(t *testing.T, req symbiotic.SignatureRequest) common.Hash
⋮----
func TestKeySignatureRequestBinaryFormat(t *testing.T)
⋮----
func TestKeySignatureRequestPendingBinaryFormat(t *testing.T)
⋮----
func TestBadgerRepository_SignatureRequest(t *testing.T)
⋮----
type reqWithTargetID struct {
	req  symbiotic.SignatureRequest
	hash common.Hash
}
⋮----
func TestBadgerRepository_GetSignatureRequestsByEpoch(t *testing.T)
⋮----
// Sort requests by hash (lexicographic order) to match expected retrieval order
⋮----
// Verify they are in correct order
⋮----
// Verify first 3 requests
⋮----
// Get first page (2 items)
⋮----
// Get second page using cursor
⋮----
// Get third page using cursor
⋮----
// Get fourth page (should be empty)
⋮----
// Use a hash that doesn't exist in this epoch
⋮----
// Should return results after the cursor position in lexicographic order
⋮----
// This test validates that when a cursor hash falls between stored keys,
// we don't skip the first valid item after the seek (off-by-one bug)
// Get the first two requests to determine a cursor that falls between them
⋮----
// Create a cursor hash that falls lexicographically between the first two stored hashes
⋮----
// Create a hash that's lexicographically between first and second
var betweenHash common.Hash
⋮----
// Increment the last byte to create a hash between first and second
⋮----
// Verify the hash is actually between the two stored hashes
⋮----
// Query with this between-hash cursor - should start from secondHash (not skip it)
⋮----
// Should return all items starting from the second item (no off-by-one skip)
require.Len(t, results, 4) // Should have 4 remaining items (total 5 - first 1)
⋮----
// Verify the sequence is correct
⋮----
expectedIndex := i + 1 // Skip first item, start from second
⋮----
func TestBadgerRepository_GetSignatureRequestsByEpoch_MultipleEpochs(t *testing.T)
⋮----
// Create requests for epoch1
⋮----
// Create requests for epoch2
⋮----
// Query epoch1 should return only epoch1 requests
⋮----
// Query epoch2 should return only epoch2 requests
⋮----
func randomSignatureRequest(t *testing.T) symbiotic.SignatureRequest
⋮----
func randomSignatureRequestForEpoch(t *testing.T, epoch symbiotic.Epoch) symbiotic.SignatureRequest
⋮----
func randomSignatureExtendedForEpoch(t *testing.T, epoch symbiotic.Epoch) symbiotic.Signature
⋮----
func TestBadgerRepository_GetSignatureRequestIDsByEpoch(t *testing.T)
⋮----
// Create 5 signature requests for the same epoch
⋮----
// Sort expected IDs by hex string (lexicographic order)
⋮----
// Verify they are in correct lexicographic order
⋮----
// Query epoch1 should return only epoch1 IDs
⋮----
// Query epoch2 should return only epoch2 IDs
⋮----
// Verify no overlap between epochs
⋮----
func TestBadgerRepository_GetSignatureRequestsWithIDByEpoch(t *testing.T)
⋮----
// Verify they are in correct order and have correct request IDs
⋮----
// Verify all results are for epoch1
⋮----
// Verify all results are for epoch2
⋮----
// Create a single request with known values
⋮----
// Retrieve it
⋮----
// Verify the request ID matches what we saved
```

## File: internal/client/repository/badger/badger_repository_signature_request.go

```go
package badger
⋮----
import (
	"bytes"
	"context"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	keySignatureRequestPrefix        = "signature_request:"
	keySignatureRequestPendingPrefix = "signature_pending:"
)
⋮----
func keySignatureRequest(epoch symbiotic.Epoch, requestID common.Hash) []byte
⋮----
func keySignatureRequestEpochPrefix(epoch symbiotic.Epoch) []byte
⋮----
func keyRequestIDIndex(requestID common.Hash) []byte
⋮----
func keySignatureRequestPending(epoch symbiotic.Epoch, requestID common.Hash) []byte
⋮----
// saveSignatureRequestToKey saves a signature request to a specific key
func (r *Repository) saveSignatureRequestToKey(ctx context.Context, req symbiotic.SignatureRequest, key []byte) error
⋮----
// Store the record
⋮----
func (r *Repository) SaveSignatureRequest(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
⋮----
// Save pending signature for all key tags because we should attempt
// to sync signatures from all signers even when keytag is non aggregation
⋮----
func (r *Repository) saveSignatureRequest(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
⋮----
func (r *Repository) saveSignaturePending(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
⋮----
// Store just a marker (empty value) - we don't need the full request data here
⋮----
func (r *Repository) RemoveSignaturePending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
// Remove from pending collection
⋮----
var (
	signatureRequestToBytes = codec.SignatureRequestToBytes
	bytesToSignatureRequest = codec.BytesToSignatureRequest
)
⋮----
func (r *Repository) GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
⋮----
var req symbiotic.SignatureRequest
⋮----
// Get primary key from hash index
⋮----
// Get actual data using primary key
⋮----
// GetSignatureRequestsWithIDByEpoch returns one page of signature requests for
// the given epoch, paginated via opaque cursor `from` (32-byte requestID raw).
// nextFrom == nil signals the last page; invalid `from` returns entity.ErrInvalidCursor.
func (r *Repository) GetSignatureRequestsWithIDByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]entity.SignatureRequestWithID, []byte, error)
⋮----
var (
		requests []entity.SignatureRequestWithID
		lastID   common.Hash
		moreLeft bool
	)
⋮----
// Skip exact-match cursor item (already returned in previous page).
⋮----
// GetSignatureRequestIDsByEpoch returns one page of request IDs for the given
// epoch (keys only — no value materialization). Cursor format same as
// GetSignatureRequestsWithIDByEpoch.
func (r *Repository) GetSignatureRequestIDsByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]common.Hash, []byte, error)
⋮----
var (
		requestIDs []common.Hash
		lastID     common.Hash
		moreLeft   bool
	)
⋮----
func (r *Repository) GetSignaturePending(ctx context.Context, limit int) ([]common.Hash, error)
⋮----
var requests []common.Hash
⋮----
// Iterate through pending signature markers
⋮----
// Stop if we've reached the limit
```

## File: internal/client/repository/badger/badger_repository_signature_test.go

```go
package badger
⋮----
import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/stretchr/testify/require"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestBadgerRepository_Signature(t *testing.T)
⋮----
require.Len(t, signatures, 3) // sig1 from first test + sig1 and sig2 from this test
⋮----
// Verify we can retrieve each signature by index
⋮----
func TestBadgerRepository_SignatureOrdering(t *testing.T)
⋮----
// Test numeric ordering with indices that would be wrong in lexicographic string order
⋮----
expectedOrder := []uint32{2, 9, 11, 100, 1000} // Expected numeric order
⋮----
// Save signatures with test indices
⋮----
sigCopy.PublicKey = priv.PublicKey() // Different public key for each
⋮----
// Retrieve all signatures and verify they are returned in numeric order
⋮----
// Verify each signature can be retrieved by its expected index
⋮----
// Verify this is the signature we expect (by checking the public key byte)
⋮----
// The signature returned by GetAllSignatures should match
⋮----
func TestBadgerRepository_GetSignaturesByEpoch(t *testing.T)
```

## File: internal/client/repository/badger/badger_repository_signature.go

```go
package badger
⋮----
import (
	"bytes"
	"context"
	"fmt"
	"log/slog"
	"strconv"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"fmt"
"log/slog"
"strconv"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func keySignature(requestID common.Hash, validatorIndex uint32) []byte
⋮----
func keySignatureRequestIDPrefix(requestID common.Hash) []byte
⋮----
// extractValidatorIndexFromSignatureKey parses the trailing 10-digit vIdx
// out of `signature:<hex>:<NNNNNNNNNN>`. Returns an error if the key shape is
// unexpected (corrupted store).
func extractValidatorIndexFromSignatureKey(key []byte) (uint32, error)
⋮----
func (r *Repository) saveSignature(
	ctx context.Context,
	validatorIndex uint32,
	sig symbiotic.Signature,
) error
⋮----
func (r *Repository) GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
⋮----
var signatures []symbiotic.Signature
⋮----
var err error
⋮----
func (r *Repository) GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (symbiotic.Signature, error)
⋮----
var signature symbiotic.Signature
⋮----
// GetSignaturesByEpoch returns one page of signatures for the given epoch,
// paginated via 36-byte composite cursor `from` (requestID || BE32(vIdx)).
// Pagination is per-signature so pageSize is honored exactly even when groups
// (signatures sharing a requestID) are large. nextFrom == nil signals last page.
func (r *Repository) GetSignaturesByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]symbiotic.Signature, []byte, error)
⋮----
var (
		signatures    []symbiotic.Signature
		lastRequestID common.Hash
		lastVIdx      uint32
		moreLeft      bool
	)
⋮----
// Seek to the index entry for fromRequestID (or start). We do NOT
// skip-on-exact-match: when the cursor lands on a known requestID we
// still need to read its remaining signatures (vIdx > fromVIdx).
⋮----
// Within the cursor's group, skip already-returned signatures.
// fromRequestID is zero only when from == nil, so a hash match
// here implies a real cursor — fromVIdx may legitimately be 0.
⋮----
func gatAllSignatures(txn *badger.Txn, requestID common.Hash) ([]symbiotic.Signature, error)
⋮----
var (
	signatureToBytes = codec.SignatureToBytes
	bytesToSignature = codec.BytesToSignature
)
```

## File: internal/client/repository/badger/badger_repository_test.go

```go
package badger
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"crypto/rand"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func randomBytes(t *testing.T, n int) []byte
⋮----
func randomAddr(t *testing.T) symbiotic.CrossChainAddress
⋮----
func randomBigInt(t *testing.T) *big.Int
⋮----
func TestKeyRequestIDEpoch(t *testing.T)
⋮----
epoch:     ^symbiotic.Epoch(0), // max uint64
⋮----
func TestExtractRequestIDFromEpochKey_InvalidKeys(t *testing.T)
⋮----
func TestKeyRequestIDEpochPrefix(t *testing.T)
⋮----
func TestKeyRequestIDEpochAll(t *testing.T)
⋮----
func TestExtractEpochFromKey(t *testing.T)
⋮----
func TestExtractEpochFromKey_Errors(t *testing.T)
⋮----
func TestExtractEpochFromValue(t *testing.T)
⋮----
func TestExtractEpochFromValue_Errors(t *testing.T)
```

## File: internal/client/repository/badger/badger_repository_transaction_test.go

```go
package badger
⋮----
import (
	"context"
	"testing"

	"github.com/dgraph-io/badger/v4"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"testing"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func TestRepository_DoUpdateInTx(t *testing.T)
⋮----
var executedInTx bool
⋮----
// Verify we have a transaction in the context
⋮----
// Perform a simple write operation
⋮----
// Verify the data was actually committed
⋮----
// Write some data
⋮----
// Return an error to trigger rollback
⋮----
// Verify the data was not committed due to rollback
⋮----
var outerTxn, innerTxn *badger.Txn
⋮----
// Nested transaction should reuse the same transaction
⋮----
// Should be the same transaction object
⋮----
// Write data using the nested context
⋮----
// Verify the nested write was committed
⋮----
// Write multiple keys in the same transaction
⋮----
// Verify all data was committed atomically
⋮----
// Attempt to perform write operation in view transaction
// This should fail because view transactions are read-only
⋮----
// BadgerDB returns ErrReadOnlyTxn when trying to write in a read-only transaction
⋮----
// First create a key to attempt to delete
⋮----
// Now try to delete it in a view transaction
⋮----
// Attempt to delete in view transaction
⋮----
// Verify the key still exists (delete didn't work)
```

## File: internal/client/repository/badger/badger_repository_transaction.go

```go
package badger
⋮----
import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/dgraph-io/badger/v4"
	"github.com/go-errors/errors"
	"github.com/samber/lo"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"context"
"sync"
"sync/atomic"
"time"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
type ctxTxnKey struct{}
⋮----
var badgerTxnKey ctxTxnKey
⋮----
type ctxQueryNameKey struct{}
⋮----
var ctxQueryName ctxQueryNameKey
⋮----
// mutexWithUseTime wraps a mutex with a timestamp of last access
type mutexWithUseTime struct {
	mutex        sync.Mutex
	lastAccessNs atomic.Int64 // Unix nanoseconds
}
⋮----
lastAccessNs atomic.Int64 // Unix nanoseconds
⋮----
func (m *mutexWithUseTime) lock()
⋮----
func (m *mutexWithUseTime) unlock()
⋮----
func (m *mutexWithUseTime) lastAccess() time.Time
⋮----
func (m *mutexWithUseTime) tryLock() bool
⋮----
func (r *Repository) doUpdateInTxWithLock(ctx context.Context, name string, f func(ctx context.Context) error, lockMap *sync.Map, key any) error
⋮----
func (r *Repository) doUpdateInTx(ctx context.Context, name string, f func(ctx context.Context) error) error
⋮----
func (r *Repository) doViewInTx(ctx context.Context, name string, f func(ctx context.Context) error) error
⋮----
func getTxn(ctx context.Context) *badger.Txn
⋮----
func (r *Repository) withName(ctx context.Context, name string) context.Context
⋮----
func nameFromCtx(ctx context.Context) string
```

## File: internal/client/repository/badger/badger_repository_validator_set_test.go

```go
package badger
⋮----
import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_ValidatorSet(t *testing.T)
⋮----
// Create two validator sets with different epochs
⋮----
// Test saving validator sets
⋮----
// Save newer epoch first
⋮----
// Save older epoch
⋮----
// Try to save the same epoch again
⋮----
// Test getting validator set by epoch
⋮----
// Get newer epoch
⋮----
// Get older epoch
⋮----
// Get non-existent epoch
⋮----
// Test getting latest validator set via epoch lookup
⋮----
// Latest should be vs1 (epoch 2) even though we saved it first
⋮----
// Test getting latest validator set epoch
⋮----
// Latest epoch should be vs1's epoch (2) even though we saved it first
⋮----
// Test getting validator set header by epoch
⋮----
// Get header for newer epoch
⋮----
// Verify header matches expected values from validator set
⋮----
// Get header for older epoch
⋮----
// Get non-existent epoch header
⋮----
// Test getting latest validator set header
⋮----
// Latest header should be from vs1 (epoch 2)
⋮----
// Test getting individual validators by key
⋮----
// Test with vs1 (epoch 2)
⋮----
// Get validator by key should return the correct validator
⋮----
// Test with vs2 (epoch 1)
⋮----
// Test non-existent validator
⋮----
// Test non-existent epoch
⋮----
func TestRepository_ValidatorSet_EmptyRepository(t *testing.T)
⋮----
func TestRepository_GetOldestValidatorSetEpoch(t *testing.T)
⋮----
func TestRepository_ValidatorSet_EpochOrdering(t *testing.T)
⋮----
// Create validator sets with different epochs in non-chronological order
⋮----
// Save them in random order
require.NoError(t, repo.saveValidatorSet(t.Context(), vs2)) // epoch 1
require.NoError(t, repo.saveValidatorSet(t.Context(), vs4)) // epoch 3
require.NoError(t, repo.saveValidatorSet(t.Context(), vs3)) // epoch 10
require.NoError(t, repo.saveValidatorSet(t.Context(), vs1)) // epoch 5
⋮----
assert.Equal(t, vs3, latest) // epoch 10 should be latest
⋮----
assert.Equal(t, vs3.Epoch, latestEpoch) // epoch 10 should be latest
⋮----
func TestRepository_ValidatorSet_ValidatorIndexing(t *testing.T)
⋮----
// Create a validator set with multiple validators having multiple keys
⋮----
// Should be able to find validator by any of their keys
⋮----
wrongKeyTag := key.Tag + 100 // Use a different key tag
⋮----
// Should not find validator with wrong key tag but same payload
⋮----
func TestRepository_ValidatorSet_MultiKeyStorageProblem(t *testing.T)
⋮----
// Create a validator with multiple keys to test storage duplication
⋮----
// Modify the first validator to have 3 different keys
⋮----
// Retrieve the validator set and check if deduplication works correctly
⋮----
// The validator should appear only once despite having multiple keys
⋮----
// Find our multi-key validator in the retrieved set
var foundValidator *symbiotic.Validator
⋮----
// Verify the validator has all its keys
⋮----
func TestRepository_ValidatorSet_ActiveIndex(t *testing.T)
⋮----
// Create validator set with mixed active/inactive validators
⋮----
// Modify validators to have specific active/inactive states and addresses
// Note: validators must be sorted by operator address ascending
⋮----
IsActive:    true, // Should get active index 0 (first when sorted by address)
⋮----
IsActive:    false, // Should get active index 0 (inactive) - positioned between two active validators
⋮----
IsActive:    true, // Should get active index 1 (second active validator, despite inactive validator in between)
⋮----
// Save validator set
⋮----
// Test first active validator (0x0000... should be index 0)
⋮----
// Test second active validator (0x3333... should be index 1, even though inactive 0x2222... is between them)
⋮----
// Test inactive validator
⋮----
func TestRepository_FirstUncommittedValidatorSetEpoch(t *testing.T)
⋮----
// Save first uncommitted epoch
⋮----
// Get first uncommitted epoch
⋮----
// Update to a different epoch
⋮----
// Verify it was updated
⋮----
func TestRepository_FirstUncommittedValidatorSetEpoch_EmptyRepository(t *testing.T)
⋮----
// Should return 0 and no error when not set (based on implementation)
⋮----
func setupTestRepository(t *testing.T) *Repository
⋮----
func randomValidatorSet(t *testing.T, epoch symbiotic.Epoch) symbiotic.ValidatorSet
```

## File: internal/client/repository/badger/badger_repository_validator_set.go

```go
package badger
⋮----
import (
	"context"
	"encoding/binary"
	"strconv"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"encoding/binary"
"strconv"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	latestValidatorSetEpochKey           = "latest_validator_set_epoch"
	latestAggregatedValidatorSetEpochKey = "latest_aggregated_validator_set_epoch"
	firstUncommittedValidatorSetEpoch    = "first_uncommitted_validator_set_epoch"
	validatorPrefixStr                   = "validator:"
	validatorKeyLookupPrefixStr          = "validator_key_lookup:"
	validatorSetStatusPrefix             = "validator_set_status:"
	validatorSetMetadataPrefix           = "validator_set_metadata:"
	activeValidatorCountPrefix           = "active_validator_count:"
)
⋮----
// keyValidatorSetHeader returns key for validator set header
// Format: "validator_set_header:" + epoch.Bytes()
// Using epoch.Bytes() ensures proper lexicographic sorting
func keyValidatorSetHeader(epoch symbiotic.Epoch) []byte
⋮----
// keyValidatorSetHeaderPrefix returns prefix for all validator set headers
func keyValidatorSetHeaderPrefix() []byte
⋮----
func keyValidatorByOperator(epoch symbiotic.Epoch, operator common.Address) []byte
⋮----
func keyValidatorPrefix(epoch symbiotic.Epoch) []byte
⋮----
func keyValidatorKeyLookup(epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKeyHash common.Hash) []byte
⋮----
func keyValidatorKeyLookupPrefix(epoch symbiotic.Epoch) []byte
⋮----
func keyValidatorSetStatus(epoch symbiotic.Epoch) []byte
⋮----
func keyValidatorSetMetadata(epoch symbiotic.Epoch) []byte
⋮----
func (r *Repository) saveValidatorSetMetadata(ctx context.Context, data symbiotic.ValidatorSetMetadata) error
⋮----
func (r *Repository) GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)
⋮----
var metadata symbiotic.ValidatorSetMetadata
⋮----
func (r *Repository) saveValidatorSet(ctx context.Context, valset symbiotic.ValidatorSet) error
⋮----
// Check if this epoch already exists by checking the header
⋮----
// Save the validator set header for its epoch
⋮----
// Check if this is a newer epoch than the latest one
⋮----
// Save individual validators and their key indexes
⋮----
// Save the validator data once
⋮----
// Create an index for each key that points to the validator's operator address
⋮----
// Store the total active validator count for this epoch
⋮----
func (r *Repository) SaveFirstUncommittedValidatorSetEpoch(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) UpdateValidatorSetStatusAndRemovePendingProof(ctx context.Context, valset symbiotic.ValidatorSet) error
⋮----
func (r *Repository) UpdateValidatorSetStatus(ctx context.Context, epoch symbiotic.Epoch, status symbiotic.ValidatorSetStatus) error
⋮----
func (r *Repository) updateLatestEpochIfNeeded(ctx context.Context, key []byte, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) GetValidatorSetHeaderByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetHeader, error)
⋮----
var header symbiotic.ValidatorSetHeader
⋮----
func (r *Repository) getAllValidatorsByEpoch(txn *badger.Txn, epoch symbiotic.Epoch) (symbiotic.Validators, error)
⋮----
var validators symbiotic.Validators
⋮----
func (r *Repository) GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
⋮----
var vs symbiotic.ValidatorSet
⋮----
// Get the validator set header
⋮----
// Get all validators for this epoch
⋮----
// Extract bitmap indices from header data
⋮----
// Build the validator set from header + validators
⋮----
func (r *Repository) GetLatestValidatorSetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
⋮----
// Get the latest epoch
⋮----
// Get the validator set header for that epoch in the same transaction
⋮----
func (r *Repository) GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
var epoch symbiotic.Epoch
⋮----
func keyActiveValidatorCount(epoch symbiotic.Epoch) []byte
⋮----
func (r *Repository) GetActiveValidatorCountByEpoch(ctx context.Context, epoch symbiotic.Epoch) (uint32, error)
⋮----
var count uint32
⋮----
func (r *Repository) GetOldestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
var err error
⋮----
func (r *Repository) GetFirstUncommittedValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
func (r *Repository) GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
⋮----
var validator symbiotic.Validator
var activeIndex uint32
⋮----
// First, find the operator address from the key lookup table
⋮----
// Now, retrieve the full validator data
⋮----
// This would indicate data inconsistency
⋮----
var (
	validatorToBytes                    = codec.ValidatorToBytes
	bytesToValidator                    = codec.BytesToValidator
	validatorSetHeaderToBytes           = codec.ValidatorSetHeaderToBytes
	bytesToValidatorSetHeader           = codec.BytesToValidatorSetHeader
	extractAdditionalInfoFromHeaderData = codec.ExtractAdditionalInfoFromHeaderData
)
⋮----
var (
	validatorSetMetadataToBytes = codec.ValidatorSetMetadataToBytes
	bytesToValidatorSetMetadata = codec.BytesToValidatorSetMetadata
)
⋮----
func (r *Repository) GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
```

## File: internal/client/repository/badger/badger_repository.go

```go
package badger
⋮----
import (
	"bytes"
	"context"
	"fmt"
	"log/slog"
	"sync"
	"time"

	"github.com/dgraph-io/badger/v4"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"fmt"
"log/slog"
"sync"
"time"
⋮----
"github.com/dgraph-io/badger/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
var _ cached.Repository = (*Repository)(nil)
⋮----
type Config struct {
	Dir                      string        `validate:"required"`
	Metrics                  metrics       `validate:"required"`
	MutexCleanupInterval     time.Duration // How often to run mutex cleanup (e.g., 1 hour). Zero disables cleanup.
	MutexCleanupStaleTimeout time.Duration // Remove mutexes not used for this duration, default 1 hour.
	ValueLogGCInterval       time.Duration // How often to run value log GC (e.g., 5m). Zero disables GC.
	ValueLogGCDiscardRatio   float64       // Discard ratio threshold for GC (0.0-1.0). Default 0.5.
	BlockCacheSize           int64         // -1 = use badger default, 0 = disabled, >0 = size in bytes
	MemTableSize             int64
	NumMemtables             int
	NumLevelZeroTables       int
	NumLevelZeroTablesStall  int
	CompactL0OnClose         bool
	NumCompactors            int
	ValueLogFileSize         int64
}
⋮----
MutexCleanupInterval     time.Duration // How often to run mutex cleanup (e.g., 1 hour). Zero disables cleanup.
MutexCleanupStaleTimeout time.Duration // Remove mutexes not used for this duration, default 1 hour.
ValueLogGCInterval       time.Duration // How often to run value log GC (e.g., 5m). Zero disables GC.
ValueLogGCDiscardRatio   float64       // Discard ratio threshold for GC (0.0-1.0). Default 0.5.
BlockCacheSize           int64         // -1 = use badger default, 0 = disabled, >0 = size in bytes
⋮----
func (c Config) Validate() error
⋮----
type Repository struct {
	db      *badger.DB
	metrics metrics

	requestIDMutexMap sync.Map // map[requestId]*mutexWithUseTime
	valsetMutexMap    sync.Map // map[epoch]*mutexWithUseTime

	valueLogGCDiscardRatio float64

	done chan struct{}
⋮----
requestIDMutexMap sync.Map // map[requestId]*mutexWithUseTime
valsetMutexMap    sync.Map // map[epoch]*mutexWithUseTime
⋮----
func New(cfg Config) (*Repository, error)
⋮----
// applyBadgerTuning overrides badger.Options with config values.
// For most fields, zero means "use badger default". For BlockCacheSize,
// -1 means "use badger default", 0 means "disabled", >0 means explicit size.
func applyBadgerTuning(opts *badger.Options, cfg Config)
⋮----
// CompactL0OnClose is a bool — always apply since the tuned default is true
// and badger's default is false. When cfg comes from CLI flags, the default is true.
// When cfg comes from tests (zero-value), this is a no-op (false == badger default).
⋮----
func (r *Repository) Close() error
⋮----
// MaxValueLogGCIterations bounds the value-log GC loop in Flatten. Each
// successful RunValueLogGC rewrites at most one vlog file, so this caps the
// total number of rewrites at a safe-but-large value to prevent pathological
// infinite loops if badger ever returns nil indefinitely. Exported so callers
// can include the value in user-facing messages.
const MaxValueLogGCIterations = 100
⋮----
// Flatten compacts all SST levels into the lowest possible LSM structure and then
// repeatedly runs value-log GC at the Config-supplied ValueLogGCDiscardRatio
// (default 0.5) until no more rewrites are needed. Intended for offline
// maintenance (e.g. one-shot CLI) — must not run alongside active write traffic.
//
// The bool return is true if the value-log GC loop hit MaxValueLogGCIterations
// without observing ErrNoRewrite — in that case there may still be reclaimable
// space and re-running Flatten is recommended. Callers should surface this
// signal to the operator (a fresh sidecar startup will also keep grinding).
func (r *Repository) Flatten(ctx context.Context, workers int) (capHit bool, err error)
⋮----
// db.Flatten and RunValueLogGC are blocking and don't accept a ctx, so we
// can only honor cancellation between phases / iterations. A SIGINT received
// mid-flatten will not abort the in-flight LSM rewrite (badger has no API
// for that); the second Ctrl+C / SIGKILL is the operator's escape hatch.
⋮----
type slogBadgerLogger struct{}
⋮----
func (l *slogBadgerLogger) Errorf(s string, args ...any)
func (l *slogBadgerLogger) Warningf(s string, args ...any)
func (l *slogBadgerLogger) Infof(s string, args ...any)
func (l *slogBadgerLogger) Debugf(string, ...any)
⋮----
func (r *Repository) startMutexCleanup(interval, staleTimeout time.Duration)
⋮----
func (r *Repository) startValueLogGC(interval time.Duration, discardRatio float64)
⋮----
func (r *Repository) startSizeReporter()
⋮----
func (r *Repository) reportDBSize()
⋮----
// cleanupStaleMutexes removes mutexes that haven't been used for longer than cleanupStaleAfter
func (r *Repository) cleanupStaleMutexes(staleTimeout time.Duration)
⋮----
// Default stale timeout to 1 hour if not set
⋮----
// cleanupMutexMap removes stale mutexes from a single sync.Map using double-check pattern
func cleanupMutexMap(mutexMap *sync.Map, staleThreshold time.Time) int
⋮----
var count int
⋮----
// First check: if recently accessed, skip
⋮----
// Try to acquire the lock to ensure it's not in use
⋮----
// Double-check last access time after acquiring lock
// This handles the race where updateAccess() was called between the first check and TryLock
⋮----
// Safe to delete now
⋮----
var errCorruptedRequestIDEpochLink = errors.New("corrupted request id epoch link")
⋮----
func keyRequestIDEpoch(epoch symbiotic.Epoch, requestID common.Hash) []byte
⋮----
func keyRequestIDEpochPrefix(epoch symbiotic.Epoch) []byte
⋮----
func keyRequestIDEpochAll() []byte
⋮----
const (
	epochLen   = 8
	hashLen    = 32
	hashHexLen = 66
	colonByte  = byte(':')
⋮----
// extractRequestIDFromEpochKey extracts request ID from the epoch key link
// Key format: "request_id_epoch" (16 bytes) + epoch (8 bytes) + requestID (32 bytes)
func extractRequestIDFromEpochKey(key []byte) (common.Hash, error)
⋮----
func epochKey(prefix string, epoch symbiotic.Epoch) []byte
⋮----
func epochKeyWithColon(prefix string, epoch symbiotic.Epoch) []byte
⋮----
func extractRequestIDFromEpochDelimitedKey(key []byte, prefix string) (common.Hash, error)
⋮----
// extractEpochFromKey extracts epoch from a key with format: prefix + epoch
func extractEpochFromKey(key []byte, prefix string) (symbiotic.Epoch, error)
⋮----
// extractEpochFromValue extracts epoch from a stored value (8-byte big-endian uint64)
func extractEpochFromValue(value []byte) (symbiotic.Epoch, error)
```

## File: internal/client/repository/badger/pagination_fuzz_test.go

```go
package badger
⋮----
import (
	"context"
	"crypto/rand"
	"encoding/binary"
	"sort"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"crypto/rand"
"encoding/binary"
"sort"
"strconv"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
// fuzz_buildEpochCorpus seeds a deterministic corpus into the repo:
// epoch=100 with numReqs requests, sigsPerGroup signatures per request,
// matching aggregation proofs; plus a small decoy in epoch=200.
func fuzz_buildEpochCorpus(t *testing.T, repo *Repository, numReqs, sigsPerGroup int) (mainIDs []common.Hash, totalSigs int)
⋮----
// Decoy epoch.
⋮----
// badger keys store hash.Hex() — lex hex order = lex byte order for fixed-length values.
⋮----
func allPages[T any](t *testing.T, pageSize int, fn func(from []byte) ([]T, []byte, error)) []T
⋮----
var (
		all    []T
		from   []byte
		safety = 100000
	)
⋮----
func TestFuzz_Badger_RequestsByEpoch(t *testing.T)
⋮----
const numReqs = 200
⋮----
// 1. unbounded.
⋮----
// 2. various pageSizes.
⋮----
// 3. exact total → next == nil.
⋮----
// 4. cursor exclusivity.
⋮----
// 5. invalid cursor lengths.
⋮----
// 6. cursor past the end.
⋮----
// 7. empty epoch.
⋮----
func TestFuzz_Badger_SignaturesByEpoch_PerSignature(t *testing.T)
⋮----
const (
		numReqs       = 30
		sigsPerGroup  = 7
		expectedTotal = numReqs * sigsPerGroup
	)
⋮----
// Unbounded baseline.
⋮----
// Reconstruct via various pageSizes including ones that cut groups.
⋮----
// MaxUint32 cursor must not crash.
⋮----
// Invalid lengths.
⋮----
// Cursor at exactly last vIdx of last group → empty next page.
⋮----
func TestFuzz_Badger_AggregationProofsByEpoch(t *testing.T)
⋮----
const numReqs = 100
⋮----
// Reconstruct with several pageSizes.
```

## File: internal/client/repository/bbolt/bbolt_repository_add_proof.go

```go
package bbolt
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) SaveProof(ctx context.Context, aggregationProof symbiotic.AggregationProof) error
⋮----
// Remove from pending in the same transaction
```

## File: internal/client/repository/bbolt/bbolt_repository_add_signature.go

```go
package bbolt
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) SaveSignature(ctx context.Context, signature symbiotic.Signature, validator symbiotic.Validator, activeIndex uint32) error
⋮----
func (r *Repository) saveSignatureWithPending(ctx context.Context, validatorIndex uint32, sig symbiotic.Signature) error
⋮----
// Maintain request_id_epochs index
⋮----
// Save pending proof if aggregation proof does not exist yet
⋮----
func (r *Repository) addToSignatureMapCache(ctx context.Context, requestID common.Hash, activeIndex uint32, votingPower symbiotic.VotingPower) (entity.SignatureMap, error)
⋮----
// loadSignatureMap returns the signature map for requestID, populating the cache atomically
// with an entry shared by all concurrent callers.
// Propagates ErrEntityNotFound from the rebuild without populating the cache, so callers
// (e.g. GetSignatureMap) can distinguish "no signatures yet" from a real cache hit.
func (r *Repository) loadSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
```

## File: internal/client/repository/bbolt/bbolt_repository_aggregation_proof_test.go

```go
package bbolt
⋮----
import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_AggregationProof(t *testing.T)
⋮----
func TestRepository_GetAggregationProofsByEpoch(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_aggregation_proof.go

```go
package bbolt
⋮----
import (
	"bytes"
	"context"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func putAggregationProofTx(tx *bolt.Tx, requestIDBytes []byte, data []byte, epoch symbiotic.Epoch) error
⋮----
// Maintain request_id_epochs index
⋮----
func (r *Repository) saveAggregationProof(ctx context.Context, requestID common.Hash, ap symbiotic.AggregationProof) error
⋮----
func (r *Repository) GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
⋮----
var ap symbiotic.AggregationProof
⋮----
var err error
⋮----
// GetAggregationProofsByEpoch returns one page of aggregation proofs for the
// given epoch, paginated via opaque cursor `from` (32-byte requestID raw).
// Iterates the request_id_epoch index sorted by requestID within epoch.
// nextFrom == nil signals the last page.
func (r *Repository) GetAggregationProofsByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]symbiotic.AggregationProof, []byte, error)
⋮----
var (
		proofs   []symbiotic.AggregationProof
		lastID   common.Hash
		moreLeft bool
	)
⋮----
func (r *Repository) RemoveAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch symbiotic.Epoch, limit int, lastHash common.Hash) ([]symbiotic.SignatureRequestWithID, error)
⋮----
var requests []symbiotic.SignatureRequestWithID
⋮----
// Get the actual signature request
```

## File: internal/client/repository/bbolt/bbolt_repository_network_config_test.go

```go
package bbolt
⋮----
import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
func TestRepository_NetworkConfig(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_network_config.go

```go
package bbolt
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) SaveConfig(ctx context.Context, config symbiotic.NetworkConfig, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
⋮----
var config symbiotic.NetworkConfig
⋮----
var err error
```

## File: internal/client/repository/bbolt/bbolt_repository_next_valset_data.go

```go
package bbolt
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
func (r *Repository) SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error
```

## File: internal/client/repository/bbolt/bbolt_repository_proof_commits_test.go

```go
package bbolt
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_SaveProofCommitPending(t *testing.T)
⋮----
func TestRepository_RemoveProofCommitPending(t *testing.T)
⋮----
func TestRepository_GetPendingProofCommitsSinceEpoch(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_proof_commits.go

```go
package bbolt
⋮----
import (
	"context"
	"encoding/binary"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"encoding/binary"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) saveProofCommitPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
⋮----
func (r *Repository) removeProofCommitPending(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) GetPendingProofCommitsSinceEpoch(ctx context.Context, epoch symbiotic.Epoch, limit int) ([]symbiotic.ProofCommitKey, error)
⋮----
var keys []symbiotic.ProofCommitKey
```

## File: internal/client/repository/bbolt/bbolt_repository_prune_test.go

```go
package bbolt
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestRepository_PruneAllEntityTypes(t *testing.T)
⋮----
func TestRepository_PruneEntityTypes_Separately(t *testing.T)
⋮----
func TestRepository_PruneRequestIDEpochIndices(t *testing.T)
⋮----
func TestRepository_PruneBatching(t *testing.T)
⋮----
var requestIDs []common.Hash
```

## File: internal/client/repository/bbolt/bbolt_repository_prune.go

```go
package bbolt
⋮----
import (
	"bytes"
	"context"
	"log/slog"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	bolt "go.etcd.io/bbolt"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"log/slog"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
bolt "go.etcd.io/bbolt"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) PruneValsetEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
// Delete network config
⋮----
// Delete static validator set keys
⋮----
// Delete all validators for this epoch
⋮----
func (r *Repository) PruneProofEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *Repository) PruneSignatureEntitiesForEpoch(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
// Invalidate cache BEFORE DB delete: a concurrent reader on cache miss
// would rebuild from DB; if we deleted the cache after the DB delete,
// the reader could see a stale cached map for an already-pruned request.
⋮----
func (r *Repository) PruneRequestIDEpochIndices(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *Repository) getRequestIDsByEpoch(ctx context.Context, epoch symbiotic.Epoch) ([]common.Hash, error)
⋮----
var requestIDs []common.Hash
⋮----
func getRequestIDsByEpochTx(tx *bolt.Tx, epoch symbiotic.Epoch) []common.Hash
⋮----
// deletePrefixedKeys buffers all matching keys during a single forward scan, then deletes
// them by key. The naive c.Delete()+re-Seek loop re-descends the B+tree from the root on
// every iteration (cursor is invalidated after Delete), so its scan cost is O(N·log N).
// Here the scan is O(N) — one Seek plus linear Next() walks across linked leaf pages —
// while deletion stays O(log N) per key but avoids the redundant re-seek churn.
func deletePrefixedKeys(b *bolt.Bucket, prefix []byte) error
⋮----
var keys [][]byte
⋮----
func pruneBatchSize(batchSize, total int) int
⋮----
// pausePrune sleeps for the configured prune pause window or returns early if ctx is cancelled.
// Returns true if pruning should stop (ctx cancelled), false otherwise.
func (r *Repository) pausePrune(ctx context.Context, epoch symbiotic.Epoch) bool
```

## File: internal/client/repository/bbolt/bbolt_repository_signature_map_test.go

```go
package bbolt
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func randomRequestID(t *testing.T) common.Hash
⋮----
func TestRepository_GetSignatureMap_NotFound(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_signature_request_test.go

```go
package bbolt
⋮----
import (
	"sort"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"sort"
"strconv"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func signatureRequestID(t *testing.T, req symbiotic.SignatureRequest) common.Hash
⋮----
func randomSignatureRequest(t *testing.T) symbiotic.SignatureRequest
⋮----
func randomSignatureRequestForEpoch(t *testing.T, epoch symbiotic.Epoch) symbiotic.SignatureRequest
⋮----
type reqWithTargetID struct {
	req  symbiotic.SignatureRequest
	hash common.Hash
}
⋮----
func TestRepository_SignatureRequest(t *testing.T)
⋮----
func TestRepository_GetSignatureRequestsByEpoch(t *testing.T)
⋮----
func TestRepository_GetSignatureRequestIDsByEpoch(t *testing.T)
⋮----
func TestRepository_GetSignatureRequestsWithIDByEpoch(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_signature_test.go

```go
package bbolt
⋮----
import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/stretchr/testify/require"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_Signature(t *testing.T)
⋮----
require.Len(t, signatures, 3) // sig1 at 5, sig1 at 10, sig2 at 20
⋮----
func TestRepository_SignatureOrdering(t *testing.T)
⋮----
func TestRepository_GetSignaturesByEpoch(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_signature.go

```go
package bbolt
⋮----
import (
	"bytes"
	"context"
	"encoding/binary"
	"encoding/hex"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (r *Repository) GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
⋮----
var signatures []symbiotic.Signature
⋮----
var err error
⋮----
func getAllSignatures(tx *bolt.Tx, requestID common.Hash) ([]symbiotic.Signature, error)
⋮----
prefix := requestID.Bytes() // 32 bytes
⋮----
func (r *Repository) GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (symbiotic.Signature, error)
⋮----
var sig symbiotic.Signature
⋮----
// GetSignaturesByEpoch returns one page of signatures for the given epoch,
// paginated via 36-byte composite cursor `from` (requestID || BE32(vIdx)).
// Pagination is per-signature so pageSize is honored exactly even when groups
// are large. nextFrom == nil signals the last page.
func (r *Repository) GetSignaturesByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]symbiotic.Signature, []byte, error)
⋮----
var (
		signatures    []symbiotic.Signature
		lastRequestID common.Hash
		lastVIdx      uint32
		moreLeft      bool
	)
⋮----
// fromRequestID is zero only when from == nil, so a hash match
// here implies a real cursor — fromVIdx may legitimately be 0.
⋮----
func (r *Repository) GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
⋮----
func (r *Repository) rebuildSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
⋮----
var sm entity.SignatureMap
⋮----
// Scan stored signatures: extract activeIndices and discover epoch from first signature
⋮----
var epoch symbiotic.Epoch
var activeIndices []uint32
⋮----
if len(k) != 36 { // 32 (requestID) + 4 (activeIndex)
⋮----
// Build activeIndex → votingPower from stored validators
⋮----
func (r *Repository) SaveSignatureRequest(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
⋮----
// Save signature request
⋮----
// Save request ID index: requestID → epoch bytes
⋮----
// Save pending signature marker
⋮----
return nil // Already pending
⋮----
func (r *Repository) GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
⋮----
var req symbiotic.SignatureRequest
⋮----
// Look up epoch from index
⋮----
// GetSignatureRequestsWithIDByEpoch returns one page of signature requests for
// the given epoch, paginated via opaque cursor `from` (32-byte requestID raw).
// nextFrom == nil signals the last page.
func (r *Repository) GetSignatureRequestsWithIDByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]entity.SignatureRequestWithID, []byte, error)
⋮----
var (
		requests []entity.SignatureRequestWithID
		lastID   common.Hash
		moreLeft bool
	)
⋮----
// GetSignatureRequestIDsByEpoch returns one page of request IDs for the given
// epoch (keys only — no value materialization). Cursor format same as
// GetSignatureRequestsWithIDByEpoch.
func (r *Repository) GetSignatureRequestIDsByEpoch(
	ctx context.Context,
	epoch symbiotic.Epoch,
	pageSize int,
	from []byte,
) ([]common.Hash, []byte, error)
⋮----
var (
		ids      []common.Hash
		lastID   common.Hash
		moreLeft bool
	)
⋮----
func (r *Repository) GetSignaturePending(ctx context.Context, limit int) ([]common.Hash, error)
⋮----
var requests []common.Hash
⋮----
func (r *Repository) RemoveSignaturePending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
```

## File: internal/client/repository/bbolt/bbolt_repository_test.go

```go
package bbolt
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"crypto/rand"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func randomBytes(t *testing.T, n int) []byte
⋮----
func randomAddr(t *testing.T) symbiotic.CrossChainAddress
⋮----
func randomBigInt(t *testing.T) *big.Int
⋮----
func setupTestRepository(t *testing.T) *Repository
⋮----
func randomValidatorSet(t *testing.T, epoch symbiotic.Epoch) symbiotic.ValidatorSet
⋮----
func randomNetworkConfig(t *testing.T) symbiotic.NetworkConfig
⋮----
func randomAggregationProof(t *testing.T) symbiotic.AggregationProof
```

## File: internal/client/repository/bbolt/bbolt_repository_validator_set_test.go

```go
package bbolt
⋮----
import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestRepository_ValidatorSet(t *testing.T)
⋮----
func TestRepository_ValidatorSet_EmptyRepository(t *testing.T)
⋮----
func TestRepository_GetOldestValidatorSetEpoch(t *testing.T)
⋮----
func TestRepository_ValidatorSet_EpochOrdering(t *testing.T)
⋮----
func TestRepository_ValidatorSet_ActiveIndex(t *testing.T)
⋮----
func TestRepository_FirstUncommittedValidatorSetEpoch(t *testing.T)
⋮----
func TestRepository_FirstUncommittedValidatorSetEpoch_EmptyRepository(t *testing.T)
```

## File: internal/client/repository/bbolt/bbolt_repository_validator_set.go

```go
package bbolt
⋮----
import (
	"bytes"
	"context"
	"encoding/binary"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	bolt "go.etcd.io/bbolt"

	"github.com/symbioticfi/relay/internal/client/repository/codec"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"context"
"encoding/binary"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
bolt "go.etcd.io/bbolt"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/codec"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
var (
	metaLatestValidatorSetEpoch     = []byte("latest_validator_set_epoch")
⋮----
func (r *Repository) saveValidatorSet(ctx context.Context, valset symbiotic.ValidatorSet) error
⋮----
// Check if exists
⋮----
// Update latest epoch
⋮----
func updateLatestEpochIfNeeded(tx *bolt.Tx, key []byte, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) SaveFirstUncommittedValidatorSetEpoch(ctx context.Context, epoch symbiotic.Epoch) error
⋮----
func (r *Repository) UpdateValidatorSetStatusAndRemovePendingProof(ctx context.Context, valset symbiotic.ValidatorSet) error
⋮----
// Remove pending proof commit (ignore not found)
⋮----
func (r *Repository) UpdateValidatorSetStatus(ctx context.Context, epoch symbiotic.Epoch, status symbiotic.ValidatorSetStatus) error
⋮----
func (r *Repository) GetValidatorSetHeaderByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetHeader, error)
⋮----
var header symbiotic.ValidatorSetHeader
⋮----
var err error
⋮----
func (r *Repository) getAllValidatorsByEpoch(tx *bolt.Tx, epoch symbiotic.Epoch) (symbiotic.Validators, error)
⋮----
var validators symbiotic.Validators
⋮----
func (r *Repository) GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
⋮----
var vs symbiotic.ValidatorSet
⋮----
func (r *Repository) GetLatestValidatorSetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
⋮----
func (r *Repository) GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
var epoch symbiotic.Epoch
⋮----
func (r *Repository) GetOldestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
func (r *Repository) GetActiveValidatorCountByEpoch(ctx context.Context, epoch symbiotic.Epoch) (uint32, error)
⋮----
var count uint32
⋮----
func (r *Repository) GetFirstUncommittedValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
return nil // No uncommitted epoch found, return zero
⋮----
func (r *Repository) GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
⋮----
var val symbiotic.Validator
var activeIndex uint32
⋮----
func (r *Repository) GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
⋮----
func (r *Repository) saveValidatorSetMetadata(ctx context.Context, data symbiotic.ValidatorSetMetadata) error
⋮----
func (r *Repository) GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)
⋮----
var metadata symbiotic.ValidatorSetMetadata
```

## File: internal/client/repository/bbolt/bbolt_repository.go

```go
package bbolt
⋮----
import (
	"context"
	"encoding/binary"
	"log/slog"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	bolt "go.etcd.io/bbolt"
	"golang.org/x/sync/singleflight"

	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"context"
"encoding/binary"
"log/slog"
"os"
"path/filepath"
"sync"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
bolt "go.etcd.io/bbolt"
"golang.org/x/sync/singleflight"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
var _ cached.Repository = (*Repository)(nil)
⋮----
type Config struct {
	Dir              string           `validate:"required"`
	Metrics          repoutil.Metrics `validate:"required"`
	DBFilename       string
	InitialMmapSize  int
	StatsLogInterval time.Duration
	PrunePause       time.Duration
	CompactOnStartup bool
	NoFreelistSync   bool
	NoSync           bool
	MaxBatchDelay    time.Duration
	MaxBatchSize     int
}
⋮----
var (
	bucketSignatures          = []byte("signatures")
⋮----
var allBuckets = [][]byte{
	bucketSignatures, bucketSignatureRequests, bucketSignaturePending,
	bucketRequestIDIndex, bucketRequestIDEpochs, bucketAggregationProofs, bucketAggProofPending,
	bucketAggProofCommits, bucketValidatorSetHeaders, bucketValidatorSetStatus, bucketValidatorSetMeta,
	bucketValidators, bucketValidatorKeyLookups, bucketActiveValCounts, bucketNetworkConfigs,
	bucketMeta,
}
⋮----
type Repository struct {
	db      *bolt.DB
	dbPath  string
	metrics repoutil.Metrics

	signatureMapCache  sync.Map // map[common.Hash]entity.SignatureMap
	signatureMapLoader singleflight.Group

	prunePause time.Duration

	done chan struct{}
⋮----
signatureMapCache  sync.Map // map[common.Hash]entity.SignatureMap
⋮----
// CompactDB rewrites the bbolt file at dbPath into a compacted copy and atomically
// replaces the original. Acquires an exclusive flock on the source for the entire
// rewrite, so no other process may have the database open while this runs.
func CompactDB(dbPath string) error
⋮----
return nil // DB doesn't exist yet, nothing to compact
⋮----
// Open source in writable mode to acquire an exclusive flock for the whole
// compaction window. This prevents any other process from opening the DB
// between Compact and Rename, which would otherwise observe an inode swap.
⋮----
// Compact rewrites the underlying bbolt file into a compacted copy and
// atomically replaces the original, reusing the already-open *bolt.DB handle
// as source. Avoids the cost of a fresh RW open (freelist build, flock).
//
// The receiver's handle points at the now-unlinked old inode after the rename,
// so the only safe action is closing it. CompactAndClose closes the handle
// internally (even on compaction failure) to make the foot-gun unreachable.
// The Repository is unusable after this call returns; do not invoke Close
// afterwards.
func (r *Repository) CompactAndClose() error
⋮----
// compactSrcInto runs bolt.Compact from src into a tmp file next to dbPath,
// then atomically renames into place. Caller is responsible for ensuring src
// holds an exclusive flock on dbPath for the duration so no concurrent opener
// can observe the inode swap.
func compactSrcInto(src *bolt.DB, dbPath string) error
⋮----
// Drop any stale tmp file from a previously crashed compaction so we don't
// merge into pre-existing data.
⋮----
const compactTxMaxSize = 64 << 20 // 64 MB per transaction to limit memory usage
⋮----
// Rename happens while src still holds the exclusive flock on dbPath, so
// no concurrent opener can race in and observe the swapped inode.
⋮----
func New(cfg Config) (*Repository, error)
⋮----
func (r *Repository) Close() error
⋮----
func (r *Repository) Stats() bolt.Stats
⋮----
func (r *Repository) startStatsLogger(interval time.Duration)
⋮----
var prevTxStats bolt.TxStats
⋮----
func (r *Repository) startSizeReporter(interval time.Duration)
⋮----
r.reportDBSize() // report once at startup
⋮----
func (r *Repository) reportDBSize()
⋮----
func (r *Repository) logStats(prevTxStats *bolt.TxStats)
⋮----
// Only log when there was write activity
⋮----
// DB-level: open read txns can block page reclamation and slow writes
⋮----
// Write breakdown since last log:
// spillTime = B-tree restructuring (CPU-bound)
// writeTime = disk write + fsync (IO-bound) — this is the fsync cost
⋮----
// How many write operations happened
⋮----
// Key encoding helpers — all use raw bytes for efficiency.
⋮----
func epochBytes(epoch uint64) []byte
⋮----
func uint32Bytes(v uint32) []byte
⋮----
// epochHashKey returns epoch(8) + hash(32) = 40 bytes
func epochHashKey(epoch uint64, hash []byte) []byte
⋮----
// epochOperatorKey returns epoch(8) + operator(20) = 28 bytes
func epochOperatorKey(epoch uint64, operator []byte) []byte
⋮----
// hashIndexKey returns requestID(32) + validatorIndex(4) = 36 bytes
func signatureKey(requestID []byte, validatorIndex uint32) []byte
⋮----
// validatorKeyLookupKey returns epoch(8) + keyTag(4) + pubKeyHash(32) = 44 bytes
func validatorKeyLookupKey(epoch uint64, keyTag uint32, pubKeyHash []byte) []byte
⋮----
const statusError = "error"
⋮----
type txKey struct{}
⋮----
func withTx(ctx context.Context, tx *bolt.Tx) context.Context
⋮----
func getTx(ctx context.Context) *bolt.Tx
⋮----
func (r *Repository) doView(ctx context.Context, name string, fn func(tx *bolt.Tx) error) error
⋮----
var err error
⋮----
// doBatch wraps db.Batch, which coalesces concurrent writers into a single bbolt
// transaction. The callback fn MUST be idempotent: bbolt re-runs it if the batch
// transaction commits but a peer's callback panics, or on internal retry. Do not
// rely on side effects performed before the final, committed call.
func (r *Repository) doBatch(ctx context.Context, name string, fn func(tx *bolt.Tx) error) error
```

## File: internal/client/repository/bbolt/pagination_fuzz_test.go

```go
package bbolt
⋮----
import (
	"context"
	"crypto/rand"
	"encoding/binary"
	"sort"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"crypto/rand"
"encoding/binary"
"sort"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
// fuzz_buildEpochCorpus seeds a deterministic corpus into the repo:
//   - epoch=100: numReqs signature requests + matching aggregation proofs and
//     sigsPerGroup signatures per request.
//   - epoch=200: a small decoy set to verify epoch isolation.
//
// Returns the main-epoch requestIDs in storage order plus the total number of
// signatures actually written.
func fuzz_buildEpochCorpus(t *testing.T, repo *Repository, numReqs, sigsPerGroup int) (mainReqIDs []common.Hash, totalSigs int)
⋮----
// Decoy epoch (verifies isolation).
⋮----
// bbolt sorts by raw bytes; for fixed-length 32-byte values lex hex == lex bytes.
⋮----
// allPages drains every page of a paginated callable into a flat slice and the
// list of cursors handed back. Asserts no infinite loop.
func allPages[T any](t *testing.T, pageSize int, fn func(from []byte) ([]T, []byte, error)) ([]T, [][]byte)
⋮----
var (
		all     []T
		from    []byte
		cursors [][]byte
		safety  = 100000
	)
⋮----
func TestFuzz_GetSignatureRequestsWithIDByEpoch_Invariants(t *testing.T)
⋮----
const numReqs = 200
⋮----
// 1. unbounded baseline.
⋮----
// 2. various pageSizes — union must equal baseline, no dups.
⋮----
// 3. exact pageSize == numReqs → 1 page, next == nil.
⋮----
// 4. pageSize == numReqs - 1 → 1st page = numReqs-1, 2nd page = 1, then next==nil.
⋮----
// 5. cursor exclusivity — taking lastID as cursor must NOT return that item.
⋮----
// 6. cursor on non-existent hash (random; gap between two real ones).
⋮----
// Result is real items strictly greater than `notExisting`. No assert on count, just that no item == notExisting.
⋮----
// 7. cursor past the very end → empty page, next==nil.
⋮----
// 8. invalid cursors — wrong length.
⋮----
// 9. empty epoch → empty page, nil next.
⋮----
func TestFuzz_GetSignatureRequestIDsByEpoch_MatchesRequests(t *testing.T)
⋮----
const numReqs = 150
⋮----
func TestFuzz_GetAggregationProofsByEpoch(t *testing.T)
⋮----
const numReqs = 100
⋮----
// Page through and reconstruct.
⋮----
// Invalid cursor lengths.
⋮----
func TestFuzz_GetSignaturesByEpoch_PerSignaturePagination(t *testing.T)
⋮----
const (
		numReqs       = 30
		sigsPerGroup  = 7
		expectedTotal = numReqs * sigsPerGroup
	)
⋮----
// 1. Unbounded baseline.
⋮----
// 2. Reconstruct via various pageSizes — including ones that cut groups in
//    half (sigsPerGroup-2, sigsPerGroup-1, sigsPerGroup, sigsPerGroup+1).
⋮----
// Compare set: same MessageHash+vIdx? Since we don't know vIdx from
// Signature struct, we instead verify each baseline element appears
// the same number of times.
⋮----
// 3. exact pageSize == expectedTotal → 1 page, next==nil.
⋮----
// 4. invalid cursors for sig endpoint (must be 36 bytes).
⋮----
// 5. boundary: pageSize=1 with sigsPerGroup=7 → 7 pages traverse one group then move.
⋮----
// 6. cursor bytes layout: cursor === requestID || BE32(vIdx). Construct
//    a synthetic cursor pointing right BEFORE the first signature of the
//    very first group: requestID=mainReqIDs[0], vIdx=MaxUint32 (overflow → 0
//    is filtered by `+1` in code). The first call without cursor should
//    start at vIdx=0; an explicit cursor (mainReqIDs[0], MaxUint32) tests
//    overflow safety.
⋮----
// signatureBag counts each unique (MessageHash, KeyTag, Epoch, PubKey) signature.
func signatureBag(sigs []symbiotic.Signature) map[string]int
⋮----
func TestFuzz_RepoutilCursor_RoundTrip(t *testing.T)
⋮----
var h common.Hash
⋮----
// signature cursor round trip
⋮----
// nil/empty
⋮----
func itoa(n int) string
⋮----
var buf [20]byte
```

## File: internal/client/repository/cache/generic_cache.go

```go
package cache
⋮----
import (
	"github.com/elastic/go-freelru"
	"github.com/go-errors/errors"
)
⋮----
"github.com/elastic/go-freelru"
"github.com/go-errors/errors"
⋮----
// Cache provides a generic LRU cache interface
type Cache[K comparable, V any] interface {
	Get(key K) (V, bool)
	Add(key K, value V)
	Delete(key K)
}
⋮----
// Config holds cache configuration
type Config struct {
	Size int
}
⋮----
// lruCache implements Cache using freelru
type lruCache[K comparable, V any] struct {
	cache *freelru.ShardedLRU[K, V]
}
⋮----
// NewCache creates a new generic LRU cache
func NewCache[K comparable, V any](cfg Config, hashFunc func(K) uint32) (Cache[K, V], error)
⋮----
cfg.Size = 50 // default cache size
⋮----
func (c *lruCache[K, V]) Get(key K) (V, bool)
⋮----
func (c *lruCache[K, V]) Add(key K, value V)
⋮----
func (c *lruCache[K, V]) Delete(key K)
```

## File: internal/client/repository/cached/cached_repository.go

```go
package cached
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/client/repository/cache"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/client/repository/cache"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type Repository interface {
	Close() error

	// Signatures
	SaveSignature(ctx context.Context, signature symbiotic.Signature, validator symbiotic.Validator, activeIndex uint32) error
	GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
	GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (symbiotic.Signature, error)
	// GetSignaturesByEpoch lists signatures of an epoch one page at a time.
	// `from` is an opaque cursor (nil to start); returns (items, nextFrom, err).
	// nextFrom == nil signals the last page; invalid `from` returns entity.ErrInvalidCursor.
	GetSignaturesByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]symbiotic.Signature, []byte, error)

	// Signature Maps
	GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)

	// Signature Requests
	SaveSignatureRequest(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
	GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
	GetSignatureRequestsWithIDByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]entity.SignatureRequestWithID, []byte, error)
	GetSignatureRequestIDsByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]common.Hash, []byte, error)
	GetSignaturePending(ctx context.Context, limit int) ([]common.Hash, error)
	RemoveSignaturePending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error

	// Aggregation Proofs
	SaveProof(ctx context.Context, aggregationProof symbiotic.AggregationProof) error
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	GetAggregationProofsByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]symbiotic.AggregationProof, []byte, error)
	GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch symbiotic.Epoch, limit int, lastHash common.Hash) ([]symbiotic.SignatureRequestWithID, error)
	RemoveAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error

	// Validator Sets
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	GetValidatorSetHeaderByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetHeader, error)
	GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
	GetActiveValidatorCountByEpoch(ctx context.Context, epoch symbiotic.Epoch) (uint32, error)
	GetLatestValidatorSetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
	GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetOldestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
	UpdateValidatorSetStatus(ctx context.Context, epoch symbiotic.Epoch, status symbiotic.ValidatorSetStatus) error
	UpdateValidatorSetStatusAndRemovePendingProof(ctx context.Context, valset symbiotic.ValidatorSet) error
	SaveFirstUncommittedValidatorSetEpoch(ctx context.Context, epoch symbiotic.Epoch) error
	GetFirstUncommittedValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)

	// Validator Set Metadata
	GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)

	// Network Config
	SaveConfig(ctx context.Context, config symbiotic.NetworkConfig, epoch symbiotic.Epoch) error
	GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)

	// Proof Commits
	GetPendingProofCommitsSinceEpoch(ctx context.Context, epoch symbiotic.Epoch, limit int) ([]symbiotic.ProofCommitKey, error)

	// Composite Operations
	SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error

	// Pruning
	PruneValsetEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneProofEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneSignatureEntitiesForEpoch(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneRequestIDEpochIndices(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
}
⋮----
// Signatures
⋮----
// GetSignaturesByEpoch lists signatures of an epoch one page at a time.
// `from` is an opaque cursor (nil to start); returns (items, nextFrom, err).
// nextFrom == nil signals the last page; invalid `from` returns entity.ErrInvalidCursor.
⋮----
// Signature Maps
⋮----
// Signature Requests
⋮----
// Aggregation Proofs
⋮----
// Validator Sets
⋮----
// Validator Set Metadata
⋮----
// Network Config
⋮----
// Proof Commits
⋮----
// Composite Operations
⋮----
// Pruning
⋮----
type Config struct {
	NetworkConfigCacheSize int
	ValidatorSetCacheSize  int
}
⋮----
type CachedRepository struct {
	Repository

	networkConfigCache        cache.Cache[symbiotic.Epoch, symbiotic.NetworkConfig]
	validatorSetCache         cache.Cache[symbiotic.Epoch, symbiotic.ValidatorSet]
	validatorSetMetadataCache cache.Cache[symbiotic.Epoch, symbiotic.ValidatorSetMetadata]
}
⋮----
func NewCached(repo Repository, cfg Config) (*CachedRepository, error)
⋮----
func (r *CachedRepository) GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
⋮----
func (r *CachedRepository) SaveConfig(ctx context.Context, config symbiotic.NetworkConfig, epoch symbiotic.Epoch) error
⋮----
func (r *CachedRepository) GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
⋮----
func (r *CachedRepository) GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)
⋮----
func (r *CachedRepository) PruneValsetEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
⋮----
func (r *CachedRepository) SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error
⋮----
func (r *CachedRepository) evictValsetCaches(epoch symbiotic.Epoch)
```

## File: internal/client/repository/codec/codec.go

```go
package codec
⋮----
import (
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	ethcrypto "github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/protobuf/proto"

	pb "github.com/symbioticfi/relay/internal/client/repository/badger/proto/v1"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"math/big"
⋮----
"github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/protobuf/proto"
⋮----
pb "github.com/symbioticfi/relay/internal/client/repository/badger/proto/v1"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func MarshalProto(msg proto.Message) ([]byte, error)
⋮----
func UnmarshalProto(data []byte, msg proto.Message) error
⋮----
// Signature
⋮----
func SignatureToBytes(sig symbiotic.Signature) ([]byte, error)
⋮----
func BytesToSignature(value []byte) (symbiotic.Signature, error)
⋮----
// SignatureMap
⋮----
func SignatureMapToBytes(vm entity.SignatureMap) ([]byte, error)
⋮----
func BytesToSignatureMap(data []byte) (entity.SignatureMap, error)
⋮----
// SignatureRequest
⋮----
func SignatureRequestToBytes(req symbiotic.SignatureRequest) ([]byte, error)
⋮----
func BytesToSignatureRequest(data []byte) (symbiotic.SignatureRequest, error)
⋮----
// AggregationProof
⋮----
func AggregationProofToBytes(ap symbiotic.AggregationProof) ([]byte, error)
⋮----
func BytesToAggregationProof(value []byte) (symbiotic.AggregationProof, error)
⋮----
// Validator
⋮----
func ValidatorToBytes(validator symbiotic.Validator, activeIndex uint32) ([]byte, error)
⋮----
func BytesToValidator(data []byte) (symbiotic.Validator, uint32, error)
⋮----
// ValidatorSetHeader
⋮----
func ValidatorSetHeaderToBytes(valset symbiotic.ValidatorSet) ([]byte, error)
⋮----
var aggIndices, commIndices []byte
⋮----
func BytesToValidatorSetHeader(data []byte) (symbiotic.ValidatorSetHeader, error)
⋮----
func ExtractAdditionalInfoFromHeaderData(data []byte) (aggIndices []uint32, commIndices []uint32, err error)
⋮----
// ValidatorSetMetadata
⋮----
func ValidatorSetMetadataToBytes(data symbiotic.ValidatorSetMetadata) ([]byte, error)
⋮----
func BytesToValidatorSetMetadata(data []byte) (symbiotic.ValidatorSetMetadata, error)
⋮----
// NetworkConfig
⋮----
func NetworkConfigToBytes(config symbiotic.NetworkConfig) ([]byte, error)
⋮----
func BytesToNetworkConfig(data []byte) (symbiotic.NetworkConfig, error)
⋮----
// ValidatorKeyHash computes the keccak256 hash of a public key for key lookup indexing.
func ValidatorKeyHash(publicKey []byte) common.Hash
```

## File: internal/client/repository/loadtest/savesignature_test.go

```go
package loadtest
⋮----
import (
	"context"
	"crypto/rand"
	"fmt"
	"math/big"
	"os"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"

	badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"crypto/rand"
"fmt"
"math/big"
"os"
"sort"
"strconv"
"sync"
"sync/atomic"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type loadConfig struct {
	validators      int
	requestInterval time.Duration
	duration        time.Duration
}
⋮----
func getLoadConfig() loadConfig
⋮----
type testBackend struct {
	repo       cached.Repository
	validators []symbiotic.Validator
	keys       []crypto.PrivateKey
	cleanup    func()
}
⋮----
func setupBbolt(b *testing.B, numValidators int) testBackend
⋮----
func setupBadger(b *testing.B, numValidators int) testBackend
⋮----
BlockCacheSize: 64 << 20, // 64MB
⋮----
func generateValidators(b *testing.B, n int) ([]crypto.PrivateKey, []symbiotic.Validator)
⋮----
// Use deterministic operator addresses so they sort consistently
⋮----
// Sort by operator address ascending (required by saveValidatorSet)
⋮----
// Re-order keys to match sorted validators
⋮----
// Rebuild keys array matching sorted order
⋮----
func findKeyForValidator(keys []crypto.PrivateKey, v symbiotic.Validator, _ []symbiotic.Validator) crypto.PrivateKey
⋮----
func seedData(b *testing.B, repo cached.Repository, validators []symbiotic.Validator, _ []crypto.PrivateKey)
⋮----
type pregenSignatures struct {
	signatures [][]symbiotic.Signature // [requestIdx][validatorIdx]
	messages   [][]byte
}
⋮----
signatures [][]symbiotic.Signature // [requestIdx][validatorIdx]
⋮----
func pregenerate(b *testing.B, keys []crypto.PrivateKey, numRequests int) pregenSignatures
⋮----
type latencyCollector struct {
	samples []time.Duration
	idx     atomic.Int64
}
⋮----
func newLatencyCollector(capacity int) *latencyCollector
⋮----
func (lc *latencyCollector) record(d time.Duration)
⋮----
func (lc *latencyCollector) results() []time.Duration
⋮----
func percentile(sorted []time.Duration, p float64) time.Duration
⋮----
func BenchmarkSaveSignature(b *testing.B)
⋮----
func runLoadTest(b *testing.B, backend testBackend, cfg loadConfig, numRequests int)
⋮----
var errCount atomic.Int64
⋮----
var wg sync.WaitGroup
⋮----
func randomBytes(b *testing.B) []byte
```

## File: internal/client/repository/repoutil/cursor.go

```go
package repoutil
⋮----
import (
	"encoding/binary"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"encoding/binary"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
// Internal pagination cursor format. Public API exposes opaque base64; the
// repo serializes raw bytes here. Two layouts are used:
//
//   - hash cursor (32 bytes): requestID. Used by Requests/IDs/Proofs listings.
//   - signature cursor (36 bytes): requestID || BE32(validatorIndex). Used by
//     Signatures listing because pagination is per-signature within a group.
const signatureCursorLen = common.HashLength + 4
⋮----
// DecodeHashCursor parses a 32-byte cursor. Empty cursor → zero-hash (start).
// Wrong length → entity.ErrInvalidCursor.
func DecodeHashCursor(from []byte) (common.Hash, error)
⋮----
// EncodeHashCursor returns the raw bytes of a hash cursor.
func EncodeHashCursor(h common.Hash) []byte
⋮----
// DecodeSignatureCursor parses a 36-byte composite cursor (requestID + vIdx).
// Empty cursor → (zero-hash, 0) meaning "start from the beginning".
func DecodeSignatureCursor(from []byte) (common.Hash, uint32, error)
⋮----
// EncodeSignatureCursor packs (hash, vIdx) into the 36-byte cursor format.
func EncodeSignatureCursor(h common.Hash, vIdx uint32) []byte
```

## File: internal/client/repository/repoutil/metrics.go

```go
package repoutil
⋮----
import "time"
⋮----
type Metrics interface {
	ObserveRepoQueryDuration(queryName string, status string, d time.Duration)
	ObserveRepoQueryTotalDuration(queryName string, status string, d time.Duration)
	SetDBSizeBytes(sizeBytes float64)
}
⋮----
type DoNothingMetrics struct{}
⋮----
func (DoNothingMetrics) ObserveRepoQueryDuration(string, string, time.Duration)
func (DoNothingMetrics) ObserveRepoQueryTotalDuration(string, string, time.Duration)
func (DoNothingMetrics) SetDBSizeBytes(float64)
```

## File: internal/entity/entity_aggregation_proof_sync_test.go

```go
package entity
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestAggregationProofSync_Integration(t *testing.T)
⋮----
// Step 1: Create request for missing aggregation proofs
⋮----
// Step 2: Create response with available proofs (only 2 out of 3)
⋮----
// hash3 is missing - peer doesn't have it
⋮----
// Step 3: Process response and track stats
⋮----
// Simulate processing each requested hash
⋮----
// Proof found and processed successfully
_ = proof // Use the proof
⋮----
// Proof not found in response - no error, just missing
// This is normal behavior when peers don't have all proofs
⋮----
// Step 4: Simulate some processing errors for remaining proof
stats.VerificationFailCount = 1 // hash3 had verification error
```

## File: internal/entity/entity_error.go

```go
package entity
⋮----
type StringError string
⋮----
func (e StringError) Error() string
⋮----
const (
	ErrEntityNotFound     = StringError("entity not found")
```

## File: internal/entity/entity_signature_map_test.go

```go
package entity
⋮----
import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestSignatureMap_SetValidatorPresent(t *testing.T)
⋮----
// Setup common test data
⋮----
vm := NewSignatureMap(requestID, symbiotic.Epoch(epoch), 2) // 2 total validators for setup
⋮----
// Verify validator index is marked as present
⋮----
// Verify voting power is updated
expectedVotingPower := symbiotic.ToVotingPower(big.NewInt(100)) // activeValidator1's voting power
⋮----
// Set first validator present (index 0)
⋮----
// Set second validator present (index 1)
⋮----
// Verify both validator indexes are marked as present
⋮----
// Verify total voting power is cumulative
expectedVotingPower := symbiotic.ToVotingPower(big.NewInt(300)) // 100 + 200
⋮----
// Set validator index present first time
⋮----
// Try to set the same validator index present again
⋮----
// Verify voting power is not double-counted
expectedVotingPower := symbiotic.ToVotingPower(big.NewInt(100)) // Should still be 100, not 200
⋮----
func TestSignatureMap_ThresholdReached(t *testing.T)
⋮----
func TestSignatureMap_IntegrationScenarios(t *testing.T)
⋮----
// Setup validators with different voting powers
⋮----
// Total active voting power: 750
// Set quorum threshold to 67% (approximately 500)
⋮----
vm := NewSignatureMap(requestID, symbiotic.Epoch(epoch), 4) // 4 total validators
⋮----
// Verify initial state
⋮----
// Add first validator (100) - threshold not reached
⋮----
// Add second validator (100 + 200 = 300) - threshold not reached
⋮----
// Add third validator (300 + 300 = 600) - threshold reached!
⋮----
// Add fourth validator (600 + 150 = 750) - threshold still reached
⋮----
IsActive:    false, // Inactive - not available for signatures
⋮----
// Total active voting power: 300 (only first two validators)
// Set high quorum threshold that can't be reached
⋮----
// Add all available active validators (first two are active)
⋮----
// Even with all active validators, threshold should not be reached
⋮----
// Total active voting power: 500
// Set quorum threshold to 100%
⋮----
// Add first validator - threshold not reached
⋮----
// Add second validator - threshold exactly reached
⋮----
func TestSignatureMap_GetMissingValidators(t *testing.T)
⋮----
// All validators should be missing
⋮----
// Set validators 0 and 2 as present
⋮----
// Only validators 1 and 3 should be missing
⋮----
// Set all validators as present
⋮----
// No validators should be missing
⋮----
// Single validator should be missing
⋮----
// After setting present
⋮----
func TestBitmapFromBytes(t *testing.T)
⋮----
// Create a bitmap with some values
⋮----
// Serialize to bytes
⋮----
// Deserialize from bytes
⋮----
// Verify the restored bitmap has the same values
⋮----
// Create empty bitmap
⋮----
// Verify the restored bitmap is empty
⋮----
// Test with invalid byte sequence
⋮----
// Create bitmap with large indices
⋮----
// Verify all large indices are preserved
⋮----
// Test multiple roundtrips to ensure consistency
⋮----
// Serialize
⋮----
// Deserialize
⋮----
// Verify equality
⋮----
// Use restored for next iteration
```

## File: internal/entity/entity_signature_map.go

```go
package entity
⋮----
import (
	"math/big"

	"github.com/RoaringBitmap/roaring/v2"
	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
⋮----
"github.com/RoaringBitmap/roaring/v2"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type SignatureMap struct {
	RequestID              common.Hash
	Epoch                  symbiotic.Epoch
	SignedValidatorsBitmap Bitmap
	CurrentVotingPower     symbiotic.VotingPower
	TotalValidators        uint32
}
⋮----
func NewSignatureMap(requestID common.Hash, epoch symbiotic.Epoch, totalValidators uint32) SignatureMap
⋮----
func (vm *SignatureMap) SetValidatorPresent(activeIndex uint32, votingPower symbiotic.VotingPower) error
⋮----
func (vm *SignatureMap) ThresholdReached(quorumThreshold symbiotic.VotingPower) bool
⋮----
func (vm *SignatureMap) Clone() SignatureMap
⋮----
func (vm *SignatureMap) GetMissingValidators() Bitmap
⋮----
type Bitmap struct {
	*roaring.Bitmap
}
⋮----
func NewBitmap() Bitmap
⋮----
func NewBitmapOf(dat ...uint32) Bitmap
⋮----
func BitmapFromBytes(b []byte) (Bitmap, error)
```

## File: internal/entity/entity_signature_request.go

```go
package entity
⋮----
import (
	"github.com/ethereum/go-ethereum/common"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// SignatureRequestWithID represents a signature request with its request ID
type SignatureRequestWithID struct {
	RequestID        common.Hash
	SignatureRequest symbiotic.SignatureRequest
}
⋮----
type NextValsetData struct {
	NextValidatorSet  symbiotic.ValidatorSet
	NextNetworkConfig symbiotic.NetworkConfig

	PrevValidatorSet  symbiotic.ValidatorSet
	PrevNetworkConfig symbiotic.NetworkConfig

	SignatureRequest *symbiotic.SignatureRequest

	ValidatorSetMetadata symbiotic.ValidatorSetMetadata
}
```

## File: internal/entity/entity_signature_sync.go

```go
package entity
⋮----
import (
	"github.com/ethereum/go-ethereum/common"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// WantSignaturesRequest represents a request to resync signatures for a specific epoch.
// Contains missing validator indices for each incomplete signature request.
type WantSignaturesRequest struct {
	WantSignatures map[common.Hash]Bitmap // requestID -> missing validator indices bitmap
}
⋮----
WantSignatures map[common.Hash]Bitmap // requestID -> missing validator indices bitmap
⋮----
// WantSignaturesResponse contains signatures grouped by Request id.
// Each signature includes the validator index for consistent mapping.
type WantSignaturesResponse struct {
	Signatures map[common.Hash][]ValidatorSignature
}
⋮----
// ValidatorSignature pairs a signature with its validator index in the active validator set.
// The validator index corresponds to the position in ValidatorSet.Validators.GetActiveValidators().
type ValidatorSignature struct {
	ValidatorIndex uint32              // Index in active validator set
	Signature      symbiotic.Signature // The actual signature data
}
⋮----
ValidatorIndex uint32              // Index in active validator set
Signature      symbiotic.Signature // The actual signature data
⋮----
// SignatureProcessingStats contains detailed statistics for processing received signatures
type SignatureProcessingStats struct {
	ProcessedCount            int // Successfully processed signatures
	UnrequestedSignatureCount int // Signatures for validators we didn't request
	UnrequestedHashCount      int // Signatures for hashes we didn't request
	SignatureRequestFailCount int // Failed to get signature request
	ProcessingFailCount       int // Failed to process signature
	AlreadyExistCount         int // Signature already exists (ErrEntityAlreadyExist)
}
⋮----
ProcessedCount            int // Successfully processed signatures
UnrequestedSignatureCount int // Signatures for validators we didn't request
UnrequestedHashCount      int // Signatures for hashes we didn't request
SignatureRequestFailCount int // Failed to get signature request
ProcessingFailCount       int // Failed to process signature
AlreadyExistCount         int // Signature already exists (ErrEntityAlreadyExist)
⋮----
// TotalErrors returns the total number of errors encountered
func (s SignatureProcessingStats) TotalErrors() int
⋮----
// WantAggregationProofsRequest represents a request to resync aggregation proofs for specific signature requests.
// Contains request ids for which aggregation proofs are needed.
type WantAggregationProofsRequest struct {
	RequestIDs []common.Hash // requestID list for missing aggregation proofs
}
⋮----
RequestIDs []common.Hash // requestID list for missing aggregation proofs
⋮----
// WantAggregationProofsResponse contains aggregation proofs grouped by request id.
// Each aggregation proof corresponds to a complete signature aggregation for a request.
type WantAggregationProofsResponse struct {
	Proofs map[common.Hash]symbiotic.AggregationProof // requestID -> aggregation proof
}
⋮----
Proofs map[common.Hash]symbiotic.AggregationProof // requestID -> aggregation proof
⋮----
// AggregationProofProcessingStats contains detailed statistics for processing received aggregation proofs
type AggregationProofProcessingStats struct {
	ProcessedCount        int // Successfully processed aggregation proofs
	UnrequestedProofCount int // Proofs for hashes we didn't request
	VerificationFailCount int // Failed to verify aggregation proof
	ProcessingFailCount   int // Failed to process aggregation proof
	AlreadyExistCount     int // Aggregation proof already exists (ErrEntityAlreadyExist)
}
⋮----
ProcessedCount        int // Successfully processed aggregation proofs
UnrequestedProofCount int // Proofs for hashes we didn't request
VerificationFailCount int // Failed to verify aggregation proof
ProcessingFailCount   int // Failed to process aggregation proof
AlreadyExistCount     int // Aggregation proof already exists (ErrEntityAlreadyExist)
```

## File: internal/entity/p2p_entity.go

```go
package entity
⋮----
type SenderInfo struct {
	// Sender is a p2p peer id
	Sender    string
	PublicKey []byte
}
⋮----
// Sender is a p2p peer id
⋮----
// P2PMessage is a generic message structure for P2P communication, containing SenderInfo and a message of type T.
type P2PMessage[T any] struct {
	SenderInfo   SenderInfo
	Message      T
	TraceContext map[string]string
}
```

## File: internal/gen/api/v1/api_grpc.pb.go

```go
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc             (unknown)
// source: v1/api.proto
⋮----
package v1
⋮----
import (
	context "context"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
)
⋮----
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
⋮----
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
⋮----
const (
	SymbioticAPIService_SignMessage_FullMethodName                   = "/api.proto.v1.SymbioticAPIService/SignMessage"
	SymbioticAPIService_GetAggregationProof_FullMethodName           = "/api.proto.v1.SymbioticAPIService/GetAggregationProof"
	SymbioticAPIService_GetAggregationProofsByEpoch_FullMethodName   = "/api.proto.v1.SymbioticAPIService/GetAggregationProofsByEpoch"
	SymbioticAPIService_GetCurrentEpoch_FullMethodName               = "/api.proto.v1.SymbioticAPIService/GetCurrentEpoch"
	SymbioticAPIService_GetSignatures_FullMethodName                 = "/api.proto.v1.SymbioticAPIService/GetSignatures"
	SymbioticAPIService_GetSignaturesByEpoch_FullMethodName          = "/api.proto.v1.SymbioticAPIService/GetSignaturesByEpoch"
	SymbioticAPIService_GetSignatureRequestIDsByEpoch_FullMethodName = "/api.proto.v1.SymbioticAPIService/GetSignatureRequestIDsByEpoch"
	SymbioticAPIService_GetSignatureRequestsByEpoch_FullMethodName   = "/api.proto.v1.SymbioticAPIService/GetSignatureRequestsByEpoch"
	SymbioticAPIService_GetSignatureRequest_FullMethodName           = "/api.proto.v1.SymbioticAPIService/GetSignatureRequest"
	SymbioticAPIService_GetAggregationStatus_FullMethodName          = "/api.proto.v1.SymbioticAPIService/GetAggregationStatus"
	SymbioticAPIService_GetValidatorSet_FullMethodName               = "/api.proto.v1.SymbioticAPIService/GetValidatorSet"
	SymbioticAPIService_GetValidatorByAddress_FullMethodName         = "/api.proto.v1.SymbioticAPIService/GetValidatorByAddress"
	SymbioticAPIService_GetValidatorByKey_FullMethodName             = "/api.proto.v1.SymbioticAPIService/GetValidatorByKey"
	SymbioticAPIService_GetLocalValidator_FullMethodName             = "/api.proto.v1.SymbioticAPIService/GetLocalValidator"
	SymbioticAPIService_GetValidatorSetHeader_FullMethodName         = "/api.proto.v1.SymbioticAPIService/GetValidatorSetHeader"
	SymbioticAPIService_GetLastCommitted_FullMethodName              = "/api.proto.v1.SymbioticAPIService/GetLastCommitted"
	SymbioticAPIService_GetLastAllCommitted_FullMethodName           = "/api.proto.v1.SymbioticAPIService/GetLastAllCommitted"
	SymbioticAPIService_GetValidatorSetMetadata_FullMethodName       = "/api.proto.v1.SymbioticAPIService/GetValidatorSetMetadata"
	SymbioticAPIService_GetCustomScheduleNodeStatus_FullMethodName   = "/api.proto.v1.SymbioticAPIService/GetCustomScheduleNodeStatus"
	SymbioticAPIService_ListenSignatures_FullMethodName              = "/api.proto.v1.SymbioticAPIService/ListenSignatures"
	SymbioticAPIService_ListenProofs_FullMethodName                  = "/api.proto.v1.SymbioticAPIService/ListenProofs"
	SymbioticAPIService_ListenValidatorSet_FullMethodName            = "/api.proto.v1.SymbioticAPIService/ListenValidatorSet"
)
⋮----
// SymbioticAPIServiceClient is the client API for SymbioticAPIService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
⋮----
// SymbioticAPI provides access to the Symbiotic relay functions
type SymbioticAPIServiceClient interface {
	// Sign a message
	SignMessage(ctx context.Context, in *SignMessageRequest, opts ...grpc.CallOption) (*SignMessageResponse, error)
	// Get aggregation proof
	GetAggregationProof(ctx context.Context, in *GetAggregationProofRequest, opts ...grpc.CallOption) (*GetAggregationProofResponse, error)
	// Get aggregation proofs by epoch
	GetAggregationProofsByEpoch(ctx context.Context, in *GetAggregationProofsByEpochRequest, opts ...grpc.CallOption) (*GetAggregationProofsByEpochResponse, error)
	// Get current epoch
	GetCurrentEpoch(ctx context.Context, in *GetCurrentEpochRequest, opts ...grpc.CallOption) (*GetCurrentEpochResponse, error)
	// Get signature by request id
	GetSignatures(ctx context.Context, in *GetSignaturesRequest, opts ...grpc.CallOption) (*GetSignaturesResponse, error)
	// Get signature by epoch
	GetSignaturesByEpoch(ctx context.Context, in *GetSignaturesByEpochRequest, opts ...grpc.CallOption) (*GetSignaturesByEpochResponse, error)
	// Get all signature request IDs by epoch
	GetSignatureRequestIDsByEpoch(ctx context.Context, in *GetSignatureRequestIDsByEpochRequest, opts ...grpc.CallOption) (*GetSignatureRequestIDsByEpochResponse, error)
	// Get all signature requests by epoch
	GetSignatureRequestsByEpoch(ctx context.Context, in *GetSignatureRequestsByEpochRequest, opts ...grpc.CallOption) (*GetSignatureRequestsByEpochResponse, error)
	// Get signature request by request id
	GetSignatureRequest(ctx context.Context, in *GetSignatureRequestRequest, opts ...grpc.CallOption) (*GetSignatureRequestResponse, error)
	// Get aggregation status, can be sent only to aggregator nodes
	GetAggregationStatus(ctx context.Context, in *GetAggregationStatusRequest, opts ...grpc.CallOption) (*GetAggregationStatusResponse, error)
	// Get current validator set
	GetValidatorSet(ctx context.Context, in *GetValidatorSetRequest, opts ...grpc.CallOption) (*GetValidatorSetResponse, error)
	// Get validator by address
	GetValidatorByAddress(ctx context.Context, in *GetValidatorByAddressRequest, opts ...grpc.CallOption) (*GetValidatorByAddressResponse, error)
	// Get validator by key
	GetValidatorByKey(ctx context.Context, in *GetValidatorByKeyRequest, opts ...grpc.CallOption) (*GetValidatorByKeyResponse, error)
	// Get local validator
	GetLocalValidator(ctx context.Context, in *GetLocalValidatorRequest, opts ...grpc.CallOption) (*GetLocalValidatorResponse, error)
	// Get validator set header
	GetValidatorSetHeader(ctx context.Context, in *GetValidatorSetHeaderRequest, opts ...grpc.CallOption) (*GetValidatorSetHeaderResponse, error)
	// Get last committed epoch for a specific settlement chain
	GetLastCommitted(ctx context.Context, in *GetLastCommittedRequest, opts ...grpc.CallOption) (*GetLastCommittedResponse, error)
	// Get last committed epochs for all settlement chains
	GetLastAllCommitted(ctx context.Context, in *GetLastAllCommittedRequest, opts ...grpc.CallOption) (*GetLastAllCommittedResponse, error)
	// Get validator set metadata like extra data and request id to fetch aggregation and signature requests
	GetValidatorSetMetadata(ctx context.Context, in *GetValidatorSetMetadataRequest, opts ...grpc.CallOption) (*GetValidatorSetMetadataResponse, error)
	// Checks if the current node should be active based on a custom schedule derived from the validator set.
	// This enables external applications to use the relay's validator set for coordinating distributed tasks,
	// such as deciding which application instances should commit data on-chain or perform other coordinated actions.
	// The schedule ensures deterministic but randomized selection of active nodes at any given time.
	GetCustomScheduleNodeStatus(ctx context.Context, in *GetCustomScheduleNodeStatusRequest, opts ...grpc.CallOption) (*GetCustomScheduleNodeStatusResponse, error)
	// Stream signatures in real-time. If start_epoch is provided, sends historical data first
	ListenSignatures(ctx context.Context, in *ListenSignaturesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenSignaturesResponse], error)
	// Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first
	ListenProofs(ctx context.Context, in *ListenProofsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenProofsResponse], error)
	// Stream validator set changes in real-time. If start_epoch is provided, sends historical data first
	ListenValidatorSet(ctx context.Context, in *ListenValidatorSetRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenValidatorSetResponse], error)
}
⋮----
// Sign a message
⋮----
// Get aggregation proof
⋮----
// Get aggregation proofs by epoch
⋮----
// Get current epoch
⋮----
// Get signature by request id
⋮----
// Get signature by epoch
⋮----
// Get all signature request IDs by epoch
⋮----
// Get all signature requests by epoch
⋮----
// Get signature request by request id
⋮----
// Get aggregation status, can be sent only to aggregator nodes
⋮----
// Get current validator set
⋮----
// Get validator by address
⋮----
// Get validator by key
⋮----
// Get local validator
⋮----
// Get validator set header
⋮----
// Get last committed epoch for a specific settlement chain
⋮----
// Get last committed epochs for all settlement chains
⋮----
// Get validator set metadata like extra data and request id to fetch aggregation and signature requests
⋮----
// Checks if the current node should be active based on a custom schedule derived from the validator set.
// This enables external applications to use the relay's validator set for coordinating distributed tasks,
// such as deciding which application instances should commit data on-chain or perform other coordinated actions.
// The schedule ensures deterministic but randomized selection of active nodes at any given time.
⋮----
// Stream signatures in real-time. If start_epoch is provided, sends historical data first
⋮----
// Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first
⋮----
// Stream validator set changes in real-time. If start_epoch is provided, sends historical data first
⋮----
type symbioticAPIServiceClient struct {
	cc grpc.ClientConnInterface
}
⋮----
func NewSymbioticAPIServiceClient(cc grpc.ClientConnInterface) SymbioticAPIServiceClient
⋮----
func (c *symbioticAPIServiceClient) SignMessage(ctx context.Context, in *SignMessageRequest, opts ...grpc.CallOption) (*SignMessageResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetAggregationProof(ctx context.Context, in *GetAggregationProofRequest, opts ...grpc.CallOption) (*GetAggregationProofResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetAggregationProofsByEpoch(ctx context.Context, in *GetAggregationProofsByEpochRequest, opts ...grpc.CallOption) (*GetAggregationProofsByEpochResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetCurrentEpoch(ctx context.Context, in *GetCurrentEpochRequest, opts ...grpc.CallOption) (*GetCurrentEpochResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetSignatures(ctx context.Context, in *GetSignaturesRequest, opts ...grpc.CallOption) (*GetSignaturesResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetSignaturesByEpoch(ctx context.Context, in *GetSignaturesByEpochRequest, opts ...grpc.CallOption) (*GetSignaturesByEpochResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetSignatureRequestIDsByEpoch(ctx context.Context, in *GetSignatureRequestIDsByEpochRequest, opts ...grpc.CallOption) (*GetSignatureRequestIDsByEpochResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetSignatureRequestsByEpoch(ctx context.Context, in *GetSignatureRequestsByEpochRequest, opts ...grpc.CallOption) (*GetSignatureRequestsByEpochResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetSignatureRequest(ctx context.Context, in *GetSignatureRequestRequest, opts ...grpc.CallOption) (*GetSignatureRequestResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetAggregationStatus(ctx context.Context, in *GetAggregationStatusRequest, opts ...grpc.CallOption) (*GetAggregationStatusResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetValidatorSet(ctx context.Context, in *GetValidatorSetRequest, opts ...grpc.CallOption) (*GetValidatorSetResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetValidatorByAddress(ctx context.Context, in *GetValidatorByAddressRequest, opts ...grpc.CallOption) (*GetValidatorByAddressResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetValidatorByKey(ctx context.Context, in *GetValidatorByKeyRequest, opts ...grpc.CallOption) (*GetValidatorByKeyResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetLocalValidator(ctx context.Context, in *GetLocalValidatorRequest, opts ...grpc.CallOption) (*GetLocalValidatorResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetValidatorSetHeader(ctx context.Context, in *GetValidatorSetHeaderRequest, opts ...grpc.CallOption) (*GetValidatorSetHeaderResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetLastCommitted(ctx context.Context, in *GetLastCommittedRequest, opts ...grpc.CallOption) (*GetLastCommittedResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetLastAllCommitted(ctx context.Context, in *GetLastAllCommittedRequest, opts ...grpc.CallOption) (*GetLastAllCommittedResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetValidatorSetMetadata(ctx context.Context, in *GetValidatorSetMetadataRequest, opts ...grpc.CallOption) (*GetValidatorSetMetadataResponse, error)
⋮----
func (c *symbioticAPIServiceClient) GetCustomScheduleNodeStatus(ctx context.Context, in *GetCustomScheduleNodeStatusRequest, opts ...grpc.CallOption) (*GetCustomScheduleNodeStatusResponse, error)
⋮----
func (c *symbioticAPIServiceClient) ListenSignatures(ctx context.Context, in *ListenSignaturesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenSignaturesResponse], error)
⋮----
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
⋮----
func (c *symbioticAPIServiceClient) ListenProofs(ctx context.Context, in *ListenProofsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenProofsResponse], error)
⋮----
func (c *symbioticAPIServiceClient) ListenValidatorSet(ctx context.Context, in *ListenValidatorSetRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ListenValidatorSetResponse], error)
⋮----
// SymbioticAPIServiceServer is the server API for SymbioticAPIService service.
// All implementations must embed UnimplementedSymbioticAPIServiceServer
// for forward compatibility.
⋮----
type SymbioticAPIServiceServer interface {
	// Sign a message
	SignMessage(context.Context, *SignMessageRequest) (*SignMessageResponse, error)
	// Get aggregation proof
	GetAggregationProof(context.Context, *GetAggregationProofRequest) (*GetAggregationProofResponse, error)
	// Get aggregation proofs by epoch
	GetAggregationProofsByEpoch(context.Context, *GetAggregationProofsByEpochRequest) (*GetAggregationProofsByEpochResponse, error)
	// Get current epoch
	GetCurrentEpoch(context.Context, *GetCurrentEpochRequest) (*GetCurrentEpochResponse, error)
	// Get signature by request id
	GetSignatures(context.Context, *GetSignaturesRequest) (*GetSignaturesResponse, error)
	// Get signature by epoch
	GetSignaturesByEpoch(context.Context, *GetSignaturesByEpochRequest) (*GetSignaturesByEpochResponse, error)
	// Get all signature request IDs by epoch
	GetSignatureRequestIDsByEpoch(context.Context, *GetSignatureRequestIDsByEpochRequest) (*GetSignatureRequestIDsByEpochResponse, error)
	// Get all signature requests by epoch
	GetSignatureRequestsByEpoch(context.Context, *GetSignatureRequestsByEpochRequest) (*GetSignatureRequestsByEpochResponse, error)
	// Get signature request by request id
	GetSignatureRequest(context.Context, *GetSignatureRequestRequest) (*GetSignatureRequestResponse, error)
	// Get aggregation status, can be sent only to aggregator nodes
	GetAggregationStatus(context.Context, *GetAggregationStatusRequest) (*GetAggregationStatusResponse, error)
	// Get current validator set
	GetValidatorSet(context.Context, *GetValidatorSetRequest) (*GetValidatorSetResponse, error)
	// Get validator by address
	GetValidatorByAddress(context.Context, *GetValidatorByAddressRequest) (*GetValidatorByAddressResponse, error)
	// Get validator by key
	GetValidatorByKey(context.Context, *GetValidatorByKeyRequest) (*GetValidatorByKeyResponse, error)
	// Get local validator
	GetLocalValidator(context.Context, *GetLocalValidatorRequest) (*GetLocalValidatorResponse, error)
	// Get validator set header
	GetValidatorSetHeader(context.Context, *GetValidatorSetHeaderRequest) (*GetValidatorSetHeaderResponse, error)
	// Get last committed epoch for a specific settlement chain
	GetLastCommitted(context.Context, *GetLastCommittedRequest) (*GetLastCommittedResponse, error)
	// Get last committed epochs for all settlement chains
	GetLastAllCommitted(context.Context, *GetLastAllCommittedRequest) (*GetLastAllCommittedResponse, error)
	// Get validator set metadata like extra data and request id to fetch aggregation and signature requests
	GetValidatorSetMetadata(context.Context, *GetValidatorSetMetadataRequest) (*GetValidatorSetMetadataResponse, error)
	// Checks if the current node should be active based on a custom schedule derived from the validator set.
	// This enables external applications to use the relay's validator set for coordinating distributed tasks,
	// such as deciding which application instances should commit data on-chain or perform other coordinated actions.
	// The schedule ensures deterministic but randomized selection of active nodes at any given time.
	GetCustomScheduleNodeStatus(context.Context, *GetCustomScheduleNodeStatusRequest) (*GetCustomScheduleNodeStatusResponse, error)
	// Stream signatures in real-time. If start_epoch is provided, sends historical data first
	ListenSignatures(*ListenSignaturesRequest, grpc.ServerStreamingServer[ListenSignaturesResponse]) error
	// Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first
	ListenProofs(*ListenProofsRequest, grpc.ServerStreamingServer[ListenProofsResponse]) error
	// Stream validator set changes in real-time. If start_epoch is provided, sends historical data first
	ListenValidatorSet(*ListenValidatorSetRequest, grpc.ServerStreamingServer[ListenValidatorSetResponse]) error
	mustEmbedUnimplementedSymbioticAPIServiceServer()
}
⋮----
// UnimplementedSymbioticAPIServiceServer must be embedded to have
// forward compatible implementations.
⋮----
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedSymbioticAPIServiceServer struct{}
⋮----
func (UnimplementedSymbioticAPIServiceServer) mustEmbedUnimplementedSymbioticAPIServiceServer()
func (UnimplementedSymbioticAPIServiceServer) testEmbeddedByValue()
⋮----
// UnsafeSymbioticAPIServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SymbioticAPIServiceServer will
// result in compilation errors.
type UnsafeSymbioticAPIServiceServer interface {
	mustEmbedUnimplementedSymbioticAPIServiceServer()
}
⋮----
func RegisterSymbioticAPIServiceServer(s grpc.ServiceRegistrar, srv SymbioticAPIServiceServer)
⋮----
// If the following call pancis, it indicates UnimplementedSymbioticAPIServiceServer was
// embedded by pointer and is nil.  This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
⋮----
func _SymbioticAPIService_SignMessage_Handler(srv interface
⋮----
func _SymbioticAPIService_GetAggregationProof_Handler(srv interface
⋮----
func _SymbioticAPIService_GetAggregationProofsByEpoch_Handler(srv interface
⋮----
func _SymbioticAPIService_GetCurrentEpoch_Handler(srv interface
⋮----
func _SymbioticAPIService_GetSignatures_Handler(srv interface
⋮----
func _SymbioticAPIService_GetSignaturesByEpoch_Handler(srv interface
⋮----
func _SymbioticAPIService_GetSignatureRequestIDsByEpoch_Handler(srv interface
⋮----
func _SymbioticAPIService_GetSignatureRequestsByEpoch_Handler(srv interface
⋮----
func _SymbioticAPIService_GetSignatureRequest_Handler(srv interface
⋮----
func _SymbioticAPIService_GetAggregationStatus_Handler(srv interface
⋮----
func _SymbioticAPIService_GetValidatorSet_Handler(srv interface
⋮----
func _SymbioticAPIService_GetValidatorByAddress_Handler(srv interface
⋮----
func _SymbioticAPIService_GetValidatorByKey_Handler(srv interface
⋮----
func _SymbioticAPIService_GetLocalValidator_Handler(srv interface
⋮----
func _SymbioticAPIService_GetValidatorSetHeader_Handler(srv interface
⋮----
func _SymbioticAPIService_GetLastCommitted_Handler(srv interface
⋮----
func _SymbioticAPIService_GetLastAllCommitted_Handler(srv interface
⋮----
func _SymbioticAPIService_GetValidatorSetMetadata_Handler(srv interface
⋮----
func _SymbioticAPIService_GetCustomScheduleNodeStatus_Handler(srv interface
⋮----
func _SymbioticAPIService_ListenSignatures_Handler(srv interface
⋮----
func _SymbioticAPIService_ListenProofs_Handler(srv interface
⋮----
func _SymbioticAPIService_ListenValidatorSet_Handler(srv interface
⋮----
// SymbioticAPIService_ServiceDesc is the grpc.ServiceDesc for SymbioticAPIService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var SymbioticAPIService_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "api.proto.v1.SymbioticAPIService",
	HandlerType: (*SymbioticAPIServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "SignMessage",
			Handler:    _SymbioticAPIService_SignMessage_Handler,
		},
		{
			MethodName: "GetAggregationProof",
			Handler:    _SymbioticAPIService_GetAggregationProof_Handler,
		},
		{
			MethodName: "GetAggregationProofsByEpoch",
			Handler:    _SymbioticAPIService_GetAggregationProofsByEpoch_Handler,
		},
		{
			MethodName: "GetCurrentEpoch",
			Handler:    _SymbioticAPIService_GetCurrentEpoch_Handler,
		},
		{
			MethodName: "GetSignatures",
			Handler:    _SymbioticAPIService_GetSignatures_Handler,
		},
		{
			MethodName: "GetSignaturesByEpoch",
			Handler:    _SymbioticAPIService_GetSignaturesByEpoch_Handler,
		},
		{
			MethodName: "GetSignatureRequestIDsByEpoch",
			Handler:    _SymbioticAPIService_GetSignatureRequestIDsByEpoch_Handler,
		},
		{
			MethodName: "GetSignatureRequestsByEpoch",
			Handler:    _SymbioticAPIService_GetSignatureRequestsByEpoch_Handler,
		},
		{
			MethodName: "GetSignatureRequest",
			Handler:    _SymbioticAPIService_GetSignatureRequest_Handler,
		},
		{
			MethodName: "GetAggregationStatus",
			Handler:    _SymbioticAPIService_GetAggregationStatus_Handler,
		},
		{
			MethodName: "GetValidatorSet",
			Handler:    _SymbioticAPIService_GetValidatorSet_Handler,
		},
		{
			MethodName: "GetValidatorByAddress",
			Handler:    _SymbioticAPIService_GetValidatorByAddress_Handler,
		},
		{
			MethodName: "GetValidatorByKey",
			Handler:    _SymbioticAPIService_GetValidatorByKey_Handler,
		},
		{
			MethodName: "GetLocalValidator",
			Handler:    _SymbioticAPIService_GetLocalValidator_Handler,
		},
		{
			MethodName: "GetValidatorSetHeader",
			Handler:    _SymbioticAPIService_GetValidatorSetHeader_Handler,
		},
		{
			MethodName: "GetLastCommitted",
			Handler:    _SymbioticAPIService_GetLastCommitted_Handler,
		},
		{
			MethodName: "GetLastAllCommitted",
			Handler:    _SymbioticAPIService_GetLastAllCommitted_Handler,
		},
		{
			MethodName: "GetValidatorSetMetadata",
			Handler:    _SymbioticAPIService_GetValidatorSetMetadata_Handler,
		},
		{
			MethodName: "GetCustomScheduleNodeStatus",
			Handler:    _SymbioticAPIService_GetCustomScheduleNodeStatus_Handler,
		},
	},
	Streams: []grpc.StreamDesc{
		{
			StreamName:    "ListenSignatures",
			Handler:       _SymbioticAPIService_ListenSignatures_Handler,
			ServerStreams: true,
		},
		{
			StreamName:    "ListenProofs",
			Handler:       _SymbioticAPIService_ListenProofs_Handler,
			ServerStreams: true,
		},
		{
			StreamName:    "ListenValidatorSet",
			Handler:       _SymbioticAPIService_ListenValidatorSet_Handler,
			ServerStreams: true,
		},
	},
	Metadata: "v1/api.proto",
}
```

## File: internal/gen/api/v1/api.pb.go

```go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.36.6
// 	protoc        (unknown)
// source: v1/api.proto
⋮----
package v1
⋮----
import (
	_ "google.golang.org/genproto/googleapis/api/annotations"
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
	reflect "reflect"
	sync "sync"
	unsafe "unsafe"
)
⋮----
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
⋮----
const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
⋮----
// Verify that this generated code is sufficiently up-to-date.
⋮----
// Verify that runtime/protoimpl is sufficiently up-to-date.
⋮----
// Validator set status enumeration
type ValidatorSetStatus int32
⋮----
const (
	// Default/unknown status
	ValidatorSetStatus_VALIDATOR_SET_STATUS_UNSPECIFIED ValidatorSetStatus = 0
	// Derived status
	ValidatorSetStatus_VALIDATOR_SET_STATUS_DERIVED ValidatorSetStatus = 1
	// Aggregated status
	ValidatorSetStatus_VALIDATOR_SET_STATUS_AGGREGATED ValidatorSetStatus = 2
	// Committed status
	ValidatorSetStatus_VALIDATOR_SET_STATUS_COMMITTED ValidatorSetStatus = 3
)
⋮----
// Default/unknown status
⋮----
// Derived status
⋮----
// Aggregated status
⋮----
// Committed status
⋮----
// Enum value maps for ValidatorSetStatus.
var (
	ValidatorSetStatus_name = map[int32]string{
		0: "VALIDATOR_SET_STATUS_UNSPECIFIED",
		1: "VALIDATOR_SET_STATUS_DERIVED",
		2: "VALIDATOR_SET_STATUS_AGGREGATED",
		3: "VALIDATOR_SET_STATUS_COMMITTED",
	}
	ValidatorSetStatus_value = map[string]int32{
		"VALIDATOR_SET_STATUS_UNSPECIFIED": 0,
		"VALIDATOR_SET_STATUS_DERIVED":     1,
		"VALIDATOR_SET_STATUS_AGGREGATED":  2,
		"VALIDATOR_SET_STATUS_COMMITTED":   3,
	}
)
⋮----
func (x ValidatorSetStatus) Enum() *ValidatorSetStatus
⋮----
func (x ValidatorSetStatus) String() string
⋮----
func (ValidatorSetStatus) Descriptor() protoreflect.EnumDescriptor
⋮----
func (ValidatorSetStatus) Type() protoreflect.EnumType
⋮----
func (x ValidatorSetStatus) Number() protoreflect.EnumNumber
⋮----
// Deprecated: Use ValidatorSetStatus.Descriptor instead.
func (ValidatorSetStatus) EnumDescriptor() ([]byte, []int)
⋮----
// Signing process status enumeration
type SigningStatus int32
⋮----
const (
	// Default/unknown status
	SigningStatus_SIGNING_STATUS_UNSPECIFIED SigningStatus = 0
	// Request has been created and is waiting for signatures
	SigningStatus_SIGNING_STATUS_PENDING SigningStatus = 1
	// Signing process completed successfully with proof
	SigningStatus_SIGNING_STATUS_COMPLETED SigningStatus = 2
	// Signing process failed
	SigningStatus_SIGNING_STATUS_FAILED SigningStatus = 3
	// Signing request timed out
	SigningStatus_SIGNING_STATUS_TIMEOUT SigningStatus = 4
)
⋮----
// Request has been created and is waiting for signatures
⋮----
// Signing process completed successfully with proof
⋮----
// Signing process failed
⋮----
// Signing request timed out
⋮----
// Enum value maps for SigningStatus.
var (
	SigningStatus_name = map[int32]string{
		0: "SIGNING_STATUS_UNSPECIFIED",
		1: "SIGNING_STATUS_PENDING",
		2: "SIGNING_STATUS_COMPLETED",
		3: "SIGNING_STATUS_FAILED",
		4: "SIGNING_STATUS_TIMEOUT",
	}
	SigningStatus_value = map[string]int32{
		"SIGNING_STATUS_UNSPECIFIED": 0,
		"SIGNING_STATUS_PENDING":     1,
		"SIGNING_STATUS_COMPLETED":   2,
		"SIGNING_STATUS_FAILED":      3,
		"SIGNING_STATUS_TIMEOUT":     4,
	}
)
⋮----
// Deprecated: Use SigningStatus.Descriptor instead.
⋮----
// Error code enumeration
type ErrorCode int32
⋮----
const (
	// Default/unknown error
	ErrorCode_ERROR_CODE_UNSPECIFIED ErrorCode = 0
	// No data found
	ErrorCode_ERROR_CODE_NO_DATA ErrorCode = 1
	// Internal server error
	ErrorCode_ERROR_CODE_INTERNAL ErrorCode = 2
	// Not an aggregator node
	ErrorCode_ERROR_CODE_NOT_AGGREGATOR ErrorCode = 3
)
⋮----
// Default/unknown error
⋮----
// No data found
⋮----
// Internal server error
⋮----
// Not an aggregator node
⋮----
// Enum value maps for ErrorCode.
var (
	ErrorCode_name = map[int32]string{
		0: "ERROR_CODE_UNSPECIFIED",
		1: "ERROR_CODE_NO_DATA",
		2: "ERROR_CODE_INTERNAL",
		3: "ERROR_CODE_NOT_AGGREGATOR",
	}
	ErrorCode_value = map[string]int32{
		"ERROR_CODE_UNSPECIFIED":    0,
		"ERROR_CODE_NO_DATA":        1,
		"ERROR_CODE_INTERNAL":       2,
		"ERROR_CODE_NOT_AGGREGATOR": 3,
	}
)
⋮----
// Deprecated: Use ErrorCode.Descriptor instead.
⋮----
// Request to check if the current node should be active in a custom schedule.
// The validator set is divided into groups that rotate through time slots.
// Use this to coordinate distributed tasks among multiple application instances.
type GetCustomScheduleNodeStatusRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number to use for the validator set (optional, defaults to current epoch)
	Epoch *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	// Custom seed for randomizing the schedule (optional). Different seeds produce different schedules
	// for the same epoch, allowing multiple independent scheduling schemes. If not provided, the schedule
	// is deterministic based on epoch alone.
	Seed []byte `protobuf:"bytes,2,opt,name=seed,proto3,oneof" json:"seed,omitempty"`
	// Duration of each time slot in seconds. Determines how frequently active groups rotate.
	// Example: 60 seconds means a new group becomes active every minute.
	SlotDurationSeconds uint64 `protobuf:"varint,3,opt,name=slot_duration_seconds,json=slotDurationSeconds,proto3" json:"slot_duration_seconds,omitempty"`
	// Maximum validators per group. Controls redundancy: 1 for single-instance actions (less redundancy),
	// 2+ for multi-instance actions (more reliability). All validators in a group are active simultaneously.
	MaxParticipantsPerSlot uint32 `protobuf:"varint,4,opt,name=max_participants_per_slot,json=maxParticipantsPerSlot,proto3" json:"max_participants_per_slot,omitempty"`
	// Minimum validators required to form a remainder group. When dividing validators into groups,
	// any remainder smaller than this is not scheduled. Set equal to max for strict group sizes.
	MinParticipantsPerSlot uint32 `protobuf:"varint,5,opt,name=min_participants_per_slot,json=minParticipantsPerSlot,proto3" json:"min_participants_per_slot,omitempty"`
	unknownFields          protoimpl.UnknownFields
	sizeCache              protoimpl.SizeCache
}
⋮----
// Epoch number to use for the validator set (optional, defaults to current epoch)
⋮----
// Custom seed for randomizing the schedule (optional). Different seeds produce different schedules
// for the same epoch, allowing multiple independent scheduling schemes. If not provided, the schedule
// is deterministic based on epoch alone.
⋮----
// Duration of each time slot in seconds. Determines how frequently active groups rotate.
// Example: 60 seconds means a new group becomes active every minute.
⋮----
// Maximum validators per group. Controls redundancy: 1 for single-instance actions (less redundancy),
// 2+ for multi-instance actions (more reliability). All validators in a group are active simultaneously.
⋮----
// Minimum validators required to form a remainder group. When dividing validators into groups,
// any remainder smaller than this is not scheduled. Set equal to max for strict group sizes.
⋮----
func (x *GetCustomScheduleNodeStatusRequest) Reset()
⋮----
func (*GetCustomScheduleNodeStatusRequest) ProtoMessage()
⋮----
func (x *GetCustomScheduleNodeStatusRequest) ProtoReflect() protoreflect.Message
⋮----
// Deprecated: Use GetCustomScheduleNodeStatusRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *GetCustomScheduleNodeStatusRequest) GetEpoch() uint64
⋮----
func (x *GetCustomScheduleNodeStatusRequest) GetSeed() []byte
⋮----
func (x *GetCustomScheduleNodeStatusRequest) GetSlotDurationSeconds() uint64
⋮----
func (x *GetCustomScheduleNodeStatusRequest) GetMaxParticipantsPerSlot() uint32
⋮----
func (x *GetCustomScheduleNodeStatusRequest) GetMinParticipantsPerSlot() uint32
⋮----
// Response indicating whether the current node should be active now.
type GetCustomScheduleNodeStatusResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// True if this node is active in the current time slot and should perform the scheduled action.
	// False if this node should wait (another group is active). When multiple validators share a slot,
	// all return true simultaneously, enabling coordinated redundancy.
	IsActive bool `protobuf:"varint,1,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
	// Start time of the current active slot. This marks the beginning of the current slot time window.
	// Can be used to determine how much time is left in the slot.
	CurrentSlotStartTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=current_slot_start_time,json=currentSlotStartTime,proto3" json:"current_slot_start_time,omitempty"`
	// End time of the current active slot. This marks the end of the current slot time window.
	// Can be used to determine how much time is left in the slot.
	CurrentSlotEndTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=current_slot_end_time,json=currentSlotEndTime,proto3" json:"current_slot_end_time,omitempty"`
	unknownFields      protoimpl.UnknownFields
	sizeCache          protoimpl.SizeCache
}
⋮----
// True if this node is active in the current time slot and should perform the scheduled action.
// False if this node should wait (another group is active). When multiple validators share a slot,
// all return true simultaneously, enabling coordinated redundancy.
⋮----
// Start time of the current active slot. This marks the beginning of the current slot time window.
// Can be used to determine how much time is left in the slot.
⋮----
// End time of the current active slot. This marks the end of the current slot time window.
⋮----
// Deprecated: Use GetCustomScheduleNodeStatusResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetCustomScheduleNodeStatusResponse) GetIsActive() bool
⋮----
func (x *GetCustomScheduleNodeStatusResponse) GetCurrentSlotStartTime() *timestamppb.Timestamp
⋮----
func (x *GetCustomScheduleNodeStatusResponse) GetCurrentSlotEndTime() *timestamppb.Timestamp
⋮----
// Request message for signing a message
type SignMessageRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Key tag identifier (0-127)
	KeyTag uint32 `protobuf:"varint,1,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	// Message to be signed
	Message []byte `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
	// Required epoch (optional, if not provided latest committed epoch will be used)
	RequiredEpoch *uint64 `protobuf:"varint,3,opt,name=required_epoch,json=requiredEpoch,proto3,oneof" json:"required_epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Key tag identifier (0-127)
⋮----
// Message to be signed
⋮----
// Required epoch (optional, if not provided latest committed epoch will be used)
⋮----
// Deprecated: Use SignMessageRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *SignMessageRequest) GetKeyTag() uint32
⋮----
func (x *SignMessageRequest) GetMessage() []byte
⋮----
func (x *SignMessageRequest) GetRequiredEpoch() uint64
⋮----
// Response message for sign message request
type SignMessageResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Hash of the signature request
	RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	// Epoch number
	Epoch         uint64 `protobuf:"varint,2,opt,name=epoch,proto3" json:"epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Hash of the signature request
⋮----
// Epoch number
⋮----
// Deprecated: Use SignMessageResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *SignMessageResponse) GetRequestId() string
⋮----
// Request message for listening to signatures stream
type ListenSignaturesRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates
	// If not provided, only signatures generated after stream creation will be sent
	StartEpoch    *uint64 `protobuf:"varint,1,opt,name=start_epoch,json=startEpoch,proto3,oneof" json:"start_epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates
// If not provided, only signatures generated after stream creation will be sent
⋮----
// Deprecated: Use ListenSignaturesRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *ListenSignaturesRequest) GetStartEpoch() uint64
⋮----
// Response message for signatures stream
type ListenSignaturesResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Id of the signature request
	RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,2,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Signature data
	Signature     *Signature `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Id of the signature request
⋮----
// Signature data
⋮----
// Deprecated: Use ListenSignaturesResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *ListenSignaturesResponse) GetSignature() *Signature
⋮----
// Request message for listening to aggregation proofs stream
type ListenProofsRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates
	// If not provided, only proofs generated after stream creation will be sent
	StartEpoch    *uint64 `protobuf:"varint,1,opt,name=start_epoch,json=startEpoch,proto3,oneof" json:"start_epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates
// If not provided, only proofs generated after stream creation will be sent
⋮----
// Deprecated: Use ListenProofsRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for aggregation proofs stream
type ListenProofsResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Id of the request
	RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,2,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Final aggregation proof
	AggregationProof *AggregationProof `protobuf:"bytes,3,opt,name=aggregation_proof,json=aggregationProof,proto3" json:"aggregation_proof,omitempty"`
	unknownFields    protoimpl.UnknownFields
	sizeCache        protoimpl.SizeCache
}
⋮----
// Id of the request
⋮----
// Final aggregation proof
⋮----
// Deprecated: Use ListenProofsResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *ListenProofsResponse) GetAggregationProof() *AggregationProof
⋮----
// Request message for listening to validator set changes stream
type ListenValidatorSetRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates
	// If not provided, only validator sets generated after stream creation will be sent
	StartEpoch    *uint64 `protobuf:"varint,1,opt,name=start_epoch,json=startEpoch,proto3,oneof" json:"start_epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates
// If not provided, only validator sets generated after stream creation will be sent
⋮----
// Deprecated: Use ListenValidatorSetRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for validator set changes stream
type ListenValidatorSetResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// The validator set
	ValidatorSet  *ValidatorSet `protobuf:"bytes,1,opt,name=validator_set,json=validatorSet,proto3" json:"validator_set,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// The validator set
⋮----
// Deprecated: Use ListenValidatorSetResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *ListenValidatorSetResponse) GetValidatorSet() *ValidatorSet
⋮----
// Request message for getting aggregation proof
type GetAggregationProofRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	RequestId     string                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetAggregationProofRequest.ProtoReflect.Descriptor instead.
⋮----
type GetAggregationProofsByEpochRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
	PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	// Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
	From          string `protobuf:"bytes,3,opt,name=from,proto3" json:"from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
⋮----
// Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
⋮----
// Deprecated: Use GetAggregationProofsByEpochRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *GetAggregationProofsByEpochRequest) GetPageSize() uint32
⋮----
func (x *GetAggregationProofsByEpochRequest) GetFrom() string
⋮----
// Request message for getting current epoch
type GetCurrentEpochRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetCurrentEpochRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting signatures
type GetSignaturesRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	RequestId     string                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetSignaturesRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting signatures by epoch
type GetSignaturesByEpochRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
	PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	// Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
	From          string `protobuf:"bytes,3,opt,name=from,proto3" json:"from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetSignaturesByEpochRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting signatures
type GetSignaturesResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of signatures
	Signatures    []*Signature `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// List of signatures
⋮----
// Deprecated: Use GetSignaturesResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetSignaturesResponse) GetSignatures() []*Signature
⋮----
// Response message for getting signatures by epoch
type GetSignaturesByEpochResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of signatures
	Signatures []*Signature `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"`
	// Cursor to retrieve the next page. Empty when this is the last page.
	NextFrom      string `protobuf:"bytes,2,opt,name=next_from,json=nextFrom,proto3" json:"next_from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Cursor to retrieve the next page. Empty when this is the last page.
⋮----
// Deprecated: Use GetSignaturesByEpochResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetSignaturesByEpochResponse) GetNextFrom() string
⋮----
// Request message for getting all signature request IDs by epoch
type GetSignatureRequestIDsByEpochRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Maximum number of items to return. 0 = server default (1000). Server clamps to max (10000).
	PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	// Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
	From          string `protobuf:"bytes,3,opt,name=from,proto3" json:"from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Maximum number of items to return. 0 = server default (1000). Server clamps to max (10000).
⋮----
// Deprecated: Use GetSignatureRequestIDsByEpochRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting all signature request IDs by epoch
type GetSignatureRequestIDsByEpochResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of all signature request IDs for the epoch
	RequestIds []string `protobuf:"bytes,1,rep,name=request_ids,json=requestIds,proto3" json:"request_ids,omitempty"`
	// Cursor to retrieve the next page. Empty when this is the last page.
	NextFrom      string `protobuf:"bytes,2,opt,name=next_from,json=nextFrom,proto3" json:"next_from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// List of all signature request IDs for the epoch
⋮----
// Deprecated: Use GetSignatureRequestIDsByEpochResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetSignatureRequestIDsByEpochResponse) GetRequestIds() []string
⋮----
// Request message for getting all signature requests by epoch
type GetSignatureRequestsByEpochRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Maximum number of items to return. 0 = server default (100). Server clamps to max (1000).
	PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	// Opaque pagination cursor from a previous response's `next_from`. Empty string starts from the beginning.
	From          string `protobuf:"bytes,3,opt,name=from,proto3" json:"from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetSignatureRequestsByEpochRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting all signature requests by epoch
type GetSignatureRequestsByEpochResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of all signature requests for the epoch
	SignatureRequests []*SignatureRequest `protobuf:"bytes,1,rep,name=signature_requests,json=signatureRequests,proto3" json:"signature_requests,omitempty"`
	// Cursor to retrieve the next page. Empty when this is the last page.
	NextFrom      string `protobuf:"bytes,2,opt,name=next_from,json=nextFrom,proto3" json:"next_from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// List of all signature requests for the epoch
⋮----
// Deprecated: Use GetSignatureRequestsByEpochResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetSignatureRequestsByEpochResponse) GetSignatureRequests() []*SignatureRequest
⋮----
// Request message for getting signature request
type GetSignatureRequestRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	RequestId     string                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetSignatureRequestRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting aggregation status
type GetAggregationStatusRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	RequestId     string                 `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetAggregationStatusRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting validator set
type GetValidatorSetRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch         *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Epoch number (optional, if not provided current epoch will be used)
⋮----
// Deprecated: Use GetValidatorSetRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting validator by address
type GetValidatorByAddressRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	// Validator address (required)
	Address       string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Validator address (required)
⋮----
// Deprecated: Use GetValidatorByAddressRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *GetValidatorByAddressRequest) GetAddress() string
⋮----
// Request message for getting validator by key
type GetValidatorByKeyRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	// Validator key tag (required)
	KeyTag uint32 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	// Validator on chain (public) key (required)
	OnChainKey    []byte `protobuf:"bytes,3,opt,name=on_chain_key,json=onChainKey,proto3" json:"on_chain_key,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Validator key tag (required)
⋮----
// Validator on chain (public) key (required)
⋮----
// Deprecated: Use GetValidatorByKeyRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *GetValidatorByKeyRequest) GetOnChainKey() []byte
⋮----
// Request message for getting local validator
type GetLocalValidatorRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch         *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetLocalValidatorRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting validator set header
type GetValidatorSetHeaderRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch         *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetValidatorSetHeaderRequest.ProtoReflect.Descriptor instead.
⋮----
// Request message for getting validator set metadata
type GetValidatorSetMetadataRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number (optional, if not provided current epoch will be used)
	Epoch         *uint64 `protobuf:"varint,1,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetValidatorSetMetadataRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting current epoch
type GetCurrentEpochResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Epoch number
	Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Epoch start time
	StartTime     *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Epoch start time
⋮----
// Deprecated: Use GetCurrentEpochResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetCurrentEpochResponse) GetStartTime() *timestamppb.Timestamp
⋮----
// SignatureRequest represents a signature request
type SignatureRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Request ID
	RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	// Key tag identifier (0-127)
	KeyTag uint32 `protobuf:"varint,2,opt,name=key_tag,json=keyTag,proto3" json:"key_tag,omitempty"`
	// Message to be signed
	Message []byte `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
	// Required epoch
	RequiredEpoch uint64 `protobuf:"varint,4,opt,name=required_epoch,json=requiredEpoch,proto3" json:"required_epoch,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Request ID
⋮----
// Required epoch
⋮----
// Deprecated: Use SignatureRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting signature request
type GetSignatureRequestResponse struct {
	state            protoimpl.MessageState `protogen:"open.v1"`
	SignatureRequest *SignatureRequest      `protobuf:"bytes,1,opt,name=signature_request,json=signatureRequest,proto3" json:"signature_request,omitempty"`
	unknownFields    protoimpl.UnknownFields
	sizeCache        protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetSignatureRequestResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetSignatureRequestResponse) GetSignatureRequest() *SignatureRequest
⋮----
// Response message for getting aggregation proof
type GetAggregationProofResponse struct {
	state            protoimpl.MessageState `protogen:"open.v1"`
	AggregationProof *AggregationProof      `protobuf:"bytes,1,opt,name=aggregation_proof,json=aggregationProof,proto3" json:"aggregation_proof,omitempty"`
	unknownFields    protoimpl.UnknownFields
	sizeCache        protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetAggregationProofResponse.ProtoReflect.Descriptor instead.
⋮----
type GetAggregationProofsByEpochResponse struct {
	state             protoimpl.MessageState `protogen:"open.v1"`
	AggregationProofs []*AggregationProof    `protobuf:"bytes,1,rep,name=aggregation_proofs,json=aggregationProofs,proto3" json:"aggregation_proofs,omitempty"`
	// Cursor to retrieve the next page. Empty when this is the last page.
	NextFrom      string `protobuf:"bytes,2,opt,name=next_from,json=nextFrom,proto3" json:"next_from,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetAggregationProofsByEpochResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetAggregationProofsByEpochResponse) GetAggregationProofs() []*AggregationProof
⋮----
type AggregationProof struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Message hash
	MessageHash []byte `protobuf:"bytes,2,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	// Proof data
	Proof []byte `protobuf:"bytes,3,opt,name=proof,proto3" json:"proof,omitempty"`
	// Request ID
	RequestId     string `protobuf:"bytes,4,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Message hash
⋮----
// Proof data
⋮----
// Deprecated: Use AggregationProof.ProtoReflect.Descriptor instead.
⋮----
func (x *AggregationProof) GetMessageHash() []byte
⋮----
func (x *AggregationProof) GetProof() []byte
⋮----
// Response message for getting aggregation status
type GetAggregationStatusResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Current voting power of the aggregator (big integer as string)
	CurrentVotingPower string `protobuf:"bytes,1,opt,name=current_voting_power,json=currentVotingPower,proto3" json:"current_voting_power,omitempty"`
	// List of operator addresses that signed the request
	SignerOperators []string `protobuf:"bytes,2,rep,name=signer_operators,json=signerOperators,proto3" json:"signer_operators,omitempty"`
	unknownFields   protoimpl.UnknownFields
	sizeCache       protoimpl.SizeCache
}
⋮----
// Current voting power of the aggregator (big integer as string)
⋮----
// List of operator addresses that signed the request
⋮----
// Deprecated: Use GetAggregationStatusResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetAggregationStatusResponse) GetCurrentVotingPower() string
⋮----
func (x *GetAggregationStatusResponse) GetSignerOperators() []string
⋮----
// Digital signature
type Signature struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Signature data
	Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
	// Message hash
	MessageHash []byte `protobuf:"bytes,2,opt,name=message_hash,json=messageHash,proto3" json:"message_hash,omitempty"`
	// Public key
	PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
	// Request ID
	RequestId     string `protobuf:"bytes,4,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Public key
⋮----
// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
⋮----
func (x *Signature) GetPublicKey() []byte
⋮----
// Response message for getting validator set
type GetValidatorSetResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// The validator set
	ValidatorSet  *ValidatorSet `protobuf:"bytes,1,opt,name=validator_set,json=validatorSet,proto3" json:"validator_set,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetValidatorSetResponse.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting validator by address
type GetValidatorByAddressResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// The validator
	Validator     *Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// The validator
⋮----
// Deprecated: Use GetValidatorByAddressResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetValidatorByAddressResponse) GetValidator() *Validator
⋮----
// Response message for getting validator by key
type GetValidatorByKeyResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// The validator
	Validator     *Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetValidatorByKeyResponse.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting local validator
type GetLocalValidatorResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// The validator
	Validator     *Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetLocalValidatorResponse.ProtoReflect.Descriptor instead.
⋮----
type ExtraData struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	Key           []byte                 `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
	Value         []byte                 `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use ExtraData.ProtoReflect.Descriptor instead.
⋮----
func (x *ExtraData) GetKey() []byte
⋮----
func (x *ExtraData) GetValue() []byte
⋮----
// Response message for getting validator set header
type GetValidatorSetMetadataResponse struct {
	state          protoimpl.MessageState `protogen:"open.v1"`
	ExtraData      []*ExtraData           `protobuf:"bytes,1,rep,name=extra_data,json=extraData,proto3" json:"extra_data,omitempty"`
	CommitmentData []byte                 `protobuf:"bytes,2,opt,name=commitment_data,json=commitmentData,proto3" json:"commitment_data,omitempty"`
	RequestId      string                 `protobuf:"bytes,3,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
	unknownFields  protoimpl.UnknownFields
	sizeCache      protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetValidatorSetMetadataResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetValidatorSetMetadataResponse) GetExtraData() []*ExtraData
⋮----
func (x *GetValidatorSetMetadataResponse) GetCommitmentData() []byte
⋮----
type GetValidatorSetHeaderResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Version of the validator set
	Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	// Key tag required to commit next validator set
	RequiredKeyTag uint32 `protobuf:"varint,2,opt,name=required_key_tag,json=requiredKeyTag,proto3" json:"required_key_tag,omitempty"`
	// Validator set epoch
	Epoch uint64 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Epoch capture timestamp
	CaptureTimestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=capture_timestamp,json=captureTimestamp,proto3" json:"capture_timestamp,omitempty"`
	// Quorum threshold (big integer as string)
	QuorumThreshold string `protobuf:"bytes,5,opt,name=quorum_threshold,json=quorumThreshold,proto3" json:"quorum_threshold,omitempty"`
	// Total voting power (big integer as string)
	TotalVotingPower string `protobuf:"bytes,6,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"`
	// Validators SSZ Merkle root (hex string)
	ValidatorsSszMroot string `protobuf:"bytes,7,opt,name=validators_ssz_mroot,json=validatorsSszMroot,proto3" json:"validators_ssz_mroot,omitempty"`
	unknownFields      protoimpl.UnknownFields
	sizeCache          protoimpl.SizeCache
}
⋮----
// Version of the validator set
⋮----
// Key tag required to commit next validator set
⋮----
// Validator set epoch
⋮----
// Epoch capture timestamp
⋮----
// Quorum threshold (big integer as string)
⋮----
// Total voting power (big integer as string)
⋮----
// Validators SSZ Merkle root (hex string)
⋮----
// Deprecated: Use GetValidatorSetHeaderResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetValidatorSetHeaderResponse) GetVersion() uint32
⋮----
func (x *GetValidatorSetHeaderResponse) GetRequiredKeyTag() uint32
⋮----
func (x *GetValidatorSetHeaderResponse) GetCaptureTimestamp() *timestamppb.Timestamp
⋮----
func (x *GetValidatorSetHeaderResponse) GetQuorumThreshold() string
⋮----
func (x *GetValidatorSetHeaderResponse) GetTotalVotingPower() string
⋮----
func (x *GetValidatorSetHeaderResponse) GetValidatorsSszMroot() string
⋮----
// Validator information
type Validator struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Operator address (hex string)
	Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"`
	// Voting power of the validator (big integer as string)
	VotingPower string `protobuf:"bytes,2,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
	// Indicates if the validator is active
	IsActive bool `protobuf:"varint,3,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
	// List of cryptographic keys
	Keys []*Key `protobuf:"bytes,4,rep,name=keys,proto3" json:"keys,omitempty"`
	// List of validator vaults
	Vaults        []*ValidatorVault `protobuf:"bytes,5,rep,name=vaults,proto3" json:"vaults,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Operator address (hex string)
⋮----
// Voting power of the validator (big integer as string)
⋮----
// Indicates if the validator is active
⋮----
// List of cryptographic keys
⋮----
// List of validator vaults
⋮----
// Deprecated: Use Validator.ProtoReflect.Descriptor instead.
⋮----
func (x *Validator) GetOperator() string
⋮----
func (x *Validator) GetVotingPower() string
⋮----
func (x *Validator) GetKeys() []*Key
⋮----
func (x *Validator) GetVaults() []*ValidatorVault
⋮----
// Cryptographic key
type Key struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Key tag identifier (0-127)
	Tag uint32 `protobuf:"varint,1,opt,name=tag,proto3" json:"tag,omitempty"`
	// Key payload
	Payload       []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Key payload
⋮----
// Deprecated: Use Key.ProtoReflect.Descriptor instead.
⋮----
func (x *Key) GetTag() uint32
⋮----
func (x *Key) GetPayload() []byte
⋮----
// Validator vault information
type ValidatorVault struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Chain identifier
	ChainId uint64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
	// Vault address
	Vault string `protobuf:"bytes,2,opt,name=vault,proto3" json:"vault,omitempty"`
	// Voting power for this vault (big integer as string)
	VotingPower   string `protobuf:"bytes,3,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Chain identifier
⋮----
// Vault address
⋮----
// Voting power for this vault (big integer as string)
⋮----
// Deprecated: Use ValidatorVault.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorVault) GetChainId() uint64
⋮----
func (x *ValidatorVault) GetVault() string
⋮----
// Request message for getting last committed epoch for a specific settlement chain
type GetLastCommittedRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Settlement chain ID
	SettlementChainId uint64 `protobuf:"varint,1,opt,name=settlement_chain_id,json=settlementChainId,proto3" json:"settlement_chain_id,omitempty"`
	unknownFields     protoimpl.UnknownFields
	sizeCache         protoimpl.SizeCache
}
⋮----
// Settlement chain ID
⋮----
// Deprecated: Use GetLastCommittedRequest.ProtoReflect.Descriptor instead.
⋮----
func (x *GetLastCommittedRequest) GetSettlementChainId() uint64
⋮----
// Response message for getting last committed epoch
type GetLastCommittedResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Settlement chain ID
	SettlementChainId uint64          `protobuf:"varint,1,opt,name=settlement_chain_id,json=settlementChainId,proto3" json:"settlement_chain_id,omitempty"`
	EpochInfo         *ChainEpochInfo `protobuf:"bytes,2,opt,name=epoch_info,json=epochInfo,proto3" json:"epoch_info,omitempty"`
	unknownFields     protoimpl.UnknownFields
	sizeCache         protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetLastCommittedResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetLastCommittedResponse) GetEpochInfo() *ChainEpochInfo
⋮----
// Request message for getting last committed epochs for all chains
type GetLastAllCommittedRequest struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetLastAllCommittedRequest.ProtoReflect.Descriptor instead.
⋮----
// Response message for getting all last committed epochs
type GetLastAllCommittedResponse struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// List of settlement chains with their last committed epochs
	EpochInfos map[uint64]*ChainEpochInfo `protobuf:"bytes,1,rep,name=epoch_infos,json=epochInfos,proto3" json:"epoch_infos,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
	// Suggested epoch info for signatures, it is the minimum commited epoch among all chains
	SuggestedEpochInfo *ChainEpochInfo `protobuf:"bytes,2,opt,name=suggested_epoch_info,json=suggestedEpochInfo,proto3" json:"suggested_epoch_info,omitempty"`
	unknownFields      protoimpl.UnknownFields
	sizeCache          protoimpl.SizeCache
}
⋮----
// List of settlement chains with their last committed epochs
⋮----
// Suggested epoch info for signatures, it is the minimum commited epoch among all chains
⋮----
// Deprecated: Use GetLastAllCommittedResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetLastAllCommittedResponse) GetEpochInfos() map[uint64]*ChainEpochInfo
⋮----
func (x *GetLastAllCommittedResponse) GetSuggestedEpochInfo() *ChainEpochInfo
⋮----
// Settlement chain with its last committed epoch
type ChainEpochInfo struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Last committed epoch for this chain
	LastCommittedEpoch uint64 `protobuf:"varint,1,opt,name=last_committed_epoch,json=lastCommittedEpoch,proto3" json:"last_committed_epoch,omitempty"`
	// Epoch start time
	StartTime     *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Last committed epoch for this chain
⋮----
// Deprecated: Use ChainEpochInfo.ProtoReflect.Descriptor instead.
⋮----
func (x *ChainEpochInfo) GetLastCommittedEpoch() uint64
⋮----
type ValidatorSet struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Version of the validator set
	Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	// Key tag required to commit next validator set
	RequiredKeyTag uint32 `protobuf:"varint,2,opt,name=required_key_tag,json=requiredKeyTag,proto3" json:"required_key_tag,omitempty"`
	// Validator set epoch
	Epoch uint64 `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Epoch capture timestamp
	CaptureTimestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=capture_timestamp,json=captureTimestamp,proto3" json:"capture_timestamp,omitempty"`
	// Quorum threshold (big integer as string)
	QuorumThreshold string `protobuf:"bytes,5,opt,name=quorum_threshold,json=quorumThreshold,proto3" json:"quorum_threshold,omitempty"`
	// Status of validator set header
	Status ValidatorSetStatus `protobuf:"varint,6,opt,name=status,proto3,enum=api.proto.v1.ValidatorSetStatus" json:"status,omitempty"`
	// List of validators
	Validators    []*Validator `protobuf:"bytes,7,rep,name=validators,proto3" json:"validators,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Status of validator set header
⋮----
// List of validators
⋮----
// Deprecated: Use ValidatorSet.ProtoReflect.Descriptor instead.
⋮----
func (x *ValidatorSet) GetStatus() ValidatorSetStatus
⋮----
func (x *ValidatorSet) GetValidators() []*Validator
⋮----
var File_v1_api_proto protoreflect.FileDescriptor
⋮----
const file_v1_api_proto_rawDesc = "" +
	"\n" +
	"\fv1/api.proto\x12\fapi.proto.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1cgoogle/api/annotations.proto\"\x95\x02\n" +
	"\"GetCustomScheduleNodeStatusRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01\x12\x17\n" +
	"\x04seed\x18\x02 \x01(\fH\x01R\x04seed\x88\x01\x01\x122\n" +
	"\x15slot_duration_seconds\x18\x03 \x01(\x04R\x13slotDurationSeconds\x129\n" +
	"\x19max_participants_per_slot\x18\x04 \x01(\rR\x16maxParticipantsPerSlot\x129\n" +
	"\x19min_participants_per_slot\x18\x05 \x01(\rR\x16minParticipantsPerSlotB\b\n" +
	"\x06_epochB\a\n" +
	"\x05_seed\"\xe4\x01\n" +
	"#GetCustomScheduleNodeStatusResponse\x12\x1b\n" +
	"\tis_active\x18\x01 \x01(\bR\bisActive\x12Q\n" +
	"\x17current_slot_start_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x14currentSlotStartTime\x12M\n" +
	"\x15current_slot_end_time\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x12currentSlotEndTime\"\x86\x01\n" +
	"\x12SignMessageRequest\x12\x17\n" +
	"\akey_tag\x18\x01 \x01(\rR\x06keyTag\x12\x18\n" +
	"\amessage\x18\x02 \x01(\fR\amessage\x12*\n" +
	"\x0erequired_epoch\x18\x03 \x01(\x04H\x00R\rrequiredEpoch\x88\x01\x01B\x11\n" +
	"\x0f_required_epoch\"J\n" +
	"\x13SignMessageResponse\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\x12\x14\n" +
	"\x05epoch\x18\x02 \x01(\x04R\x05epoch\"O\n" +
	"\x17ListenSignaturesRequest\x12$\n" +
	"\vstart_epoch\x18\x01 \x01(\x04H\x00R\n" +
	"startEpoch\x88\x01\x01B\x0e\n" +
	"\f_start_epoch\"\x86\x01\n" +
	"\x18ListenSignaturesResponse\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\x12\x14\n" +
	"\x05epoch\x18\x02 \x01(\x04R\x05epoch\x125\n" +
	"\tsignature\x18\x03 \x01(\v2\x17.api.proto.v1.SignatureR\tsignature\"K\n" +
	"\x13ListenProofsRequest\x12$\n" +
	"\vstart_epoch\x18\x01 \x01(\x04H\x00R\n" +
	"startEpoch\x88\x01\x01B\x0e\n" +
	"\f_start_epoch\"\x98\x01\n" +
	"\x14ListenProofsResponse\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\x12\x14\n" +
	"\x05epoch\x18\x02 \x01(\x04R\x05epoch\x12K\n" +
	"\x11aggregation_proof\x18\x03 \x01(\v2\x1e.api.proto.v1.AggregationProofR\x10aggregationProof\"Q\n" +
	"\x19ListenValidatorSetRequest\x12$\n" +
	"\vstart_epoch\x18\x01 \x01(\x04H\x00R\n" +
	"startEpoch\x88\x01\x01B\x0e\n" +
	"\f_start_epoch\"]\n" +
	"\x1aListenValidatorSetResponse\x12?\n" +
	"\rvalidator_set\x18\x01 \x01(\v2\x1a.api.proto.v1.ValidatorSetR\fvalidatorSet\";\n" +
	"\x1aGetAggregationProofRequest\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\"k\n" +
	"\"GetAggregationProofsByEpochRequest\x12\x14\n" +
	"\x05epoch\x18\x01 \x01(\x04R\x05epoch\x12\x1b\n" +
	"\tpage_size\x18\x02 \x01(\rR\bpageSize\x12\x12\n" +
	"\x04from\x18\x03 \x01(\tR\x04from\"\x18\n" +
	"\x16GetCurrentEpochRequest\"5\n" +
	"\x14GetSignaturesRequest\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\"d\n" +
	"\x1bGetSignaturesByEpochRequest\x12\x14\n" +
	"\x05epoch\x18\x01 \x01(\x04R\x05epoch\x12\x1b\n" +
	"\tpage_size\x18\x02 \x01(\rR\bpageSize\x12\x12\n" +
	"\x04from\x18\x03 \x01(\tR\x04from\"P\n" +
	"\x15GetSignaturesResponse\x127\n" +
	"\n" +
	"signatures\x18\x01 \x03(\v2\x17.api.proto.v1.SignatureR\n" +
	"signatures\"t\n" +
	"\x1cGetSignaturesByEpochResponse\x127\n" +
	"\n" +
	"signatures\x18\x01 \x03(\v2\x17.api.proto.v1.SignatureR\n" +
	"signatures\x12\x1b\n" +
	"\tnext_from\x18\x02 \x01(\tR\bnextFrom\"m\n" +
	"$GetSignatureRequestIDsByEpochRequest\x12\x14\n" +
	"\x05epoch\x18\x01 \x01(\x04R\x05epoch\x12\x1b\n" +
	"\tpage_size\x18\x02 \x01(\rR\bpageSize\x12\x12\n" +
	"\x04from\x18\x03 \x01(\tR\x04from\"e\n" +
	"%GetSignatureRequestIDsByEpochResponse\x12\x1f\n" +
	"\vrequest_ids\x18\x01 \x03(\tR\n" +
	"requestIds\x12\x1b\n" +
	"\tnext_from\x18\x02 \x01(\tR\bnextFrom\"k\n" +
	"\"GetSignatureRequestsByEpochRequest\x12\x14\n" +
	"\x05epoch\x18\x01 \x01(\x04R\x05epoch\x12\x1b\n" +
	"\tpage_size\x18\x02 \x01(\rR\bpageSize\x12\x12\n" +
	"\x04from\x18\x03 \x01(\tR\x04from\"\x91\x01\n" +
	"#GetSignatureRequestsByEpochResponse\x12M\n" +
	"\x12signature_requests\x18\x01 \x03(\v2\x1e.api.proto.v1.SignatureRequestR\x11signatureRequests\x12\x1b\n" +
	"\tnext_from\x18\x02 \x01(\tR\bnextFrom\";\n" +
	"\x1aGetSignatureRequestRequest\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\"<\n" +
	"\x1bGetAggregationStatusRequest\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\"=\n" +
	"\x16GetValidatorSetRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01B\b\n" +
	"\x06_epoch\"]\n" +
	"\x1cGetValidatorByAddressRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01\x12\x18\n" +
	"\aaddress\x18\x02 \x01(\tR\aaddressB\b\n" +
	"\x06_epoch\"z\n" +
	"\x18GetValidatorByKeyRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12 \n" +
	"\fon_chain_key\x18\x03 \x01(\fR\n" +
	"onChainKeyB\b\n" +
	"\x06_epoch\"?\n" +
	"\x18GetLocalValidatorRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01B\b\n" +
	"\x06_epoch\"C\n" +
	"\x1cGetValidatorSetHeaderRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01B\b\n" +
	"\x06_epoch\"E\n" +
	"\x1eGetValidatorSetMetadataRequest\x12\x19\n" +
	"\x05epoch\x18\x01 \x01(\x04H\x00R\x05epoch\x88\x01\x01B\b\n" +
	"\x06_epoch\"j\n" +
	"\x17GetCurrentEpochResponse\x12\x14\n" +
	"\x05epoch\x18\x01 \x01(\x04R\x05epoch\x129\n" +
	"\n" +
	"start_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\"\x8b\x01\n" +
	"\x10SignatureRequest\x12\x1d\n" +
	"\n" +
	"request_id\x18\x01 \x01(\tR\trequestId\x12\x17\n" +
	"\akey_tag\x18\x02 \x01(\rR\x06keyTag\x12\x18\n" +
	"\amessage\x18\x03 \x01(\fR\amessage\x12%\n" +
	"\x0erequired_epoch\x18\x04 \x01(\x04R\rrequiredEpoch\"j\n" +
	"\x1bGetSignatureRequestResponse\x12K\n" +
	"\x11signature_request\x18\x01 \x01(\v2\x1e.api.proto.v1.SignatureRequestR\x10signatureRequest\"j\n" +
	"\x1bGetAggregationProofResponse\x12K\n" +
	"\x11aggregation_proof\x18\x01 \x01(\v2\x1e.api.proto.v1.AggregationProofR\x10aggregationProof\"\x91\x01\n" +
	"#GetAggregationProofsByEpochResponse\x12M\n" +
	"\x12aggregation_proofs\x18\x01 \x03(\v2\x1e.api.proto.v1.AggregationProofR\x11aggregationProofs\x12\x1b\n" +
	"\tnext_from\x18\x02 \x01(\tR\bnextFrom\"j\n" +
	"\x10AggregationProof\x12!\n" +
	"\fmessage_hash\x18\x02 \x01(\fR\vmessageHash\x12\x14\n" +
	"\x05proof\x18\x03 \x01(\fR\x05proof\x12\x1d\n" +
	"\n" +
	"request_id\x18\x04 \x01(\tR\trequestId\"{\n" +
	"\x1cGetAggregationStatusResponse\x120\n" +
	"\x14current_voting_power\x18\x01 \x01(\tR\x12currentVotingPower\x12)\n" +
	"\x10signer_operators\x18\x02 \x03(\tR\x0fsignerOperators\"\x8a\x01\n" +
	"\tSignature\x12\x1c\n" +
	"\tsignature\x18\x01 \x01(\fR\tsignature\x12!\n" +
	"\fmessage_hash\x18\x02 \x01(\fR\vmessageHash\x12\x1d\n" +
	"\n" +
	"public_key\x18\x03 \x01(\fR\tpublicKey\x12\x1d\n" +
	"\n" +
	"request_id\x18\x04 \x01(\tR\trequestId\"Z\n" +
	"\x17GetValidatorSetResponse\x12?\n" +
	"\rvalidator_set\x18\x01 \x01(\v2\x1a.api.proto.v1.ValidatorSetR\fvalidatorSet\"V\n" +
	"\x1dGetValidatorByAddressResponse\x125\n" +
	"\tvalidator\x18\x01 \x01(\v2\x17.api.proto.v1.ValidatorR\tvalidator\"R\n" +
	"\x19GetValidatorByKeyResponse\x125\n" +
	"\tvalidator\x18\x01 \x01(\v2\x17.api.proto.v1.ValidatorR\tvalidator\"R\n" +
	"\x19GetLocalValidatorResponse\x125\n" +
	"\tvalidator\x18\x01 \x01(\v2\x17.api.proto.v1.ValidatorR\tvalidator\"3\n" +
	"\tExtraData\x12\x10\n" +
	"\x03key\x18\x01 \x01(\fR\x03key\x12\x14\n" +
	"\x05value\x18\x02 \x01(\fR\x05value\"\xa1\x01\n" +
	"\x1fGetValidatorSetMetadataResponse\x126\n" +
	"\n" +
	"extra_data\x18\x01 \x03(\v2\x17.api.proto.v1.ExtraDataR\textraData\x12'\n" +
	"\x0fcommitment_data\x18\x02 \x01(\fR\x0ecommitmentData\x12\x1d\n" +
	"\n" +
	"request_id\x18\x03 \x01(\tR\trequestId\"\xcd\x02\n" +
	"\x1dGetValidatorSetHeaderResponse\x12\x18\n" +
	"\aversion\x18\x01 \x01(\rR\aversion\x12(\n" +
	"\x10required_key_tag\x18\x02 \x01(\rR\x0erequiredKeyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12G\n" +
	"\x11capture_timestamp\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\x10captureTimestamp\x12)\n" +
	"\x10quorum_threshold\x18\x05 \x01(\tR\x0fquorumThreshold\x12,\n" +
	"\x12total_voting_power\x18\x06 \x01(\tR\x10totalVotingPower\x120\n" +
	"\x14validators_ssz_mroot\x18\a \x01(\tR\x12validatorsSszMroot\"\xc4\x01\n" +
	"\tValidator\x12\x1a\n" +
	"\boperator\x18\x01 \x01(\tR\boperator\x12!\n" +
	"\fvoting_power\x18\x02 \x01(\tR\vvotingPower\x12\x1b\n" +
	"\tis_active\x18\x03 \x01(\bR\bisActive\x12%\n" +
	"\x04keys\x18\x04 \x03(\v2\x11.api.proto.v1.KeyR\x04keys\x124\n" +
	"\x06vaults\x18\x05 \x03(\v2\x1c.api.proto.v1.ValidatorVaultR\x06vaults\"1\n" +
	"\x03Key\x12\x10\n" +
	"\x03tag\x18\x01 \x01(\rR\x03tag\x12\x18\n" +
	"\apayload\x18\x02 \x01(\fR\apayload\"d\n" +
	"\x0eValidatorVault\x12\x19\n" +
	"\bchain_id\x18\x01 \x01(\x04R\achainId\x12\x14\n" +
	"\x05vault\x18\x02 \x01(\tR\x05vault\x12!\n" +
	"\fvoting_power\x18\x03 \x01(\tR\vvotingPower\"I\n" +
	"\x17GetLastCommittedRequest\x12.\n" +
	"\x13settlement_chain_id\x18\x01 \x01(\x04R\x11settlementChainId\"\x87\x01\n" +
	"\x18GetLastCommittedResponse\x12.\n" +
	"\x13settlement_chain_id\x18\x01 \x01(\x04R\x11settlementChainId\x12;\n" +
	"\n" +
	"epoch_info\x18\x02 \x01(\v2\x1c.api.proto.v1.ChainEpochInfoR\tepochInfo\"\x1c\n" +
	"\x1aGetLastAllCommittedRequest\"\xa6\x02\n" +
	"\x1bGetLastAllCommittedResponse\x12Z\n" +
	"\vepoch_infos\x18\x01 \x03(\v29.api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntryR\n" +
	"epochInfos\x12N\n" +
	"\x14suggested_epoch_info\x18\x02 \x01(\v2\x1c.api.proto.v1.ChainEpochInfoR\x12suggestedEpochInfo\x1a[\n" +
	"\x0fEpochInfosEntry\x12\x10\n" +
	"\x03key\x18\x01 \x01(\x04R\x03key\x122\n" +
	"\x05value\x18\x02 \x01(\v2\x1c.api.proto.v1.ChainEpochInfoR\x05value:\x028\x01\"}\n" +
	"\x0eChainEpochInfo\x120\n" +
	"\x14last_committed_epoch\x18\x01 \x01(\x04R\x12lastCommittedEpoch\x129\n" +
	"\n" +
	"start_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\"\xcf\x02\n" +
	"\fValidatorSet\x12\x18\n" +
	"\aversion\x18\x01 \x01(\rR\aversion\x12(\n" +
	"\x10required_key_tag\x18\x02 \x01(\rR\x0erequiredKeyTag\x12\x14\n" +
	"\x05epoch\x18\x03 \x01(\x04R\x05epoch\x12G\n" +
	"\x11capture_timestamp\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\x10captureTimestamp\x12)\n" +
	"\x10quorum_threshold\x18\x05 \x01(\tR\x0fquorumThreshold\x128\n" +
	"\x06status\x18\x06 \x01(\x0e2 .api.proto.v1.ValidatorSetStatusR\x06status\x127\n" +
	"\n" +
	"validators\x18\a \x03(\v2\x17.api.proto.v1.ValidatorR\n" +
	"validators*\xa5\x01\n" +
	"\x12ValidatorSetStatus\x12$\n" +
	" VALIDATOR_SET_STATUS_UNSPECIFIED\x10\x00\x12 \n" +
	"\x1cVALIDATOR_SET_STATUS_DERIVED\x10\x01\x12#\n" +
	"\x1fVALIDATOR_SET_STATUS_AGGREGATED\x10\x02\x12\"\n" +
	"\x1eVALIDATOR_SET_STATUS_COMMITTED\x10\x03*\xa0\x01\n" +
	"\rSigningStatus\x12\x1e\n" +
	"\x1aSIGNING_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n" +
	"\x16SIGNING_STATUS_PENDING\x10\x01\x12\x1c\n" +
	"\x18SIGNING_STATUS_COMPLETED\x10\x02\x12\x19\n" +
	"\x15SIGNING_STATUS_FAILED\x10\x03\x12\x1a\n" +
	"\x16SIGNING_STATUS_TIMEOUT\x10\x04*w\n" +
	"\tErrorCode\x12\x1a\n" +
	"\x16ERROR_CODE_UNSPECIFIED\x10\x00\x12\x16\n" +
	"\x12ERROR_CODE_NO_DATA\x10\x01\x12\x17\n" +
	"\x13ERROR_CODE_INTERNAL\x10\x02\x12\x1d\n" +
	"\x19ERROR_CODE_NOT_AGGREGATOR\x10\x032\xc9\x19\n" +
	"\x13SymbioticAPIService\x12g\n" +
	"\vSignMessage\x12 .api.proto.v1.SignMessageRequest\x1a!.api.proto.v1.SignMessageResponse\"\x13\x82\xd3\xe4\x93\x02\r:\x01*\"\b/v1/sign\x12\x96\x01\n" +
	"\x13GetAggregationProof\x12(.api.proto.v1.GetAggregationProofRequest\x1a).api.proto.v1.GetAggregationProofResponse\"*\x82\xd3\xe4\x93\x02$\x12\"/v1/aggregation/proof/{request_id}\x12\xb0\x01\n" +
	"\x1bGetAggregationProofsByEpoch\x120.api.proto.v1.GetAggregationProofsByEpochRequest\x1a1.api.proto.v1.GetAggregationProofsByEpochResponse\",\x82\xd3\xe4\x93\x02&\x12$/v1/aggregation/proofs/epoch/{epoch}\x12y\n" +
	"\x0fGetCurrentEpoch\x12$.api.proto.v1.GetCurrentEpochRequest\x1a%.api.proto.v1.GetCurrentEpochResponse\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/epoch/current\x12}\n" +
	"\rGetSignatures\x12\".api.proto.v1.GetSignaturesRequest\x1a#.api.proto.v1.GetSignaturesResponse\"#\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/signatures/{request_id}\x12\x93\x01\n" +
	"\x14GetSignaturesByEpoch\x12).api.proto.v1.GetSignaturesByEpochRequest\x1a*.api.proto.v1.GetSignaturesByEpochResponse\"$\x82\xd3\xe4\x93\x02\x1e\x12\x1c/v1/signatures/epoch/{epoch}\x12\xb9\x01\n" +
	"\x1dGetSignatureRequestIDsByEpoch\x122.api.proto.v1.GetSignatureRequestIDsByEpochRequest\x1a3.api.proto.v1.GetSignatureRequestIDsByEpochResponse\"/\x82\xd3\xe4\x93\x02)\x12'/v1/signature-request-ids/epoch/{epoch}\x12\xb0\x01\n" +
	"\x1bGetSignatureRequestsByEpoch\x120.api.proto.v1.GetSignatureRequestsByEpochRequest\x1a1.api.proto.v1.GetSignatureRequestsByEpochResponse\",\x82\xd3\xe4\x93\x02&\x12$/v1/signature-requests/epoch/{epoch}\x12\x96\x01\n" +
	"\x13GetSignatureRequest\x12(.api.proto.v1.GetSignatureRequestRequest\x1a).api.proto.v1.GetSignatureRequestResponse\"*\x82\xd3\xe4\x93\x02$\x12\"/v1/signature-request/{request_id}\x12\x9a\x01\n" +
	"\x14GetAggregationStatus\x12).api.proto.v1.GetAggregationStatusRequest\x1a*.api.proto.v1.GetAggregationStatusResponse\"+\x82\xd3\xe4\x93\x02%\x12#/v1/aggregation/status/{request_id}\x12y\n" +
	"\x0fGetValidatorSet\x12$.api.proto.v1.GetValidatorSetRequest\x1a%.api.proto.v1.GetValidatorSetResponse\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/validator-set\x12\x99\x01\n" +
	"\x15GetValidatorByAddress\x12*.api.proto.v1.GetValidatorByAddressRequest\x1a+.api.proto.v1.GetValidatorByAddressResponse\"'\x82\xd3\xe4\x93\x02!\x12\x1f/v1/validator/address/{address}\x12\x98\x01\n" +
	"\x11GetValidatorByKey\x12&.api.proto.v1.GetValidatorByKeyRequest\x1a'.api.proto.v1.GetValidatorByKeyResponse\"2\x82\xd3\xe4\x93\x02,\x12*/v1/validator/key/{key_tag}/{on_chain_key}\x12\x81\x01\n" +
	"\x11GetLocalValidator\x12&.api.proto.v1.GetLocalValidatorRequest\x1a'.api.proto.v1.GetLocalValidatorResponse\"\x1b\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/validator/local\x12\x92\x01\n" +
	"\x15GetValidatorSetHeader\x12*.api.proto.v1.GetValidatorSetHeaderRequest\x1a+.api.proto.v1.GetValidatorSetHeaderResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/v1/validator-set/header\x12\x94\x01\n" +
	"\x10GetLastCommitted\x12%.api.proto.v1.GetLastCommittedRequest\x1a&.api.proto.v1.GetLastCommittedResponse\"1\x82\xd3\xe4\x93\x02+\x12)/v1/committed/chain/{settlement_chain_id}\x12\x85\x01\n" +
	"\x13GetLastAllCommitted\x12(.api.proto.v1.GetLastAllCommittedRequest\x1a).api.proto.v1.GetLastAllCommittedResponse\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/committed/all\x12\x9a\x01\n" +
	"\x17GetValidatorSetMetadata\x12,.api.proto.v1.GetValidatorSetMetadataRequest\x1a-.api.proto.v1.GetValidatorSetMetadataResponse\"\"\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/validator-set/metadata\x12\xb9\x01\n" +
	"\x1bGetCustomScheduleNodeStatus\x120.api.proto.v1.GetCustomScheduleNodeStatusRequest\x1a1.api.proto.v1.GetCustomScheduleNodeStatusResponse\"5\x82\xd3\xe4\x93\x02/\x12-/v1/validator-set/custom-schedule/node-status\x12\x82\x01\n" +
	"\x10ListenSignatures\x12%.api.proto.v1.ListenSignaturesRequest\x1a&.api.proto.v1.ListenSignaturesResponse\"\x1d\x82\xd3\xe4\x93\x02\x17\x12\x15/v1/stream/signatures0\x01\x12r\n" +
	"\fListenProofs\x12!.api.proto.v1.ListenProofsRequest\x1a\".api.proto.v1.ListenProofsResponse\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/stream/proofs0\x01\x12\x8b\x01\n" +
	"\x12ListenValidatorSet\x12'.api.proto.v1.ListenValidatorSetRequest\x1a(.api.proto.v1.ListenValidatorSetResponse\" \x82\xd3\xe4\x93\x02\x1a\x12\x18/v1/stream/validator-set0\x01B\x99\x01\n" +
	"\x10com.api.proto.v1B\bApiProtoP\x01Z)github.com/symbioticfi/relay/api/proto/v1\xa2\x02\x03APX\xaa\x02\fApi.Proto.V1\xca\x02\fApi\\Proto\\V1\xe2\x02\x18Api\\Proto\\V1\\GPBMetadata\xea\x02\x0eApi::Proto::V1b\x06proto3"
⋮----
var (
	file_v1_api_proto_rawDescOnce sync.Once
	file_v1_api_proto_rawDescData []byte
)
⋮----
func file_v1_api_proto_rawDescGZIP() []byte
⋮----
var file_v1_api_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 54)
var file_v1_api_proto_goTypes = []any{
	(ValidatorSetStatus)(0),                       // 0: api.proto.v1.ValidatorSetStatus
	(SigningStatus)(0),                            // 1: api.proto.v1.SigningStatus
	(ErrorCode)(0),                                // 2: api.proto.v1.ErrorCode
	(*GetCustomScheduleNodeStatusRequest)(nil),    // 3: api.proto.v1.GetCustomScheduleNodeStatusRequest
	(*GetCustomScheduleNodeStatusResponse)(nil),   // 4: api.proto.v1.GetCustomScheduleNodeStatusResponse
	(*SignMessageRequest)(nil),                    // 5: api.proto.v1.SignMessageRequest
	(*SignMessageResponse)(nil),                   // 6: api.proto.v1.SignMessageResponse
	(*ListenSignaturesRequest)(nil),               // 7: api.proto.v1.ListenSignaturesRequest
	(*ListenSignaturesResponse)(nil),              // 8: api.proto.v1.ListenSignaturesResponse
	(*ListenProofsRequest)(nil),                   // 9: api.proto.v1.ListenProofsRequest
	(*ListenProofsResponse)(nil),                  // 10: api.proto.v1.ListenProofsResponse
	(*ListenValidatorSetRequest)(nil),             // 11: api.proto.v1.ListenValidatorSetRequest
	(*ListenValidatorSetResponse)(nil),            // 12: api.proto.v1.ListenValidatorSetResponse
	(*GetAggregationProofRequest)(nil),            // 13: api.proto.v1.GetAggregationProofRequest
	(*GetAggregationProofsByEpochRequest)(nil),    // 14: api.proto.v1.GetAggregationProofsByEpochRequest
	(*GetCurrentEpochRequest)(nil),                // 15: api.proto.v1.GetCurrentEpochRequest
	(*GetSignaturesRequest)(nil),                  // 16: api.proto.v1.GetSignaturesRequest
	(*GetSignaturesByEpochRequest)(nil),           // 17: api.proto.v1.GetSignaturesByEpochRequest
	(*GetSignaturesResponse)(nil),                 // 18: api.proto.v1.GetSignaturesResponse
	(*GetSignaturesByEpochResponse)(nil),          // 19: api.proto.v1.GetSignaturesByEpochResponse
	(*GetSignatureRequestIDsByEpochRequest)(nil),  // 20: api.proto.v1.GetSignatureRequestIDsByEpochRequest
	(*GetSignatureRequestIDsByEpochResponse)(nil), // 21: api.proto.v1.GetSignatureRequestIDsByEpochResponse
	(*GetSignatureRequestsByEpochRequest)(nil),    // 22: api.proto.v1.GetSignatureRequestsByEpochRequest
	(*GetSignatureRequestsByEpochResponse)(nil),   // 23: api.proto.v1.GetSignatureRequestsByEpochResponse
	(*GetSignatureRequestRequest)(nil),            // 24: api.proto.v1.GetSignatureRequestRequest
	(*GetAggregationStatusRequest)(nil),           // 25: api.proto.v1.GetAggregationStatusRequest
	(*GetValidatorSetRequest)(nil),                // 26: api.proto.v1.GetValidatorSetRequest
	(*GetValidatorByAddressRequest)(nil),          // 27: api.proto.v1.GetValidatorByAddressRequest
	(*GetValidatorByKeyRequest)(nil),              // 28: api.proto.v1.GetValidatorByKeyRequest
	(*GetLocalValidatorRequest)(nil),              // 29: api.proto.v1.GetLocalValidatorRequest
	(*GetValidatorSetHeaderRequest)(nil),          // 30: api.proto.v1.GetValidatorSetHeaderRequest
	(*GetValidatorSetMetadataRequest)(nil),        // 31: api.proto.v1.GetValidatorSetMetadataRequest
	(*GetCurrentEpochResponse)(nil),               // 32: api.proto.v1.GetCurrentEpochResponse
	(*SignatureRequest)(nil),                      // 33: api.proto.v1.SignatureRequest
	(*GetSignatureRequestResponse)(nil),           // 34: api.proto.v1.GetSignatureRequestResponse
	(*GetAggregationProofResponse)(nil),           // 35: api.proto.v1.GetAggregationProofResponse
	(*GetAggregationProofsByEpochResponse)(nil),   // 36: api.proto.v1.GetAggregationProofsByEpochResponse
	(*AggregationProof)(nil),                      // 37: api.proto.v1.AggregationProof
	(*GetAggregationStatusResponse)(nil),          // 38: api.proto.v1.GetAggregationStatusResponse
	(*Signature)(nil),                             // 39: api.proto.v1.Signature
	(*GetValidatorSetResponse)(nil),               // 40: api.proto.v1.GetValidatorSetResponse
	(*GetValidatorByAddressResponse)(nil),         // 41: api.proto.v1.GetValidatorByAddressResponse
	(*GetValidatorByKeyResponse)(nil),             // 42: api.proto.v1.GetValidatorByKeyResponse
	(*GetLocalValidatorResponse)(nil),             // 43: api.proto.v1.GetLocalValidatorResponse
	(*ExtraData)(nil),                             // 44: api.proto.v1.ExtraData
	(*GetValidatorSetMetadataResponse)(nil),       // 45: api.proto.v1.GetValidatorSetMetadataResponse
	(*GetValidatorSetHeaderResponse)(nil),         // 46: api.proto.v1.GetValidatorSetHeaderResponse
	(*Validator)(nil),                             // 47: api.proto.v1.Validator
	(*Key)(nil),                                   // 48: api.proto.v1.Key
	(*ValidatorVault)(nil),                        // 49: api.proto.v1.ValidatorVault
	(*GetLastCommittedRequest)(nil),               // 50: api.proto.v1.GetLastCommittedRequest
	(*GetLastCommittedResponse)(nil),              // 51: api.proto.v1.GetLastCommittedResponse
	(*GetLastAllCommittedRequest)(nil),            // 52: api.proto.v1.GetLastAllCommittedRequest
	(*GetLastAllCommittedResponse)(nil),           // 53: api.proto.v1.GetLastAllCommittedResponse
	(*ChainEpochInfo)(nil),                        // 54: api.proto.v1.ChainEpochInfo
	(*ValidatorSet)(nil),                          // 55: api.proto.v1.ValidatorSet
	nil,                                           // 56: api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry
	(*timestamppb.Timestamp)(nil),                 // 57: google.protobuf.Timestamp
}
⋮----
(ValidatorSetStatus)(0),                       // 0: api.proto.v1.ValidatorSetStatus
(SigningStatus)(0),                            // 1: api.proto.v1.SigningStatus
(ErrorCode)(0),                                // 2: api.proto.v1.ErrorCode
(*GetCustomScheduleNodeStatusRequest)(nil),    // 3: api.proto.v1.GetCustomScheduleNodeStatusRequest
(*GetCustomScheduleNodeStatusResponse)(nil),   // 4: api.proto.v1.GetCustomScheduleNodeStatusResponse
(*SignMessageRequest)(nil),                    // 5: api.proto.v1.SignMessageRequest
(*SignMessageResponse)(nil),                   // 6: api.proto.v1.SignMessageResponse
(*ListenSignaturesRequest)(nil),               // 7: api.proto.v1.ListenSignaturesRequest
(*ListenSignaturesResponse)(nil),              // 8: api.proto.v1.ListenSignaturesResponse
(*ListenProofsRequest)(nil),                   // 9: api.proto.v1.ListenProofsRequest
(*ListenProofsResponse)(nil),                  // 10: api.proto.v1.ListenProofsResponse
(*ListenValidatorSetRequest)(nil),             // 11: api.proto.v1.ListenValidatorSetRequest
(*ListenValidatorSetResponse)(nil),            // 12: api.proto.v1.ListenValidatorSetResponse
(*GetAggregationProofRequest)(nil),            // 13: api.proto.v1.GetAggregationProofRequest
(*GetAggregationProofsByEpochRequest)(nil),    // 14: api.proto.v1.GetAggregationProofsByEpochRequest
(*GetCurrentEpochRequest)(nil),                // 15: api.proto.v1.GetCurrentEpochRequest
(*GetSignaturesRequest)(nil),                  // 16: api.proto.v1.GetSignaturesRequest
(*GetSignaturesByEpochRequest)(nil),           // 17: api.proto.v1.GetSignaturesByEpochRequest
(*GetSignaturesResponse)(nil),                 // 18: api.proto.v1.GetSignaturesResponse
(*GetSignaturesByEpochResponse)(nil),          // 19: api.proto.v1.GetSignaturesByEpochResponse
(*GetSignatureRequestIDsByEpochRequest)(nil),  // 20: api.proto.v1.GetSignatureRequestIDsByEpochRequest
(*GetSignatureRequestIDsByEpochResponse)(nil), // 21: api.proto.v1.GetSignatureRequestIDsByEpochResponse
(*GetSignatureRequestsByEpochRequest)(nil),    // 22: api.proto.v1.GetSignatureRequestsByEpochRequest
(*GetSignatureRequestsByEpochResponse)(nil),   // 23: api.proto.v1.GetSignatureRequestsByEpochResponse
(*GetSignatureRequestRequest)(nil),            // 24: api.proto.v1.GetSignatureRequestRequest
(*GetAggregationStatusRequest)(nil),           // 25: api.proto.v1.GetAggregationStatusRequest
(*GetValidatorSetRequest)(nil),                // 26: api.proto.v1.GetValidatorSetRequest
(*GetValidatorByAddressRequest)(nil),          // 27: api.proto.v1.GetValidatorByAddressRequest
(*GetValidatorByKeyRequest)(nil),              // 28: api.proto.v1.GetValidatorByKeyRequest
(*GetLocalValidatorRequest)(nil),              // 29: api.proto.v1.GetLocalValidatorRequest
(*GetValidatorSetHeaderRequest)(nil),          // 30: api.proto.v1.GetValidatorSetHeaderRequest
(*GetValidatorSetMetadataRequest)(nil),        // 31: api.proto.v1.GetValidatorSetMetadataRequest
(*GetCurrentEpochResponse)(nil),               // 32: api.proto.v1.GetCurrentEpochResponse
(*SignatureRequest)(nil),                      // 33: api.proto.v1.SignatureRequest
(*GetSignatureRequestResponse)(nil),           // 34: api.proto.v1.GetSignatureRequestResponse
(*GetAggregationProofResponse)(nil),           // 35: api.proto.v1.GetAggregationProofResponse
(*GetAggregationProofsByEpochResponse)(nil),   // 36: api.proto.v1.GetAggregationProofsByEpochResponse
(*AggregationProof)(nil),                      // 37: api.proto.v1.AggregationProof
(*GetAggregationStatusResponse)(nil),          // 38: api.proto.v1.GetAggregationStatusResponse
(*Signature)(nil),                             // 39: api.proto.v1.Signature
(*GetValidatorSetResponse)(nil),               // 40: api.proto.v1.GetValidatorSetResponse
(*GetValidatorByAddressResponse)(nil),         // 41: api.proto.v1.GetValidatorByAddressResponse
(*GetValidatorByKeyResponse)(nil),             // 42: api.proto.v1.GetValidatorByKeyResponse
(*GetLocalValidatorResponse)(nil),             // 43: api.proto.v1.GetLocalValidatorResponse
(*ExtraData)(nil),                             // 44: api.proto.v1.ExtraData
(*GetValidatorSetMetadataResponse)(nil),       // 45: api.proto.v1.GetValidatorSetMetadataResponse
(*GetValidatorSetHeaderResponse)(nil),         // 46: api.proto.v1.GetValidatorSetHeaderResponse
(*Validator)(nil),                             // 47: api.proto.v1.Validator
(*Key)(nil),                                   // 48: api.proto.v1.Key
(*ValidatorVault)(nil),                        // 49: api.proto.v1.ValidatorVault
(*GetLastCommittedRequest)(nil),               // 50: api.proto.v1.GetLastCommittedRequest
(*GetLastCommittedResponse)(nil),              // 51: api.proto.v1.GetLastCommittedResponse
(*GetLastAllCommittedRequest)(nil),            // 52: api.proto.v1.GetLastAllCommittedRequest
(*GetLastAllCommittedResponse)(nil),           // 53: api.proto.v1.GetLastAllCommittedResponse
(*ChainEpochInfo)(nil),                        // 54: api.proto.v1.ChainEpochInfo
(*ValidatorSet)(nil),                          // 55: api.proto.v1.ValidatorSet
nil,                                           // 56: api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry
(*timestamppb.Timestamp)(nil),                 // 57: google.protobuf.Timestamp
⋮----
var file_v1_api_proto_depIdxs = []int32{
	57, // 0: api.proto.v1.GetCustomScheduleNodeStatusResponse.current_slot_start_time:type_name -> google.protobuf.Timestamp
	57, // 1: api.proto.v1.GetCustomScheduleNodeStatusResponse.current_slot_end_time:type_name -> google.protobuf.Timestamp
	39, // 2: api.proto.v1.ListenSignaturesResponse.signature:type_name -> api.proto.v1.Signature
	37, // 3: api.proto.v1.ListenProofsResponse.aggregation_proof:type_name -> api.proto.v1.AggregationProof
	55, // 4: api.proto.v1.ListenValidatorSetResponse.validator_set:type_name -> api.proto.v1.ValidatorSet
	39, // 5: api.proto.v1.GetSignaturesResponse.signatures:type_name -> api.proto.v1.Signature
	39, // 6: api.proto.v1.GetSignaturesByEpochResponse.signatures:type_name -> api.proto.v1.Signature
	33, // 7: api.proto.v1.GetSignatureRequestsByEpochResponse.signature_requests:type_name -> api.proto.v1.SignatureRequest
	57, // 8: api.proto.v1.GetCurrentEpochResponse.start_time:type_name -> google.protobuf.Timestamp
	33, // 9: api.proto.v1.GetSignatureRequestResponse.signature_request:type_name -> api.proto.v1.SignatureRequest
	37, // 10: api.proto.v1.GetAggregationProofResponse.aggregation_proof:type_name -> api.proto.v1.AggregationProof
	37, // 11: api.proto.v1.GetAggregationProofsByEpochResponse.aggregation_proofs:type_name -> api.proto.v1.AggregationProof
	55, // 12: api.proto.v1.GetValidatorSetResponse.validator_set:type_name -> api.proto.v1.ValidatorSet
	47, // 13: api.proto.v1.GetValidatorByAddressResponse.validator:type_name -> api.proto.v1.Validator
	47, // 14: api.proto.v1.GetValidatorByKeyResponse.validator:type_name -> api.proto.v1.Validator
	47, // 15: api.proto.v1.GetLocalValidatorResponse.validator:type_name -> api.proto.v1.Validator
	44, // 16: api.proto.v1.GetValidatorSetMetadataResponse.extra_data:type_name -> api.proto.v1.ExtraData
	57, // 17: api.proto.v1.GetValidatorSetHeaderResponse.capture_timestamp:type_name -> google.protobuf.Timestamp
	48, // 18: api.proto.v1.Validator.keys:type_name -> api.proto.v1.Key
	49, // 19: api.proto.v1.Validator.vaults:type_name -> api.proto.v1.ValidatorVault
	54, // 20: api.proto.v1.GetLastCommittedResponse.epoch_info:type_name -> api.proto.v1.ChainEpochInfo
	56, // 21: api.proto.v1.GetLastAllCommittedResponse.epoch_infos:type_name -> api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry
	54, // 22: api.proto.v1.GetLastAllCommittedResponse.suggested_epoch_info:type_name -> api.proto.v1.ChainEpochInfo
	57, // 23: api.proto.v1.ChainEpochInfo.start_time:type_name -> google.protobuf.Timestamp
	57, // 24: api.proto.v1.ValidatorSet.capture_timestamp:type_name -> google.protobuf.Timestamp
	0,  // 25: api.proto.v1.ValidatorSet.status:type_name -> api.proto.v1.ValidatorSetStatus
	47, // 26: api.proto.v1.ValidatorSet.validators:type_name -> api.proto.v1.Validator
	54, // 27: api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry.value:type_name -> api.proto.v1.ChainEpochInfo
	5,  // 28: api.proto.v1.SymbioticAPIService.SignMessage:input_type -> api.proto.v1.SignMessageRequest
	13, // 29: api.proto.v1.SymbioticAPIService.GetAggregationProof:input_type -> api.proto.v1.GetAggregationProofRequest
	14, // 30: api.proto.v1.SymbioticAPIService.GetAggregationProofsByEpoch:input_type -> api.proto.v1.GetAggregationProofsByEpochRequest
	15, // 31: api.proto.v1.SymbioticAPIService.GetCurrentEpoch:input_type -> api.proto.v1.GetCurrentEpochRequest
	16, // 32: api.proto.v1.SymbioticAPIService.GetSignatures:input_type -> api.proto.v1.GetSignaturesRequest
	17, // 33: api.proto.v1.SymbioticAPIService.GetSignaturesByEpoch:input_type -> api.proto.v1.GetSignaturesByEpochRequest
	20, // 34: api.proto.v1.SymbioticAPIService.GetSignatureRequestIDsByEpoch:input_type -> api.proto.v1.GetSignatureRequestIDsByEpochRequest
	22, // 35: api.proto.v1.SymbioticAPIService.GetSignatureRequestsByEpoch:input_type -> api.proto.v1.GetSignatureRequestsByEpochRequest
	24, // 36: api.proto.v1.SymbioticAPIService.GetSignatureRequest:input_type -> api.proto.v1.GetSignatureRequestRequest
	25, // 37: api.proto.v1.SymbioticAPIService.GetAggregationStatus:input_type -> api.proto.v1.GetAggregationStatusRequest
	26, // 38: api.proto.v1.SymbioticAPIService.GetValidatorSet:input_type -> api.proto.v1.GetValidatorSetRequest
	27, // 39: api.proto.v1.SymbioticAPIService.GetValidatorByAddress:input_type -> api.proto.v1.GetValidatorByAddressRequest
	28, // 40: api.proto.v1.SymbioticAPIService.GetValidatorByKey:input_type -> api.proto.v1.GetValidatorByKeyRequest
	29, // 41: api.proto.v1.SymbioticAPIService.GetLocalValidator:input_type -> api.proto.v1.GetLocalValidatorRequest
	30, // 42: api.proto.v1.SymbioticAPIService.GetValidatorSetHeader:input_type -> api.proto.v1.GetValidatorSetHeaderRequest
	50, // 43: api.proto.v1.SymbioticAPIService.GetLastCommitted:input_type -> api.proto.v1.GetLastCommittedRequest
	52, // 44: api.proto.v1.SymbioticAPIService.GetLastAllCommitted:input_type -> api.proto.v1.GetLastAllCommittedRequest
	31, // 45: api.proto.v1.SymbioticAPIService.GetValidatorSetMetadata:input_type -> api.proto.v1.GetValidatorSetMetadataRequest
	3,  // 46: api.proto.v1.SymbioticAPIService.GetCustomScheduleNodeStatus:input_type -> api.proto.v1.GetCustomScheduleNodeStatusRequest
	7,  // 47: api.proto.v1.SymbioticAPIService.ListenSignatures:input_type -> api.proto.v1.ListenSignaturesRequest
	9,  // 48: api.proto.v1.SymbioticAPIService.ListenProofs:input_type -> api.proto.v1.ListenProofsRequest
	11, // 49: api.proto.v1.SymbioticAPIService.ListenValidatorSet:input_type -> api.proto.v1.ListenValidatorSetRequest
	6,  // 50: api.proto.v1.SymbioticAPIService.SignMessage:output_type -> api.proto.v1.SignMessageResponse
	35, // 51: api.proto.v1.SymbioticAPIService.GetAggregationProof:output_type -> api.proto.v1.GetAggregationProofResponse
	36, // 52: api.proto.v1.SymbioticAPIService.GetAggregationProofsByEpoch:output_type -> api.proto.v1.GetAggregationProofsByEpochResponse
	32, // 53: api.proto.v1.SymbioticAPIService.GetCurrentEpoch:output_type -> api.proto.v1.GetCurrentEpochResponse
	18, // 54: api.proto.v1.SymbioticAPIService.GetSignatures:output_type -> api.proto.v1.GetSignaturesResponse
	19, // 55: api.proto.v1.SymbioticAPIService.GetSignaturesByEpoch:output_type -> api.proto.v1.GetSignaturesByEpochResponse
	21, // 56: api.proto.v1.SymbioticAPIService.GetSignatureRequestIDsByEpoch:output_type -> api.proto.v1.GetSignatureRequestIDsByEpochResponse
	23, // 57: api.proto.v1.SymbioticAPIService.GetSignatureRequestsByEpoch:output_type -> api.proto.v1.GetSignatureRequestsByEpochResponse
	34, // 58: api.proto.v1.SymbioticAPIService.GetSignatureRequest:output_type -> api.proto.v1.GetSignatureRequestResponse
	38, // 59: api.proto.v1.SymbioticAPIService.GetAggregationStatus:output_type -> api.proto.v1.GetAggregationStatusResponse
	40, // 60: api.proto.v1.SymbioticAPIService.GetValidatorSet:output_type -> api.proto.v1.GetValidatorSetResponse
	41, // 61: api.proto.v1.SymbioticAPIService.GetValidatorByAddress:output_type -> api.proto.v1.GetValidatorByAddressResponse
	42, // 62: api.proto.v1.SymbioticAPIService.GetValidatorByKey:output_type -> api.proto.v1.GetValidatorByKeyResponse
	43, // 63: api.proto.v1.SymbioticAPIService.GetLocalValidator:output_type -> api.proto.v1.GetLocalValidatorResponse
	46, // 64: api.proto.v1.SymbioticAPIService.GetValidatorSetHeader:output_type -> api.proto.v1.GetValidatorSetHeaderResponse
	51, // 65: api.proto.v1.SymbioticAPIService.GetLastCommitted:output_type -> api.proto.v1.GetLastCommittedResponse
	53, // 66: api.proto.v1.SymbioticAPIService.GetLastAllCommitted:output_type -> api.proto.v1.GetLastAllCommittedResponse
	45, // 67: api.proto.v1.SymbioticAPIService.GetValidatorSetMetadata:output_type -> api.proto.v1.GetValidatorSetMetadataResponse
	4,  // 68: api.proto.v1.SymbioticAPIService.GetCustomScheduleNodeStatus:output_type -> api.proto.v1.GetCustomScheduleNodeStatusResponse
	8,  // 69: api.proto.v1.SymbioticAPIService.ListenSignatures:output_type -> api.proto.v1.ListenSignaturesResponse
	10, // 70: api.proto.v1.SymbioticAPIService.ListenProofs:output_type -> api.proto.v1.ListenProofsResponse
	12, // 71: api.proto.v1.SymbioticAPIService.ListenValidatorSet:output_type -> api.proto.v1.ListenValidatorSetResponse
	50, // [50:72] is the sub-list for method output_type
	28, // [28:50] is the sub-list for method input_type
	28, // [28:28] is the sub-list for extension type_name
	28, // [28:28] is the sub-list for extension extendee
	0,  // [0:28] is the sub-list for field type_name
}
⋮----
57, // 0: api.proto.v1.GetCustomScheduleNodeStatusResponse.current_slot_start_time:type_name -> google.protobuf.Timestamp
57, // 1: api.proto.v1.GetCustomScheduleNodeStatusResponse.current_slot_end_time:type_name -> google.protobuf.Timestamp
39, // 2: api.proto.v1.ListenSignaturesResponse.signature:type_name -> api.proto.v1.Signature
37, // 3: api.proto.v1.ListenProofsResponse.aggregation_proof:type_name -> api.proto.v1.AggregationProof
55, // 4: api.proto.v1.ListenValidatorSetResponse.validator_set:type_name -> api.proto.v1.ValidatorSet
39, // 5: api.proto.v1.GetSignaturesResponse.signatures:type_name -> api.proto.v1.Signature
39, // 6: api.proto.v1.GetSignaturesByEpochResponse.signatures:type_name -> api.proto.v1.Signature
33, // 7: api.proto.v1.GetSignatureRequestsByEpochResponse.signature_requests:type_name -> api.proto.v1.SignatureRequest
57, // 8: api.proto.v1.GetCurrentEpochResponse.start_time:type_name -> google.protobuf.Timestamp
33, // 9: api.proto.v1.GetSignatureRequestResponse.signature_request:type_name -> api.proto.v1.SignatureRequest
37, // 10: api.proto.v1.GetAggregationProofResponse.aggregation_proof:type_name -> api.proto.v1.AggregationProof
37, // 11: api.proto.v1.GetAggregationProofsByEpochResponse.aggregation_proofs:type_name -> api.proto.v1.AggregationProof
55, // 12: api.proto.v1.GetValidatorSetResponse.validator_set:type_name -> api.proto.v1.ValidatorSet
47, // 13: api.proto.v1.GetValidatorByAddressResponse.validator:type_name -> api.proto.v1.Validator
47, // 14: api.proto.v1.GetValidatorByKeyResponse.validator:type_name -> api.proto.v1.Validator
47, // 15: api.proto.v1.GetLocalValidatorResponse.validator:type_name -> api.proto.v1.Validator
44, // 16: api.proto.v1.GetValidatorSetMetadataResponse.extra_data:type_name -> api.proto.v1.ExtraData
57, // 17: api.proto.v1.GetValidatorSetHeaderResponse.capture_timestamp:type_name -> google.protobuf.Timestamp
48, // 18: api.proto.v1.Validator.keys:type_name -> api.proto.v1.Key
49, // 19: api.proto.v1.Validator.vaults:type_name -> api.proto.v1.ValidatorVault
54, // 20: api.proto.v1.GetLastCommittedResponse.epoch_info:type_name -> api.proto.v1.ChainEpochInfo
56, // 21: api.proto.v1.GetLastAllCommittedResponse.epoch_infos:type_name -> api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry
54, // 22: api.proto.v1.GetLastAllCommittedResponse.suggested_epoch_info:type_name -> api.proto.v1.ChainEpochInfo
57, // 23: api.proto.v1.ChainEpochInfo.start_time:type_name -> google.protobuf.Timestamp
57, // 24: api.proto.v1.ValidatorSet.capture_timestamp:type_name -> google.protobuf.Timestamp
0,  // 25: api.proto.v1.ValidatorSet.status:type_name -> api.proto.v1.ValidatorSetStatus
47, // 26: api.proto.v1.ValidatorSet.validators:type_name -> api.proto.v1.Validator
54, // 27: api.proto.v1.GetLastAllCommittedResponse.EpochInfosEntry.value:type_name -> api.proto.v1.ChainEpochInfo
5,  // 28: api.proto.v1.SymbioticAPIService.SignMessage:input_type -> api.proto.v1.SignMessageRequest
13, // 29: api.proto.v1.SymbioticAPIService.GetAggregationProof:input_type -> api.proto.v1.GetAggregationProofRequest
14, // 30: api.proto.v1.SymbioticAPIService.GetAggregationProofsByEpoch:input_type -> api.proto.v1.GetAggregationProofsByEpochRequest
15, // 31: api.proto.v1.SymbioticAPIService.GetCurrentEpoch:input_type -> api.proto.v1.GetCurrentEpochRequest
16, // 32: api.proto.v1.SymbioticAPIService.GetSignatures:input_type -> api.proto.v1.GetSignaturesRequest
17, // 33: api.proto.v1.SymbioticAPIService.GetSignaturesByEpoch:input_type -> api.proto.v1.GetSignaturesByEpochRequest
20, // 34: api.proto.v1.SymbioticAPIService.GetSignatureRequestIDsByEpoch:input_type -> api.proto.v1.GetSignatureRequestIDsByEpochRequest
22, // 35: api.proto.v1.SymbioticAPIService.GetSignatureRequestsByEpoch:input_type -> api.proto.v1.GetSignatureRequestsByEpochRequest
24, // 36: api.proto.v1.SymbioticAPIService.GetSignatureRequest:input_type -> api.proto.v1.GetSignatureRequestRequest
25, // 37: api.proto.v1.SymbioticAPIService.GetAggregationStatus:input_type -> api.proto.v1.GetAggregationStatusRequest
26, // 38: api.proto.v1.SymbioticAPIService.GetValidatorSet:input_type -> api.proto.v1.GetValidatorSetRequest
27, // 39: api.proto.v1.SymbioticAPIService.GetValidatorByAddress:input_type -> api.proto.v1.GetValidatorByAddressRequest
28, // 40: api.proto.v1.SymbioticAPIService.GetValidatorByKey:input_type -> api.proto.v1.GetValidatorByKeyRequest
29, // 41: api.proto.v1.SymbioticAPIService.GetLocalValidator:input_type -> api.proto.v1.GetLocalValidatorRequest
30, // 42: api.proto.v1.SymbioticAPIService.GetValidatorSetHeader:input_type -> api.proto.v1.GetValidatorSetHeaderRequest
50, // 43: api.proto.v1.SymbioticAPIService.GetLastCommitted:input_type -> api.proto.v1.GetLastCommittedRequest
52, // 44: api.proto.v1.SymbioticAPIService.GetLastAllCommitted:input_type -> api.proto.v1.GetLastAllCommittedRequest
31, // 45: api.proto.v1.SymbioticAPIService.GetValidatorSetMetadata:input_type -> api.proto.v1.GetValidatorSetMetadataRequest
3,  // 46: api.proto.v1.SymbioticAPIService.GetCustomScheduleNodeStatus:input_type -> api.proto.v1.GetCustomScheduleNodeStatusRequest
7,  // 47: api.proto.v1.SymbioticAPIService.ListenSignatures:input_type -> api.proto.v1.ListenSignaturesRequest
9,  // 48: api.proto.v1.SymbioticAPIService.ListenProofs:input_type -> api.proto.v1.ListenProofsRequest
11, // 49: api.proto.v1.SymbioticAPIService.ListenValidatorSet:input_type -> api.proto.v1.ListenValidatorSetRequest
6,  // 50: api.proto.v1.SymbioticAPIService.SignMessage:output_type -> api.proto.v1.SignMessageResponse
35, // 51: api.proto.v1.SymbioticAPIService.GetAggregationProof:output_type -> api.proto.v1.GetAggregationProofResponse
36, // 52: api.proto.v1.SymbioticAPIService.GetAggregationProofsByEpoch:output_type -> api.proto.v1.GetAggregationProofsByEpochResponse
32, // 53: api.proto.v1.SymbioticAPIService.GetCurrentEpoch:output_type -> api.proto.v1.GetCurrentEpochResponse
18, // 54: api.proto.v1.SymbioticAPIService.GetSignatures:output_type -> api.proto.v1.GetSignaturesResponse
19, // 55: api.proto.v1.SymbioticAPIService.GetSignaturesByEpoch:output_type -> api.proto.v1.GetSignaturesByEpochResponse
21, // 56: api.proto.v1.SymbioticAPIService.GetSignatureRequestIDsByEpoch:output_type -> api.proto.v1.GetSignatureRequestIDsByEpochResponse
23, // 57: api.proto.v1.SymbioticAPIService.GetSignatureRequestsByEpoch:output_type -> api.proto.v1.GetSignatureRequestsByEpochResponse
34, // 58: api.proto.v1.SymbioticAPIService.GetSignatureRequest:output_type -> api.proto.v1.GetSignatureRequestResponse
38, // 59: api.proto.v1.SymbioticAPIService.GetAggregationStatus:output_type -> api.proto.v1.GetAggregationStatusResponse
40, // 60: api.proto.v1.SymbioticAPIService.GetValidatorSet:output_type -> api.proto.v1.GetValidatorSetResponse
41, // 61: api.proto.v1.SymbioticAPIService.GetValidatorByAddress:output_type -> api.proto.v1.GetValidatorByAddressResponse
42, // 62: api.proto.v1.SymbioticAPIService.GetValidatorByKey:output_type -> api.proto.v1.GetValidatorByKeyResponse
43, // 63: api.proto.v1.SymbioticAPIService.GetLocalValidator:output_type -> api.proto.v1.GetLocalValidatorResponse
46, // 64: api.proto.v1.SymbioticAPIService.GetValidatorSetHeader:output_type -> api.proto.v1.GetValidatorSetHeaderResponse
51, // 65: api.proto.v1.SymbioticAPIService.GetLastCommitted:output_type -> api.proto.v1.GetLastCommittedResponse
53, // 66: api.proto.v1.SymbioticAPIService.GetLastAllCommitted:output_type -> api.proto.v1.GetLastAllCommittedResponse
45, // 67: api.proto.v1.SymbioticAPIService.GetValidatorSetMetadata:output_type -> api.proto.v1.GetValidatorSetMetadataResponse
4,  // 68: api.proto.v1.SymbioticAPIService.GetCustomScheduleNodeStatus:output_type -> api.proto.v1.GetCustomScheduleNodeStatusResponse
8,  // 69: api.proto.v1.SymbioticAPIService.ListenSignatures:output_type -> api.proto.v1.ListenSignaturesResponse
10, // 70: api.proto.v1.SymbioticAPIService.ListenProofs:output_type -> api.proto.v1.ListenProofsResponse
12, // 71: api.proto.v1.SymbioticAPIService.ListenValidatorSet:output_type -> api.proto.v1.ListenValidatorSetResponse
50, // [50:72] is the sub-list for method output_type
28, // [28:50] is the sub-list for method input_type
28, // [28:28] is the sub-list for extension type_name
28, // [28:28] is the sub-list for extension extendee
0,  // [0:28] is the sub-list for field type_name
⋮----
func init()
func file_v1_api_proto_init()
⋮----
type x struct{}
```

## File: internal/gen/api/v1/api.pb.gw.go

```go
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: v1/api.proto
⋮----
/*
Package v1 is a reverse proxy.

It translates gRPC into RESTful JSON APIs.
*/
package v1
⋮----
import (
	"context"
	"errors"
	"io"
	"net/http"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/proto"
)
⋮----
"context"
"errors"
"io"
"net/http"
⋮----
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
⋮----
// Suppress "imported and not used" errors
var (
	_ codes.Code
	_ io.Reader
	_ status.Status
	_ = errors.New
	_ = runtime.String
	_ = utilities.NewDoubleArray
	_ = metadata.Join
)
⋮----
func request_SymbioticAPIService_SignMessage_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq SignMessageRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_SignMessage_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetAggregationProof_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetAggregationProofRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetAggregationProof_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetAggregationProofsByEpoch_0 = &utilities.DoubleArray{Encoding: map[string]int{"epoch": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
⋮----
func request_SymbioticAPIService_GetAggregationProofsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetAggregationProofsByEpochRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetAggregationProofsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetCurrentEpoch_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetCurrentEpochRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetCurrentEpoch_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetSignatures_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetSignaturesRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetSignatures_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetSignaturesByEpoch_0 = &utilities.DoubleArray{Encoding: map[string]int{"epoch": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
⋮----
func request_SymbioticAPIService_GetSignaturesByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetSignaturesByEpochRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetSignaturesByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetSignatureRequestIDsByEpoch_0 = &utilities.DoubleArray{Encoding: map[string]int{"epoch": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
⋮----
func request_SymbioticAPIService_GetSignatureRequestIDsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetSignatureRequestIDsByEpochRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetSignatureRequestIDsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetSignatureRequestsByEpoch_0 = &utilities.DoubleArray{Encoding: map[string]int{"epoch": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
⋮----
func request_SymbioticAPIService_GetSignatureRequestsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetSignatureRequestsByEpochRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetSignatureRequestsByEpoch_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetSignatureRequest_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetSignatureRequestRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetSignatureRequest_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetAggregationStatus_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetAggregationStatusRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetAggregationStatus_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetValidatorSet_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_GetValidatorSet_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetValidatorSetRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetValidatorSet_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetValidatorByAddress_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
⋮----
func request_SymbioticAPIService_GetValidatorByAddress_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetValidatorByAddressRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetValidatorByAddress_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetValidatorByKey_0 = &utilities.DoubleArray{Encoding: map[string]int{"key_tag": 0, "on_chain_key": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
⋮----
func request_SymbioticAPIService_GetValidatorByKey_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetValidatorByKeyRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetValidatorByKey_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetLocalValidator_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_GetLocalValidator_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetLocalValidatorRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetLocalValidator_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetValidatorSetHeader_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_GetValidatorSetHeader_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetValidatorSetHeaderRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetValidatorSetHeader_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetLastCommitted_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetLastCommittedRequest
		metadata runtime.ServerMetadata
		err      error
	)
⋮----
func local_request_SymbioticAPIService_GetLastCommitted_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
func request_SymbioticAPIService_GetLastAllCommitted_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetLastAllCommittedRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetLastAllCommitted_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetValidatorSetMetadata_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_GetValidatorSetMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetValidatorSetMetadataRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetValidatorSetMetadata_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_GetCustomScheduleNodeStatus_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_GetCustomScheduleNodeStatus_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var (
		protoReq GetCustomScheduleNodeStatusRequest
		metadata runtime.ServerMetadata
	)
⋮----
func local_request_SymbioticAPIService_GetCustomScheduleNodeStatus_0(ctx context.Context, marshaler runtime.Marshaler, server SymbioticAPIServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
⋮----
var filter_SymbioticAPIService_ListenSignatures_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_ListenSignatures_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (SymbioticAPIService_ListenSignaturesClient, runtime.ServerMetadata, error)
⋮----
var (
		protoReq ListenSignaturesRequest
		metadata runtime.ServerMetadata
	)
⋮----
var filter_SymbioticAPIService_ListenProofs_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_ListenProofs_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (SymbioticAPIService_ListenProofsClient, runtime.ServerMetadata, error)
⋮----
var (
		protoReq ListenProofsRequest
		metadata runtime.ServerMetadata
	)
⋮----
var filter_SymbioticAPIService_ListenValidatorSet_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
⋮----
func request_SymbioticAPIService_ListenValidatorSet_0(ctx context.Context, marshaler runtime.Marshaler, client SymbioticAPIServiceClient, req *http.Request, pathParams map[string]string) (SymbioticAPIService_ListenValidatorSetClient, runtime.ServerMetadata, error)
⋮----
var (
		protoReq ListenValidatorSetRequest
		metadata runtime.ServerMetadata
	)
⋮----
// RegisterSymbioticAPIServiceHandlerServer registers the http handlers for service SymbioticAPIService to "mux".
// UnaryRPC     :call SymbioticAPIServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterSymbioticAPIServiceHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterSymbioticAPIServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server SymbioticAPIServiceServer) error
⋮----
var stream runtime.ServerTransportStream
⋮----
// RegisterSymbioticAPIServiceHandlerFromEndpoint is same as RegisterSymbioticAPIServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterSymbioticAPIServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error)
⋮----
// RegisterSymbioticAPIServiceHandler registers the http handlers for service SymbioticAPIService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterSymbioticAPIServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error
⋮----
// RegisterSymbioticAPIServiceHandlerClient registers the http handlers for service SymbioticAPIService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "SymbioticAPIServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "SymbioticAPIServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "SymbioticAPIServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterSymbioticAPIServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SymbioticAPIServiceClient) error
⋮----
var (
	pattern_SymbioticAPIService_SignMessage_0                   = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "sign"}, ""))
⋮----
var (
	forward_SymbioticAPIService_SignMessage_0                   = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetAggregationProof_0           = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetAggregationProofsByEpoch_0   = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetCurrentEpoch_0               = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetSignatures_0                 = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetSignaturesByEpoch_0          = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetSignatureRequestIDsByEpoch_0 = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetSignatureRequestsByEpoch_0   = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetSignatureRequest_0           = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetAggregationStatus_0          = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetValidatorSet_0               = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetValidatorByAddress_0         = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetValidatorByKey_0             = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetLocalValidator_0             = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetValidatorSetHeader_0         = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetLastCommitted_0              = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetLastAllCommitted_0           = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetValidatorSetMetadata_0       = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_GetCustomScheduleNodeStatus_0   = runtime.ForwardResponseMessage
	forward_SymbioticAPIService_ListenSignatures_0              = runtime.ForwardResponseStream
	forward_SymbioticAPIService_ListenProofs_0                  = runtime.ForwardResponseStream
	forward_SymbioticAPIService_ListenValidatorSet_0            = runtime.ForwardResponseStream
)
```

## File: internal/gen/votingpower/v1/votingpower_grpc.pb.go

```go
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc             (unknown)
// source: v1/votingpower.proto
⋮----
package votingpowerv1
⋮----
import (
	context "context"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
)
⋮----
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
⋮----
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
⋮----
const (
	VotingPowerProviderService_GetVotingPowersAt_FullMethodName = "/votingpower.v1.VotingPowerProviderService/GetVotingPowersAt"
)
⋮----
// VotingPowerProviderServiceClient is the client API for VotingPowerProviderService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
⋮----
// VotingPowerProviderService is implemented by external voting power providers.
type VotingPowerProviderServiceClient interface {
	// GetVotingPowersAt returns voting power for operators at a specific timestamp.
	GetVotingPowersAt(ctx context.Context, in *GetVotingPowersAtRequest, opts ...grpc.CallOption) (*GetVotingPowersAtResponse, error)
}
⋮----
// GetVotingPowersAt returns voting power for operators at a specific timestamp.
⋮----
type votingPowerProviderServiceClient struct {
	cc grpc.ClientConnInterface
}
⋮----
func NewVotingPowerProviderServiceClient(cc grpc.ClientConnInterface) VotingPowerProviderServiceClient
⋮----
func (c *votingPowerProviderServiceClient) GetVotingPowersAt(ctx context.Context, in *GetVotingPowersAtRequest, opts ...grpc.CallOption) (*GetVotingPowersAtResponse, error)
⋮----
// VotingPowerProviderServiceServer is the server API for VotingPowerProviderService service.
// All implementations must embed UnimplementedVotingPowerProviderServiceServer
// for forward compatibility.
⋮----
type VotingPowerProviderServiceServer interface {
	// GetVotingPowersAt returns voting power for operators at a specific timestamp.
	GetVotingPowersAt(context.Context, *GetVotingPowersAtRequest) (*GetVotingPowersAtResponse, error)
	mustEmbedUnimplementedVotingPowerProviderServiceServer()
}
⋮----
// UnimplementedVotingPowerProviderServiceServer must be embedded to have
// forward compatible implementations.
⋮----
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedVotingPowerProviderServiceServer struct{}
⋮----
func (UnimplementedVotingPowerProviderServiceServer) mustEmbedUnimplementedVotingPowerProviderServiceServer()
func (UnimplementedVotingPowerProviderServiceServer) testEmbeddedByValue()
⋮----
// UnsafeVotingPowerProviderServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to VotingPowerProviderServiceServer will
// result in compilation errors.
type UnsafeVotingPowerProviderServiceServer interface {
	mustEmbedUnimplementedVotingPowerProviderServiceServer()
}
⋮----
func RegisterVotingPowerProviderServiceServer(s grpc.ServiceRegistrar, srv VotingPowerProviderServiceServer)
⋮----
// If the following call pancis, it indicates UnimplementedVotingPowerProviderServiceServer was
// embedded by pointer and is nil.  This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
⋮----
func _VotingPowerProviderService_GetVotingPowersAt_Handler(srv interface
⋮----
// VotingPowerProviderService_ServiceDesc is the grpc.ServiceDesc for VotingPowerProviderService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var VotingPowerProviderService_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "votingpower.v1.VotingPowerProviderService",
	HandlerType: (*VotingPowerProviderServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "GetVotingPowersAt",
			Handler:    _VotingPowerProviderService_GetVotingPowersAt_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "v1/votingpower.proto",
}
```

## File: internal/gen/votingpower/v1/votingpower.pb.go

```go
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.36.6
// 	protoc        (unknown)
// source: v1/votingpower.proto
⋮----
package votingpowerv1
⋮----
import (
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
	unsafe "unsafe"
)
⋮----
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
⋮----
const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
⋮----
// Verify that this generated code is sufficiently up-to-date.
⋮----
// Verify that runtime/protoimpl is sufficiently up-to-date.
⋮----
type GetVotingPowersAtRequest struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Unix timestamp in seconds.
	Timestamp     uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Unix timestamp in seconds.
⋮----
func (x *GetVotingPowersAtRequest) Reset()
⋮----
func (x *GetVotingPowersAtRequest) String() string
⋮----
func (*GetVotingPowersAtRequest) ProtoMessage()
⋮----
func (x *GetVotingPowersAtRequest) ProtoReflect() protoreflect.Message
⋮----
// Deprecated: Use GetVotingPowersAtRequest.ProtoReflect.Descriptor instead.
func (*GetVotingPowersAtRequest) Descriptor() ([]byte, []int)
⋮----
func (x *GetVotingPowersAtRequest) GetTimestamp() uint64
⋮----
type GetVotingPowersAtResponse struct {
	state         protoimpl.MessageState `protogen:"open.v1"`
	VotingPowers  []*OperatorVotingPower `protobuf:"bytes,1,rep,name=voting_powers,json=votingPowers,proto3" json:"voting_powers,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Deprecated: Use GetVotingPowersAtResponse.ProtoReflect.Descriptor instead.
⋮----
func (x *GetVotingPowersAtResponse) GetVotingPowers() []*OperatorVotingPower
⋮----
type OperatorVotingPower struct {
	state protoimpl.MessageState `protogen:"open.v1"`
	// Operator address as hex string.
	Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"`
	// Decimal string voting power.
	VotingPower   string `protobuf:"bytes,2,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
⋮----
// Operator address as hex string.
⋮----
// Decimal string voting power.
⋮----
// Deprecated: Use OperatorVotingPower.ProtoReflect.Descriptor instead.
⋮----
func (x *OperatorVotingPower) GetOperator() string
⋮----
func (x *OperatorVotingPower) GetVotingPower() string
⋮----
var File_v1_votingpower_proto protoreflect.FileDescriptor
⋮----
const file_v1_votingpower_proto_rawDesc = "" +
	"\n" +
	"\x14v1/votingpower.proto\x12\x0evotingpower.v1\"8\n" +
	"\x18GetVotingPowersAtRequest\x12\x1c\n" +
	"\ttimestamp\x18\x01 \x01(\x04R\ttimestamp\"e\n" +
	"\x19GetVotingPowersAtResponse\x12H\n" +
	"\rvoting_powers\x18\x01 \x03(\v2#.votingpower.v1.OperatorVotingPowerR\fvotingPowers\"T\n" +
	"\x13OperatorVotingPower\x12\x1a\n" +
	"\boperator\x18\x01 \x01(\tR\boperator\x12!\n" +
	"\fvoting_power\x18\x02 \x01(\tR\vvotingPower2\x86\x01\n" +
	"\x1aVotingPowerProviderService\x12h\n" +
	"\x11GetVotingPowersAt\x12(.votingpower.v1.GetVotingPowersAtRequest\x1a).votingpower.v1.GetVotingPowersAtResponseB\xc7\x01\n" +
	"\x12com.votingpower.v1B\x10VotingpowerProtoP\x01ZFgithub.com/symbioticfi/relay/internal/gen/votingpower/v1;votingpowerv1\xa2\x02\x03VXX\xaa\x02\x0eVotingpower.V1\xca\x02\x0eVotingpower\\V1\xe2\x02\x1aVotingpower\\V1\\GPBMetadata\xea\x02\x0fVotingpower::V1b\x06proto3"
⋮----
var (
	file_v1_votingpower_proto_rawDescOnce sync.Once
	file_v1_votingpower_proto_rawDescData []byte
)
⋮----
func file_v1_votingpower_proto_rawDescGZIP() []byte
⋮----
var file_v1_votingpower_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_v1_votingpower_proto_goTypes = []any{
	(*GetVotingPowersAtRequest)(nil),  // 0: votingpower.v1.GetVotingPowersAtRequest
	(*GetVotingPowersAtResponse)(nil), // 1: votingpower.v1.GetVotingPowersAtResponse
	(*OperatorVotingPower)(nil),       // 2: votingpower.v1.OperatorVotingPower
}
⋮----
(*GetVotingPowersAtRequest)(nil),  // 0: votingpower.v1.GetVotingPowersAtRequest
(*GetVotingPowersAtResponse)(nil), // 1: votingpower.v1.GetVotingPowersAtResponse
(*OperatorVotingPower)(nil),       // 2: votingpower.v1.OperatorVotingPower
⋮----
var file_v1_votingpower_proto_depIdxs = []int32{
	2, // 0: votingpower.v1.GetVotingPowersAtResponse.voting_powers:type_name -> votingpower.v1.OperatorVotingPower
	0, // 1: votingpower.v1.VotingPowerProviderService.GetVotingPowersAt:input_type -> votingpower.v1.GetVotingPowersAtRequest
	1, // 2: votingpower.v1.VotingPowerProviderService.GetVotingPowersAt:output_type -> votingpower.v1.GetVotingPowersAtResponse
	2, // [2:3] is the sub-list for method output_type
	1, // [1:2] is the sub-list for method input_type
	1, // [1:1] is the sub-list for extension type_name
	1, // [1:1] is the sub-list for extension extendee
	0, // [0:1] is the sub-list for field type_name
}
⋮----
2, // 0: votingpower.v1.GetVotingPowersAtResponse.voting_powers:type_name -> votingpower.v1.OperatorVotingPower
0, // 1: votingpower.v1.VotingPowerProviderService.GetVotingPowersAt:input_type -> votingpower.v1.GetVotingPowersAtRequest
1, // 2: votingpower.v1.VotingPowerProviderService.GetVotingPowersAt:output_type -> votingpower.v1.GetVotingPowersAtResponse
2, // [2:3] is the sub-list for method output_type
1, // [1:2] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
⋮----
func init()
func file_v1_votingpower_proto_init()
⋮----
type x struct{}
```

## File: internal/usecase/aggregation-policy/low-cost/low_cost_policy.go

```go
package lowCostPolicy
⋮----
import (
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
type LowCostPolicy struct {
	maxUnsigners uint64
}
⋮----
func NewLowCostPolicy(maxUnsigners uint64) *LowCostPolicy
⋮----
func (lcp *LowCostPolicy) ShouldAggregate(signatureMap entity.SignatureMap, validatorSet symbiotic.ValidatorSet) bool
```

## File: internal/usecase/aggregation-policy/low-latency/low_latency_policy.go

```go
package lowLatencyPolicy
⋮----
import (
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type LowLatencyPolicy struct {
}
⋮----
func NewLowLatencyPolicy() *LowLatencyPolicy
⋮----
func (llp *LowLatencyPolicy) ShouldAggregate(signatureMap entity.SignatureMap, validatorSet symbiotic.ValidatorSet) bool
```

## File: internal/usecase/aggregation-policy/types/types.go

```go
package aggregationPolicyTypes
⋮----
import (
	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type AggregationPolicy interface {
	ShouldAggregate(signatureMap entity.SignatureMap, validatorSet symbiotic.ValidatorSet) bool
}
```

## File: internal/usecase/aggregation-policy/aggregation_policies.go

```go
package aggregationPolicy
⋮----
import (
	"errors"

	lowCostPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/low-cost"
	lowLatencyPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/low-latency"
	aggregationPolicyTypes "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/types"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"errors"
⋮----
lowCostPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/low-cost"
lowLatencyPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/low-latency"
aggregationPolicyTypes "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/types"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func NewAggregationPolicy(aggregationPolicyType symbiotic.AggregationPolicyType, maxUnsigners uint64) (aggregationPolicyTypes.AggregationPolicy, error)
```

## File: internal/usecase/aggregator-app/mocks/aggregator_app.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: aggregator_app.go
//
// Generated by this command:
⋮----
//	mockgen -source=aggregator_app.go -destination=mocks/aggregator_app.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"
	time "time"

	common "github.com/ethereum/go-ethereum/common"
	entity "github.com/symbioticfi/relay/internal/entity"
	entity0 "github.com/symbioticfi/relay/symbiotic/entity"
	crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
time "time"
⋮----
common "github.com/ethereum/go-ethereum/common"
entity "github.com/symbioticfi/relay/internal/entity"
entity0 "github.com/symbioticfi/relay/symbiotic/entity"
crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
gomock "go.uber.org/mock/gomock"
⋮----
// Mockrepository is a mock of repository interface.
type Mockrepository struct {
	ctrl     *gomock.Controller
	recorder *MockrepositoryMockRecorder
	isgomock struct{}
⋮----
// MockrepositoryMockRecorder is the mock recorder for Mockrepository.
type MockrepositoryMockRecorder struct {
	mock *Mockrepository
}
⋮----
// NewMockrepository creates a new mock instance.
func NewMockrepository(ctrl *gomock.Controller) *Mockrepository
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Mockrepository) EXPECT() *MockrepositoryMockRecorder
⋮----
// GetAggregationProof mocks base method.
func (m *Mockrepository) GetAggregationProof(ctx context.Context, requestID common.Hash) (entity0.AggregationProof, error)
⋮----
// GetAggregationProof indicates an expected call of GetAggregationProof.
⋮----
// GetAllSignatures mocks base method.
func (m *Mockrepository) GetAllSignatures(ctx context.Context, requestID common.Hash) ([]entity0.Signature, error)
⋮----
// GetAllSignatures indicates an expected call of GetAllSignatures.
⋮----
// GetConfigByEpoch mocks base method.
func (m *Mockrepository) GetConfigByEpoch(ctx context.Context, epoch entity0.Epoch) (entity0.NetworkConfig, error)
⋮----
// GetConfigByEpoch indicates an expected call of GetConfigByEpoch.
⋮----
// GetLatestValidatorSetEpoch mocks base method.
func (m *Mockrepository) GetLatestValidatorSetEpoch(ctx context.Context) (entity0.Epoch, error)
⋮----
// GetLatestValidatorSetEpoch indicates an expected call of GetLatestValidatorSetEpoch.
⋮----
// GetSignatureMap mocks base method.
func (m *Mockrepository) GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
⋮----
// GetSignatureMap indicates an expected call of GetSignatureMap.
⋮----
// GetSignatureRequest mocks base method.
func (m *Mockrepository) GetSignatureRequest(arg0 context.Context, requestID common.Hash) (entity0.SignatureRequest, error)
⋮----
// GetSignatureRequest indicates an expected call of GetSignatureRequest.
⋮----
// GetSignatureRequestsWithoutAggregationProof mocks base method.
func (m *Mockrepository) GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch entity0.Epoch, limit int, lastHash common.Hash) ([]entity0.SignatureRequestWithID, error)
⋮----
// GetSignatureRequestsWithoutAggregationProof indicates an expected call of GetSignatureRequestsWithoutAggregationProof.
⋮----
// GetValidatorSetByEpoch mocks base method.
func (m *Mockrepository) GetValidatorSetByEpoch(ctx context.Context, epoch entity0.Epoch) (entity0.ValidatorSet, error)
⋮----
// GetValidatorSetByEpoch indicates an expected call of GetValidatorSetByEpoch.
⋮----
// RemoveAggregationProofPending mocks base method.
func (m *Mockrepository) RemoveAggregationProofPending(ctx context.Context, epoch entity0.Epoch, requestID common.Hash) error
⋮----
// RemoveAggregationProofPending indicates an expected call of RemoveAggregationProofPending.
⋮----
// Mockp2pClient is a mock of p2pClient interface.
type Mockp2pClient struct {
	ctrl     *gomock.Controller
	recorder *Mockp2pClientMockRecorder
	isgomock struct{}
⋮----
// Mockp2pClientMockRecorder is the mock recorder for Mockp2pClient.
type Mockp2pClientMockRecorder struct {
	mock *Mockp2pClient
}
⋮----
// NewMockp2pClient creates a new mock instance.
func NewMockp2pClient(ctrl *gomock.Controller) *Mockp2pClient
⋮----
// BroadcastSignatureAggregatedMessage mocks base method.
func (m *Mockp2pClient) BroadcastSignatureAggregatedMessage(ctx context.Context, proof entity0.AggregationProof) error
⋮----
// BroadcastSignatureAggregatedMessage indicates an expected call of BroadcastSignatureAggregatedMessage.
⋮----
// Mockmetrics is a mock of metrics interface.
type Mockmetrics struct {
	ctrl     *gomock.Controller
	recorder *MockmetricsMockRecorder
	isgomock struct{}
⋮----
// MockmetricsMockRecorder is the mock recorder for Mockmetrics.
type MockmetricsMockRecorder struct {
	mock *Mockmetrics
}
⋮----
// NewMockmetrics creates a new mock instance.
func NewMockmetrics(ctrl *gomock.Controller) *Mockmetrics
⋮----
// ObserveAppAggregateDuration mocks base method.
func (m *Mockmetrics) ObserveAppAggregateDuration(d time.Duration)
⋮----
// ObserveAppAggregateDuration indicates an expected call of ObserveAppAggregateDuration.
⋮----
// ObserveOnlyAggregateDuration mocks base method.
func (m *Mockmetrics) ObserveOnlyAggregateDuration(d time.Duration)
⋮----
// ObserveOnlyAggregateDuration indicates an expected call of ObserveOnlyAggregateDuration.
⋮----
// Mockaggregator is a mock of aggregator interface.
type Mockaggregator struct {
	ctrl     *gomock.Controller
	recorder *MockaggregatorMockRecorder
	isgomock struct{}
⋮----
// MockaggregatorMockRecorder is the mock recorder for Mockaggregator.
type MockaggregatorMockRecorder struct {
	mock *Mockaggregator
}
⋮----
// NewMockaggregator creates a new mock instance.
func NewMockaggregator(ctrl *gomock.Controller) *Mockaggregator
⋮----
// Aggregate mocks base method.
func (m *Mockaggregator) Aggregate(ctx context.Context, valset entity0.ValidatorSet, signatures []entity0.Signature) (entity0.AggregationProof, error)
⋮----
// Aggregate indicates an expected call of Aggregate.
⋮----
// MockkeyProvider is a mock of keyProvider interface.
type MockkeyProvider struct {
	ctrl     *gomock.Controller
	recorder *MockkeyProviderMockRecorder
	isgomock struct{}
⋮----
// MockkeyProviderMockRecorder is the mock recorder for MockkeyProvider.
type MockkeyProviderMockRecorder struct {
	mock *MockkeyProvider
}
⋮----
// NewMockkeyProvider creates a new mock instance.
func NewMockkeyProvider(ctrl *gomock.Controller) *MockkeyProvider
⋮----
// GetOnchainKeyFromCache mocks base method.
func (m *MockkeyProvider) GetOnchainKeyFromCache(keyTag entity0.KeyTag) (entity0.CompactPublicKey, error)
⋮----
// GetOnchainKeyFromCache indicates an expected call of GetOnchainKeyFromCache.
⋮----
// GetPrivateKey mocks base method.
func (m *MockkeyProvider) GetPrivateKey(keyTag entity0.KeyTag) (crypto.PrivateKey, error)
⋮----
// GetPrivateKey indicates an expected call of GetPrivateKey.
⋮----
// MockentityProcessor is a mock of entityProcessor interface.
type MockentityProcessor struct {
	ctrl     *gomock.Controller
	recorder *MockentityProcessorMockRecorder
	isgomock struct{}
⋮----
// MockentityProcessorMockRecorder is the mock recorder for MockentityProcessor.
type MockentityProcessorMockRecorder struct {
	mock *MockentityProcessor
}
⋮----
// NewMockentityProcessor creates a new mock instance.
func NewMockentityProcessor(ctrl *gomock.Controller) *MockentityProcessor
⋮----
// ProcessAggregationProof mocks base method.
func (m *MockentityProcessor) ProcessAggregationProof(ctx context.Context, proof entity0.AggregationProof, self bool) error
⋮----
// ProcessAggregationProof indicates an expected call of ProcessAggregationProof.
```

## File: internal/usecase/aggregator-app/aggregator_app_test.go

```go
package aggregator_app
⋮----
import (
	"context"
	"fmt"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/internal/entity"
	aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
	"github.com/symbioticfi/relay/internal/usecase/aggregator-app/mocks"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"fmt"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/internal/entity"
aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
"github.com/symbioticfi/relay/internal/usecase/aggregator-app/mocks"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type testSetup struct {
	ctrl                *gomock.Controller
	mockRepo            *mocks.Mockrepository
	mockP2PClient       *mocks.Mockp2pClient
	mockAggregator      *mocks.Mockaggregator
	mockEntityProcessor *mocks.MockentityProcessor
	mockMetrics         *mocks.Mockmetrics
	app                 *AggregatorApp
	privateKey          crypto.PrivateKey
}
⋮----
func newTestSetup(t *testing.T, policyType symbiotic.AggregationPolicyType, maxUnsigners uint64) *testSetup
⋮----
func createTestSignatureExtended(t *testing.T, pk crypto.PrivateKey) symbiotic.Signature
⋮----
// Unified test data structure that keeps ValidatorSet and SignatureMap in sync
type testData struct {
	ValidatorSet symbiotic.ValidatorSet
	SignatureMap entity.SignatureMap
}
⋮----
// Create unified test data with a single ValidatorSet used consistently
func createTestData(requestID common.Hash, epoch symbiotic.Epoch, totalValidators, signers int, key crypto.PrivateKey) testData
⋮----
// Create validators
⋮----
VotingPower: symbiotic.ToVotingPower(big.NewInt(100)), // Each validator has 100 voting power
⋮----
// Create the unified ValidatorSet
⋮----
QuorumThreshold: symbiotic.ToVotingPower(big.NewInt(670)), // Need 670 voting power for quorum
⋮----
// Create SignatureMap using the same ValidatorSet
⋮----
// Add signers (first 'signers' number of validators)
⋮----
votingPower := validatorSet.Validators[i].VotingPower // Use actual voting power from validator
⋮----
// Convenience function for common test scenarios
func createTestDataWithQuorum(requestID common.Hash, epoch symbiotic.Epoch, thresholdReached bool, key crypto.PrivateKey) testData
⋮----
// 8 signers * 100 voting power = 800 > 670 threshold
⋮----
// 6 signers * 100 voting power = 600 < 670 threshold
⋮----
// Setup mocks for successful aggregation using unified test data
func setupSuccessfulAggregationMocks(setup *testSetup, msg symbiotic.Signature, testData testData)
⋮----
var signatures []symbiotic.Signature
⋮----
// Use the unified test data
⋮----
// LOW LATENCY POLICY TESTS
⋮----
func TestHandleSignatureGeneratedMessage_LowLatencyPolicy_QuorumNotReached(t *testing.T)
⋮----
// Setup mocks for quorum NOT reached case
⋮----
// Execute
⋮----
// Verify - should return nil (no error) when quorum not reached, no aggregation
⋮----
func TestHandleSignatureGeneratedMessage_LowLatencyPolicy_QuorumReached(t *testing.T)
⋮----
// Setup mocks for quorum reached case - LowLatency should aggregate immediately
⋮----
// Verify - should successfully aggregate when quorum reached
⋮----
// LOW COST POLICY TESTS
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_QuorumNotReached(t *testing.T)
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_QuorumReached_TooManyUnsigners(t *testing.T)
⋮----
setup := newTestSetup(t, symbiotic.AggregationPolicyLowCost, 2) // Allow max 2 unsigners
⋮----
// Setup: 10 total validators, 7 signers = 3 unsigners (exceeds maxUnsigners=2)
⋮----
// Verify - should not aggregate due to too many unsigners
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_QuorumReached_AcceptableUnsigners(t *testing.T)
⋮----
setup := newTestSetup(t, symbiotic.AggregationPolicyLowCost, 3) // Allow max 3 unsigners
⋮----
// Setup: 10 total validators, 8 signers = 2 unsigners (within maxUnsigners=3)
⋮----
// Verify - should successfully aggregate when unsigners within limit
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_QuorumReached_ExactUnsignersLimit(t *testing.T)
⋮----
// Setup: 10 total validators, 7 signers = 3 unsigners (exactly maxUnsigners=3)
⋮----
// Verify - should successfully aggregate when exactly at unsigners limit
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_AllValidatorsSigned(t *testing.T)
⋮----
setup := newTestSetup(t, symbiotic.AggregationPolicyLowCost, 1) // Allow max 1 unsigner
⋮----
// Setup: 10 total validators, 10 signers = 0 unsigners (well within limit)
⋮----
// Verify - should successfully aggregate when all validators signed
⋮----
// EDGE CASES
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_ZeroMaxUnsigners(t *testing.T)
⋮----
setup := newTestSetup(t, symbiotic.AggregationPolicyLowCost, 0) // Allow 0 unsigners
⋮----
// Setup: 5 total validators, 4 signers = 1 unsigner (exceeds maxUnsigners=0)
⋮----
// Verify - should not aggregate due to any unsigners when maxUnsigners=0
⋮----
func TestHandleSignatureGeneratedMessage_LowCostPolicy_HighMaxUnsigners(t *testing.T)
⋮----
setup := newTestSetup(t, symbiotic.AggregationPolicyLowCost, 100) // Allow 100 unsigners
⋮----
// Setup: 10 total validators, 7 signers = 3 unsigners (well within limit)
// 7 signers = 7*100 = 700 > 670 for quorum
⋮----
// Verify - should successfully aggregate with high unsigners limit
⋮----
// Test helper function to verify SignatureMap functionality with unified test data
func TestSignatureMapFunctionality(t *testing.T)
⋮----
// Test with unified creation
⋮----
testingData := createTestData(requestID, 1, 5, 0, pk) // 5 validators, 0 signers initially
⋮----
// Initially no validators signed
⋮----
// Add 3 validators using their actual voting power from the validator set
⋮----
require.False(t, signatureMap.ThresholdReached(validatorSet.QuorumThreshold)) // 300 < 670
⋮----
// Add 4 more validators (5 total = 5 * 100 = 500 voting power)
⋮----
require.False(t, signatureMap.ThresholdReached(validatorSet.QuorumThreshold))            // 500 < 670
require.True(t, signatureMap.ThresholdReached(symbiotic.ToVotingPower(big.NewInt(400)))) // 500 >= 400
⋮----
// Verify that the SignatureMap and ValidatorSet are consistent
⋮----
// CATCH-UP LOOP TESTS
⋮----
func newTestSetupWithCatchup(t *testing.T, catchupCfg ProofCatchupConfig) *testSetup
⋮----
func TestCatchup_NoEpochsSynced(t *testing.T)
⋮----
func TestCatchup_SmallChainScansAllEpochs(t *testing.T)
⋮----
// Should scan epochs 5, 4, 3, 2, 1, 0 — all return empty
⋮----
func TestCatchup_MaxRequestsPerCycleLimit(t *testing.T)
⋮----
// Return 3 requests, but limit is 2 — only 2 should be enqueued
⋮----
// Catch-up checks if proof exists for each request before enqueuing
// All 3 are checked, but only 2 enqueued due to limit
⋮----
// Verify only 2 items were enqueued
⋮----
func TestCatchup_EnqueuesAllRequests(t *testing.T)
⋮----
// Second page: empty
⋮----
// Both requests should be enqueued
⋮----
// CROSS-EPOCH AGGREGATION TESTS
⋮----
func newTestSetupWithCrossEpoch(t *testing.T) *testSetup
⋮----
func TestCrossEpochAggregation_AggregatesForOldEpoch(t *testing.T)
⋮----
// msg has epoch=1, we'll make latest epoch=5
⋮----
// Request's epoch data — node is NOT aggregator for epoch 1
⋮----
testingData.ValidatorSet.AggregatorIndices = []uint32{} // not an aggregator for this epoch
⋮----
// Latest epoch data — node IS aggregator
⋮----
// Mocks
⋮----
// Should proceed with aggregation
⋮----
func TestCrossEpochAggregation_SkipsWhenDisabled(t *testing.T)
⋮----
// CrossEpochAggregation is false by default in newTestSetup
⋮----
testingData.ValidatorSet.AggregatorIndices = []uint32{} // not an aggregator
⋮----
// Should NOT call GetLatestValidatorSetEpoch — cross-epoch is disabled
⋮----
func TestCrossEpochAggregation_SkipsWhenRequestIsLatestEpoch(t *testing.T)
⋮----
// Latest epoch == request epoch → no fallback
⋮----
func TestCrossEpochAggregation_SkipsWhenNotAggregatorForLatestEpoch(t *testing.T)
⋮----
testingData.ValidatorSet.AggregatorIndices = []uint32{} // not an aggregator for epoch 1
⋮----
// Latest epoch — node is also NOT aggregator
⋮----
AggregatorIndices: []uint32{0}, // different validator
```

## File: internal/usecase/aggregator-app/aggregator_app.go

```go
package aggregator_app
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	validate "github.com/go-playground/validator/v10"
	"k8s.io/client-go/util/workqueue"

	"github.com/symbioticfi/relay/internal/entity"
	aggregationPolicyTypes "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/types"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
validate "github.com/go-playground/validator/v10"
"k8s.io/client-go/util/workqueue"
⋮----
"github.com/symbioticfi/relay/internal/entity"
aggregationPolicyTypes "github.com/symbioticfi/relay/internal/usecase/aggregation-policy/types"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
//go:generate mockgen -source=aggregator_app.go -destination=mocks/aggregator_app.go -package=mocks
type repository interface {
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	GetSignatureRequest(_ context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
	GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
	GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
	GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch symbiotic.Epoch, limit int, lastHash common.Hash) ([]symbiotic.SignatureRequestWithID, error)
	GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	RemoveAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
}
⋮----
type p2pClient interface {
	BroadcastSignatureAggregatedMessage(ctx context.Context, proof symbiotic.AggregationProof) error
}
⋮----
type metrics interface {
	ObserveOnlyAggregateDuration(d time.Duration)
	ObserveAppAggregateDuration(d time.Duration)
}
⋮----
type aggregator interface {
	Aggregate(ctx context.Context, valset symbiotic.ValidatorSet, signatures []symbiotic.Signature) (symbiotic.AggregationProof, error)
}
⋮----
type keyProvider interface {
	GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
	GetOnchainKeyFromCache(keyTag symbiotic.KeyTag) (symbiotic.CompactPublicKey, error)
}
⋮----
type entityProcessor interface {
	ProcessAggregationProof(ctx context.Context, proof symbiotic.AggregationProof, self bool) error
}
⋮----
type ProofCatchupConfig struct {
	Enabled             bool
	Interval            time.Duration `validate:"gte=0"`
	EpochsToCheck       int           `validate:"gte=0"`
	EpochsOffset        int           `validate:"gte=0"`
	MaxRequestsPerCycle int           `validate:"gte=0"`
}
⋮----
type Config struct {
	Repo                  repository       `validate:"required"`
	P2PClient             p2pClient        `validate:"required"`
	Aggregator            aggregator       `validate:"required"`
	EntityProcessor       entityProcessor  `validate:"required"`
	Metrics               metrics          `validate:"required"`
	AggregationPolicy     aggregatorPolicy `validate:"required"`
	KeyProvider           keyProvider      `validate:"required"`
	ForceAggregator       bool
	CrossEpochAggregation bool
	ProofCatchup          ProofCatchupConfig
}
⋮----
func (c Config) Validate() error
⋮----
type AggregatorApp struct {
	cfg   Config
	queue *workqueue.Typed[common.Hash]
}
⋮----
func NewAggregatorApp(cfg Config) (*AggregatorApp, error)
⋮----
func (s *AggregatorApp) HandleSignatureProcessedMessage(ctx context.Context, msg symbiotic.Signature) error
⋮----
func (s *AggregatorApp) EnqueueRequestID(ctx context.Context, requestID common.Hash)
⋮----
func (s *AggregatorApp) HandleAggregationRequests(ctx context.Context, workerCount int) error
⋮----
func (s *AggregatorApp) worker(ctx context.Context, id int)
⋮----
func (s *AggregatorApp) TryAggregateProofForRequestID(ctx context.Context, requestID common.Hash) error
⋮----
// Get validator set for quorum threshold checks
⋮----
func (s *AggregatorApp) isLatestEpochAggregator(ctx context.Context, requestEpoch symbiotic.Epoch, onchainKey symbiotic.CompactPublicKey) bool
⋮----
func (s *AggregatorApp) tryAggregateRequestsWithoutProof(ctx context.Context) error
⋮----
// Catch-up scans a bounded window of older epochs for missing proofs.
// EpochsOffset skips recent "hot" epochs still being actively aggregated.
// EpochsToCheck limits how far back we look.
// Example: latestEpoch=100, EpochsOffset=5, EpochsToCheck=20
//   scanEnd = 100 - 5 = 95, startEpoch = 95 - 20 + 1 = 76 → scans 76..95
var scanEnd symbiotic.Epoch
⋮----
var lastHash common.Hash
⋮----
// Non-aggregation key — clean up pending only when all signatures collected
⋮----
// Check if proof already exists — clean up stale pending marker
⋮----
break // Prevent underflow when decrementing unsigned epoch
⋮----
func (s *AggregatorApp) StartCatchupLoop(ctx context.Context) error
⋮----
timer := time.NewTimer(0) // Fire immediately on first tick
⋮----
func (s *AggregatorApp) GetAggregationStatus(ctx context.Context, requestID common.Hash) (symbiotic.AggregationStatus, error)
⋮----
func extractPublicKeys(signatures []symbiotic.Signature) []symbiotic.CompactPublicKey
```

## File: internal/usecase/api-server/mocks/app_mock.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: app.go
//
// Generated by this command:
⋮----
//	mockgen -source=app.go -destination=mocks/app_mock.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"

	common "github.com/ethereum/go-ethereum/common"
	entity "github.com/symbioticfi/relay/internal/entity"
	entity0 "github.com/symbioticfi/relay/symbiotic/entity"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
⋮----
common "github.com/ethereum/go-ethereum/common"
entity "github.com/symbioticfi/relay/internal/entity"
entity0 "github.com/symbioticfi/relay/symbiotic/entity"
gomock "go.uber.org/mock/gomock"
⋮----
// Mocksigner is a mock of signer interface.
type Mocksigner struct {
	ctrl     *gomock.Controller
	recorder *MocksignerMockRecorder
	isgomock struct{}
⋮----
// MocksignerMockRecorder is the mock recorder for Mocksigner.
type MocksignerMockRecorder struct {
	mock *Mocksigner
}
⋮----
// NewMocksigner creates a new mock instance.
func NewMocksigner(ctrl *gomock.Controller) *Mocksigner
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Mocksigner) EXPECT() *MocksignerMockRecorder
⋮----
// RequestSignature mocks base method.
func (m *Mocksigner) RequestSignature(ctx context.Context, req entity0.SignatureRequest) (common.Hash, error)
⋮----
// RequestSignature indicates an expected call of RequestSignature.
⋮----
// Mockrepo is a mock of repo interface.
type Mockrepo struct {
	ctrl     *gomock.Controller
	recorder *MockrepoMockRecorder
	isgomock struct{}
⋮----
// MockrepoMockRecorder is the mock recorder for Mockrepo.
type MockrepoMockRecorder struct {
	mock *Mockrepo
}
⋮----
// NewMockrepo creates a new mock instance.
func NewMockrepo(ctrl *gomock.Controller) *Mockrepo
⋮----
// GetAggregationProof mocks base method.
func (m *Mockrepo) GetAggregationProof(ctx context.Context, requestID common.Hash) (entity0.AggregationProof, error)
⋮----
// GetAggregationProof indicates an expected call of GetAggregationProof.
⋮----
// GetAggregationProofsByEpoch mocks base method.
func (m *Mockrepo) GetAggregationProofsByEpoch(ctx context.Context, epoch entity0.Epoch, pageSize int, from []byte) ([]entity0.AggregationProof, []byte, error)
⋮----
// GetAggregationProofsByEpoch indicates an expected call of GetAggregationProofsByEpoch.
⋮----
// GetAllSignatures mocks base method.
func (m *Mockrepo) GetAllSignatures(ctx context.Context, requestID common.Hash) ([]entity0.Signature, error)
⋮----
// GetAllSignatures indicates an expected call of GetAllSignatures.
⋮----
// GetLatestValidatorSetEpoch mocks base method.
func (m *Mockrepo) GetLatestValidatorSetEpoch(arg0 context.Context) (entity0.Epoch, error)
⋮----
// GetLatestValidatorSetEpoch indicates an expected call of GetLatestValidatorSetEpoch.
⋮----
// GetLatestValidatorSetHeader mocks base method.
func (m *Mockrepo) GetLatestValidatorSetHeader(arg0 context.Context) (entity0.ValidatorSetHeader, error)
⋮----
// GetLatestValidatorSetHeader indicates an expected call of GetLatestValidatorSetHeader.
⋮----
// GetSignatureRequest mocks base method.
func (m *Mockrepo) GetSignatureRequest(ctx context.Context, requestID common.Hash) (entity0.SignatureRequest, error)
⋮----
// GetSignatureRequest indicates an expected call of GetSignatureRequest.
⋮----
// GetSignatureRequestIDsByEpoch mocks base method.
func (m *Mockrepo) GetSignatureRequestIDsByEpoch(ctx context.Context, epoch entity0.Epoch, pageSize int, from []byte) ([]common.Hash, []byte, error)
⋮----
// GetSignatureRequestIDsByEpoch indicates an expected call of GetSignatureRequestIDsByEpoch.
⋮----
// GetSignatureRequestsWithIDByEpoch mocks base method.
func (m *Mockrepo) GetSignatureRequestsWithIDByEpoch(ctx context.Context, epoch entity0.Epoch, pageSize int, from []byte) ([]entity.SignatureRequestWithID, []byte, error)
⋮----
// GetSignatureRequestsWithIDByEpoch indicates an expected call of GetSignatureRequestsWithIDByEpoch.
⋮----
// GetSignaturesByEpoch mocks base method.
func (m *Mockrepo) GetSignaturesByEpoch(ctx context.Context, epoch entity0.Epoch, pageSize int, from []byte) ([]entity0.Signature, []byte, error)
⋮----
// GetSignaturesByEpoch indicates an expected call of GetSignaturesByEpoch.
⋮----
// GetValidatorSetByEpoch mocks base method.
func (m *Mockrepo) GetValidatorSetByEpoch(arg0 context.Context, epoch entity0.Epoch) (entity0.ValidatorSet, error)
⋮----
// GetValidatorSetByEpoch indicates an expected call of GetValidatorSetByEpoch.
⋮----
// GetValidatorSetMetadata mocks base method.
func (m *Mockrepo) GetValidatorSetMetadata(ctx context.Context, epoch entity0.Epoch) (entity0.ValidatorSetMetadata, error)
⋮----
// GetValidatorSetMetadata indicates an expected call of GetValidatorSetMetadata.
⋮----
// MockevmClient is a mock of evmClient interface.
type MockevmClient struct {
	ctrl     *gomock.Controller
	recorder *MockevmClientMockRecorder
	isgomock struct{}
⋮----
// MockevmClientMockRecorder is the mock recorder for MockevmClient.
type MockevmClientMockRecorder struct {
	mock *MockevmClient
}
⋮----
// NewMockevmClient creates a new mock instance.
func NewMockevmClient(ctrl *gomock.Controller) *MockevmClient
⋮----
// GetConfig mocks base method.
func (m *MockevmClient) GetConfig(ctx context.Context, timestamp entity0.Timestamp, epoch entity0.Epoch) (entity0.NetworkConfig, error)
⋮----
// GetConfig indicates an expected call of GetConfig.
⋮----
// GetCurrentEpoch mocks base method.
func (m *MockevmClient) GetCurrentEpoch(ctx context.Context) (entity0.Epoch, error)
⋮----
// GetCurrentEpoch indicates an expected call of GetCurrentEpoch.
⋮----
// GetEpochStart mocks base method.
func (m *MockevmClient) GetEpochStart(ctx context.Context, epoch entity0.Epoch) (entity0.Timestamp, error)
⋮----
// GetEpochStart indicates an expected call of GetEpochStart.
⋮----
// GetLastCommittedHeaderEpoch mocks base method.
func (m *MockevmClient) GetLastCommittedHeaderEpoch(ctx context.Context, addr entity0.CrossChainAddress, opts ...entity0.EVMOption) (entity0.Epoch, error)
⋮----
// GetLastCommittedHeaderEpoch indicates an expected call of GetLastCommittedHeaderEpoch.
⋮----
// Mockaggregator is a mock of aggregator interface.
type Mockaggregator struct {
	ctrl     *gomock.Controller
	recorder *MockaggregatorMockRecorder
	isgomock struct{}
⋮----
// MockaggregatorMockRecorder is the mock recorder for Mockaggregator.
type MockaggregatorMockRecorder struct {
	mock *Mockaggregator
}
⋮----
// NewMockaggregator creates a new mock instance.
func NewMockaggregator(ctrl *gomock.Controller) *Mockaggregator
⋮----
// GetAggregationStatus mocks base method.
func (m *Mockaggregator) GetAggregationStatus(ctx context.Context, requestID common.Hash) (entity0.AggregationStatus, error)
⋮----
// GetAggregationStatus indicates an expected call of GetAggregationStatus.
⋮----
// Mockderiver is a mock of deriver interface.
type Mockderiver struct {
	ctrl     *gomock.Controller
	recorder *MockderiverMockRecorder
	isgomock struct{}
⋮----
// MockderiverMockRecorder is the mock recorder for Mockderiver.
type MockderiverMockRecorder struct {
	mock *Mockderiver
}
⋮----
// NewMockderiver creates a new mock instance.
func NewMockderiver(ctrl *gomock.Controller) *Mockderiver
⋮----
// GetValidatorSet mocks base method.
func (m *Mockderiver) GetValidatorSet(ctx context.Context, epoch entity0.Epoch, config entity0.NetworkConfig) (entity0.ValidatorSet, error)
⋮----
// GetValidatorSet indicates an expected call of GetValidatorSet.
⋮----
// MockkeyProvider is a mock of keyProvider interface.
type MockkeyProvider struct {
	ctrl     *gomock.Controller
	recorder *MockkeyProviderMockRecorder
	isgomock struct{}
⋮----
// MockkeyProviderMockRecorder is the mock recorder for MockkeyProvider.
type MockkeyProviderMockRecorder struct {
	mock *MockkeyProvider
}
⋮----
// NewMockkeyProvider creates a new mock instance.
func NewMockkeyProvider(ctrl *gomock.Controller) *MockkeyProvider
⋮----
// GetOnchainKeyFromCache mocks base method.
func (m *MockkeyProvider) GetOnchainKeyFromCache(keyTag entity0.KeyTag) (entity0.CompactPublicKey, error)
⋮----
// GetOnchainKeyFromCache indicates an expected call of GetOnchainKeyFromCache.
```

## File: internal/usecase/api-server/app.go

```go
package api_server
⋮----
import (
	"context"
	"log/slog"
	"net"
	"net/http"
	"net/http/pprof"
	"strings"
	"time"

	"github.com/symbioticfi/relay/internal/usecase/broadcaster"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/metrics"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/server"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"net"
"net/http"
"net/http/pprof"
"strings"
"time"
⋮----
"github.com/symbioticfi/relay/internal/usecase/broadcaster"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/reflection"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/server"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
//go:generate mockgen -source=app.go -destination=mocks/app_mock.go -package=mocks
type signer interface {
	RequestSignature(ctx context.Context, req symbiotic.SignatureRequest) (common.Hash, error)
}
⋮----
type repo interface {
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	GetValidatorSetByEpoch(_ context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
	GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
	GetLatestValidatorSetHeader(_ context.Context) (symbiotic.ValidatorSetHeader, error)
	GetLatestValidatorSetEpoch(_ context.Context) (symbiotic.Epoch, error)
	GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)
	// Listing methods. `from` is an opaque cursor returned by a previous call (nil to start).
	// Returns (items, nextFrom, err). nextFrom == nil signals last page.
	// Invalid `from` (wrong size / format) returns entity.ErrInvalidCursor.
	GetSignatureRequestIDsByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]common.Hash, []byte, error)
	GetSignatureRequestsWithIDByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]entity.SignatureRequestWithID, []byte, error)
	GetSignaturesByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]symbiotic.Signature, []byte, error)
	GetAggregationProofsByEpoch(ctx context.Context, epoch symbiotic.Epoch, pageSize int, from []byte) ([]symbiotic.AggregationProof, []byte, error)
}
⋮----
// Listing methods. `from` is an opaque cursor returned by a previous call (nil to start).
// Returns (items, nextFrom, err). nextFrom == nil signals last page.
// Invalid `from` (wrong size / format) returns entity.ErrInvalidCursor.
⋮----
type evmClient interface {
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, opts ...symbiotic.EVMOption) (_ symbiotic.Epoch, err error)
}
⋮----
type aggregator interface {
	GetAggregationStatus(ctx context.Context, requestID common.Hash) (symbiotic.AggregationStatus, error)
}
⋮----
type deriver interface {
	GetValidatorSet(ctx context.Context, epoch symbiotic.Epoch, config symbiotic.NetworkConfig) (symbiotic.ValidatorSet, error)
}
⋮----
type keyProvider interface {
	GetOnchainKeyFromCache(keyTag symbiotic.KeyTag) (symbiotic.CompactPublicKey, error)
}
⋮----
type Config struct {
	Address           string        `validate:"required"`
	ReadHeaderTimeout time.Duration `validate:"required,gt=0"`
	ShutdownTimeout   time.Duration `validate:"required,gt=0"`

	Signer                 signer      `validate:"required"`
	Repo                   repo        `validate:"required"`
	EvmClient              evmClient   `validate:"required"`
	Deriver                deriver     `validate:"required"`
	KeyProvider            keyProvider `validate:"required"`
	Aggregator             aggregator
	ServeMetrics           bool
	ServePprof             bool
	ServeHTTPGateway       bool
	Metrics                *metrics.Metrics `validate:"required"`
	VerboseLogging         bool
	MaxAllowedStreamsCount int `validate:"required,gt=0"`
}
⋮----
func (c Config) Validate() error
⋮----
// grpcHandler implements the gRPC service interface
type grpcHandler struct {
	apiv1.SymbioticAPIServiceServer

	cfg Config

	proofsHub        *broadcaster.Hub[symbiotic.AggregationProof]
	signatureHub     *broadcaster.Hub[symbiotic.Signature]
	validatorSetsHub *broadcaster.Hub[symbiotic.ValidatorSet]
}
type SymbioticServer struct {
	grpcServer       *grpc.Server
	httpServer       *http.Server
	listener         net.Listener
	cfg              Config
	handler          *grpcHandler
	startGatewayFunc func() error
}
⋮----
func NewSymbioticServer(ctx context.Context, cfg Config) (*SymbioticServer, error)
⋮----
// Create listener
⋮----
// Create gRPC server with interceptors
⋮----
//nolint:contextcheck // the context comes from th stream
⋮----
// Create and register the handler
⋮----
// Register health service
⋮----
// Register reflection service for development
⋮----
// Create HTTP server for documentation with panic recovery
⋮----
// Wrap the entire mux with panic recovery
⋮----
// Register HTTP gateway if enabled
var startGatewayFunc func() error
⋮----
// Root redirect to docs
⋮----
// Health check endpoint
⋮----
// Debug pprof endpoints if enabled
⋮----
// Serve API documentation
⋮----
// Serve metrics endpoint if enabled
⋮----
// Create HTTP/2 server that can handle both HTTP and gRPC
⋮----
// createMuxHandler creates a handler that multiplexes between gRPC and HTTP
func createMuxHandler(grpcServer *grpc.Server, httpHandler http.Handler) http.Handler
⋮----
// Check if this is a gRPC request
⋮----
// Handle gRPC request
⋮----
// Handle as HTTP request (documentation, health checks, etc.)
⋮----
func (a *SymbioticServer) Start(ctx context.Context) error
⋮----
// Start serving in a goroutine
⋮----
// Initialize HTTP gateway connection after server starts
⋮----
// Retry connection to gRPC server with exponential backoff
const maxRetries = 5
var lastErr error
⋮----
// Wait for context cancellation or server error
⋮----
// Graceful shutdown with timeout
⋮----
// Shutdown HTTP server
//nolint:contextcheck // we need to use background context here as the original context is already cancelled
⋮----
// Force stop gRPC server
⋮----
// Graceful stop for gRPC server
⋮----
func (a *SymbioticServer) HandleProofAggregated() func(context.Context, symbiotic.AggregationProof) error
⋮----
func (a *SymbioticServer) HandleSignatureProcessed() func(context.Context, symbiotic.Signature) error
⋮----
func (a *SymbioticServer) HandleValidatorSet() func(context.Context, symbiotic.ValidatorSet) error
```

## File: internal/usecase/api-server/get_aggregation_proof_v1_test.go

```go
package api_server
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetAggregationProof_Success_ReturnsProof(t *testing.T)
⋮----
func TestGetAggregationProof_NotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetAggregationProof_RepositoryError_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_aggregation_proof_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
// GetAggregationProof handles the gRPC GetAggregationProof request
func (h *grpcHandler) GetAggregationProof(ctx context.Context, req *apiv1.GetAggregationProofRequest) (*apiv1.GetAggregationProofResponse, error)
⋮----
func convertAggregationProofToPB(proof symbiotic.AggregationProof) *apiv1.AggregationProof
```

## File: internal/usecase/api-server/get_aggregation_proofs_by_epoch_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetAggregationProofsByEpoch_Success(t *testing.T)
⋮----
func TestGetAggregationProofsByEpoch_EmptyResult(t *testing.T)
⋮----
func TestGetAggregationProofsByEpoch_RepositoryError(t *testing.T)
```

## File: internal/usecase/api-server/get_aggregation_proofs_by_epoch_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	"github.com/samber/lo"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (h *grpcHandler) GetAggregationProofsByEpoch(ctx context.Context, req *apiv1.GetAggregationProofsByEpochRequest) (*apiv1.GetAggregationProofsByEpochResponse, error)
```

## File: internal/usecase/api-server/get_aggregation_status_v1_test.go

```go
package api_server
⋮----
import (
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetAggregationStatus_Success_ReturnsStatusWithSortedOperators(t *testing.T)
⋮----
func TestGetAggregationStatus_NoAggregator_ReturnsError(t *testing.T)
⋮----
func TestGetAggregationStatus_NotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetAggregationStatus_AggregatorError_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_aggregation_status_v1.go

```go
package api_server
⋮----
import (
	"context"
	"sort"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"sort"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetAggregationStatus handles the gRPC GetAggregationStatus request
func (h *grpcHandler) GetAggregationStatus(ctx context.Context, req *apiv1.GetAggregationStatusRequest) (*apiv1.GetAggregationStatusResponse, error)
```

## File: internal/usecase/api-server/get_current_epoch_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetCurrentEpoch_Success_ReturnsEpochAndStartTime(t *testing.T)
⋮----
captureTimestamp := symbiotic.Timestamp(1640995200) // 2022-01-01 00:00:00 UTC
⋮----
func TestGetCurrentEpoch_NotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetCurrentEpoch_RepositoryError_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_current_epoch_v1.go

```go
package api_server
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/timestamppb"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
⋮----
// GetCurrentEpoch handles the gRPC GetCurrentEpoch request
func (h *grpcHandler) GetCurrentEpoch(ctx context.Context, req *apiv1.GetCurrentEpochRequest) (*apiv1.GetCurrentEpochResponse, error)
```

## File: internal/usecase/api-server/get_custom_schedule_node_status_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetCustomScheduleNodeStatus(t *testing.T)
⋮----
slotDuration := uint64(60) // 60 seconds per slot
⋮----
// IsActive can be true or false depending on the schedule
⋮----
SlotDurationSeconds:    0, // Invalid
⋮----
MaxParticipantsPerSlot: 0, // Invalid
⋮----
MinParticipantsPerSlot: 5, // Greater than max
⋮----
// Mark all validators as inactive
⋮----
// Verify slot times are populated
⋮----
// Verify slot duration is correct
⋮----
// Set local key to an inactive validator
⋮----
require.False(t, response.GetIsActive()) // Should return false, not error
⋮----
// Verify slot times are still populated even when inactive (showing current slot)
⋮----
// Test the schedule algorithm logic
func TestIsNodeActiveInCustomSchedule_SingleValidator(t *testing.T)
⋮----
currentSlot := uint64(0) // First slot
⋮----
1, // max 1 per slot
1, // min 1 per slot
⋮----
// With only 1 active validator, it should always be active in slot 0
⋮----
func TestIsNodeActiveInCustomSchedule_MultipleValidators(t *testing.T)
⋮----
// Test that the validator is active in exactly one slot per cycle
⋮----
// Should find at least one active slot
⋮----
func TestGetCurrentSlot_BeforeEpochStart(t *testing.T)
⋮----
return epochStart.Add(-30 * time.Second) // Before epoch start
⋮----
// Should return an error when current time is before epoch start
⋮----
func TestIsNodeActiveInCustomSchedule_NotInValidatorSet(t *testing.T)
⋮----
// Should not be active if address is not in validator set
⋮----
func TestIsNodeActiveInCustomSchedule_DifferentSeeds(t *testing.T)
⋮----
// Different seeds should potentially produce different schedules
⋮----
func TestIsNodeActiveInCustomSchedule_GroupCycling(t *testing.T)
⋮----
// With 2 validators and max 1 per slot, we have 2 groups
// Groups should cycle: slot 0 -> group 0, slot 1 -> group 1, slot 2 -> group 0, etc.
⋮----
0, // Slot 0
⋮----
2, // Slot 2 (should cycle back)
⋮----
// Slot 0 and slot 2 should have the same status (cycling)
⋮----
func TestIsNodeActiveInCustomSchedule_RemainderGroup(t *testing.T)
⋮----
// With 2 validators, max 3, min 1: should create 1 group with 2 validators
// (remainder 2 >= min 1, but since it's less than a full group, all go in one group)
⋮----
3, // max 3 per slot
⋮----
// At least one validator should be active in slot 0
⋮----
func TestIsNodeActiveInCustomSchedule_MultipleValidatorsInSameGroup(t *testing.T)
⋮----
// With 2 validators, max 2, min 1: should create 1 group with both validators
⋮----
2, // max 2 per slot - both validators fit in one group
⋮----
// BOTH validators should be active in the same slot since they're in the same group
⋮----
func TestIsNodeActiveInCustomSchedule_TooFewValidators(t *testing.T)
⋮----
// With 2 validators, max 5, min 3: no valid groups can be formed
// (remainder 2 < min 3)
⋮----
5, // max 5 per slot
3, // min 3 per slot
⋮----
// Should return an error when no valid groups can be formed
⋮----
func TestGetCurrentSlot(t *testing.T)
⋮----
// Test slot 0 (0-60 seconds)
⋮----
// Test slot 1 (60-120 seconds)
⋮----
func TestCreateSeededRNG(t *testing.T)
⋮----
// Same seed should produce same sequence
⋮----
// Different seeds should produce different sequences (with high probability)
⋮----
// Different epochs should produce different sequences (with high probability)
```

## File: internal/usecase/api-server/get_custom_schedule_node_status_v1.go

```go
package api_server
⋮----
import (
	"context"
	"crypto/sha256"
	"encoding/binary"
	"math/rand"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/timestamppb"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"crypto/sha256"
"encoding/binary"
"math/rand"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetCustomScheduleNodeStatus handles the gRPC GetCustomScheduleNodeStatus request
func (h *grpcHandler) GetCustomScheduleNodeStatus(ctx context.Context, req *apiv1.GetCustomScheduleNodeStatusRequest) (*apiv1.GetCustomScheduleNodeStatusResponse, error)
⋮----
// Validate request parameters
⋮----
// Get the latest epoch if not provided
⋮----
// Validate epoch is not from the future
⋮----
// Get validator set for the epoch
⋮----
// Get epoch start time
⋮----
// Get local validator address
⋮----
// Dev: currently only returns schedule for active validators so returning false if not active in valset
⋮----
// Check if node is active in the custom schedule
⋮----
// getCurrentSlot calculates the current slot number and its start time based on epoch start time and slot duration
// Returns: currentSlot, slotStartTime, error
func getCurrentSlot(
	epochStartTime time.Time,
	currentTimeFunc func() time.Time,
	slotDurationSeconds uint64,
) (uint64, time.Time, error)
⋮----
// Calculate current slot number
⋮----
// Current time is before epoch start
⋮----
// Calculate slot start and end times
⋮----
// isNodeActiveInCustomSchedule checks if the node is active at the current time in a custom schedule
// Returns: isActive, slotStartTime, slotEndTime, error
func isNodeActiveInCustomSchedule(
	activeValidators symbiotic.Validators,
	epoch symbiotic.Epoch,
	seed []byte,
	currentSlot uint64,
	maxParticipantsPerSlot uint32,
	minParticipantsPerSlot uint32,
	localAddress common.Address,
) (bool, error)
⋮----
// Create a deterministic random number generator seeded with epoch and seed
⋮----
// Create shuffled indices array
⋮----
// Fisher-Yates shuffle
⋮----
// Calculate number of groups based on max and min constraints
⋮----
// If no valid groups can be formed, no validator is active
⋮----
// Groups cycle through slots using modulo
⋮----
// Check if local validator is in the current group
⋮----
// createSeededRNG creates a deterministic random number generator seeded with epoch and seed bytes
func createSeededRNG(epoch symbiotic.Epoch, seed []byte) *rand.Rand
⋮----
// Create a deterministic seed by combining epoch and seed
⋮----
// Get hash and convert to int64 seed
⋮----
// Create new random source and generator
⋮----
return rand.New(source) //nolint:gosec // we need deterministic randomness here so need to use math/rand
```

## File: internal/usecase/api-server/get_last_all_committed_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
⋮----
func TestGetLastAllCommitted_Success_ReturnsAllChainsWithMinimum(t *testing.T)
⋮----
func TestGetLastAllCommitted_GetConfigFails_ReturnsError(t *testing.T)
⋮----
func TestGetLastAllCommitted_GetLastCommittedEpochFails_ReturnsError(t *testing.T)
⋮----
func TestGetLastAllCommitted_GetEpochStartFails_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_last_all_committed_v1.go

```go
package api_server
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/internal/entity"
	"google.golang.org/protobuf/types/known/timestamppb"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/internal/entity"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetLastAllCommitted handles the gRPC GetLastAllCommitted request
func (h *grpcHandler) GetLastAllCommitted(ctx context.Context, _ *apiv1.GetLastAllCommittedRequest) (*apiv1.GetLastAllCommittedResponse, error)
⋮----
var minLastCommited *apiv1.ChainEpochInfo
```

## File: internal/usecase/api-server/get_last_committed_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
⋮----
func TestGetLastCommitted_Success_ReturnsLastCommittedEpoch(t *testing.T)
⋮----
func TestGetLastCommitted_ZeroChainID_ReturnsInvalidArgumentError(t *testing.T)
⋮----
func TestGetLastCommitted_ChainNotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetLastCommitted_GetLastCommittedHeaderEpochFails_ReturnsError(t *testing.T)
⋮----
func TestGetLastCommitted_GetEpochStartFails_ReturnsError(t *testing.T)
⋮----
func TestGetLastCommitted_GetConfigFails_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_last_committed_v1.go

```go
package api_server
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/internal/entity"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/timestamppb"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/internal/entity"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetLastCommitted handles the gRPC GetLastCommitted request
func (h *grpcHandler) GetLastCommitted(ctx context.Context, req *apiv1.GetLastCommittedRequest) (*apiv1.GetLastCommittedResponse, error)
⋮----
var settlementChain *symbiotic.CrossChainAddress
⋮----
// TODO: Get the epoch start time
```

## File: internal/usecase/api-server/get_local_validator_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetLocalValidator_Success(t *testing.T)
⋮----
func TestGetLocalValidator_UseCurrentEpoch(t *testing.T)
⋮----
func TestGetLocalValidator_ErrorWhenEpochFromFuture(t *testing.T)
⋮----
func TestGetLocalValidator_ErrorWhenKeyProviderFails(t *testing.T)
⋮----
func TestGetLocalValidator_ErrorWhenValidatorNotFound(t *testing.T)
⋮----
func TestGetLocalValidator_ErrorWhenRepositoryFails(t *testing.T)
```

## File: internal/usecase/api-server/get_local_validator_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetLocalValidator handles the gRPC GetLocalValidator request
func (h *grpcHandler) GetLocalValidator(ctx context.Context, req *apiv1.GetLocalValidatorRequest) (*apiv1.GetLocalValidatorResponse, error)
```

## File: internal/usecase/api-server/get_signature_request_ids_by_epoch_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetSignatureRequestIDsByEpoch_Success(t *testing.T)
⋮----
func TestGetSignatureRequestIDsByEpoch_EmptyResult(t *testing.T)
⋮----
func TestGetSignatureRequestIDsByEpoch_RepositoryError(t *testing.T)
```

## File: internal/usecase/api-server/get_signature_request_ids_by_epoch_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (h *grpcHandler) GetSignatureRequestIDsByEpoch(ctx context.Context, req *apiv1.GetSignatureRequestIDsByEpochRequest) (*apiv1.GetSignatureRequestIDsByEpochResponse, error)
```

## File: internal/usecase/api-server/get_signature_request_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetSignatureRequest_Success(t *testing.T)
⋮----
// Verify request ID is included
⋮----
func TestGetSignatureRequest_NotFound(t *testing.T)
⋮----
// Check that it's a NotFound error
⋮----
func TestGetSignatureRequest_RepositoryError(t *testing.T)
```

## File: internal/usecase/api-server/get_signature_request_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
⋮----
// GetSignatureRequest handles the gRPC GetSignatureRequest request
func (h *grpcHandler) GetSignatureRequest(ctx context.Context, req *apiv1.GetSignatureRequestRequest) (*apiv1.GetSignatureRequestResponse, error)
```

## File: internal/usecase/api-server/get_signature_requests_by_epoch_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetSignatureRequestsByEpoch_Success(t *testing.T)
⋮----
// Verify first request
⋮----
// Verify second request
⋮----
func TestGetSignatureRequestsByEpoch_EmptyResult(t *testing.T)
⋮----
func TestGetSignatureRequestsByEpoch_RepositoryError(t *testing.T)
```

## File: internal/usecase/api-server/get_signature_requests_by_epoch_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	"github.com/samber/lo"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (h *grpcHandler) GetSignatureRequestsByEpoch(ctx context.Context, req *apiv1.GetSignatureRequestsByEpochRequest) (*apiv1.GetSignatureRequestsByEpochResponse, error)
```

## File: internal/usecase/api-server/get_signature_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetSignatures handles the gRPC GetSignatures request
func (h *grpcHandler) GetSignatures(ctx context.Context, req *apiv1.GetSignaturesRequest) (*apiv1.GetSignaturesResponse, error)
⋮----
func convertSignaturesToPB(signatures []symbiotic.Signature) []*apiv1.Signature
⋮----
func convertSignatureToPB(sig symbiotic.Signature) *apiv1.Signature
```

## File: internal/usecase/api-server/get_signatures_by_epoch_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestGetSignaturesByEpoch_Success(t *testing.T)
⋮----
func TestGetSignaturesByEpoch_EmptyResult(t *testing.T)
⋮----
func TestGetSignaturesByEpoch_RepositoryError(t *testing.T)
```

## File: internal/usecase/api-server/get_signatures_by_epoch_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/go-errors/errors"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (h *grpcHandler) GetSignaturesByEpoch(ctx context.Context, req *apiv1.GetSignaturesByEpochRequest) (*apiv1.GetSignaturesByEpochResponse, error)
```

## File: internal/usecase/api-server/get_signatures_v1_test.go

```go
package api_server
⋮----
import (
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestGetSignatures_Success_ReturnsAllSignatures(t *testing.T)
⋮----
func TestGetSignatures_NotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetSignatures_RepositoryError_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_validator_by_address_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetValidatorByAddress_ValidatorFoundInRepo(t *testing.T)
⋮----
// Create test data
⋮----
expectedValidator := validatorSet.Validators[0] // First validator has address 0x123
⋮----
// Setup mocks - validator set found in repository
⋮----
// Execute the method under test
⋮----
// Assertions
⋮----
func TestGetValidatorByAddress_ValidatorSetNotInRepo_DerivedFail(t *testing.T)
⋮----
// Setup mocks - validator set not in repository, needs to be derived
⋮----
func TestGetValidatorByAddress_UseCurrentEpoch_WhenNoEpochSpecified(t *testing.T)
⋮----
// Setup mocks - no epoch specified, should use current epoch
⋮----
// Execute the method under test - no epoch specified
⋮----
func TestGetValidatorByAddress_ErrorWhenEpochFromFuture(t *testing.T)
⋮----
// Setup mocks
⋮----
func TestGetValidatorByAddress_ErrorWhenInvalidAddress(t *testing.T)
⋮----
func TestGetValidatorByAddress_ErrorWhenValidatorNotFound(t *testing.T)
⋮----
// Create test data without the requested validator
⋮----
func TestGetValidatorByAddress_ErrorWhenGetCurrentEpochFails(t *testing.T)
⋮----
func TestGetValidatorByAddress_ErrorWhenRepositoryFails(t *testing.T)
```

## File: internal/usecase/api-server/get_validator_by_address_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetValidatorByAddress handles the gRPC GetValidatorByAddress request
func (h *grpcHandler) GetValidatorByAddress(ctx context.Context, req *apiv1.GetValidatorByAddressRequest) (*apiv1.GetValidatorByAddressResponse, error)
⋮----
// epoch from future
⋮----
// parse validator address
⋮----
// get validator set for the epoch
⋮----
// find validator by address
```

## File: internal/usecase/api-server/get_validator_by_key_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetValidatorByKey_Success(t *testing.T)
⋮----
func TestGetValidatorByKey_UseCurrentEpoch(t *testing.T)
⋮----
func TestGetValidatorByKey_ErrorWhenEpochFromFuture(t *testing.T)
⋮----
func TestGetValidatorByKey_ErrorWhenKeyTagIsZero(t *testing.T)
⋮----
func TestGetValidatorByKey_ErrorWhenOnChainKeyIsEmpty(t *testing.T)
⋮----
func TestGetValidatorByKey_ErrorWhenValidatorNotFound(t *testing.T)
⋮----
func TestGetValidatorByKey_ErrorWhenRepositoryFails(t *testing.T)
```

## File: internal/usecase/api-server/get_validator_by_key_v1.go

```go
package api_server
⋮----
import (
	"bytes"
	"context"

	"github.com/go-errors/errors"
	"github.com/samber/lo"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
⋮----
"bytes"
"context"
⋮----
"github.com/go-errors/errors"
"github.com/samber/lo"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
// GetValidatorByKey handles the gRPC GetValidatorByKey request
func (h *grpcHandler) GetValidatorByKey(ctx context.Context, req *apiv1.GetValidatorByKeyRequest) (*apiv1.GetValidatorByKeyResponse, error)
```

## File: internal/usecase/api-server/get_validator_set_header_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetValidatorSetHeader_ValidatorSetFoundInRepo(t *testing.T)
⋮----
// Create test data
⋮----
expectedHeader, err := validatorSet.GetHeader() // Use the real GetHeader method
⋮----
// Setup mocks - validator set found in repository
⋮----
// Execute the method under test
⋮----
// Assertions
⋮----
func TestGetValidatorSetHeader_UseCurrentEpoch_WhenNoEpochSpecified(t *testing.T)
⋮----
// Setup mocks - no epoch specified, should use current epoch
⋮----
// Execute the method under test - no epoch specified
⋮----
func TestGetValidatorSetHeader_ErrorWhenEpochFromFuture(t *testing.T)
⋮----
// Setup mocks
⋮----
func TestGetValidatorSetHeader_ErrorWhenGetCurrentEpochFails(t *testing.T)
⋮----
func TestGetValidatorSetHeader_ErrorWhenRepositoryFails(t *testing.T)
```

## File: internal/usecase/api-server/get_validator_set_header_v1.go

```go
package api_server
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/timestamppb"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetValidatorSetHeader handles the gRPC GetValidatorSetHeader request
func (h *grpcHandler) GetValidatorSetHeader(ctx context.Context, req *apiv1.GetValidatorSetHeaderRequest) (*apiv1.GetValidatorSetHeaderResponse, error)
⋮----
// epoch from future
⋮----
// get header from validator set
```

## File: internal/usecase/api-server/get_validator_set_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetValidatorSet_WithoutEpoch_ReturnsLatestValidatorSet(t *testing.T)
⋮----
func TestGetValidatorSet_WithSpecificEpoch_ReturnsRequestedValidatorSet(t *testing.T)
⋮----
func TestGetValidatorSet_FutureEpoch_ReturnsInvalidArgumentError(t *testing.T)
⋮----
func TestGetValidatorSet_GetLatestEpochFails_ReturnsError(t *testing.T)
⋮----
func TestConvertValidatorSetStatusToPB_AllStatuses(t *testing.T)
```

## File: internal/usecase/api-server/get_validator_set_v1.go

```go
package api_server
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/timestamppb"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetValidatorSet handles the gRPC GetValidatorSet request
func (h *grpcHandler) GetValidatorSet(ctx context.Context, req *apiv1.GetValidatorSetRequest) (*apiv1.GetValidatorSetResponse, error)
⋮----
// epoch from future
⋮----
// getValidatorSetForEpoch retrieves validator set for a given epoch, either from repo or by deriving it
func (h *grpcHandler) getValidatorSetForEpoch(ctx context.Context, epochRequested symbiotic.Epoch) (symbiotic.ValidatorSet, error)
⋮----
func convertValidatorSetToPB(valSet symbiotic.ValidatorSet) *apiv1.ValidatorSet
⋮----
func convertValidatorToPB(v symbiotic.Validator) *apiv1.Validator
⋮----
func convertValidatorSetStatusToPB(status symbiotic.ValidatorSetStatus) apiv1.ValidatorSetStatus
```

## File: internal/usecase/api-server/get_validatorset_metadata_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetValidatorSetMetadata_WithoutEpoch_ReturnsLatestMetadata(t *testing.T)
⋮----
func TestGetValidatorSetMetadata_WithEpoch_ReturnsMetadataForEpoch(t *testing.T)
⋮----
func TestGetValidatorSetMetadata_NotFound_ReturnsNotFoundError(t *testing.T)
⋮----
func TestGetValidatorSetMetadata_RepositoryError_ReturnsError(t *testing.T)
⋮----
func TestGetValidatorSetMetadata_GetLatestEpochFails_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/get_validatorset_metadata_v1.go

```go
package api_server
⋮----
import (
	"context"

	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/go-errors/errors"
"github.com/samber/lo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// GetValidatorSetMetadata handles the gRPC GetValidatorSetMetadata request
func (h *grpcHandler) GetValidatorSetMetadata(ctx context.Context, req *apiv1.GetValidatorSetMetadataRequest) (*apiv1.GetValidatorSetMetadataResponse, error)
⋮----
var epochRequested symbiotic.Epoch
```

## File: internal/usecase/api-server/helpers_test.go

```go
package api_server
⋮----
import (
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
)
⋮----
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
deriverMocks "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
⋮----
// testSetup contains all the mocks and test helper functions
// This unified setup can be used for all API server endpoint tests
type testSetup struct {
	ctrl          *gomock.Controller
	mockEvmClient *deriverMocks.MockEvmClient
	mockRepo      *mocks.Mockrepo
	mockDeriver   *mocks.Mockderiver
	handler       *grpcHandler
}
⋮----
// newTestSetup creates a new test setup with mocked dependencies
// This reuses the same construction pattern as production code
func newTestSetup(t *testing.T) *testSetup
⋮----
// Create Config using the same structure as production
⋮----
Address:           ":8080", // not used in unit tests
⋮----
// Inject mocked dependencies
⋮----
// Create grpcHandler using the same pattern as production
⋮----
// createTestValidatorSet creates a sample validator set for testing
// This is the simpler version used for GetValidatorSetHeader tests
func createTestValidatorSet(epoch symbiotic.Epoch) symbiotic.ValidatorSet
⋮----
CaptureTimestamp: 1640995200, // 2022-01-01 00:00:00 UTC
⋮----
// createTestValidatorSetWithMultipleValidators creates a sample validator set with multiple validators for testing
// This is the richer version used for GetValidatorByAddress tests
func createTestValidatorSetWithMultipleValidators(epoch symbiotic.Epoch) symbiotic.ValidatorSet
```

## File: internal/usecase/api-server/http_test.go

```go
package api_server
⋮----
import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/go-errors/errors"
)
⋮----
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
⋮----
"github.com/go-errors/errors"
⋮----
// mockFlusher implements http.Flusher for testing
type mockFlusher struct {
	flushCount int
}
⋮----
func (m *mockFlusher) Flush()
⋮----
// mockResponseWriter implements http.ResponseWriter and http.Flusher for testing
type mockResponseWriter struct {
	mockFlusher

	header     http.Header
	body       bytes.Buffer
	statusCode int
}
⋮----
func newMockResponseWriter() *mockResponseWriter
⋮----
func (m *mockResponseWriter) Header() http.Header
⋮----
func (m *mockResponseWriter) Write(b []byte) (int, error)
⋮----
func (m *mockResponseWriter) WriteHeader(statusCode int)
⋮----
func TestSSEResponseWriter_CompleteMessages(t *testing.T)
⋮----
// Write complete JSON messages
⋮----
// Check output is in SSE format
⋮----
// Check that flush was called for each message
⋮----
// Verify headers were set correctly
⋮----
func TestSSEResponseWriter_PartialWrites(t *testing.T)
⋮----
// Simulate json.Encoder behavior: writes in chunks without newline
⋮----
// Write chunks one by one
⋮----
// After first write, no output should be produced (no complete line yet)
⋮----
// Still no output (no newline yet)
⋮----
// Now we should have complete output
⋮----
// Should have flushed once (after complete line)
⋮----
func TestSSEResponseWriter_EmptyLines(t *testing.T)
⋮----
// Write with empty lines
⋮----
// Empty lines should be skipped
⋮----
func TestSSEResponseWriter_MultipleMessagesWithPartials(t *testing.T)
⋮----
// Write complete message followed by partial
⋮----
// Check that first message was output
⋮----
// Complete the partial message
⋮----
// Now both messages should be present
⋮----
func TestSSEResponseWriter_BufferOverflow(t *testing.T)
⋮----
// Create a message larger than 5MB (the maxBufferSize) without newline
⋮----
func TestSSEResponseWriter_WriteError(t *testing.T)
⋮----
// Create a mock that fails on write
⋮----
// Should still return the bytes we accepted from input
⋮----
// failingResponseWriter always fails on Write
type failingResponseWriter struct {
	header http.Header
}
⋮----
func TestSSEResponseWriter_BufferPersistence(t *testing.T)
⋮----
// Write partial message
⋮----
// Check buffer contains partial data
⋮----
// Write more partial data
⋮----
// Buffer should have grown
⋮----
// Complete the message
⋮----
// Buffer should be empty (or contain only remaining data)
⋮----
// Verify complete message was output
⋮----
func TestSSEResponseWriter_EmptyWrite(t *testing.T)
⋮----
// Write empty data
⋮----
// Should produce no output
⋮----
func TestSSEResponseWriter_NilFlusher(t *testing.T)
⋮----
flusher:        nil, // nil flusher
⋮----
// Write should fail with nil flusher
⋮----
func TestSSEResponseWriter_ConcurrentWrites(t *testing.T)
⋮----
// Perform concurrent writes
const numGoroutines = 10
⋮----
// Wait for all goroutines
⋮----
// Should have written all messages (order may vary due to concurrency)
⋮----
func TestSSEResponseWriter_FlushWithNilFlusher(t *testing.T)
⋮----
// Flush should not panic with nil flusher
⋮----
func TestSSEResponseWriter_RealWorldScenario(t *testing.T)
⋮----
// Simulate real httptest.ResponseRecorder behavior
⋮----
// Simulate json.Encoder writing large objects in chunks
// This is the actual problematic scenario described in the issue
⋮----
// Simulate chunked writes (what json.Encoder does)
⋮----
// Don't add newline until the end
⋮----
// Verify the complete JSON was output as a single SSE event
⋮----
// Count number of SSE events (should be 1)
⋮----
// Verify the JSON is complete and valid
```

## File: internal/usecase/api-server/http.go

```go
package api_server
⋮----
import (
	"bytes"
	"context"
	"fmt"
	"io"
	"log/slog"
	"net/http"
	"strings"
	"sync"

	"github.com/go-errors/errors"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)
⋮----
"bytes"
"context"
"fmt"
"io"
"log/slog"
"net/http"
"strings"
"sync"
⋮----
"github.com/go-errors/errors"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
⋮----
const maxBufferSize = 5 * 1024 * 1024 // 5MB
⋮----
// sseResponseWriter wraps http.ResponseWriter to convert newline-delimited JSON to SSE format
type sseResponseWriter struct {
	http.ResponseWriter

	flusher        http.Flusher
	headersWritten bool
	buffer         bytes.Buffer // Buffer for incomplete lines
	mu             sync.Mutex   // Protect buffer from concurrent writes
}
⋮----
buffer         bytes.Buffer // Buffer for incomplete lines
mu             sync.Mutex   // Protect buffer from concurrent writes
⋮----
// WriteHeader intercepts header writes to set SSE headers
func (s *sseResponseWriter) WriteHeader(statusCode int)
⋮----
// Override content-type for SSE
⋮----
func (s *sseResponseWriter) Write(b []byte) (int, error)
⋮----
// Process complete lines (those ending with \n)
⋮----
// No complete line yet - restore partial data to buffer
// ReadBytes with EOF consumes all data from buffer, so we put it back
⋮----
// Unexpected error from ReadBytes
⋮----
// Write in SSE format: data: {json}\n\n
⋮----
// Return the number of bytes we accepted from the input
⋮----
func (s *sseResponseWriter) Flush()
⋮----
// setupHttpProxy configures the HTTP-to-gRPC gateway proxy
// Returns a start function that should be called after the gRPC server starts listening
func setupHttpProxy(ctx context.Context, grpcAddr string, httpMux *http.ServeMux) func() error
⋮----
// Create gRPC client connection to the actual gRPC server via TCP
⋮----
grpc.MaxCallRecvMsgSize(10*1024*1024), // 10MB
grpc.MaxCallSendMsgSize(10*1024*1024), // 10MB
⋮----
var conn *grpc.ClientConn
⋮----
// Start function that will be called after gRPC server is listening
⋮----
var err error
⋮----
// Mount the gateway under /api prefix with CORS and streaming support
⋮----
// Check if gateway is initialized
⋮----
// Set CORS headers
⋮----
w.Header().Set("Access-Control-Max-Age", "86400") // 24 hours
⋮----
// Handle preflight OPTIONS request
⋮----
// For streaming endpoints, wrap the response writer to intercept and convert to SSE
⋮----
// Wrap with SSE writer that will handle headers and format conversion
```

## File: internal/usecase/api-server/interceptors_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
func TestConvertToGRPCError_NilError_ReturnsNil(t *testing.T)
⋮----
func TestConvertToGRPCError_AlreadyGRPCError_ReturnsAsIs(t *testing.T)
⋮----
func TestConvertToGRPCError_ErrNotAnAggregator_ReturnsPermissionDenied(t *testing.T)
⋮----
func TestConvertToGRPCError_ErrEntityNotFound_ReturnsNotFound(t *testing.T)
⋮----
func TestConvertToGRPCError_ErrChainNotFound_ReturnsNotFound(t *testing.T)
⋮----
func TestConvertToGRPCError_ErrEntityAlreadyExist_ReturnsAlreadyExists(t *testing.T)
⋮----
func TestConvertToGRPCError_ErrNoPeers_ReturnsUnavailable(t *testing.T)
⋮----
func TestConvertToGRPCError_ContextCanceled_ReturnsCanceled(t *testing.T)
⋮----
func TestConvertToGRPCError_ContextDeadlineExceeded_ReturnsDeadlineExceeded(t *testing.T)
⋮----
func TestConvertToGRPCError_UnknownError_ReturnsInternal(t *testing.T)
⋮----
func TestErrorHandlingInterceptor_HandlerReturnsNil_ReturnsSuccess(t *testing.T)
⋮----
func TestErrorHandlingInterceptor_HandlerReturnsError_ConvertsError(t *testing.T)
⋮----
func TestErrorHandlingInterceptor_HandlerReturnsGRPCError_ReturnsAsIs(t *testing.T)
⋮----
type mockServerStream struct {
	grpc.ServerStream

	ctx context.Context
}
⋮----
func (m *mockServerStream) Context() context.Context
⋮----
func TestStreamErrorHandlingInterceptor_HandlerReturnsNil_ReturnsSuccess(t *testing.T)
⋮----
func TestStreamErrorHandlingInterceptor_HandlerReturnsError_ConvertsError(t *testing.T)
⋮----
func TestStreamErrorHandlingInterceptor_HandlerReturnsGRPCError_ReturnsAsIs(t *testing.T)
```

## File: internal/usecase/api-server/interceptors.go

```go
package api_server
⋮----
import (
	"context"
	"log/slog"

	"github.com/go-errors/errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
// convertToGRPCError converts internal errors to gRPC status errors
func convertToGRPCError(ctx context.Context, err error) error
⋮----
// If the error is already a gRPC status error, return it as-is
⋮----
// Handle known entity errors
⋮----
// Log internal errors
⋮----
// ErrorHandlingInterceptor handles error conversion for unary RPCs
func ErrorHandlingInterceptor() grpc.UnaryServerInterceptor
⋮----
// StreamErrorHandlingInterceptor handles error conversion for streaming RPCs
func StreamErrorHandlingInterceptor() grpc.StreamServerInterceptor
```

## File: internal/usecase/api-server/listen_proofs_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/metadata"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	"github.com/symbioticfi/relay/internal/usecase/broadcaster"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/metadata"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
"github.com/symbioticfi/relay/internal/usecase/broadcaster"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type mockProofsStream struct {
	ctx        context.Context
	sentItems  []*apiv1.ListenProofsResponse
	sendError  error
	sendCalled chan struct{}
⋮----
func (m *mockProofsStream) Context() context.Context
⋮----
func (m *mockProofsStream) Send(msg *apiv1.ListenProofsResponse) error
⋮----
func (m *mockProofsStream) SendMsg(interface
⋮----
func (m *mockProofsStream) RecvMsg(interface
⋮----
func (m *mockProofsStream) SetHeader(metadata.MD) error
⋮----
func (m *mockProofsStream) SendHeader(metadata.MD) error
⋮----
func (m *mockProofsStream) SetTrailer(metadata.MD)
⋮----
func TestListenProofs_OnlyHistoricalData(t *testing.T)
⋮----
func TestListenProofs_OnlyBroadcast(t *testing.T)
⋮----
func TestListenProofs_HistoricalAndBroadcast(t *testing.T)
⋮----
func TestListenProofs_RepositoryError(t *testing.T)
⋮----
func TestListenProofs_StreamSendError(t *testing.T)
⋮----
func TestListenProofs_MultipleBroadcasts(t *testing.T)
⋮----
func TestListenProofs_MaxStreamsReached_ReturnsError(t *testing.T)
⋮----
func TestListenProofs_EmptyHistoricalData(t *testing.T)
```

## File: internal/usecase/api-server/listen_proofs_v1.go

```go
package api_server
⋮----
import (
	"github.com/go-errors/errors"
	"github.com/google/uuid"
	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
⋮----
"github.com/go-errors/errors"
"github.com/google/uuid"
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
func (h *grpcHandler) ListenProofs(
	req *apiv1.ListenProofsRequest,
	stream grpc.ServerStreamingServer[apiv1.ListenProofsResponse],
) error
⋮----
var from []byte
```

## File: internal/usecase/api-server/listen_signature_v1.go

```go
package api_server
⋮----
import (
	"github.com/go-errors/errors"
	"github.com/google/uuid"
	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
⋮----
"github.com/go-errors/errors"
"github.com/google/uuid"
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
func (h *grpcHandler) ListenSignatures(
	req *apiv1.ListenSignaturesRequest,
	stream grpc.ServerStreamingServer[apiv1.ListenSignaturesResponse],
) error
⋮----
var from []byte
```

## File: internal/usecase/api-server/listen_signatures_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/metadata"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	"github.com/symbioticfi/relay/internal/usecase/broadcaster"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/metadata"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
"github.com/symbioticfi/relay/internal/usecase/broadcaster"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type mockSignaturesStream struct {
	ctx        context.Context
	sentItems  []*apiv1.ListenSignaturesResponse
	sendError  error
	sendCalled chan struct{}
⋮----
func (m *mockSignaturesStream) Context() context.Context
⋮----
func (m *mockSignaturesStream) Send(msg *apiv1.ListenSignaturesResponse) error
⋮----
func (m *mockSignaturesStream) SendMsg(interface
⋮----
func (m *mockSignaturesStream) RecvMsg(interface
⋮----
func (m *mockSignaturesStream) SetHeader(metadata.MD) error
⋮----
func (m *mockSignaturesStream) SendHeader(metadata.MD) error
⋮----
func (m *mockSignaturesStream) SetTrailer(metadata.MD)
⋮----
func TestListenSignatures_OnlyHistoricalData(t *testing.T)
⋮----
func TestListenSignatures_OnlyBroadcast(t *testing.T)
⋮----
func TestListenSignatures_HistoricalAndBroadcast(t *testing.T)
⋮----
func TestListenSignatures_RepositoryError(t *testing.T)
⋮----
func TestListenSignatures_StreamSendError(t *testing.T)
⋮----
func TestListenSignatures_MultipleBroadcasts(t *testing.T)
⋮----
func TestListenSignatures_MaxStreamsReached_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/listen_validator_set_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc/metadata"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	"github.com/symbioticfi/relay/internal/usecase/broadcaster"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/metadata"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
"github.com/symbioticfi/relay/internal/usecase/broadcaster"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type mockValidatorSetsStream struct {
	ctx        context.Context
	sentItems  []*apiv1.ListenValidatorSetResponse
	sendError  error
	sendCalled chan struct{}
⋮----
func (m *mockValidatorSetsStream) Context() context.Context
⋮----
func (m *mockValidatorSetsStream) Send(msg *apiv1.ListenValidatorSetResponse) error
⋮----
func (m *mockValidatorSetsStream) SendMsg(interface
⋮----
func (m *mockValidatorSetsStream) RecvMsg(interface
⋮----
func (m *mockValidatorSetsStream) SetHeader(metadata.MD) error
⋮----
func (m *mockValidatorSetsStream) SendHeader(metadata.MD) error
⋮----
func (m *mockValidatorSetsStream) SetTrailer(metadata.MD)
⋮----
func TestListenValidatorSet_OnlyHistoricalData(t *testing.T)
⋮----
func TestListenValidatorSet_OnlyBroadcast(t *testing.T)
⋮----
func TestListenValidatorSet_HistoricalAndBroadcast(t *testing.T)
⋮----
func TestListenValidatorSet_RepositoryError(t *testing.T)
⋮----
func TestListenValidatorSet_StreamSendError(t *testing.T)
⋮----
func TestListenValidatorSet_MultipleBroadcasts(t *testing.T)
⋮----
func TestListenValidatorSet_EmptyHistoricalData(t *testing.T)
⋮----
func TestListenValidatorSet_ConcurrentBroadcasts(t *testing.T)
⋮----
func TestListenValidatorSet_MaxStreamsReached_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/listen_validator_set_v1.go

```go
package api_server
⋮----
import (
	"github.com/go-errors/errors"
	"github.com/google/uuid"
	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
⋮----
"github.com/go-errors/errors"
"github.com/google/uuid"
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
func (h *grpcHandler) ListenValidatorSet(
	req *apiv1.ListenValidatorSetRequest,
	stream grpc.ServerStreamingServer[apiv1.ListenValidatorSetResponse],
) error
⋮----
func convertValidatorSetToStreamResponse(valSet symbiotic.ValidatorSet) *apiv1.ListenValidatorSetResponse
```

## File: internal/usecase/api-server/pagination_handler_fuzz_test.go

```go
package api_server
⋮----
import (
	"context"
	"encoding/base64"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"encoding/base64"
"strconv"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// TestFuzz_Handler_PageSizeClamps drives every handler with extreme page_size
// values and verifies the clamp/default constants are applied at the boundary
// to the repo. Catches regressions where the handler accidentally trusts the
// user input as-is.
func TestFuzz_Handler_PageSizeClamps(t *testing.T)
⋮----
idsExpected int // for IDs handler
objExpected int // for full-object handlers
⋮----
// IDs handler — max is maxIDListPageSize.
⋮----
// Requests handler — max is maxListPageSize.
⋮----
// Signatures handler.
⋮----
// Aggregation proofs.
⋮----
// TestFuzz_Handler_CursorRoundTrip verifies the handler base64-encodes the raw
// cursor returned by the repo, and decodes a client-supplied base64 cursor
// back to the same raw bytes when forwarding to the repo.
func TestFuzz_Handler_CursorRoundTrip(t *testing.T)
⋮----
// Repo returns a raw 32-byte cursor; handler must base64-encode it in
// next_from. Then a follow-up request with that base64 in `from` must
// reach the repo as the same raw bytes.
⋮----
// Round-trip: send `encoded` back as `from`, repo must see `rawCursor`.
⋮----
// TestFuzz_Handler_InvalidBase64 verifies the handler short-circuits on
// malformed base64 BEFORE calling the repo (mock would fail otherwise).
func TestFuzz_Handler_InvalidBase64(t *testing.T)
⋮----
// gomock will FAIL the test if the repo is invoked unexpectedly. So the
// absence of an EXPECT() call here is the assertion: handler must not
// call repo on bad cursor.
⋮----
// TestFuzz_Handler_RepoCursorErrPropagates verifies that ErrInvalidCursor from
// the repo is mapped to InvalidArgument by the handler (asCursorErr).
func TestFuzz_Handler_RepoCursorErrPropagates(t *testing.T)
⋮----
// Send a syntactically valid base64 cursor that the repo will reject by
// length. We pass 5 bytes; repo returns ErrInvalidCursor.
⋮----
// TestFuzz_Handler_NextFromEmptyOnLastPage: when the repo signals last page
// (nil cursor), the handler must return next_from == "".
func TestFuzz_Handler_NextFromEmptyOnLastPage(t *testing.T)
⋮----
// TestFuzz_Handler_PartialCursorIsOpaque: an attacker passes garbage of the
// correct length 32 — repo accepts it (no ErrInvalidCursor); handler must
// forward it transparently. Used to fuzz that base64 of any length works.
func TestFuzz_Handler_PartialCursorOpaqueLengths(t *testing.T)
⋮----
// Repo will receive `raw` directly; doesn't matter what it
// returns — we're just verifying the wire layer.
```

## File: internal/usecase/api-server/pagination.go

```go
package api_server
⋮----
import (
	"encoding/base64"

	"github.com/go-errors/errors"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/internal/entity"
)
⋮----
"encoding/base64"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/internal/entity"
⋮----
// Server-side defaults and clamps for *ByEpoch listing endpoints. These bound
// memory usage per response; clients can request a smaller page_size or rely
// on the default. Anything above the max is silently clamped.
const (
	// For ID-only listings (a hex string per item is cheap to materialize).
⋮----
// For ID-only listings (a hex string per item is cheap to materialize).
⋮----
// For full-object listings (signatures, proofs, signature requests).
⋮----
// clampPageSize returns the effective page size: 0 → defaultV, > maxV → maxV.
func clampPageSize(requested int, defaultV, maxV int) int
⋮----
// decodeCursor parses an opaque base64 cursor returned by a previous response.
// Empty string yields nil (signals "start of range"). Malformed base64 yields
// codes.InvalidArgument so the client gets a useful error.
func decodeCursor(s string) ([]byte, error)
⋮----
// encodeCursor serializes a repo-supplied opaque cursor back into the wire
// format. Nil/empty input means "this is the last page".
func encodeCursor(b []byte) string
⋮----
// asCursorErr returns a non-nil InvalidArgument status when err wraps
// entity.ErrInvalidCursor, and nil otherwise — letting callers fall through to
// their own wrapping for unrelated repo errors.
func asCursorErr(err error) error
```

## File: internal/usecase/api-server/sign_message_v1_test.go

```go
package api_server
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"github.com/symbioticfi/relay/internal/usecase/api-server/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestSignMessage_WithRequiredEpoch_Success(t *testing.T)
⋮----
func TestSignMessage_WithoutRequiredEpoch_UsesLatestEpoch(t *testing.T)
⋮----
func TestSignMessage_GetLatestEpochFails_ReturnsError(t *testing.T)
⋮----
func TestSignMessage_RequestSignatureFails_ReturnsError(t *testing.T)
```

## File: internal/usecase/api-server/sign_message_v1.go

```go
package api_server
⋮----
import (
	"context"

	apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// SignMessage handles the gRPC SignMessage request
func (h *grpcHandler) SignMessage(ctx context.Context, req *apiv1.SignMessageRequest) (*apiv1.SignMessageResponse, error)
```

## File: internal/usecase/broadcaster/doc.go

```go
// Package broadcaster provides a generic Hub implementation for dynamic fan-out messaging.
//
// The Hub allows publishers to broadcast messages to a dynamic set of subscribers.
// Subscribers can join and leave at any time (0 to N subscribers).
⋮----
// Usage example:
⋮----
//	// Create a hub for string messages with custom buffer size
//	hub := broadcaster.NewHub[string](
//	    broadcaster.WithBufferSize[string](100),
//	)
⋮----
//	// Subscribe to receive messages
//	ch := hub.Subscribe("subscriber-1")
//	defer hub.Unsubscribe("subscriber-1")
⋮----
//	// Receive messages in a goroutine
//	go func() {
//	    for msg := range ch {
//	        fmt.Println("Received:", msg)
//	    }
//	}()
⋮----
//	// Broadcast to all subscribers (non-blocking)
//	hub.Broadcast("Hello, World!")
⋮----
//	// Check subscriber count
//	count := hub.Count()
//	fmt.Printf("Active subscribers: %d\n", count)
⋮----
// Thread Safety:
⋮----
// All Hub methods are thread-safe and can be called concurrently from multiple goroutines.
⋮----
// Backpressure Handling:
⋮----
// The Hub uses buffered channels for each subscriber. If a subscriber's channel buffer is full,
// the Broadcast method will drop the message for that subscriber (non-blocking).
// Use BroadcastWait if you need to ensure all subscribers receive the message (blocking).
package broadcaster
```

## File: internal/usecase/broadcaster/hub_test.go

```go
package broadcaster
⋮----
import (
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"sync"
"testing"
"time"
⋮----
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
func TestHub_SubscribeUnsubscribe(t *testing.T)
⋮----
// Subscribe
⋮----
// Subscribe another
⋮----
// Unsubscribe
⋮----
func TestHub_SubscribeIdempotent(t *testing.T)
⋮----
// Subscribe twice with same ID
⋮----
// Should return same channel
⋮----
func TestHub_BroadcastToAll(t *testing.T)
⋮----
// Subscribe multiple subscribers
⋮----
// Broadcast message
⋮----
// All should receive the message
⋮----
func TestHub_BroadcastWithNoSubscribers(t *testing.T)
⋮----
// Should not panic
⋮----
func TestHub_BroadcastDropsWhenBufferFull(t *testing.T)
⋮----
// Fill the buffer
⋮----
hub.Broadcast("msg2") // This should be dropped
⋮----
// Read one message
⋮----
// Channel should be empty now
⋮----
// Expected - no more messages
⋮----
func TestHub_BroadcastWaitBlocks(t *testing.T)
⋮----
// BroadcastWait should block until we read
⋮----
// Give it time to block
⋮----
// Should still be blocking
⋮----
// Expected
⋮----
// Read from channel to unblock
⋮----
// Now should complete
⋮----
func TestHub_ConcurrentAccess(t *testing.T)
⋮----
var wg sync.WaitGroup
⋮----
// Start subscribers
⋮----
// Start broadcasting
⋮----
// Start receiving
⋮----
func TestHub_UnsubscribeClosesChannel(t *testing.T)
⋮----
// Channel should be closed
⋮----
func TestHub_Close(t *testing.T)
⋮----
// All channels should be closed
⋮----
// Count should be 0
⋮----
func TestHub_WithOptions(t *testing.T)
⋮----
func TestHub_BroadcastAfterUnsubscribe(t *testing.T)
⋮----
// Unsubscribe one
⋮----
// Broadcast should only go to remaining subscriber
⋮----
// sub2 should receive
⋮----
// sub1 should be closed
```

## File: internal/usecase/broadcaster/hub.go

```go
package broadcaster
⋮----
import (
	"log/slog"
	"sync"
)
⋮----
"log/slog"
"sync"
⋮----
// Hub is a generic broadcaster that manages dynamic fan-out of messages to subscribers
// T is the type of messages being broadcast
type Hub[T any] struct {
	mu          sync.RWMutex
	subscribers map[string]*subscriber[T]
	bufferSize  int
}
⋮----
// subscriber represents a single subscriber with its channel
type subscriber[T any] struct {
	id      string
	ch      chan T
	stopped bool
	mu      sync.Mutex
}
⋮----
// HubOption configures the Hub
type HubOption[T any] func(*Hub[T])
⋮----
// WithBufferSize sets the buffer size for subscriber channels
func WithBufferSize[T any](size int) HubOption[T]
⋮----
// NewHub creates a new Hub with optional configuration
func NewHub[T any](opts ...HubOption[T]) *Hub[T]
⋮----
bufferSize:  100, // default buffer size
⋮----
// Subscribe adds a new subscriber with the given ID and returns the channel to receive messages
// If a subscriber with the same ID already exists, it returns the existing channel
func (h *Hub[T]) Subscribe(id string) chan T
⋮----
// Check if subscriber already exists
⋮----
// Unsubscribe removes a subscriber and closes its channel
func (h *Hub[T]) Unsubscribe(id string)
⋮----
// Broadcast sends a message to all active subscribers
// Slow subscribers will have messages dropped (non-blocking send)
func (h *Hub[T]) Broadcast(msg T)
⋮----
// successfully sent
⋮----
// channel is full, drop message
⋮----
// BroadcastWait sends a message to all active subscribers and waits for all sends to complete
// This is a blocking operation that ensures all subscribers receive the message
func (h *Hub[T]) BroadcastWait(msg T)
⋮----
// Blocking send
⋮----
// Count returns the number of active subscribers
func (h *Hub[T]) Count() int
⋮----
// Close unsubscribes all subscribers and cleans up resources
func (h *Hub[T]) Close()
```

## File: internal/usecase/entity-processor/mocks/entity_processor.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: entity_processor.go
//
// Generated by this command:
⋮----
//	mockgen -source=entity_processor.go -destination=mocks/entity_processor.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"

	common "github.com/ethereum/go-ethereum/common"
	entity "github.com/symbioticfi/relay/symbiotic/entity"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
⋮----
common "github.com/ethereum/go-ethereum/common"
entity "github.com/symbioticfi/relay/symbiotic/entity"
gomock "go.uber.org/mock/gomock"
⋮----
// MockRepository is a mock of Repository interface.
type MockRepository struct {
	ctrl     *gomock.Controller
	recorder *MockRepositoryMockRecorder
	isgomock struct{}
⋮----
// MockRepositoryMockRecorder is the mock recorder for MockRepository.
type MockRepositoryMockRecorder struct {
	mock *MockRepository
}
⋮----
// NewMockRepository creates a new mock instance.
func NewMockRepository(ctrl *gomock.Controller) *MockRepository
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder
⋮----
// GetAggregationProof mocks base method.
func (m *MockRepository) GetAggregationProof(ctx context.Context, requestID common.Hash) (entity.AggregationProof, error)
⋮----
// GetAggregationProof indicates an expected call of GetAggregationProof.
⋮----
// GetLatestAggregatedValsetHeader mocks base method.
func (m *MockRepository) GetLatestAggregatedValsetHeader(ctx context.Context) (entity.ValidatorSetHeader, error)
⋮----
// GetLatestAggregatedValsetHeader indicates an expected call of GetLatestAggregatedValsetHeader.
⋮----
// GetSignatureByIndex mocks base method.
func (m *MockRepository) GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (entity.Signature, error)
⋮----
// GetSignatureByIndex indicates an expected call of GetSignatureByIndex.
⋮----
// GetValidatorByKey mocks base method.
func (m *MockRepository) GetValidatorByKey(ctx context.Context, epoch entity.Epoch, keyTag entity.KeyTag, publicKey []byte) (entity.Validator, uint32, error)
⋮----
// GetValidatorByKey indicates an expected call of GetValidatorByKey.
⋮----
// GetValidatorSetByEpoch mocks base method.
func (m *MockRepository) GetValidatorSetByEpoch(ctx context.Context, epoch entity.Epoch) (entity.ValidatorSet, error)
⋮----
// GetValidatorSetByEpoch indicates an expected call of GetValidatorSetByEpoch.
⋮----
// GetValidatorSetMetadata mocks base method.
func (m *MockRepository) GetValidatorSetMetadata(ctx context.Context, epoch entity.Epoch) (entity.ValidatorSetMetadata, error)
⋮----
// GetValidatorSetMetadata indicates an expected call of GetValidatorSetMetadata.
⋮----
// SaveProof mocks base method.
func (m *MockRepository) SaveProof(ctx context.Context, aggregationProof entity.AggregationProof) error
⋮----
// SaveProof indicates an expected call of SaveProof.
⋮----
// SaveSignature mocks base method.
func (m *MockRepository) SaveSignature(ctx context.Context, signature entity.Signature, validator entity.Validator, activeIndex uint32) error
⋮----
// SaveSignature indicates an expected call of SaveSignature.
⋮----
// UpdateValidatorSetStatus mocks base method.
func (m *MockRepository) UpdateValidatorSetStatus(ctx context.Context, epoch entity.Epoch, item entity.ValidatorSetStatus) error
⋮----
// UpdateValidatorSetStatus indicates an expected call of UpdateValidatorSetStatus.
⋮----
// MockAggregator is a mock of Aggregator interface.
type MockAggregator struct {
	ctrl     *gomock.Controller
	recorder *MockAggregatorMockRecorder
	isgomock struct{}
⋮----
// MockAggregatorMockRecorder is the mock recorder for MockAggregator.
type MockAggregatorMockRecorder struct {
	mock *MockAggregator
}
⋮----
// NewMockAggregator creates a new mock instance.
func NewMockAggregator(ctrl *gomock.Controller) *MockAggregator
⋮----
// Verify mocks base method.
func (m *MockAggregator) Verify(ctx context.Context, valset entity.ValidatorSet, keyTag entity.KeyTag, aggregationProof entity.AggregationProof) (bool, error)
⋮----
// Verify indicates an expected call of Verify.
⋮----
// MockAggProofSignal is a mock of AggProofSignal interface.
type MockAggProofSignal struct {
	ctrl     *gomock.Controller
	recorder *MockAggProofSignalMockRecorder
	isgomock struct{}
⋮----
// MockAggProofSignalMockRecorder is the mock recorder for MockAggProofSignal.
type MockAggProofSignalMockRecorder struct {
	mock *MockAggProofSignal
}
⋮----
// NewMockAggProofSignal creates a new mock instance.
func NewMockAggProofSignal(ctrl *gomock.Controller) *MockAggProofSignal
⋮----
// Emit mocks base method.
func (m *MockAggProofSignal) Emit(payload entity.AggregationProof) error
⋮----
// Emit indicates an expected call of Emit.
⋮----
// MockMetrics is a mock of Metrics interface.
type MockMetrics struct {
	ctrl     *gomock.Controller
	recorder *MockMetricsMockRecorder
	isgomock struct{}
⋮----
// MockMetricsMockRecorder is the mock recorder for MockMetrics.
type MockMetricsMockRecorder struct {
	mock *MockMetrics
}
⋮----
// NewMockMetrics creates a new mock instance.
func NewMockMetrics(ctrl *gomock.Controller) *MockMetrics
⋮----
// ObserveEpoch mocks base method.
func (m *MockMetrics) ObserveEpoch(epochType string, epochNumber uint64)
⋮----
// ObserveEpoch indicates an expected call of ObserveEpoch.
```

## File: internal/usecase/entity-processor/entity_processor_test.go

```go
package entity_processor
⋮----
import (
	"crypto/rand"
	stderrors "errors"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"golang.org/x/sync/errgroup"

	badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"crypto/rand"
stderrors "errors"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/sync/errgroup"
⋮----
badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestEntityProcessor_ProcessSignature(t *testing.T)
⋮----
// Setup validator set header with high quorum threshold (1000)
⋮----
// Setup validator set header with low quorum threshold (50)
⋮----
expectPendingExists:  false, // Should be removed due to quorum
⋮----
// Setup validator set header with high quorum threshold
⋮----
// Setup validator set header with quorum threshold of 150
⋮----
// First signature - not enough for quorum
⋮----
// Verify pending exists after first signature
⋮----
// Return second signature that will reach quorum
⋮----
expectPendingExists:  false, // Should be removed after reaching quorum
⋮----
// Don't setup validator set header - will cause error
⋮----
// Verify signature map was created/updated
⋮----
// Verify at least one validator is present in the bitmap
⋮----
// Verify pending collection state
⋮----
func TestEntityProcessor_ProcessSignature_ConcurrentSignatures(t *testing.T)
⋮----
// Setup validator set header with quorum threshold of 300
⋮----
// Simulate 4 concurrent signatures
⋮----
// Process signatures sequentially (testing transaction consistency)
⋮----
// Verify final state
⋮----
// Since all signatures use the same key tag, they would resolve to the same validator
// So we should have at least one validator present
⋮----
// Pending collection should be empty (quorum reached)
⋮----
func TestEntityProcessor_ProcessSignature_Conflict(t *testing.T)
⋮----
func TestEntityProcessor_ProcessSignature_DuplicateSignatureForSameValidator(t *testing.T)
⋮----
// First signature should succeed
⋮----
// Duplicate signature should fail
⋮----
func TestEntityProcessor_ProcessSignature_ExactQuorumThreshold(t *testing.T)
⋮----
// Set quorum threshold to exactly 100
⋮----
// Should reach quorum and remove from pending
⋮----
// Helper functions
⋮----
func createMockAggregator(t *testing.T) *mocks.MockAggregator
⋮----
// Default behavior: return true for verification
⋮----
func createMockAggProofSignal(t *testing.T) *mocks.MockAggProofSignal
⋮----
// Default behavior: return nil for emit
⋮----
func createMockSignatureProcessedSignal(t *testing.T) *signals.Signal[symbiotic.Signature]
⋮----
type repoFactory func(t *testing.T) cached.Repository
⋮----
func backends() map[string]repoFactory
⋮----
func randomBytes(t *testing.T, n int) []byte
⋮----
func computeMessageHash(t *testing.T, keyTag symbiotic.KeyTag, message []byte) []byte
⋮----
func randomSignatureRequest(t *testing.T, epoch symbiotic.Epoch) symbiotic.SignatureRequest
⋮----
func randomSignatureExtendedForKeyWithParams(t *testing.T, privateKey crypto.PrivateKey, req symbiotic.SignatureRequest) symbiotic.Signature
⋮----
func signatureExtendedForRequest(t *testing.T, privateKey crypto.PrivateKey, req symbiotic.SignatureRequest) symbiotic.Signature
⋮----
func randomNetworkConfig() symbiotic.NetworkConfig
⋮----
func createValidatorSetWithCount(t *testing.T, epoch symbiotic.Epoch, quorumThreshold *big.Int, validatorCount int) (symbiotic.ValidatorSet, []map[symbiotic.KeyTag]crypto.PrivateKey)
⋮----
func setupValidatorSetHeader(t *testing.T, repo cached.Repository, epoch symbiotic.Epoch, quorumThreshold *big.Int) (symbiotic.ValidatorSet, []map[symbiotic.KeyTag]crypto.PrivateKey)
⋮----
func TestEntityProcessor_ProcessAggregationProof_SuccessfullyProcesses(t *testing.T)
⋮----
// Setup validator set for this epoch (required by ProcessAggregationProof)
⋮----
// Verify aggregation proof was saved
⋮----
// Verify pending aggregation proof was removed
⋮----
func TestEntityProcessor_ProcessAggregationProof_HandlesMissingPendingGracefully(t *testing.T)
⋮----
// Verify aggregation proof was still saved
⋮----
func TestEntityProcessor_ProcessAggregationProof_DoesNotUpdateValidatorSetStatusForUnrelatedProof(t *testing.T)
⋮----
func TestEntityProcessor_ProcessAggregationProof_UpdatesValidatorSetStatusForValsetProof(t *testing.T)
⋮----
func TestEntityProcessor_ProcessAggregationProof_FailsBeforeSavingWhenValsetMetadataLookupFails(t *testing.T)
⋮----
func TestEntityProcessor_ProcessAggregationProof_FailsWhenAlreadyExists(t *testing.T)
⋮----
// Attempt to process same aggregation proof should fail
⋮----
func TestEntityProcessor_ProcessSignature_SavesAggregationProofPendingForAggregationKeys(t *testing.T)
⋮----
// Verify aggregation proof pending was also saved
⋮----
func TestEntityProcessor_ProcessSignature_SaveAggregationProofPendingForNonAggregationKeys(t *testing.T)
⋮----
req.KeyTag = symbiotic.KeyTag(0x10) // Ensure it's NOT an aggregation key (EcdsaSecp256k1)
⋮----
// Verify signature request was saved but NOT to pending collection
⋮----
// Verify no pending aggregation proof requests
⋮----
func TestEntityProcessor_ProcessSignature_FullSignatureToAggregationProofFlow(t *testing.T)
⋮----
// Step 1: Process signature (should create pending aggregation proof)
⋮----
// Verify pending aggregation proof exists
⋮----
// Step 2: Process aggregation proof (should remove from pending)
⋮----
type doNothingMetrics struct{}
⋮----
func (d doNothingMetrics) ObserveEpoch(epochType string, epochNumber uint64)
```

## File: internal/usecase/entity-processor/entity_processor.go

```go
package entity_processor
⋮----
import (
	"context"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	validate "github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
validate "github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
//go:generate mockgen -source=entity_processor.go -destination=mocks/entity_processor.go -package=mocks
⋮----
// Repository defines the interface needed by the entity processor
type Repository interface {
	SaveSignature(ctx context.Context, signature symbiotic.Signature, validator symbiotic.Validator, activeIndex uint32) error
	GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (symbiotic.Signature, error)
	GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	GetValidatorSetMetadata(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSetMetadata, error)
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	SaveProof(ctx context.Context, aggregationProof symbiotic.AggregationProof) error
	UpdateValidatorSetStatus(ctx context.Context, epoch symbiotic.Epoch, item symbiotic.ValidatorSetStatus) error
	GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
}
⋮----
type Aggregator interface {
	Verify(ctx context.Context, valset symbiotic.ValidatorSet, keyTag symbiotic.KeyTag, aggregationProof symbiotic.AggregationProof) (bool, error)
}
⋮----
type AggProofSignal interface {
	Emit(payload symbiotic.AggregationProof) error
}
⋮----
type Metrics interface {
	ObserveEpoch(epochType string, epochNumber uint64)
}
⋮----
type Config struct {
	Repo                     Repository                           `validate:"required"`
	Aggregator               Aggregator                           `validate:"required"`
	AggProofSignal           AggProofSignal                       `validate:"required"`
	SignatureProcessedSignal *signals.Signal[symbiotic.Signature] `validate:"required"`
	Metrics                  Metrics                              `validate:"required"`
}
⋮----
func (c Config) Validate() error
⋮----
// EntityProcessor handles both signature and aggregation proof processing with SignatureMap operations
type EntityProcessor struct {
	cfg Config
}
⋮----
// NewEntityProcessor creates a new entity processor
func NewEntityProcessor(cfg Config) (*EntityProcessor, error)
⋮----
// ProcessSignature processes a signature with SignatureMap operations and optionally saves SignatureRequest
func (s *EntityProcessor) ProcessSignature(ctx context.Context, signature symbiotic.Signature, self bool) error
⋮----
// if self signature ignore validator check and signature existence check
⋮----
// ProcessAggregationProof processes an aggregation proof by saving it and removing from pending collection.
// When self is true, verification is skipped (proof was generated locally).
func (s *EntityProcessor) ProcessAggregationProof(ctx context.Context, aggregationProof symbiotic.AggregationProof, self bool) error
⋮----
func (s *EntityProcessor) valsetProofTargetEpoch(
	ctx context.Context,
	aggregationProof symbiotic.AggregationProof,
) (symbiotic.Epoch, bool, error)
```

## File: internal/usecase/key-provider/cache_key_provider.go

```go
package keyprovider
⋮----
import (
	"sync"

	"github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"sync"
⋮----
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type CacheKeyProvider struct {
	KeyProvider

	nodeKeyMap *sync.Map // map[keyTag]CompactPublicKey
}
⋮----
nodeKeyMap *sync.Map // map[keyTag]CompactPublicKey
⋮----
func NewCacheKeyProvider(kp KeyProvider) *CacheKeyProvider
⋮----
func (c *CacheKeyProvider) GetOnchainKeyFromCache(keyTag entity.KeyTag) (entity.CompactPublicKey, error)
```

## File: internal/usecase/key-provider/env_provider.go

```go
package keyprovider
⋮----
import (
	"encoding/base64"
	"os"
	"strings"
	"sync"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/go-errors/errors"
)
⋮----
"encoding/base64"
"os"
"strings"
"sync"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/go-errors/errors"
⋮----
type EnvKeyProvider struct {
	cache map[string]crypto.PrivateKey
	mu    sync.RWMutex
}
⋮----
func NewEnvKeyProvider() *EnvKeyProvider
⋮----
func (e *EnvKeyProvider) GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
⋮----
func (e *EnvKeyProvider) GetPrivateKeyByNamespaceTypeId(
	namespace string,
	keyType symbiotic.KeyType,
	keyId int,
) (crypto.PrivateKey, error)
⋮----
func (e *EnvKeyProvider) GetPrivateKeyByAlias(alias string) (crypto.PrivateKey, error)
⋮----
func (e *EnvKeyProvider) HasKey(keyTag symbiotic.KeyTag) (bool, error)
⋮----
func (e *EnvKeyProvider) HasKeyByAlias(alias string) (bool, error)
⋮----
func (e *EnvKeyProvider) HasKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (bool, error)
```

## File: internal/usecase/key-provider/key_provider.go

```go
package keyprovider
⋮----
import (
	"strconv"
	"strings"

	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"strconv"
"strings"
⋮----
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
const (
	SYMBIOTIC_KEY_NAMESPACE = "symb"
	EVM_KEY_NAMESPACE       = "evm"
	P2P_KEY_NAMESPACE       = "p2p"

	// DEFAULT_EVM_CHAIN_ID chain id used to identify the default key for all chains
	DEFAULT_EVM_CHAIN_ID = 0

	P2P_HOST_IDENTITY_KEY_ID = 1
)
⋮----
// DEFAULT_EVM_CHAIN_ID chain id used to identify the default key for all chains
⋮----
type KeyProvider interface {
	GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
	GetPrivateKeyByAlias(alias string) (crypto.PrivateKey, error)
	GetPrivateKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (crypto.PrivateKey, error)
	HasKey(keyTag symbiotic.KeyTag) (bool, error)
	HasKeyByAlias(alias string) (bool, error)
	HasKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (bool, error)
}
⋮----
func KeyTagToAliasWithNS(namespace string, keyTag symbiotic.KeyTag) (string, error)
⋮----
// https://github.com/symbioticfi/middleware-sdk-mirror/blob/change-header/src/contracts/libraries/utils/KeyTags.sol#L24-L40
⋮----
func KeyTagToAlias(keyTag symbiotic.KeyTag) (string, error)
⋮----
func ToAlias(namespace string, keyType symbiotic.KeyType, keyId int) (string, error)
⋮----
//nolint:revive // we need to return the ns too
func AliasToKeyTypeId(alias string) (string, symbiotic.KeyType, int, error)
```

## File: internal/usecase/key-provider/key_store_provider_test.go

```go
package keyprovider
⋮----
import (
	"testing"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/stretchr/testify/require"
)
⋮----
"testing"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/stretchr/testify/require"
⋮----
func TestNewKeystore(t *testing.T)
⋮----
func TestAddKey(t *testing.T)
⋮----
func TestForceAddKey(t *testing.T)
⋮----
func TestCreateAndReopen(t *testing.T)
⋮----
func TestDefaultEVMKey(t *testing.T)
⋮----
// shouldn't work for other chains
```

## File: internal/usecase/key-provider/key_store_provider.go

```go
package keyprovider
⋮----
import (
	"log/slog"
	"os"
	"path/filepath"
	"time"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/go-errors/errors"
	"github.com/pavlo-v-chernykh/keystore-go/v4"
)
⋮----
"log/slog"
"os"
"path/filepath"
"time"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/go-errors/errors"
"github.com/pavlo-v-chernykh/keystore-go/v4"
⋮----
type KeystoreProvider struct {
	ks       keystore.KeyStore
	filePath string
}
⋮----
func NewKeystoreProvider(filePath, password string) (*KeystoreProvider, error)
⋮----
func (k *KeystoreProvider) GetAliases() []string
⋮----
func (k *KeystoreProvider) GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
⋮----
func (k *KeystoreProvider) GetPrivateKeyByAlias(alias string) (crypto.PrivateKey, error)
⋮----
func (k *KeystoreProvider) GetPrivateKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (crypto.PrivateKey, error)
⋮----
// For EVM keys, we check for default key with chain ID 0 if the requested chain id is absent
⋮----
func (k *KeystoreProvider) HasKey(keyTag symbiotic.KeyTag) (bool, error)
⋮----
func (k *KeystoreProvider) HasKeyByAlias(alias string) (bool, error)
⋮----
func (k *KeystoreProvider) HasKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (bool, error)
⋮----
func (k *KeystoreProvider) AddKey(namespace string, keyTag symbiotic.KeyTag, privateKey crypto.PrivateKey, password string, force bool) error
⋮----
func (k *KeystoreProvider) DeleteKey(keyTag symbiotic.KeyTag, password string) error
⋮----
func (k *KeystoreProvider) AddKeyByNamespaceTypeId(ns string, tp symbiotic.KeyType, id int, privateKey crypto.PrivateKey, password string, force bool) error
⋮----
func (k *KeystoreProvider) DeleteKeyByNamespaceTypeId(ns string, tp symbiotic.KeyType, id int, password string) error
⋮----
func (k *KeystoreProvider) dump(password string) error
```

## File: internal/usecase/key-provider/simple_key_provider.go

```go
package keyprovider
⋮----
import (
	"log/slog"
	"sync"

	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"log/slog"
"sync"
⋮----
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type SimpleKeystoreProvider struct {
	keys map[string]crypto.PrivateKey
	mu   sync.RWMutex
}
⋮----
func NewSimpleKeystoreProvider() (*SimpleKeystoreProvider, error)
⋮----
func (k *SimpleKeystoreProvider) GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
⋮----
func (k *SimpleKeystoreProvider) GetPrivateKeyByAlias(alias string) (crypto.PrivateKey, error)
⋮----
func (k *SimpleKeystoreProvider) GetPrivateKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (crypto.PrivateKey, error)
⋮----
// For EVM keys, we check for default key with chain ID 0 if the requested chain id is absent
⋮----
func (k *SimpleKeystoreProvider) HasKey(keyTag symbiotic.KeyTag) (bool, error)
⋮----
func (k *SimpleKeystoreProvider) HasKeyByAlias(alias string) (bool, error)
⋮----
func (k *SimpleKeystoreProvider) HasKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (bool, error)
⋮----
func (k *SimpleKeystoreProvider) AddKey(keyTag symbiotic.KeyTag, privateKey crypto.PrivateKey) error
⋮----
func (k *SimpleKeystoreProvider) AddKeyByNamespaceTypeId(ns string, tp symbiotic.KeyType, id int, privateKey crypto.PrivateKey) error
⋮----
func (k *SimpleKeystoreProvider) DeleteKey(keyTag symbiotic.KeyTag) error
```

## File: internal/usecase/key-registerer/key_registerer_test.go

```go
package key_registerer
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
⋮----
func TestBuildArtifactECDSANormalizesSignatureAndLeavesEmptyExtraData(t *testing.T)
⋮----
func TestBuildArtifactBLS12381FormatsSignedEnvelopeForContract(t *testing.T)
⋮----
func TestBuildArtifactBLSDerivesExtraData(t *testing.T)
⋮----
func TestBuildArtifactBLS12381DerivesExtraData(t *testing.T)
⋮----
func TestBuildArtifactBLS12381ReferenceJSON(t *testing.T)
⋮----
func TestRegisterUsesArtifactBytesForTransaction(t *testing.T)
⋮----
var testEip712Domain = symbiotic.Eip712Domain{
	Name:              "Key Registry",
	Version:           "1",
	ChainId:           big.NewInt(31337),
	VerifyingContract: common.HexToAddress("0x0000000000000000000000000000000000000abc"),
}
⋮----
var testNetworkConfig = symbiotic.NetworkConfig{
	KeysProvider: symbiotic.CrossChainAddress{
		ChainId: 31337,
		Address: common.HexToAddress("0x0000000000000000000000000000000000000def"),
	},
}
⋮----
type testEVMClient struct {
	eip712RequestedFor  symbiotic.CrossChainAddress
	registerKeyAddress  symbiotic.CrossChainAddress
	registerKeyTag      symbiotic.KeyTag
	registeredKey       symbiotic.CompactPublicKey
	registeredSignature symbiotic.RawSignature
	registeredExtraData []byte
}
⋮----
func newTestRegisterer(t *testing.T) (*Registerer, *testEVMClient)
⋮----
func (t *testEVMClient) GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
⋮----
func (t *testEVMClient) GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
⋮----
func (t *testEVMClient) GetEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.Eip712Domain, error)
⋮----
func (t *testEVMClient) GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
⋮----
func (t *testEVMClient) RegisterKey(
	ctx context.Context,
	addr symbiotic.CrossChainAddress,
	keyTag symbiotic.KeyTag,
	key symbiotic.CompactPublicKey,
	signature symbiotic.RawSignature,
	extraData []byte,
) (symbiotic.TxResult, error)
```

## File: internal/usecase/key-registerer/key-registerer.go

```go
package key_registerer
⋮----
import (
	"context"
	"encoding/json"

	bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
	bls12381fp "github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/common/math"
	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/go-errors/errors"
	validate "github.com/go-playground/validator/v10"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	relaybls12381 "github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
)
⋮----
"context"
"encoding/json"
⋮----
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
bls12381fp "github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
validate "github.com/go-playground/validator/v10"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
relaybls12381 "github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
⋮----
type evmClient interface {
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.Eip712Domain, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	RegisterKey(ctx context.Context, addr symbiotic.CrossChainAddress, keyTag symbiotic.KeyTag, key symbiotic.CompactPublicKey, signature symbiotic.RawSignature, extraData []byte) (symbiotic.TxResult, error)
}
⋮----
type Config struct {
	EVMClient evmClient `validate:"required"`
}
⋮----
type Registerer struct {
	evmClient evmClient
}
⋮----
type RegistrationArtifact struct {
	KeyTag    symbiotic.KeyTag
	Key       symbiotic.CompactPublicKey
	Signature symbiotic.RawSignature
	ExtraData []byte
}
⋮----
type registrationContext struct {
	keysProvider symbiotic.CrossChainAddress
	eip712Domain symbiotic.Eip712Domain
}
⋮----
func NewRegisterer(cfg Config) (*Registerer, error)
⋮----
func (r *Registerer) Register(
	ctx context.Context,
	pk symbioticCrypto.PrivateKey,
	kt symbiotic.KeyTag,
	operatorAddress common.Address,
) (symbiotic.TxResult, error)
⋮----
func (r *Registerer) BuildArtifact(
	ctx context.Context,
	pk symbioticCrypto.PrivateKey,
	kt symbiotic.KeyTag,
	operatorAddress common.Address,
) (RegistrationArtifact, error)
⋮----
func (r *Registerer) registrationContext(
	ctx context.Context,
) (registrationContext, error)
⋮----
func buildRegistrationArtifact(
	pk symbioticCrypto.PrivateKey,
	kt symbiotic.KeyTag,
	eip712Domain symbiotic.Eip712Domain,
	operatorAddress common.Address,
) (RegistrationArtifact, error)
⋮----
func keyCommitmentData(
	eip712Domain symbiotic.Eip712Domain,
	operator common.Address,
	keyBytes []byte,
) ([]byte, error)
⋮----
func normalizeSignature(kt symbiotic.KeyTag, signature symbiotic.RawSignature) (symbiotic.RawSignature, error)
⋮----
func registrationExtraData(pk symbioticCrypto.PrivateKey, kt symbiotic.KeyTag) ([]byte, error)
⋮----
func bls12381ExtraData(pk symbioticCrypto.PrivateKey) ([]byte, error)
⋮----
func formatBls12381G1OnChain(raw []byte) (symbiotic.CompactPublicKey, error)
⋮----
func formatBls12381G2OnChain(point *bls12381.G2Affine) ([]byte, error)
⋮----
func putBls12381FieldElementOnChain(dst []byte, element bls12381fp.Element) error
⋮----
var fieldBytes [48]byte
⋮----
func (a RegistrationArtifact) MarshalJSON() ([]byte, error)
```

## File: internal/usecase/metrics/metrics_app.go

```go
package metrics
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/server"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/server"
⋮----
type AppConfig struct {
	Address           string        `validate:"required"`
	ReadHeaderTimeout time.Duration `validate:"required,gt=0"`
}
⋮----
func (c AppConfig) Validate() error
⋮----
type App struct {
	srv *server.MetricsServer
}
⋮----
func NewApp(cfg AppConfig) (*App, error)
⋮----
func (a *App) Start(ctx context.Context) error
```

## File: internal/usecase/metrics/metrics_grpc.go

```go
package metrics
⋮----
import (
	"context"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/grpc"
	"google.golang.org/grpc/status"
)
⋮----
"context"
"time"
⋮----
"github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
⋮----
// GRPCMetrics holds Prometheus metrics for gRPC requests
type GRPCMetrics struct {
	requestDuration  *prometheus.HistogramVec
	requestsTotal    *prometheus.CounterVec
	requestsInFlight *prometheus.GaugeVec
}
⋮----
// UnaryServerInterceptor returns a gRPC unary interceptor for metrics collection
func (m *Metrics) UnaryServerInterceptor() grpc.UnaryServerInterceptor
⋮----
// Track in-flight requests
⋮----
// Start timing
⋮----
// Call the handler
⋮----
// Calculate duration
⋮----
// Determine status code
⋮----
// Record metrics
⋮----
// StreamServerInterceptor returns a gRPC stream interceptor for metrics collection
func (m *Metrics) StreamServerInterceptor() grpc.StreamServerInterceptor
```

## File: internal/usecase/metrics/metrics.go

```go
package metrics
⋮----
import (
	"math/big"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/collectors"
)
⋮----
"math/big"
"strconv"
"time"
⋮----
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
⋮----
type Config struct {
	Registerer prometheus.Registerer
}
⋮----
type Metrics struct {
	GRPCMetrics

	// signatures and aggregation
	pkSignDuration         prometheus.Summary
	appSignDuration        prometheus.Summary
	onlyAggregateDuration  prometheus.Summary
	appAggregationDuration prometheus.Summary
	aggregationProofSize   *prometheus.HistogramVec

	// p2p
	p2pBroadcastDuration           *prometheus.SummaryVec
	p2pPeerMessagesSent            *prometheus.CounterVec
	p2pSyncProcessedSignatures     *prometheus.CounterVec
	p2pSyncRequestedHashes         prometheus.Counter
	p2pSyncProcessedAggProofs      *prometheus.CounterVec
	p2pSyncRequestedAggProofHashes prometheus.Counter

	// repo
	repoQueryDuration      *prometheus.HistogramVec
	repoQueryTotalDuration *prometheus.HistogramVec

	// evm
	evmMethodCall     *prometheus.HistogramVec
	evmCommitGasUsed  *prometheus.HistogramVec
	evmCommitGasPrice *prometheus.HistogramVec

	// epoch
	epochsTotal *prometheus.GaugeVec
	epochTime   *prometheus.GaugeVec

	// pruner
	prunedEpochsTotal *prometheus.CounterVec

	// storage
	dbSizeBytes prometheus.Gauge
}
⋮----
// signatures and aggregation
⋮----
// p2p
⋮----
// repo
⋮----
// evm
⋮----
// epoch
⋮----
// pruner
⋮----
// storage
⋮----
func New(cfg Config) *Metrics
⋮----
func newMetrics(registerer prometheus.Registerer) *Metrics
⋮----
var all []prometheus.Collector //nolint:prealloc // We want to keep the metrics grouped for readability
⋮----
256,     // 256B
512,     // 512B
1024,    // 1KB
2048,    // 2KB
4096,    // 4KB
8192,    // 8KB
16384,   // 16KB
32768,   // 32KB
65536,   // 64KB
131072,  // 128KB
262144,  // 256KB
393216,  // 384KB
524288,  // 512KB
786432,  // 768KB
1048576, // 1MB
⋮----
// BadgerDB expvar metrics bridged to Prometheus.
// BadgerDB registers these via expvar in init(); we expose them on /metrics.
⋮----
// Cumulative counters (expvar.Int)
⋮----
// Maps (expvar.Map) — one variable label for the map key
⋮----
func (m *Metrics) ObservePKSignDuration(d time.Duration)
⋮----
func (m *Metrics) ObserveAppSignDuration(d time.Duration)
⋮----
func (m *Metrics) ObserveOnlyAggregateDuration(d time.Duration)
⋮----
func (m *Metrics) ObserveAppAggregateDuration(d time.Duration)
⋮----
func (m *Metrics) ObserveP2PBroadcastDuration(topic, status string, d time.Duration)
⋮----
func (m *Metrics) ObserveP2PPeerMessageSent(messageType, status string)
⋮----
func (m *Metrics) ObserveEVMMethodCall(method string, chainID uint64, status string, d time.Duration)
⋮----
func (m *Metrics) ObserveCommitValsetHeaderParams(chainID uint64, gasUsed uint64, effectiveGasPrice *big.Int)
⋮----
func (m *Metrics) ObserveP2PSyncSignaturesProcessed(resultType string, count int)
⋮----
func (m *Metrics) ObserveP2PSyncRequestedHashes(count int)
⋮----
func (m *Metrics) ObserveP2PSyncAggregationProofsProcessed(resultType string, count int)
⋮----
func (m *Metrics) ObserveP2PSyncRequestedAggregationProofs(count int)
⋮----
func (m *Metrics) ObserveAggregationProofSize(proofSizeBytes int, activeValidatorCount int)
⋮----
func (m *Metrics) ObserveRepoQueryDuration(queryName, status string, d time.Duration)
⋮----
func (m *Metrics) ObserveRepoQueryTotalDuration(queryName, status string, d time.Duration)
⋮----
func (m *Metrics) SetDBSizeBytes(sizeBytes float64)
⋮----
func (m *Metrics) IncPrunedEpochsCount(entityType string)
⋮----
func (m *Metrics) ObserveEpoch(epochType string, epochNumber uint64)
```

## File: internal/usecase/pruner/mocks/pruner_mocks.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: pruner_uc.go
//
// Generated by this command:
⋮----
//	mockgen -source=pruner_uc.go -destination=mocks/pruner_mocks.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"

	entity "github.com/symbioticfi/relay/symbiotic/entity"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
⋮----
entity "github.com/symbioticfi/relay/symbiotic/entity"
gomock "go.uber.org/mock/gomock"
⋮----
// Mockmetrics is a mock of metrics interface.
type Mockmetrics struct {
	ctrl     *gomock.Controller
	recorder *MockmetricsMockRecorder
	isgomock struct{}
⋮----
// MockmetricsMockRecorder is the mock recorder for Mockmetrics.
type MockmetricsMockRecorder struct {
	mock *Mockmetrics
}
⋮----
// NewMockmetrics creates a new mock instance.
func NewMockmetrics(ctrl *gomock.Controller) *Mockmetrics
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Mockmetrics) EXPECT() *MockmetricsMockRecorder
⋮----
// IncPrunedEpochsCount mocks base method.
func (m *Mockmetrics) IncPrunedEpochsCount(entityType string)
⋮----
// IncPrunedEpochsCount indicates an expected call of IncPrunedEpochsCount.
⋮----
// Mockrepo is a mock of repo interface.
type Mockrepo struct {
	ctrl     *gomock.Controller
	recorder *MockrepoMockRecorder
	isgomock struct{}
⋮----
// MockrepoMockRecorder is the mock recorder for Mockrepo.
type MockrepoMockRecorder struct {
	mock *Mockrepo
}
⋮----
// NewMockrepo creates a new mock instance.
func NewMockrepo(ctrl *gomock.Controller) *Mockrepo
⋮----
// GetLatestValidatorSetEpoch mocks base method.
func (m *Mockrepo) GetLatestValidatorSetEpoch(ctx context.Context) (entity.Epoch, error)
⋮----
// GetLatestValidatorSetEpoch indicates an expected call of GetLatestValidatorSetEpoch.
⋮----
// GetOldestValidatorSetEpoch mocks base method.
func (m *Mockrepo) GetOldestValidatorSetEpoch(ctx context.Context) (entity.Epoch, error)
⋮----
// GetOldestValidatorSetEpoch indicates an expected call of GetOldestValidatorSetEpoch.
⋮----
// PruneProofEntities mocks base method.
func (m *Mockrepo) PruneProofEntities(ctx context.Context, epoch entity.Epoch, batchSize int) error
⋮----
// PruneProofEntities indicates an expected call of PruneProofEntities.
⋮----
// PruneRequestIDEpochIndices mocks base method.
func (m *Mockrepo) PruneRequestIDEpochIndices(ctx context.Context, epoch entity.Epoch, batchSize int) error
⋮----
// PruneRequestIDEpochIndices indicates an expected call of PruneRequestIDEpochIndices.
⋮----
// PruneSignatureEntitiesForEpoch mocks base method.
func (m *Mockrepo) PruneSignatureEntitiesForEpoch(ctx context.Context, epoch entity.Epoch, batchSize int) error
⋮----
// PruneSignatureEntitiesForEpoch indicates an expected call of PruneSignatureEntitiesForEpoch.
⋮----
// PruneValsetEntities mocks base method.
func (m *Mockrepo) PruneValsetEntities(ctx context.Context, epoch entity.Epoch, batchSize int) error
⋮----
// PruneValsetEntities indicates an expected call of PruneValsetEntities.
```

## File: internal/usecase/pruner/pruner_uc_test.go

```go
package pruner
⋮----
import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/internal/usecase/pruner/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"testing"
⋮----
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/internal/usecase/pruner/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestPruner_RetentionCalculation(t *testing.T)
⋮----
// Set expectations: expect calls for each epoch to be pruned
⋮----
func TestPruner_RetentionCalculation_AllEntityTypes(t *testing.T)
⋮----
// Expected to prune epochs 0-6, keep 7-10 (4 epochs)
⋮----
func TestPruner_EdgeCases(t *testing.T)
⋮----
// Should prune epoch 0, keep 1-5 (5 epochs)
⋮----
// Helper function to generate a range of epochs
func makeRange(start, end symbiotic.Epoch) []symbiotic.Epoch
```

## File: internal/usecase/pruner/pruner_uc.go

```go
package pruner
⋮----
import (
	"context"
	stderrors "errors"
	"log/slog"
	"time"

	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
stderrors "errors"
"log/slog"
"time"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
//go:generate mockgen -source=pruner_uc.go -destination=mocks/pruner_mocks.go -package=mocks
⋮----
type metrics interface {
	IncPrunedEpochsCount(entityType string)
}
⋮----
type NoopMetrics struct{}
⋮----
func (NoopMetrics) IncPrunedEpochsCount(string)
⋮----
type repo interface {
	GetOldestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	PruneValsetEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneProofEntities(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneSignatureEntitiesForEpoch(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
	PruneRequestIDEpochIndices(ctx context.Context, epoch symbiotic.Epoch, batchSize int) error
}
⋮----
type Config struct {
	Repo                     repo    `validate:"required"`
	Metrics                  metrics `validate:"required"`
	Enabled                  bool
	Interval                 time.Duration `validate:"gte=0"`
	ValsetRetentionEpochs    uint64
	ProofRetentionEpochs     uint64
	SignatureRetentionEpochs uint64
	PruneBatchSize           int `validate:"gte=0"`
	// ProgressFn is invoked once with current=0 when a non-empty entity-type
	// pass starts (so the caller knows the total) and again after each pruned
	// epoch with current=1..total. Optional; nil disables progress reporting.
	ProgressFn func(entityType string, current, total uint64)
}
⋮----
// ProgressFn is invoked once with current=0 when a non-empty entity-type
// pass starts (so the caller knows the total) and again after each pruned
// epoch with current=1..total. Optional; nil disables progress reporting.
⋮----
func (c Config) Validate() error
⋮----
// Pruning a valset epoch without also pruning the proof / signature data
// for that epoch leaves orphans (the dependent rows still reference an
// epoch whose validator set is gone). Require proof + signature retention
// whenever valset retention is set, and keep them no larger than valset
// retention so the dependents are removed first.
⋮----
type Service struct {
	cfg Config
}
⋮----
func New(cfg Config) (*Service, error)
⋮----
func (s *Service) Start(ctx context.Context)
⋮----
// Check if any retention is configured
⋮----
// RunOnce executes a single pruning pass over the repository: prunes valset, proof,
// signature and request-id-epoch entities according to the configured retention values.
// Safe to call without Start (e.g. from a one-shot CLI).
func (s *Service) RunOnce(ctx context.Context) error
⋮----
// Each entity-type pass is independent: a failure of one does not invalidate
// the others (e.g. proof pruning can succeed even if a single signature
// epoch fails). Continue on error and join failures so callers (sidecar
// loop logger, CLI exit code) can react. Context cancellation, however,
// short-circuits the remaining passes.
//
// Order matters for crash safety: the valset pass MUST be last. Subsequent
// runs use GetOldestValidatorSetEpoch as the lower bound for proof /
// signature / requestIdEpochIndex loops; if valset gets pruned first and we
// crash before the dependent passes finish, the next run's lower bound will
// jump forward and the orphaned dependents will never be reclaimed.
var errs []error
var proofCount, signatureCount, indexCount, valsetCount uint64
⋮----
func (s *Service) pruneValsetEntities(ctx context.Context, latestEpoch, oldestStoredEpoch symbiotic.Epoch) (uint64, error)
⋮----
func (s *Service) pruneProofEntities(ctx context.Context, latestEpoch, oldestStoredEpoch symbiotic.Epoch) (uint64, error)
⋮----
func (s *Service) pruneSignatureEntities(ctx context.Context, latestEpoch, oldestStoredEpoch symbiotic.Epoch) (uint64, error)
⋮----
// pruneRequestIDEpochIndices cleans up request ID epoch indices for old epochs.
// It uses the maximum retention window of proofs and signatures to determine which epochs
// might have indices to clean up. The actual deletion only happens if both the aggregation
// proof and signatures have been pruned for a given requestID.
func (s *Service) pruneRequestIDEpochIndices(ctx context.Context, latestEpoch, oldestStoredEpoch symbiotic.Epoch) (uint64, error)
⋮----
// Use the maximum of proof and signature retention to determine the range to scan
⋮----
// pruneEntities is a common utility function that implements the pruning logic for all entity types.
// It calculates the retention window and iterates through epochs to delete, calling the provided
// pruneFunc for each epoch.
func (s *Service) pruneEntities(
	ctx context.Context,
	latestEpoch, oldestStoredEpoch symbiotic.Epoch,
	retentionEpochs uint64,
	entityType string,
	pruneFunc func(context.Context, symbiotic.Epoch, int) error,
) (uint64, error)
```

## File: internal/usecase/signature-listener/mocks/signature_listener_uc.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: signature_listener_uc.go
//
// Generated by this command:
⋮----
//	mockgen -source=signature_listener_uc.go -destination=mocks/signature_listener_uc.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"

	entity "github.com/symbioticfi/relay/symbiotic/entity"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
⋮----
entity "github.com/symbioticfi/relay/symbiotic/entity"
gomock "go.uber.org/mock/gomock"
⋮----
// Mockrepo is a mock of repo interface.
type Mockrepo struct {
	ctrl     *gomock.Controller
	recorder *MockrepoMockRecorder
	isgomock struct{}
⋮----
// MockrepoMockRecorder is the mock recorder for Mockrepo.
type MockrepoMockRecorder struct {
	mock *Mockrepo
}
⋮----
// NewMockrepo creates a new mock instance.
func NewMockrepo(ctrl *gomock.Controller) *Mockrepo
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Mockrepo) EXPECT() *MockrepoMockRecorder
⋮----
// GetValidatorByKey mocks base method.
func (m *Mockrepo) GetValidatorByKey(ctx context.Context, epoch entity.Epoch, keyTag entity.KeyTag, publicKey []byte) (entity.Validator, uint32, error)
⋮----
// GetValidatorByKey indicates an expected call of GetValidatorByKey.
⋮----
// GetValidatorSetByEpoch mocks base method.
func (m *Mockrepo) GetValidatorSetByEpoch(ctx context.Context, epoch entity.Epoch) (entity.ValidatorSet, error)
⋮----
// GetValidatorSetByEpoch indicates an expected call of GetValidatorSetByEpoch.
⋮----
// MockentityProcessor is a mock of entityProcessor interface.
type MockentityProcessor struct {
	ctrl     *gomock.Controller
	recorder *MockentityProcessorMockRecorder
	isgomock struct{}
⋮----
// MockentityProcessorMockRecorder is the mock recorder for MockentityProcessor.
type MockentityProcessorMockRecorder struct {
	mock *MockentityProcessor
}
⋮----
// NewMockentityProcessor creates a new mock instance.
func NewMockentityProcessor(ctrl *gomock.Controller) *MockentityProcessor
⋮----
// ProcessSignature mocks base method.
func (m *MockentityProcessor) ProcessSignature(ctx context.Context, signature entity.Signature, self bool) error
⋮----
// ProcessSignature indicates an expected call of ProcessSignature.
```

## File: internal/usecase/signature-listener/signature_listener_uc_test.go

```go
package signature_listener
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	intEntity "github.com/symbioticfi/relay/internal/entity"
	entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
	"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"crypto/rand"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
intEntity "github.com/symbioticfi/relay/internal/entity"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestHandleSignatureReceivedMessage_HappyPath(t *testing.T)
⋮----
// Create real private key for signing
⋮----
// Create signature with the private key
⋮----
// Create validator set with the matching public key
⋮----
// Create P2P message with real signature
⋮----
// Execute
⋮----
// Verify that signature was saved
⋮----
// Verify the signature matches what we expect
⋮----
// Verify that signature map was updated
⋮----
type testSetup struct {
	repo    cached.Repository
	useCase *SignatureListenerUseCase
}
⋮----
func newTestSetup(t *testing.T, newRepo repoFactory) *testSetup
⋮----
// Create mock aggregator for entity processor
⋮----
// Create mock aggregation proof signal for entity processor
⋮----
// Create mock signature processed signal for entity processor
⋮----
type repoFactory func(t *testing.T) cached.Repository
⋮----
func backends() map[string]repoFactory
⋮----
func newPrivateKey(t *testing.T) crypto.PrivateKey
⋮----
func (setup *testSetup) createTestValidatorSetWithKey(t *testing.T, privateKey crypto.PrivateKey) symbiotic.ValidatorSet
⋮----
// Save the validator set to the repository
⋮----
func randomNetworkConfig() symbiotic.NetworkConfig
⋮----
func createTestP2PMessageWithSignature(privateKey crypto.PrivateKey, hash []byte, signature []byte) intEntity.P2PMessage[symbiotic.Signature]
⋮----
type doNothingMetrics struct{}
⋮----
func (d doNothingMetrics) ObserveEpoch(epochType string, epochNumber uint64)
```

## File: internal/usecase/signature-listener/signature_listener_uc.go

```go
package signature_listener
⋮----
import (
	"context"
	"log/slog"

	"github.com/go-errors/errors"
	validate "github.com/go-playground/validator/v10"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/go-errors/errors"
validate "github.com/go-playground/validator/v10"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
//go:generate mockgen -source=signature_listener_uc.go -destination=mocks/signature_listener_uc.go -package=mocks
⋮----
type repo interface {
	GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
}
⋮----
type entityProcessor interface {
	ProcessSignature(ctx context.Context, signature symbiotic.Signature, self bool) error
}
⋮----
type Config struct {
	Repo            repo            `validate:"required"`
	EntityProcessor entityProcessor `validate:"required"`
	SignalCfg       signals.Config  `validate:"required"`
	SelfP2PID       string          `validate:"required"`
}
⋮----
type SignatureListenerUseCase struct {
	cfg Config
}
⋮----
func New(cfg Config) (*SignatureListenerUseCase, error)
⋮----
func (s *SignatureListenerUseCase) HandleSignatureReceivedMessage(ctx context.Context, p2pMsg entity.P2PMessage[symbiotic.Signature]) error
```

## File: internal/usecase/signer-app/mocks/signer_app.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: signer_app.go
//
// Generated by this command:
⋮----
//	mockgen -source=signer_app.go -destination=mocks/signer_app.go -package=mocks
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"
	time "time"

	common "github.com/ethereum/go-ethereum/common"
	entity "github.com/symbioticfi/relay/symbiotic/entity"
	crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
time "time"
⋮----
common "github.com/ethereum/go-ethereum/common"
entity "github.com/symbioticfi/relay/symbiotic/entity"
crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
gomock "go.uber.org/mock/gomock"
⋮----
// Mockrepo is a mock of repo interface.
type Mockrepo struct {
	ctrl     *gomock.Controller
	recorder *MockrepoMockRecorder
	isgomock struct{}
⋮----
// MockrepoMockRecorder is the mock recorder for Mockrepo.
type MockrepoMockRecorder struct {
	mock *Mockrepo
}
⋮----
// NewMockrepo creates a new mock instance.
func NewMockrepo(ctrl *gomock.Controller) *Mockrepo
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Mockrepo) EXPECT() *MockrepoMockRecorder
⋮----
// GetSignaturePending mocks base method.
func (m *Mockrepo) GetSignaturePending(ctx context.Context, limit int) ([]common.Hash, error)
⋮----
// GetSignaturePending indicates an expected call of GetSignaturePending.
⋮----
// GetSignatureRequest mocks base method.
func (m *Mockrepo) GetSignatureRequest(ctx context.Context, requestID common.Hash) (entity.SignatureRequest, error)
⋮----
// GetSignatureRequest indicates an expected call of GetSignatureRequest.
⋮----
// GetValidatorSetByEpoch mocks base method.
func (m *Mockrepo) GetValidatorSetByEpoch(ctx context.Context, epoch entity.Epoch) (entity.ValidatorSet, error)
⋮----
// GetValidatorSetByEpoch indicates an expected call of GetValidatorSetByEpoch.
⋮----
// RemoveSignaturePending mocks base method.
func (m *Mockrepo) RemoveSignaturePending(ctx context.Context, epoch entity.Epoch, requestID common.Hash) error
⋮----
// RemoveSignaturePending indicates an expected call of RemoveSignaturePending.
⋮----
// SaveSignatureRequest mocks base method.
func (m *Mockrepo) SaveSignatureRequest(ctx context.Context, requestID common.Hash, req entity.SignatureRequest) error
⋮----
// SaveSignatureRequest indicates an expected call of SaveSignatureRequest.
⋮----
// Mockp2pService is a mock of p2pService interface.
type Mockp2pService struct {
	ctrl     *gomock.Controller
	recorder *Mockp2pServiceMockRecorder
	isgomock struct{}
⋮----
// Mockp2pServiceMockRecorder is the mock recorder for Mockp2pService.
type Mockp2pServiceMockRecorder struct {
	mock *Mockp2pService
}
⋮----
// NewMockp2pService creates a new mock instance.
func NewMockp2pService(ctrl *gomock.Controller) *Mockp2pService
⋮----
// BroadcastSignatureGeneratedMessage mocks base method.
func (m *Mockp2pService) BroadcastSignatureGeneratedMessage(ctx context.Context, msg entity.Signature) error
⋮----
// BroadcastSignatureGeneratedMessage indicates an expected call of BroadcastSignatureGeneratedMessage.
⋮----
// MockkeyProvider is a mock of keyProvider interface.
type MockkeyProvider struct {
	ctrl     *gomock.Controller
	recorder *MockkeyProviderMockRecorder
	isgomock struct{}
⋮----
// MockkeyProviderMockRecorder is the mock recorder for MockkeyProvider.
type MockkeyProviderMockRecorder struct {
	mock *MockkeyProvider
}
⋮----
// NewMockkeyProvider creates a new mock instance.
func NewMockkeyProvider(ctrl *gomock.Controller) *MockkeyProvider
⋮----
// GetOnchainKeyFromCache mocks base method.
func (m *MockkeyProvider) GetOnchainKeyFromCache(keyTag entity.KeyTag) (entity.CompactPublicKey, error)
⋮----
// GetOnchainKeyFromCache indicates an expected call of GetOnchainKeyFromCache.
⋮----
// GetPrivateKey mocks base method.
func (m *MockkeyProvider) GetPrivateKey(keyTag entity.KeyTag) (crypto.PrivateKey, error)
⋮----
// GetPrivateKey indicates an expected call of GetPrivateKey.
⋮----
// Mockmetrics is a mock of metrics interface.
type Mockmetrics struct {
	ctrl     *gomock.Controller
	recorder *MockmetricsMockRecorder
	isgomock struct{}
⋮----
// MockmetricsMockRecorder is the mock recorder for Mockmetrics.
type MockmetricsMockRecorder struct {
	mock *Mockmetrics
}
⋮----
// NewMockmetrics creates a new mock instance.
func NewMockmetrics(ctrl *gomock.Controller) *Mockmetrics
⋮----
// ObserveAppSignDuration mocks base method.
func (m *Mockmetrics) ObserveAppSignDuration(d time.Duration)
⋮----
// ObserveAppSignDuration indicates an expected call of ObserveAppSignDuration.
⋮----
// ObservePKSignDuration mocks base method.
func (m *Mockmetrics) ObservePKSignDuration(d time.Duration)
⋮----
// ObservePKSignDuration indicates an expected call of ObservePKSignDuration.
⋮----
// MockentityProcessor is a mock of entityProcessor interface.
type MockentityProcessor struct {
	ctrl     *gomock.Controller
	recorder *MockentityProcessorMockRecorder
	isgomock struct{}
⋮----
// MockentityProcessorMockRecorder is the mock recorder for MockentityProcessor.
type MockentityProcessorMockRecorder struct {
	mock *MockentityProcessor
}
⋮----
// NewMockentityProcessor creates a new mock instance.
func NewMockentityProcessor(ctrl *gomock.Controller) *MockentityProcessor
⋮----
// ProcessAggregationProof mocks base method.
func (m *MockentityProcessor) ProcessAggregationProof(ctx context.Context, proof entity.AggregationProof, self bool) error
⋮----
// ProcessAggregationProof indicates an expected call of ProcessAggregationProof.
⋮----
// ProcessSignature mocks base method.
func (m *MockentityProcessor) ProcessSignature(ctx context.Context, signature entity.Signature, self bool) error
⋮----
// ProcessSignature indicates an expected call of ProcessSignature.
```

## File: internal/usecase/signer-app/signer_app_handle_signature_aggregated_message.go

```go
package signer_app
⋮----
import (
	"context"
	"log/slog"

	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/go-errors/errors"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (s *SignerApp) HandleSignaturesAggregatedMessage(ctx context.Context, p2pMsg entity.P2PMessage[symbiotic.AggregationProof]) error
```

## File: internal/usecase/signer-app/signer_app_test.go

```go
package signer_app
⋮----
import (
	"crypto/rand"
	"log/slog"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/samber/lo"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
	entity_mocks "github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/internal/usecase/signer-app/mocks"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"crypto/rand"
"log/slog"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
entity_mocks "github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/signer-app/mocks"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
func TestSign_HappyPath(t *testing.T)
⋮----
// Add the private key to the real key provider
⋮----
// Mock the remaining dependencies
⋮----
// Sign
⋮----
// Verify that signature request was saved
⋮----
// Verify that signature is correct
⋮----
type testSetup struct {
	ctrl        *gomock.Controller
	repo        cached.Repository
	keyProvider *keyprovider.SimpleKeystoreProvider
	mockP2P     *mocks.Mockp2pService
	mockMetrics *mocks.Mockmetrics
	app         *SignerApp
}
⋮----
type repoFactory func(t *testing.T) cached.Repository
⋮----
func backends() map[string]repoFactory
⋮----
func newTestSetup(t *testing.T, newRepo repoFactory) *testSetup
⋮----
// Create mocks for other dependencies
⋮----
// Create mock aggregator for entity processor
⋮----
// Create mock aggregation proof signal for entity processor
⋮----
// Create mock signature processed signal for entity processor
⋮----
func createTestSignatureRequest(msg string) symbiotic.SignatureRequest
⋮----
func newPrivateKey(t *testing.T) crypto.PrivateKey
⋮----
func randomNetworkConfig() symbiotic.NetworkConfig
⋮----
func createTestValidatorSet(t *testing.T, setup *testSetup, privateKey crypto.PrivateKey) symbiotic.ValidatorSet
⋮----
type doNothingMetrics struct{}
⋮----
func (d doNothingMetrics) ObserveEpoch(epochType string, epochNumber uint64)
```

## File: internal/usecase/signer-app/signer_app.go

```go
package signer_app
⋮----
import (
	"context"
	"log/slog"
	"time"

	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	validate "github.com/go-playground/validator/v10"
	"k8s.io/client-go/util/workqueue"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
validate "github.com/go-playground/validator/v10"
"k8s.io/client-go/util/workqueue"
⋮----
//go:generate mockgen -source=signer_app.go -destination=mocks/signer_app.go -package=mocks
⋮----
type repo interface {
	SaveSignatureRequest(ctx context.Context, requestID common.Hash, req symbiotic.SignatureRequest) error
	RemoveSignaturePending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
	GetSignaturePending(ctx context.Context, limit int) ([]common.Hash, error)
	GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
}
⋮----
type p2pService interface {
	BroadcastSignatureGeneratedMessage(ctx context.Context, msg symbiotic.Signature) error
}
⋮----
type keyProvider interface {
	GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
	GetOnchainKeyFromCache(keyTag symbiotic.KeyTag) (symbiotic.CompactPublicKey, error)
}
⋮----
type metrics interface {
	ObservePKSignDuration(d time.Duration)
	ObserveAppSignDuration(d time.Duration)
}
⋮----
type entityProcessor interface {
	ProcessSignature(ctx context.Context, signature symbiotic.Signature, self bool) error
	ProcessAggregationProof(ctx context.Context, proof symbiotic.AggregationProof, self bool) error
}
⋮----
type Config struct {
	KeyProvider     keyProvider     `validate:"required"`
	Repo            repo            `validate:"required"`
	EntityProcessor entityProcessor `validate:"required"`
	Metrics         metrics         `validate:"required"`
	SelfP2PID       string          `validate:"required"`
}
⋮----
func (c Config) Validate() error
⋮----
type SignerApp struct {
	cfg   Config
	queue *workqueue.Typed[common.Hash]
}
⋮----
func NewSignerApp(cfg Config) (*SignerApp, error)
⋮----
// RequestSignature creates a signature request and queues it for signing, returns requestID
// The actual signing is done in the background by workers
func (s *SignerApp) RequestSignature(ctx context.Context, req symbiotic.SignatureRequest) (common.Hash, error)
⋮----
// does not return the actual signature yet
⋮----
func (s *SignerApp) EnqueueRequestID(ctx context.Context, requestID common.Hash)
⋮----
func (s *SignerApp) completeSign(ctx context.Context, requestID common.Hash, p2pService p2pService) error
⋮----
func (s *SignerApp) HandleSignatureRequests(ctx context.Context, workerCount int, p2pService p2pService) error
⋮----
// start workers
⋮----
func (s *SignerApp) worker(ctx context.Context, id int, p2pService p2pService)
⋮----
func (s *SignerApp) handleMissedSignaturesOnce(ctx context.Context) error
```

## File: internal/usecase/sync-provider/sync_provider_build_want_aggregation_proofs_request.go

```go
package sync_provider
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// BuildWantAggregationProofsRequest builds a request for missing aggregation proofs from recent epochs
func (s *Syncer) BuildWantAggregationProofsRequest(ctx context.Context) (entity.WantAggregationProofsRequest, error)
⋮----
var allRequestIDs []common.Hash
⋮----
// Iterate through epochs from newest to oldest to prioritize recent requests
⋮----
var lastHash common.Hash
⋮----
// Paginate through signature requests without aggregation proofs for this epoch
⋮----
break // No more requests for this epoch
⋮----
// Check if proof already exists — clean up stale pending marker
⋮----
lastHash = requests[len(requests)-1].RequestID // Update for pagination
⋮----
// Handle epoch == 0 to avoid underflow in unsigned arithmetic
```

## File: internal/usecase/sync-provider/sync_provider_build_want_signatures_map.go

```go
package sync_provider
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (s *Syncer) BuildWantSignaturesRequest(ctx context.Context) (entity.WantSignaturesRequest, error)
⋮----
// buildWantSignaturesMap constructs a map of request id to missing validator bitmaps
// for pending signature requests across multiple epochs.
//
// The method performs the following operations:
// 1. Determines the epoch range to scan (from latest epoch back to EpochsToSync epochs)
// 2. Iterates through epochs from newest to oldest to prioritize recent requests
// 3. For each epoch, fetches pending signature requests in batches
// 4. For each request, identifies validators that haven't provided signatures yet
// 5. Builds a map where keys are request ids and values are bitmaps of missing validators
⋮----
// The scanning is limited by MaxSignatureRequestsPerSync to prevent excessive memory usage
// and network overhead during synchronization.
⋮----
// Behavior:
//   - Scans epochs in reverse order (newest first) to prioritize recent requests
//   - Stops scanning when MaxSignatureRequestsPerSync limit is reached
//   - Only includes requests that have missing signatures (non-empty bitmaps)
//   - Uses pagination to handle large numbers of requests per epoch
func (s *Syncer) buildWantSignaturesMap(ctx context.Context) (map[common.Hash]entity.Bitmap, error)
⋮----
var startEpoch symbiotic.Epoch
⋮----
var lastHash common.Hash
⋮----
// Process each request to find missing signatures
⋮----
// For aggregation keys, check if proof already exists — clean up pending
⋮----
// Get current signature map
⋮----
// No signatures yet, all validators are missing
⋮----
// Get missing validators from signature map
⋮----
// For non-aggregation keys: all signatures collected — clean up pending
⋮----
// If we got fewer requests than requested, we've reached the end for this epoch
```

## File: internal/usecase/sync-provider/sync_provider_handle_want_aggregation_proofs_request.go

```go
package sync_provider
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// HandleWantAggregationProofsRequest handles incoming requests for aggregation proofs from peers
func (s *Syncer) HandleWantAggregationProofsRequest(ctx context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
⋮----
// Process each requested hash
⋮----
// Stop if we've reached the maximum response count
⋮----
// Try to get the aggregation proof
⋮----
// Aggregation proof not found, skip this request
⋮----
// Add the proof to the response
```

## File: internal/usecase/sync-provider/sync_provider_handle_want_signatures.go

```go
package sync_provider
⋮----
import (
	"context"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
// HandleWantSignaturesRequest processes a peer's request for missing signatures and returns
// the requested signatures that are available in local storage.
//
// The method performs the following operations:
// 1. Iterates through each request id in the incoming request
// 2. For each requested validator index, directly retrieves the signature using GetSignatureByIndex
// 3. Builds a response containing validator signatures organized by request id
⋮----
// The response is limited by MaxResponseSignatureCount to prevent memory exhaustion
// and network congestion during P2P synchronization.
⋮----
// Behavior:
//   - Processes requests in iteration order (map iteration is non-deterministic)
//   - Stops processing when MaxResponseSignatureCount limit is reached
//   - Skips validator indices where signatures are not found locally
//   - Returns empty signatures map for request ids where no matching signatures are found
func (s *Syncer) HandleWantSignaturesRequest(ctx context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
⋮----
// Check signature count limit before processing each request
⋮----
var validatorSigs []entity.ValidatorSignature
⋮----
// Iterate over requested validator indices and get signatures directly
⋮----
// Check limit before processing each signature
⋮----
// Get signature by validator index directly
⋮----
// Signature not found for this validator index, skip
```

## File: internal/usecase/sync-provider/sync_provider_process_received_aggregation_proofs.go

```go
package sync_provider
⋮----
import (
	"context"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// ProcessReceivedAggregationProofs processes aggregation proofs received from peers,
// filtering out any proofs that were not explicitly requested.
func (s *Syncer) ProcessReceivedAggregationProofs(ctx context.Context, response entity.WantAggregationProofsResponse, requestedIDs []common.Hash) (entity.AggregationProofProcessingStats, error)
⋮----
// processSingleAggregationProof processes a single aggregation proof
func (s *Syncer) processSingleAggregationProof(ctx context.Context, proof symbiotic.AggregationProof, stats *entity.AggregationProofProcessingStats)
⋮----
// Process the aggregation proof using the signature processor
⋮----
return // Continue processing other proofs
```

## File: internal/usecase/sync-provider/sync_provider_process_received_signatures.go

```go
package sync_provider
⋮----
import (
	"context"
	"log/slog"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"context"
"log/slog"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
// ProcessReceivedSignatures validates and processes signatures received from peer nodes during
// synchronization, updating local storage and tracking statistics for monitoring.
//
// The method performs the following validation and processing steps:
// 1. Validates that received signatures were actually requested (hash and validator index matching)
// 2. Retrieves original signature request metadata (epoch, key type, etc.)
// 3. Reconstructs and validates public keys from signature data
// 4. Cross-references validator information to ensure consistency
// 5. Processes valid signatures through the signature processor
// 6. Emits signature received signals for downstream components
// 7. Tracks comprehensive statistics for all outcomes
⋮----
// The method is designed to be resilient against malformed or malicious peer responses,
// validating all received data before processing and continuing on errors.
⋮----
// Behavior:
//   - Validates all received signatures against original requests
//   - Skips invalid signatures and continues processing others
//   - Handles duplicate signatures gracefully (tracks but doesn't error)
//   - Emits signals for successfully processed signatures
//   - Returns comprehensive statistics for monitoring and debugging
//   - Logs warnings for validation failures and errors
func (s *Syncer) ProcessReceivedSignatures(ctx context.Context, response entity.WantSignaturesResponse, wantSignatures map[common.Hash]entity.Bitmap) entity.SignatureProcessingStats
⋮----
var stats entity.SignatureProcessingStats
⋮----
// Validate that we actually requested this validator's signature
⋮----
// Get the original signature request to extract epoch and other details
```

## File: internal/usecase/sync-provider/sync_provider_process_received_test.go

```go
package sync_provider
⋮----
import (
	"context"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type testRepo interface {
	repo

	SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error
}
⋮----
type failingEntityProcessor struct {
	t *testing.T
}
⋮----
func (p failingEntityProcessor) ProcessSignature(context.Context, symbiotic.Signature, bool) error
⋮----
func (p failingEntityProcessor) ProcessAggregationProof(context.Context, symbiotic.AggregationProof, bool) error
⋮----
func TestSyncer_ProcessReceivedSignatures_SkipsMismatchedRequestID(t *testing.T)
⋮----
func TestSyncer_ProcessReceivedSignatures_SkipsMismatchedValidatorIndex(t *testing.T)
⋮----
func TestSyncer_ProcessReceivedAggregationProofs_SkipsMismatchedRequestID(t *testing.T)
⋮----
func signRequest(t *testing.T, privateKey crypto.PrivateKey, request symbiotic.SignatureRequest) symbiotic.Signature
⋮----
func saveValidatorSetData(
	t *testing.T,
	repo testRepo,
	validatorSet symbiotic.ValidatorSet,
	signatureRequest symbiotic.SignatureRequest,
	requestID common.Hash,
)
⋮----
func newTestSyncer(t *testing.T, repo repo, processor entityProcessor) *Syncer
```

## File: internal/usecase/sync-provider/sync_provider_test.go

```go
package sync_provider
⋮----
import (
	"crypto/rand"
	"fmt"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
	bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
	"github.com/symbioticfi/relay/internal/client/repository/cached"
	"github.com/symbioticfi/relay/internal/client/repository/repoutil"
	"github.com/symbioticfi/relay/internal/entity"
	entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
	"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
	"github.com/symbioticfi/relay/pkg/signals"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"crypto/rand"
"fmt"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
badgerrepo "github.com/symbioticfi/relay/internal/client/repository/badger"
bboltrepo "github.com/symbioticfi/relay/internal/client/repository/bbolt"
"github.com/symbioticfi/relay/internal/client/repository/cached"
"github.com/symbioticfi/relay/internal/client/repository/repoutil"
"github.com/symbioticfi/relay/internal/entity"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
"github.com/symbioticfi/relay/internal/usecase/entity-processor/mocks"
"github.com/symbioticfi/relay/pkg/signals"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type repoFactory func(t *testing.T) cached.Repository
⋮----
func backends() map[string]repoFactory
⋮----
func TestAskSignatures_HandleWantSignaturesRequest_Integration(t *testing.T)
⋮----
// Create test data
⋮----
// Save signature request and signature on peer
⋮----
// Save signature request on both repos so peer can respond to requests
⋮----
// Create peer syncer first (with a temporary mock)
⋮----
// Create requester syncer
⋮----
// Verify requester initially has no signatures
⋮----
require.Len(t, initialSignatures, 1) // Already has one signature from param1
⋮----
// Verify requester has signature request
⋮----
// Call BuildWantSignaturesRequest on requester
⋮----
// Verify requester now has the signature
⋮----
// Verify the signature is correct
⋮----
func createMockAggregator(t *testing.T) *mocks.MockAggregator
⋮----
// Default behavior: return true for verification
⋮----
func createMockAggProofSignal(t *testing.T) *mocks.MockAggProofSignal
⋮----
// Default behavior: return nil for emit
⋮----
func createMockSignatureProcessedSignal(t *testing.T) *signals.Signal[symbiotic.Signature]
⋮----
func createTestSignatureRequest(t *testing.T) symbiotic.SignatureRequest
⋮----
Message:       randomBytes(t, 100), // Random message makes each request unique
⋮----
func newPrivateKey(t *testing.T) crypto.PrivateKey
⋮----
func createTestValidatorSet(t *testing.T, privateKey ...crypto.PrivateKey) symbiotic.ValidatorSet
⋮----
func createTestValidatorSetWithMultipleValidators(t *testing.T, count int) (symbiotic.ValidatorSet, []crypto.PrivateKey)
⋮----
func randomBytes(t *testing.T, n int) []byte
⋮----
func TestHandleWantSignaturesRequest_EmptyRequest(t *testing.T)
⋮----
func TestHandleWantSignaturesRequest_MaxResponseSignatureCountLimit(t *testing.T)
⋮----
// Create test data with multiple signatures
validatorSet, privateKeys := createTestValidatorSetWithMultipleValidators(t, 5) // Create 5 validators
⋮----
// Setup repository with validator set and signature request
⋮----
// Store multiple signatures by validator index
⋮----
var requestID common.Hash
// Save signatures for multiple validator indices (simulate multiple validators)
⋮----
MaxResponseSignatureCount:   2, // Low limit
⋮----
requestID: entity.NewBitmapOf(0, 1, 2, 3, 4), // Request all 5 signatures
⋮----
require.Len(t, response.Signatures[requestID], 2) // Should return only 2 signatures due to limit
⋮----
MaxResponseSignatureCount:   3, // Allow 3 signatures
⋮----
requestID: entity.NewBitmapOf(0, 1, 2), // Request exactly 3 signatures
⋮----
func TestHandleWantSignaturesRequest_MultipleRequestIDs(t *testing.T)
⋮----
// Store signatures for both requests
⋮----
validatorSet, privateKeys := createTestValidatorSetWithMultipleValidators(t, 2) // Create 2 validators
⋮----
// Setup repository
⋮----
// Save signature for first request
⋮----
// Save signature for second request
⋮----
param1.RequestID(): entity.NewBitmapOf(0), // Request validator 0 from first request
param2.RequestID(): entity.NewBitmapOf(1), // Request validator 1 from second request
⋮----
func TestHandleWantSignaturesRequest_PartialSignatureAvailability(t *testing.T)
⋮----
validatorSet, privateKeys := createTestValidatorSetWithMultipleValidators(t, 4) // Create 4 validators
⋮----
// Save signatures only for validator indices 0 and 2 (skip 1 and 3)
⋮----
requestID: entity.NewBitmapOf(0, 1, 2, 3), // Request all 4, but only 0 and 2 exist
⋮----
// Check that we got the right validator indices
⋮----
func randomNetworkConfig() symbiotic.NetworkConfig
⋮----
type doNothingMetrics struct{}
⋮----
func (d doNothingMetrics) ObserveEpoch(epochType string, epochNumber uint64)
```

## File: internal/usecase/sync-provider/sync_provider.go

```go
package sync_provider
⋮----
import (
	"context"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/entity"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/entity"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type repo interface {
	GetSignatureMap(ctx context.Context, requestID common.Hash) (entity.SignatureMap, error)
	GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetSignatureRequest(ctx context.Context, requestID common.Hash) (symbiotic.SignatureRequest, error)
	GetValidatorByKey(ctx context.Context, epoch symbiotic.Epoch, keyTag symbiotic.KeyTag, publicKey []byte) (symbiotic.Validator, uint32, error)
	GetAllSignatures(ctx context.Context, requestID common.Hash) ([]symbiotic.Signature, error)
	GetSignatureByIndex(ctx context.Context, requestID common.Hash, validatorIndex uint32) (symbiotic.Signature, error)
	GetSignatureRequestsWithoutAggregationProof(ctx context.Context, epoch symbiotic.Epoch, limit int, lastHash common.Hash) ([]symbiotic.SignatureRequestWithID, error)
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	RemoveAggregationProofPending(ctx context.Context, epoch symbiotic.Epoch, requestID common.Hash) error
}
⋮----
type entityProcessor interface {
	ProcessSignature(ctx context.Context, signature symbiotic.Signature, self bool) error
	ProcessAggregationProof(ctx context.Context, proof symbiotic.AggregationProof, self bool) error
}
⋮----
type Config struct {
	Repo                        repo            `validate:"required"`
	EntityProcessor             entityProcessor `validate:"required"`
	EpochsToSync                uint64          `validate:"gte=0"`
	MaxSignatureRequestsPerSync int             `validate:"gt=0"`
	MaxResponseSignatureCount   int             `validate:"gt=0"`
	MaxAggProofRequestsPerSync  int             `validate:"gt=0"`
	MaxResponseAggProofCount    int             `validate:"gt=0"`
}
⋮----
type Syncer struct {
	cfg Config
}
⋮----
func New(cfg Config) (*Syncer, error)
```

## File: internal/usecase/sync-runner/sync_runner.go

```go
package sync_runner
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
type p2pService interface {
	SendWantSignaturesRequest(ctx context.Context, request entity.WantSignaturesRequest) (entity.WantSignaturesResponse, error)
	SendWantAggregationProofsRequest(ctx context.Context, request entity.WantAggregationProofsRequest) (entity.WantAggregationProofsResponse, error)
}
⋮----
type provider interface {
	BuildWantSignaturesRequest(ctx context.Context) (entity.WantSignaturesRequest, error)
	ProcessReceivedSignatures(ctx context.Context, response entity.WantSignaturesResponse, wantSignatures map[common.Hash]entity.Bitmap) entity.SignatureProcessingStats
	BuildWantAggregationProofsRequest(ctx context.Context) (entity.WantAggregationProofsRequest, error)
	ProcessReceivedAggregationProofs(ctx context.Context, response entity.WantAggregationProofsResponse, requestedIDs []common.Hash) (entity.AggregationProofProcessingStats, error)
}
⋮----
type metrics interface {
	ObserveP2PSyncSignaturesProcessed(resultType string, count int)
	ObserveP2PSyncRequestedHashes(count int)
	ObserveP2PSyncAggregationProofsProcessed(resultType string, count int)
	ObserveP2PSyncRequestedAggregationProofs(count int)
}
⋮----
type Config struct {
	Enabled     bool
	P2PService  p2pService    `validate:"required"`
	Provider    provider      `validate:"required"`
	SyncPeriod  time.Duration `validate:"gt=0"`
	SyncTimeout time.Duration `validate:"gt=0"`
	Metrics     metrics       `validate:"required"`
}
⋮----
type Runner struct {
	cfg Config
}
⋮----
func New(cfg Config) (*Runner, error)
⋮----
func (s *Runner) Start(ctx context.Context) error
⋮----
// Run signature sync
⋮----
// Run aggregation proof sync independently
⋮----
func (s *Runner) runSignatureSync(ctx context.Context) error
⋮----
// Create context with timeout for signature sync
⋮----
func (s *Runner) runAggregationProofSync(ctx context.Context) error
⋮----
// Create context with timeout for aggregation proof sync
```

## File: internal/usecase/valset-listener/valset_generator_handle_agg_proof.go

```go
package valset_listener
⋮----
import (
	"context"
	"log/slog"
	"time"

	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	minCommitterPollIntervalSeconds = uint64(5)
⋮----
func (s *Service) StartCommitterLoop(ctx context.Context) error
⋮----
// get the latest epoch and try to find schedule of committers and start committing
⋮----
// force to tick immediately as soon as it starts
⋮----
func (s *Service) tryToCommitPendingProofs(ctx context.Context) (uint64, error)
⋮----
// Dev: we check if the no. of uncommitted epochs is > the batch size then there's a chance
// that we might've already committed some epochs but those are not finalized,
// hence to optimize for both time and network calls we directly check on the
// settlement layers to see what's the latest(not finalized) commit
⋮----
func (s *Service) processPendingProof(ctx context.Context, proofKey symbiotic.ProofCommitKey) error
⋮----
// on partial failure just log error and continue, we will retry later
⋮----
func (s *Service) detectLastCommittedEpochFromDB(ctx context.Context) symbiotic.Epoch
⋮----
func (s *Service) detectLastCommittedEpochFromChain(ctx context.Context, config symbiotic.NetworkConfig) symbiotic.Epoch
⋮----
// skip chain if networking issue, we will recheck again anyway and if the rpc/chain recovers we will detect issue later
⋮----
// commitValsetToAllSettlements commits the validator set header to all configured settlement chains.
//
// Performance Optimization: This method uses entity.BlockNumberLatest instead of finalized blocks
// when checking commitment status. This optimization reduces latency by ~12-15 seconds
// on Ethereum (approximately 2 finalization epochs), allowing faster detection of already-committed
// headers and reducing unnecessary duplicate commitment transactions.
⋮----
// Safety: The pending proof cleanup happens separately in the status tracker, which uses finalized
// blocks to verify commitments before removing pending proofs. This ensures data consistency:
//   - This method: uses latest blocks for fast pre-flight checks (avoid duplicate tx submissions)
//   - Status tracker: uses finalized blocks for authoritative verification (safe pending proof removal)
⋮----
// Trade-off: Using latest blocks for pre-flight checks introduces a small reorg risk, but this is
// acceptable because:
//  1. False positives (thinking a header is committed when it's not due to reorg) may trigger a
//     duplicate transaction, but the contract will reject it
//  2. False negatives (missing a commitment due to reorg) will be corrected in the next iteration
//  3. The performance benefit of reduced latency outweighs the minimal reorg risk
//  4. Final cleanup only happens after finalized block confirmation in the status tracker
⋮----
// Returns a bool to indicate if at least once settlement commit worked and error if any commitment fails
func (s *Service) commitValsetToAllSettlements(ctx context.Context, config symbiotic.NetworkConfig, header symbiotic.ValidatorSetHeader, extraData []symbiotic.ExtraData, proof []byte) (bool, error)
⋮----
// todo replace it with tx check instead of call to contract
// if commit tx was sent but still not finalized this check will
// return false positive and trigger one more commitment tx
```

## File: internal/usecase/valset-listener/valset_listener_uc.go

```go
package valset_listener
⋮----
import (
	"context"
	"log/slog"
	"math/big"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/signals"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
"log/slog"
"math/big"
"sync"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
type signer interface {
	EnqueueRequestID(ctx context.Context, requestID common.Hash)
}
⋮----
type repo interface {
	GetLatestValidatorSetHeader(_ context.Context) (symbiotic.ValidatorSetHeader, error)
	GetOldestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetValidatorSetByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	GetConfigByEpoch(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetAggregationProof(ctx context.Context, requestID common.Hash) (symbiotic.AggregationProof, error)
	GetPendingProofCommitsSinceEpoch(ctx context.Context, epoch symbiotic.Epoch, limit int) ([]symbiotic.ProofCommitKey, error)
	SaveNextValsetData(ctx context.Context, data entity.NextValsetData) error
	GetFirstUncommittedValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	UpdateValidatorSetStatus(ctx context.Context, epoch symbiotic.Epoch, item symbiotic.ValidatorSetStatus) error
	GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
}
⋮----
type deriver interface {
	GetValidatorSet(ctx context.Context, epoch symbiotic.Epoch, config symbiotic.NetworkConfig) (symbiotic.ValidatorSet, error)
	GetNetworkData(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.NetworkData, error)
}
⋮----
type metrics interface {
	ObserveAggregationProofSize(proofSize int, validatorCount int)
	ObserveEpoch(epochType string, epochNumber uint64)
}
⋮----
type keyProvider interface {
	GetPrivateKey(keyTag symbiotic.KeyTag) (crypto.PrivateKey, error)
	GetOnchainKeyFromCache(keyTag symbiotic.KeyTag) (symbiotic.CompactPublicKey, error)
}
⋮----
type evmClient interface {
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	CommitValsetHeader(ctx context.Context, addr symbiotic.CrossChainAddress, header symbiotic.ValidatorSetHeader, extraData []symbiotic.ExtraData, proof []byte) (symbiotic.TxResult, error)
	IsValsetHeaderCommittedAtEpochs(ctx context.Context, addr symbiotic.CrossChainAddress, epochs []symbiotic.Epoch) ([]bool, error)
	GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, evmOptions ...symbiotic.EVMOption) (symbiotic.Epoch, error)
	IsValsetHeaderCommittedAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, opts ...symbiotic.EVMOption) (_ bool, err error)
}
⋮----
type Config struct {
	EvmClient           evmClient                               `validate:"required"`
	Repo                repo                                    `validate:"required"`
	Deriver             deriver                                 `validate:"required"`
	PollingInterval     time.Duration                           `validate:"required,gt=0"`
	Signer              signer                                  `validate:"required"`
	ValidatorSet        *signals.Signal[symbiotic.ValidatorSet] `validate:"required"`
	KeyProvider         keyProvider
	Aggregator          aggregator.Aggregator
	Metrics             metrics `validate:"required"`
	ForceCommitter      bool
	EpochRetentionCount uint64
}
⋮----
func (c Config) Validate() error
⋮----
type Service struct {
	cfg   Config
	mutex sync.Mutex
}
⋮----
func New(cfg Config) (*Service, error)
⋮----
// LoadAllMissingEpochs runs tryLoadMissingEpochs until all missing epochs are loaded successfully
func (s *Service) LoadAllMissingEpochs(ctx context.Context) error
⋮----
const maxRetries = 10
⋮----
func (s *Service) determineStartupSyncRangeAndLoadMissingEpochs(ctx context.Context) error
⋮----
func (s *Service) Start(ctx context.Context) error
⋮----
func (s *Service) determineSteadySyncRangeAndLoadMissingEpochs(ctx context.Context) (time.Duration, error)
⋮----
func (s *Service) determineStartupSyncRange(ctx context.Context) (from symbiotic.Epoch, to symbiotic.Epoch, err error)
⋮----
func (s *Service) determineSteadySyncRange(ctx context.Context) (from symbiotic.Epoch, to symbiotic.Epoch, err error)
⋮----
func (s *Service) determineSyncRangeFromLatestWithHeader(
	ctx context.Context,
	latestHeader symbiotic.ValidatorSetHeader,
	currentEpoch symbiotic.Epoch,
) (from symbiotic.Epoch, to symbiotic.Epoch, err error)
⋮----
func (s *Service) tryLoadMissingEpochs(ctx context.Context, nextEpoch, currentEpoch symbiotic.Epoch) (time.Duration, error)
⋮----
// locking up mutex to prevent concurrent processing
⋮----
var prevValset symbiotic.ValidatorSet
var prevNetworkConfig symbiotic.NetworkConfig
⋮----
var err error
⋮----
// we couldn't find previous valset in repo, maybe we start fresh node with empty db
⋮----
var (
		latestEpochConfig    *symbiotic.NetworkConfig
		latestEpochTimestamp *uint64
	)
⋮----
func (s *Service) process(
	ctx context.Context,
	prevNetworkConfig symbiotic.NetworkConfig,
	prevValSet symbiotic.ValidatorSet,
	valSet symbiotic.ValidatorSet,
	config symbiotic.NetworkConfig,
) error
⋮----
// if we are a signer, sign the commitment, otherwise just save the metadata
var signatureRequest *symbiotic.SignatureRequest
⋮----
func (s *Service) getNetworkData(ctx context.Context, config symbiotic.NetworkConfig) (symbiotic.NetworkData, error)
⋮----
func (s *Service) headerCommitmentData(
	networkData symbiotic.NetworkData,
	header symbiotic.ValidatorSetHeader,
	extraData []symbiotic.ExtraData,
) ([]byte, error)
⋮----
func (s *Service) derive(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, symbiotic.NetworkConfig, error)
```

## File: internal/usecase/valset-status-tracker/status_tracker.go

```go
package valsetStatusTracker
⋮----
import (
	"context"
	"log/slog"
	"math"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/pkg/log"
	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"math"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
var zeroHeaderHash = common.HexToHash("0x868e09d528a16744c1f38ea3c10cc2251e01a456434f91172247695087d129b7")
⋮----
type repo interface {
	GetConfigByEpoch(_ context.Context, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetValidatorSetByEpoch(_ context.Context, epoch symbiotic.Epoch) (symbiotic.ValidatorSet, error)
	UpdateValidatorSetStatusAndRemovePendingProof(ctx context.Context, valset symbiotic.ValidatorSet) error
	GetFirstUncommittedValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	SaveFirstUncommittedValidatorSetEpoch(_ context.Context, epoch symbiotic.Epoch) error
	GetLatestValidatorSetEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetLatestAggregatedValsetHeader(ctx context.Context) (symbiotic.ValidatorSetHeader, error)
}
⋮----
type metrics interface {
	ObserveEpoch(epochType string, epochNumber uint64)
}
⋮----
type evmClient interface {
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	GetHeaderHashAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (common.Hash, error)
	GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, evmOptions ...symbiotic.EVMOption) (symbiotic.Epoch, error)
}
⋮----
type Config struct {
	EvmClient            evmClient     `validate:"required"`
	Repo                 repo          `validate:"required"`
	PollingInterval      time.Duration `validate:"required,gt=0"`
	EpochPollingInterval time.Duration `validate:"required,gt=0"`
	Metrics              metrics       `validate:"required"`
}
⋮----
type Service struct {
	cfg Config
}
⋮----
func (c Config) Validate() error
⋮----
func New(cfg Config) (*Service, error)
⋮----
// TrackMissingEpochsStatuses runs trackCommittedEpochs until all missing epochs statuses are loaded successfully
func (s *Service) TrackMissingEpochsStatuses(ctx context.Context) error
⋮----
const maxRetries = 10
⋮----
func (s *Service) Start(ctx context.Context) error
⋮----
func (s *Service) trackCommittedEpochs(ctx context.Context) error
⋮----
var lastCommittedEpoch uint64 = math.MaxUint64
⋮----
func (s *Service) findLatestNonZeroSettlements(ctx context.Context) ([]symbiotic.CrossChainAddress, error)
⋮----
func (s *Service) RunEpochTracker(ctx context.Context) error
⋮----
func (s *Service) trackEpochs(ctx context.Context) error
```

## File: pkg/log/context_handler.go

```go
//nolint:wrapcheck // this is the library code, don't need to wrap it
package log
⋮----
import (
	"context"
	"log/slog"

	"go.opentelemetry.io/otel/trace"
)
⋮----
"context"
"log/slog"
⋮----
"go.opentelemetry.io/otel/trace"
⋮----
type ContextHandler struct {
	slog.Handler
}
⋮----
func (h ContextHandler) Handle(ctx context.Context, r slog.Record) error
⋮----
type attrsKey struct{}
⋮----
var attrsKeyValue attrsKey
⋮----
func WithComponent(ctx context.Context, component string) context.Context
⋮----
func WithTraceContext(ctx context.Context) context.Context
⋮----
func WithAttrs(ctx context.Context, as ...slog.Attr) context.Context
⋮----
func copyAttrs(parentAttrs []slog.Attr, addCapacity int) []slog.Attr
⋮----
func getAttrs(ctx context.Context) []slog.Attr
```

## File: pkg/log/log_test.go

```go
package log
⋮----
import (
	"log/slog"
	"testing"
	"time"

	"github.com/go-errors/errors"
)
⋮----
"log/slog"
"testing"
"time"
⋮----
"github.com/go-errors/errors"
⋮----
func TestLog(t *testing.T)
⋮----
func TestComponent(t *testing.T)
⋮----
func TestComponentJSON(t *testing.T)
⋮----
func errorFunc() error
⋮----
func TestSplit(t *testing.T)
```

## File: pkg/log/log.go

```go
package log
⋮----
import (
	"context"
	"fmt"
	"log/slog"
	"math/big"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-errors/errors"
	slogmulti "github.com/samber/slog-multi"
)
⋮----
"context"
"fmt"
"log/slog"
"math/big"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
⋮----
"github.com/go-errors/errors"
slogmulti "github.com/samber/slog-multi"
⋮----
var once sync.Once
⋮----
func Init(levelStr, mode string)
⋮----
func internalInit(level slog.Level, mode string)
⋮----
func parseLogLevel(levelStr string) slog.Level
⋮----
func initPretty(level slog.Level)
⋮----
func initText(level slog.Level)
⋮----
func initJson(level slog.Level)
⋮----
func errorLevel(_ context.Context, r slog.Record) bool
⋮----
func notErrorLevel(_ context.Context, r slog.Record) bool
⋮----
type humanDuration time.Duration
⋮----
func (d humanDuration) MarshalJSON() ([]byte, error)
⋮----
func replaceAttr(groups []string, a slog.Attr) slog.Attr
⋮----
// Normalize big numbers to strings to avoid scientific notation in pretty logger
⋮----
// fmtErr returns a slog.GroupValue with keys "msg" and "trace".
// If the error does not implement interface { StackTrace() errors.StackTrace },
// the "trace" key is omitted.
func fmtErr(err error) slog.Value
⋮----
var groupValues []slog.Attr
⋮----
type StackTracer interface {
		Callers() []uintptr
	}
// Find the trace to the location of the first errors.New,
// errors.Wrap, or errors.WithStack call.
var st StackTracer
```

## File: pkg/log/prettylog.go

```go
//nolint:wrapcheck // this is the library code, don't need to wrap it
package log
⋮----
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log/slog"
	"os"
	"strconv"
	"strings"
	"sync"

	"github.com/go-errors/errors"
	"gopkg.in/yaml.v2"
)
⋮----
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"os"
"strconv"
"strings"
"sync"
⋮----
"github.com/go-errors/errors"
"gopkg.in/yaml.v2"
⋮----
const (
	timeFormat = "[15:04:05.000]"

	reset = "\033[0m"

	black        = 30
	red          = 31
	green        = 32
	yellow       = 33
	blue         = 34
	magenta      = 35
	cyan         = 36
	lightGray    = 37
	darkGray     = 90
	lightRed     = 91
	lightGreen   = 92
	lightYellow  = 93
	lightBlue    = 94
	lightMagenta = 95
	lightCyan    = 96
	white        = 97
)
⋮----
func colorizer(colorCode int, v string) string
⋮----
type Handler struct {
	h                slog.Handler
	r                func([]string, slog.Attr) slog.Attr
	b                *bytes.Buffer
	m                *sync.Mutex
	writer           io.Writer
	colorize         bool
	outputEmptyAttrs bool
}
⋮----
func New(handlerOptions *slog.HandlerOptions, options ...Option) *Handler
⋮----
func NewHandler(opts *slog.HandlerOptions) *Handler
⋮----
func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool
⋮----
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler
⋮----
func (h *Handler) WithGroup(name string) slog.Handler
⋮----
func (h *Handler) computeAttrs(
	ctx context.Context,
	r slog.Record,
) (map[string]any, error)
⋮----
var attrs map[string]any
⋮----
func (h *Handler) Handle(ctx context.Context, r slog.Record) error
⋮----
var level string
⋮----
var timestamp string
⋮----
var component string
⋮----
var msg string
⋮----
var attrsAsBytes []byte
⋮----
//attrsAsBytes, err = json.MarshalIndent(attrs, "", "  ")
⋮----
func suppressDefaults(
	next func([]string, slog.Attr) slog.Attr,
) func([]string, slog.Attr) slog.Attr
⋮----
type Option func(h *Handler)
⋮----
func WithDestinationWriter(writer io.Writer) Option
⋮----
func WithColor() Option
⋮----
func WithOutputEmptyAttrs() Option
```

## File: pkg/proof/circuit.go

```go
package proof
⋮----
import (
	"encoding/hex"
	"log/slog"
	"math/big"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
	"github.com/consensys/gnark/std/algebra/emulated/sw_emulated"
	"github.com/consensys/gnark/std/hash/mimc"
	gnarkSha3 "github.com/consensys/gnark/std/hash/sha3"
	"github.com/consensys/gnark/std/math/bits"
	"github.com/consensys/gnark/std/math/emulated"
	"github.com/consensys/gnark/std/math/uints"
	"github.com/ethereum/go-ethereum/crypto"
)
⋮----
"encoding/hex"
"log/slog"
"math/big"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
"github.com/consensys/gnark/std/algebra/emulated/sw_emulated"
"github.com/consensys/gnark/std/hash/mimc"
gnarkSha3 "github.com/consensys/gnark/std/hash/sha3"
"github.com/consensys/gnark/std/math/bits"
"github.com/consensys/gnark/std/math/emulated"
"github.com/consensys/gnark/std/math/uints"
"github.com/ethereum/go-ethereum/crypto"
⋮----
// Circuit defines a pre-image knowledge proof
type Circuit struct {
	InputHash             frontend.Variable      `gnark:",public"`  // 254 bits
	SignersAggVotingPower frontend.Variable      `gnark:",private"` // 254 bits, virtually public
	Message               sw_bn254.G1Affine      `gnark:",private"` // virtually public
	Signature             sw_bn254.G1Affine      `gnark:",private"`
	SignersAggKeyG2       sw_bn254.G2Affine      `gnark:",private"`
	ValidatorData         []ValidatorDataCircuit `gnark:",private"`
}
⋮----
InputHash             frontend.Variable      `gnark:",public"`  // 254 bits
SignersAggVotingPower frontend.Variable      `gnark:",private"` // 254 bits, virtually public
Message               sw_bn254.G1Affine      `gnark:",private"` // virtually public
⋮----
type ValidatorDataCircuit struct {
	Key         sw_bn254.G1Affine
	VotingPower frontend.Variable
	IsNonSigner frontend.Variable
}
⋮----
type ProveInput struct {
	ValidatorData   []ValidatorData
	MessageG1       bn254.G1Affine
	Signature       bn254.G1Affine
	SignersAggKeyG2 bn254.G2Affine
}
⋮----
// Define declares the circuit's constraints
func (circuit *Circuit) Define(api frontend.API) error
⋮----
// --------------------------------------- Prove ValSet consistency ---------------------------------------
⋮----
// calc valset hash, agg key and agg voting power
⋮----
// hash data if VALIDATOR is not a filler
⋮----
// add power if VALIDATOR is not a filler and SIGNER
⋮----
// aggregate key if VALIDATOR is not a filler and SIGNER
⋮----
// compare with public inputs
⋮----
// --------------------------------------- Prove Input consistency ---------------------------------------
⋮----
// valset consistency checked against InputHash which is Hash{valset-hash|signers-vp|message}
⋮----
inputDataHash[0] = u64Api.ByteValueOf(u64Api.ToValue(u64Api.And(u64Api.ValueOf(inputDataHash[0].Val), uints.NewU64(0x1f)))) // zero three first bits
⋮----
// --------------------------------------- Verify Signature ---------------------------------------
⋮----
// calc alpha
⋮----
//TODO optimize
⋮----
// pairing check
⋮----
func setCircuitData(circuit *Circuit, proveInput ProveInput)
```

## File: pkg/proof/helpers_test.go

```go
package proof
⋮----
import (
	"math/big"
	"os"
	"strings"
	"testing"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
⋮----
"math/big"
"os"
"strings"
"testing"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
// TestGetMaxValidators tests the GetMaxValidators function
func TestGetMaxValidators(t *testing.T)
⋮----
// Set environment variable
⋮----
// TestGetOptimalN tests the getOptimalN function
func TestGetOptimalN(t *testing.T)
⋮----
// Temporarily override max validators
⋮----
// TestNormalizeValset tests the NormalizeValset function
func TestNormalizeValset(t *testing.T)
⋮----
// Set MAX_VALIDATORS to ensure we get a specific size
⋮----
// Should be sorted and padded to 10
⋮----
// Verify lexicographic ordering: X is primary key, Y is tiebreaker
⋮----
// Check that remaining slots are padded with zero points
⋮----
// Create validators with various private keys to get different curve points
⋮----
// Shuffle and normalize again — should produce the same order
⋮----
// All should be zero points
⋮----
// TestHashValset tests the HashValset function
func TestHashValset(t *testing.T)
⋮----
// Add zero point validator
⋮----
// Hash should ignore the zero point validator
⋮----
// TestGetNonSignersData tests the getNonSignersData function
func TestGetNonSignersData(t *testing.T)
⋮----
valset := genValset(5, []int{1, 3}) // Validators at index 1 and 3 are non-signers
⋮----
// Total voting power should be sum of all validators
⋮----
// Non-signers voting power should be sum of 2 validators
⋮----
// Aggregated key should not be infinity (we have non-signers)
⋮----
valset := genValset(3, []int{}) // All are signers
⋮----
// Total voting power
⋮----
// No non-signers
⋮----
// Aggregated key should be infinity
⋮----
valset := genValset(3, []int{0, 1, 2}) // All are non-signers
⋮----
// All voting power goes to non-signers
⋮----
// TestGetAggSignature tests the getAggSignature function
func TestGetAggSignature(t *testing.T)
⋮----
valset := genValset(5, []int{1, 3}) // Validators 1 and 3 are non-signers
⋮----
// Use a simple message point for testing
⋮----
// Should not be infinity points (we have signers)
⋮----
// Should be infinity points (no signers)
⋮----
// TestGetPubkeyG1 tests the getPubkeyG1 function
func TestGetPubkeyG1(t *testing.T)
⋮----
// Zero should give infinity point
⋮----
// One should give generator
⋮----
// TestGetPubkeyG2 tests the getPubkeyG2 function
func TestGetPubkeyG2(t *testing.T)
⋮----
// TestProofDataMarshal tests the ProofData.Marshal function
func TestProofDataMarshal(t *testing.T)
⋮----
// Fill with test data
⋮----
// Should be 256 + 64 + 64 + 32 = 416 bytes
⋮----
// Check that proof is at the beginning
⋮----
// Check commitments
⋮----
// Check commitment PoK
⋮----
// Check voting power (last 32 bytes)
⋮----
// Last 32 bytes should be zero
⋮----
// TestExists tests the exists function
func TestExists(t *testing.T)
⋮----
// Create temp file
```

## File: pkg/proof/helpers.go

```go
package proof
⋮----
import (
	"bytes"
	"math/big"
	"sort"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	mimc_native "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
	"github.com/consensys/gnark/std/hash/mimc"
	"github.com/consensys/gnark/std/math/bits"
	"github.com/consensys/gnark/std/math/uints"
)
⋮----
"bytes"
"math/big"
"sort"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
mimc_native "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
"github.com/consensys/gnark/std/hash/mimc"
"github.com/consensys/gnark/std/math/bits"
"github.com/consensys/gnark/std/math/uints"
⋮----
func (p ProofData) Marshal() []byte
⋮----
var result bytes.Buffer
⋮----
func hashAffineG1(h *mimc.MiMC, g1 *sw_bn254.G1Affine)
⋮----
func hashAffineG2(h *mimc.MiMC, g2 *sw_bn254.G2Affine)
⋮----
func variableToBytes(api frontend.API, u64api *uints.BinaryField[uints.U64], variable frontend.Variable) []uints.U8
⋮----
func keyToBytes(u64api *uints.BinaryField[uints.U64], key *sw_bn254.G1Affine) []uints.U8
⋮----
func limbsToBytes(u64api *uints.BinaryField[uints.U64], limbs []frontend.Variable) []uints.U8
⋮----
func HashValset(valset []ValidatorData) []byte
⋮----
//	outerHash.Write(innerHash.Sum(nil))
⋮----
func getPubkeyG1(pk *big.Int) bn254.G1Affine
⋮----
var p bn254.G1Affine
⋮----
func getPubkeyG2(pk *big.Int) bn254.G2Affine
⋮----
var p bn254.G2Affine
⋮----
func getNonSignersData(valset []ValidatorData) (aggKey *bn254.G1Affine, aggVotingPower *big.Int, totalVotingPower *big.Int)
⋮----
func getAggSignature(message bn254.G1Affine, valset *[]ValidatorData) (signature *bn254.G1Affine, aggKeyG2 *bn254.G2Affine, aggKeyG1 *bn254.G1Affine)
⋮----
msg := bn254.G1Affine{X: message.X, Y: message.Y} // have to copy msg since ScalarMultiplication rewrite it
⋮----
func NormalizeValset(valset []ValidatorData) []ValidatorData
⋮----
// Sort validators by key in ascending order
⋮----
func getOptimalN(valsetLength int) int
⋮----
var capSize int
```

## File: pkg/proof/proof_test.go

```go
package proof
⋮----
import (
	"encoding/hex"
	"fmt"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/consensys/gnark/backend/groth16"
	"github.com/consensys/gnark/constraint"
)
⋮----
"encoding/hex"
"fmt"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/constraint"
⋮----
func genValset(numValidators int, nonSigners []int) []ValidatorData
⋮----
//nolint:unused // will be used later
func mockValset() []ValidatorData
⋮----
func calculateInputHash(validatorSetHash []byte, signersVotingPower *big.Int, messageG1 *bn254.G1Affine) common.Hash
⋮----
var packed []byte
⋮----
func TestProof(t *testing.T)
⋮----
// generate valset
⋮----
// valset := mockValset()
⋮----
func TestProofFailOnEmptyCircuitDir(t *testing.T)
⋮----
// TestNewZkProverInitialization tests the NewZkProver initialization
func TestNewZkProverInitialization(t *testing.T)
⋮----
// Check all maps are initialized
⋮----
// Check maps are empty (no circuits loaded without dir)
⋮----
// Check maxValidators is set to default
⋮----
// Check circuitsDir is empty
⋮----
// We can't actually test NewZkProver with a real circuits dir
// because it will try to load/compile circuits which is slow.
// Instead, we manually create a prover to verify the field is set.
⋮----
// Maps should still be initialized
⋮----
// TestProveValidation tests the Prove validation paths
func TestProveValidation(t *testing.T)
⋮----
// Create prover with circuits dir but no actual circuits loaded
⋮----
// Try with 25 validators (not in {10, 100, 1000})
⋮----
// Even with 10 validators (which is in maxValidators),
// we don't have actual circuit loaded
⋮----
// TestVerifyValidation tests the Verify validation paths
func TestVerifyValidation(t *testing.T)
⋮----
// valsetLen = 5 should normalize to 10
// But since we don't have vk[10], it should error
// Note: Verify needs at least 384 bytes for proof
⋮----
// valsetLen = 5000 exceeds all sizes, getOptimalN returns 0
⋮----
// Even with exact match valsetLen=100, vk map is empty
⋮----
// TestPathHelpers tests the path generation helper functions
func TestR1csPathTmp(t *testing.T)
⋮----
func TestPkPathTmp(t *testing.T)
⋮----
func TestVkPathTmp(t *testing.T)
⋮----
func TestSolPathTmp(t *testing.T)
```

## File: pkg/proof/proof.go

```go
package proof
⋮----
import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"log/slog"
	"math/big"
	"os"
	"strconv"
	"strings"

	"github.com/ethereum/go-ethereum/common"

	"github.com/go-errors/errors"

	"github.com/consensys/gnark-crypto/ecc"
	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
	"github.com/consensys/gnark/backend"
	"github.com/consensys/gnark/backend/groth16"
	"github.com/consensys/gnark/backend/solidity"
	"github.com/consensys/gnark/constraint"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/frontend/cs/r1cs"

	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"log/slog"
"math/big"
"os"
"strconv"
"strings"
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
"github.com/go-errors/errors"
⋮----
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/backend/solidity"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
⋮----
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
var (
	defaultMaxValidators = []int{10, 100, 1000}
)
⋮----
func GetMaxValidators() []int
⋮----
var newMaxValidators []int
⋮----
func r1csPathTmp(circuitsDir, suffix string) string
⋮----
func pkPathTmp(circuitsDir, suffix string) string
⋮----
func vkPathTmp(circuitsDir, suffix string) string
⋮----
func solPathTmp(circuitsDir, suffix string) string
⋮----
type ProofData struct {
	Proof                 []byte
	Commitments           []byte
	CommitmentPok         []byte
	SignersAggVotingPower *big.Int
}
⋮----
type ValidatorData struct {
	PrivateKey  *big.Int
	Key         bn254.G1Affine
	KeyG2       bn254.G2Affine
	VotingPower *big.Int
	IsNonSigner bool
}
⋮----
type ZkProver struct {
	cs            map[int]constraint.ConstraintSystem
	pk            map[int]groth16.ProvingKey
	vk            map[int]groth16.VerifyingKey
	circuitsDir   string
	maxValidators []int
}
⋮----
func NewZkProver(circuitsDir string) *ZkProver
⋮----
func (p *ZkProver) init()
⋮----
func (p *ZkProver) Verify(ctx context.Context, valsetLen int, publicInputHash common.Hash, proofBytes []byte) (bool, error)
⋮----
//nolint:gosec // G602: proofBytes length is validated by caller, slicing is safe
⋮----
rawProofBytes = append(rawProofBytes, []byte{0, 0, 0, 1}...) //dirty hack
⋮----
func (p *ZkProver) Prove(ctx context.Context, proveInput ProveInput) (ProofData, error)
⋮----
// witness definition
⋮----
// groth16: Prove & Verify
⋮----
// Format for the specific Solidity interface
⋮----
// Format the vector of public inputs as hex strings
⋮----
// If more than 10 inputs (unlikely), you'll need to adapt the interface
⋮----
// verify proof
⋮----
// Serialize the proof
var proofBuffer bytes.Buffer
⋮----
// Assuming fpSize is 32 bytes for BN254
const fpSize = 32
⋮----
standardProof[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1]) // Ar.x
standardProof[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2]) // Ar.y
standardProof[2] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3]) // Bs.x[0]
standardProof[3] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4]) // Bs.x[1]
standardProof[4] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5]) // Bs.y[0]
standardProof[5] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6]) // Bs.y[1]
standardProof[6] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7]) // Krs.x
standardProof[7] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8]) // Krs.y
⋮----
commitments[0] = new(big.Int).SetBytes(proofBytes[4+fpSize*8 : 4+fpSize*9])  // Commitment.x
commitments[1] = new(big.Int).SetBytes(proofBytes[4+fpSize*9 : 4+fpSize*10]) // Commitment.y
⋮----
commitmentPok[0] = new(big.Int).SetBytes(proofBytes[4+fpSize*10 : 4+fpSize*11]) // CommitmentPok.x
commitmentPok[1] = new(big.Int).SetBytes(proofBytes[4+fpSize*11 : 4+fpSize*12]) // CommitmentPok.y
⋮----
//revive:disable-next-line:function-result-limit // This function returns multiple cryptographic artifacts by design.
func (p *ZkProver) loadOrInit(valsetLen int) (constraint.ConstraintSystem, groth16.ProvingKey, groth16.VerifyingKey, error)
⋮----
var buf bytes.Buffer
⋮----
func exists(path string) bool
```

## File: pkg/server/interceptors.go

```go
package server
⋮----
import (
	"context"
	"log/slog"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/symbioticfi/relay/pkg/log"
)
⋮----
"context"
"log/slog"
"time"
⋮----
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
⋮----
"github.com/symbioticfi/relay/pkg/log"
⋮----
// LoggingInterceptor provides request logging for unary RPCs
func LoggingInterceptor(verboseLogging bool) grpc.UnaryServerInterceptor
⋮----
// wrappedStream wraps grpc.ServerStream to inject context
type wrappedStream struct {
	grpc.ServerStream

	ctx context.Context
}
⋮----
func (w *wrappedStream) Context() context.Context
⋮----
// StreamLoggingInterceptor provides request logging for streaming RPCs
func StreamLoggingInterceptor(verboseLogging bool) grpc.StreamServerInterceptor
⋮----
// PanicRecoveryInterceptor recovers from panics in unary gRPC handlers
func PanicRecoveryInterceptor() grpc.UnaryServerInterceptor
⋮----
// StreamPanicRecoveryInterceptor recovers from panics in streaming gRPC handlers
func StreamPanicRecoveryInterceptor() grpc.StreamServerInterceptor
⋮----
// TraceContextInterceptor enriches the context with trace information for structured logging
func TraceContextInterceptor() grpc.UnaryServerInterceptor
⋮----
// Enrich context with trace_id and span_id from OpenTelemetry span
⋮----
// StreamTraceContextInterceptor enriches the context with trace information for streaming RPCs
func StreamTraceContextInterceptor() grpc.StreamServerInterceptor
```

## File: pkg/server/metrics_server.go

```go
package server
⋮----
import (
	"context"
	"log/slog"
	"net/http"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)
⋮----
"context"
"log/slog"
"net/http"
"time"
⋮----
"github.com/go-chi/chi/v5"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"github.com/prometheus/client_golang/prometheus/promhttp"
⋮----
type MetricsConfig struct {
	Address           string
	ReadHeaderTimeout time.Duration
}
⋮----
func (c MetricsConfig) Validate() error
⋮----
type MetricsServer struct {
	srv *http.Server
	cfg MetricsConfig
}
⋮----
func NewMetricsServer(cfg MetricsConfig) (*MetricsServer, error)
⋮----
func initMetricsHandler(_ MetricsConfig) http.Handler
⋮----
func (s *MetricsServer) Serve(ctx context.Context) error
⋮----
go func() { //nolint:gosec // we must use separate context for shutdown
⋮----
if err := s.srv.Shutdown(ctxShutdown); err != nil { //nolint:contextcheck // we must use separate context for shutdown
```

## File: pkg/signals/signal_test.go

```go
package signals
⋮----
import (
	"context"
	"errors"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)
⋮----
"context"
"errors"
"sync"
"sync/atomic"
"testing"
"time"
⋮----
"github.com/stretchr/testify/require"
⋮----
func TestNew(t *testing.T)
⋮----
func TestDefaultConfig(t *testing.T)
⋮----
func TestSetHandler_Success(t *testing.T)
⋮----
func TestSetHandler_FailsWhenHandlersAlreadySet(t *testing.T)
⋮----
func TestSetHandler_FailsWhenWorkersAlreadyStarted(t *testing.T)
⋮----
func TestSetHandler_FailsWhenAllHandlersAreNil(t *testing.T)
⋮----
func TestSetHandler_FiltersNilHandlers(t *testing.T)
⋮----
func TestEmit_SuccessWithHandlers(t *testing.T)
⋮----
func TestEmit_ReturnsNilWhenNoHandlersSet(t *testing.T)
⋮----
func TestEmit_FailsWhenSignalIsStopped(t *testing.T)
⋮----
func TestEmitWithTimeout_SuccessWithinTimeout(t *testing.T)
⋮----
func TestEmitWithTimeout_TimesOutWhenQueueIsFull(t *testing.T)
⋮----
// Fill the queue
⋮----
func TestEmitWithTimeout_ReturnsNilWhenNoHandlersSet(t *testing.T)
⋮----
func TestEmitNonBlocking_SuccessWhenQueueHasSpace(t *testing.T)
⋮----
func TestEmitNonBlocking_ReturnsFalseWhenQueueIsFull(t *testing.T)
⋮----
func TestEmitNonBlocking_ReturnsFalseWhenSignalIsStopped(t *testing.T)
⋮----
func TestStartWorkers_Success(t *testing.T)
⋮----
func TestStartWorkers_FailsWhenNoHandlersSet(t *testing.T)
⋮----
func TestStartWorkers_FailsWhenWorkersAlreadyStarted(t *testing.T)
⋮----
func TestWorkerProcessing_ProcessesEventsSuccessfully(t *testing.T)
⋮----
var callCount atomic.Int32
⋮----
// Emit events
⋮----
// Wait for processing
⋮----
func TestWorkerProcessing_ExecutesMultipleHandlersSequentially(t *testing.T)
⋮----
require.Equal(t, int32(4), callCount.Load()) // 2 events * 2 handlers
⋮----
func TestWorkerProcessing_ContinuesOnHandlerError(t *testing.T)
⋮----
// Emit event
⋮----
require.Equal(t, int32(2), callCount.Load()) // Both handlers should be called despite first one erroring
⋮----
func TestWorkerShutdown_OnContextCancellation(t *testing.T)
⋮----
// Emit an event
⋮----
// Wait for processing to start
⋮----
// Cancel context
⋮----
// Unblock handler
⋮----
// Wait for shutdown
⋮----
func TestWorkerShutdown_MultipleWorkersGracefully(t *testing.T)
⋮----
var wg sync.WaitGroup
⋮----
// Emit multiple events
⋮----
// Cancel and wait for shutdown
⋮----
func TestConcurrency_ConcurrentEmitsAreSafe(t *testing.T)
```

## File: pkg/signals/signal.go

```go
package signals
⋮----
import (
	"context"
	"log/slog"
	"sync"
	"sync/atomic"
	"time"

	"github.com/go-errors/errors"
)
⋮----
"context"
"log/slog"
"sync"
"sync/atomic"
"time"
⋮----
"github.com/go-errors/errors"
⋮----
const (
	// EmitTimeout is the default timeout for emitting events to the signal queue.
	EmitTimeout = 10 * time.Second
)
⋮----
// EmitTimeout is the default timeout for emitting events to the signal queue.
⋮----
// Signal provides a type-safe, concurrent event processing system with configurable worker pools.
// It uses a buffered channel queue to handle events and multiple worker goroutines for parallel processing.
type Signal[T any] struct {
	queue      chan Event[T]
	handlers   []SignalListener[T]
	maxWorkers int
	id         string

	// Internal state
	started bool
	stopped atomic.Bool
	mutex   sync.RWMutex
}
⋮----
// Internal state
⋮----
// Config defines the configuration for a Signal instance.
type Config struct {
	// BufferSize sets the size of the internal event queue buffer (minimum 5)
	BufferSize int `mapstructure:"buffer-size" validate:"gte=5"`
	// WorkerCount sets the number of worker goroutines to process events (5-100)
	WorkerCount int `mapstructure:"worker-count" validate:"gte=5,lte=100"`
}
⋮----
// BufferSize sets the size of the internal event queue buffer (minimum 5)
⋮----
// WorkerCount sets the number of worker goroutines to process events (5-100)
⋮----
func DefaultConfig() Config
⋮----
// Event represents a signal event containing both payload data and execution context.
type Event[T any] struct {
	// Payload contains the actual event data
	Payload T
	// Ctx is the context associated with this event for cancellation and timeout handling
	Ctx context.Context
}
⋮----
// Payload contains the actual event data
⋮----
// Ctx is the context associated with this event for cancellation and timeout handling
⋮----
// SignalListener defines the function signature for handling signal events.
// It receives the event context and payload, returning an error if processing fails.
type SignalListener[T any] func(context.Context, T) error
⋮----
// New creates a new Signal instance with the specified configuration.
// Handlers can be provided during construction or set later using SetHandlers.
// The id is used for logging and error identification.
// Nil handlers are automatically filtered out.
func New[T any](cfg Config, id string, handlers ...SignalListener[T]) *Signal[T]
⋮----
// Filter out nil handlers
var validHandlers []SignalListener[T]
⋮----
// SetHandlers sets the event handlers for this signal.
// Returns an error if workers are started or handlers are already set, as handlers cannot be replaced.
// This method is thread-safe and should be called before starting workers.
// Accepts one or more handlers which will be executed sequentially in the order provided.
⋮----
func (s *Signal[T]) SetHandlers(handlers ...SignalListener[T]) error
⋮----
// Emit sends an event to the signal queue using the default EmitTimeout.
// It will block if the queue is full until the timeout is reached.
// Returns an error if workers have stopped.
// Use EmitNonBlocking if you want non-blocking behavior or EmitWithTimeout for custom timeouts.
func (s *Signal[T]) Emit(payload T) error
⋮----
// EmitWithTimeout sends an event to the signal queue with a custom timeout.
// Returns an error if the event cannot be queued within the timeout period or if workers have stopped.
func (s *Signal[T]) EmitWithTimeout(payload T, timeout time.Duration) error
⋮----
// We might not have handlers set for specific signals like the signals dealing
// with aggregation on non aggregator nodes in such case we ignore the event completely
// if we don't ignore the queue will get full and requests will timeout
⋮----
// EmitNonBlocking attempts to send an event without blocking.
// Returns true if the event was sent, false if the queue is full or workers have stopped.
func (s *Signal[T]) EmitNonBlocking(ctx context.Context, payload T) bool
⋮----
// StartWorkers starts the configured number of worker goroutines to process events from the queue.
// It should be called once during application startup and cannot be called again.
// All workers will gracefully shut down when the provided context is cancelled.
// The signal automatically marks itself as stopped and closes the queue when all workers exit.
// Returns an error if workers are already started or if no signal handler is set.
func (s *Signal[T]) StartWorkers(ctx context.Context) error
⋮----
var shutdownWG sync.WaitGroup
⋮----
// Execute all handlers regardless of errors
⋮----
// Continue executing remaining handlers
⋮----
// wait for all workers to finish
```

## File: pkg/tracing/helpers.go

```go
package tracing
⋮----
import (
	"context"
	"fmt"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
	"go.opentelemetry.io/otel/trace"

	"github.com/symbioticfi/relay/pkg/log"
)
⋮----
"context"
"fmt"
⋮----
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
⋮----
"github.com/symbioticfi/relay/pkg/log"
⋮----
func StartSpan(ctx context.Context, spanName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func StartServerSpan(ctx context.Context, spanName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func StartClientSpan(ctx context.Context, spanName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func StartProducerSpan(ctx context.Context, spanName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func StartConsumerSpan(ctx context.Context, spanName string, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func StartDBSpan(ctx context.Context, operation, statement string) (context.Context, trace.Span)
⋮----
//nolint:spancheck // spancheck is not able to follow our context wrapping
func startSpanWithKind(ctx context.Context, spanName string, kind trace.SpanKind, attrs ...attribute.KeyValue) (context.Context, trace.Span)
⋮----
func RecordError(span trace.Span, err error)
⋮----
func AddEvent(span trace.Span, name string, attrs ...attribute.KeyValue)
⋮----
func SetAttributes(span trace.Span, attrs ...attribute.KeyValue)
⋮----
// Common attribute keys for consistency across the codebase
var (
	// Chain and network attributes
	AttrChainID    = attribute.Key("chain.id")
⋮----
// Chain and network attributes
⋮----
// Signature and validation attributes
⋮----
// P2P attributes
⋮----
// EVM attributes
⋮----
// Aggregation attributes
```

## File: pkg/tracing/tracing.go

```go
package tracing
⋮----
import (
	"context"
	"time"

	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
	"go.opentelemetry.io/otel/trace"
	"google.golang.org/grpc/credentials/insecure"
)
⋮----
"context"
"time"
⋮----
"github.com/go-errors/errors"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/credentials/insecure"
⋮----
const ServiceName = "symbiotic-relay"
⋮----
type Config struct {
	Enabled    bool
	Endpoint   string
	SampleRate float64
	InstanceID string
	Version    string
}
⋮----
type Tracer struct {
	provider *sdktrace.TracerProvider
	tracer   trace.Tracer
}
⋮----
// New creates a new tracer with OTLP exporter for Jaeger
func New(ctx context.Context, cfg Config) (*Tracer, error)
⋮----
// Return a no-op tracer when tracing is disabled
⋮----
// Create resource with service name and instance-specific attributes
⋮----
// Determine sampler based on sample rate
var sampler sdktrace.Sampler
⋮----
// Create trace provider
⋮----
// Set global trace provider
⋮----
// Set global propagator for context propagation (W3C Trace Context)
⋮----
// Shutdown gracefully shuts down the tracer provider
func (t *Tracer) Shutdown(ctx context.Context) error
```

## File: symbiotic/client/evm/abi/KeyRegistry.abi.json

```json
[
    {
        "type": "function",
        "name": "__KeyRegistry_init",
        "inputs": [
            {
                "name": "keyRegistryInitParams",
                "type": "tuple",
                "internalType": "struct IKeyRegistry.KeyRegistryInitParams",
                "components": [
                    {
                        "name": "ozEip712InitParams",
                        "type": "tuple",
                        "internalType": "struct IOzEIP712.OzEIP712InitParams",
                        "components": [
                            {
                                "name": "name",
                                "type": "string",
                                "internalType": "string"
                            },
                            {
                                "name": "version",
                                "type": "string",
                                "internalType": "string"
                            }
                        ]
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "eip712Domain",
        "inputs": [],
        "outputs": [
            {
                "name": "fields",
                "type": "bytes1",
                "internalType": "bytes1"
            },
            {
                "name": "name",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "chainId",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "verifyingContract",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "salt",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "extensions",
                "type": "uint256[]",
                "internalType": "uint256[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKey",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "tag",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeyAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "tag",
                "type": "uint8",
                "internalType": "uint8"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeys",
        "inputs": [],
        "outputs": [
            {
                "name": "operatorsKeys",
                "type": "tuple[]",
                "internalType": "struct IKeyRegistry.OperatorWithKeys[]",
                "components": [
                    {
                        "name": "operator",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "keys",
                        "type": "tuple[]",
                        "internalType": "struct IKeyRegistry.Key[]",
                        "components": [
                            {
                                "name": "tag",
                                "type": "uint8",
                                "internalType": "uint8"
                            },
                            {
                                "name": "payload",
                                "type": "bytes",
                                "internalType": "bytes"
                            }
                        ]
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeys",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "keys",
                "type": "tuple[]",
                "internalType": "struct IKeyRegistry.Key[]",
                "components": [
                    {
                        "name": "tag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "payload",
                        "type": "bytes",
                        "internalType": "bytes"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "operatorsKeys",
                "type": "tuple[]",
                "internalType": "struct IKeyRegistry.OperatorWithKeys[]",
                "components": [
                    {
                        "name": "operator",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "keys",
                        "type": "tuple[]",
                        "internalType": "struct IKeyRegistry.Key[]",
                        "components": [
                            {
                                "name": "tag",
                                "type": "uint8",
                                "internalType": "uint8"
                            },
                            {
                                "name": "payload",
                                "type": "bytes",
                                "internalType": "bytes"
                            }
                        ]
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "keys",
                "type": "tuple[]",
                "internalType": "struct IKeyRegistry.Key[]",
                "components": [
                    {
                        "name": "tag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "payload",
                        "type": "bytes",
                        "internalType": "bytes"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysOperators",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysOperatorsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysOperatorsLength",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperator",
        "inputs": [
            {
                "name": "key",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4CrossChain",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "multicall",
        "inputs": [
            {
                "name": "data",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "outputs": [
            {
                "name": "results",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setKey",
        "inputs": [
            {
                "name": "tag",
                "type": "uint8",
                "internalType": "uint8"
            },
            {
                "name": "key",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "signature",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "EIP712DomainChanged",
        "inputs": [],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitEIP712",
        "inputs": [
            {
                "name": "name",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Initialized",
        "inputs": [
            {
                "name": "version",
                "type": "uint64",
                "indexed": false,
                "internalType": "uint64"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetKey",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "tag",
                "type": "uint8",
                "indexed": true,
                "internalType": "uint8"
            },
            {
                "name": "key",
                "type": "bytes",
                "indexed": true,
                "internalType": "bytes"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "indexed": false,
                "internalType": "bytes"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "AddressEmptyCode",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "CheckpointUnorderedInsertion",
        "inputs": []
    },
    {
        "type": "error",
        "name": "FailedCall",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidDSTLength",
        "inputs": [
            {
                "name": "",
                "type": "bytes",
                "internalType": "bytes"
            }
        ]
    },
    {
        "type": "error",
        "name": "InvalidInitialization",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidKeyTag",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyBlsBls12381_InvalidBytes",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyBlsBls12381_InvalidKey",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyBlsBn254_InvalidBytes",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyBlsBn254_InvalidKey",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyEcdsaSecp256k1_InvalidBytes",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyRegistry_AlreadyUsed",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyRegistry_InvalidKeySignature",
        "inputs": []
    },
    {
        "type": "error",
        "name": "KeyRegistry_InvalidKeyType",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitializing",
        "inputs": []
    },
    {
        "type": "error",
        "name": "SigBlsBls12381_InvalidMessageLength",
        "inputs": []
    },
    {
        "type": "error",
        "name": "SigBlsBn254_InvalidMessageLength",
        "inputs": []
    },
    {
        "type": "error",
        "name": "SigEcdsaSecp256k1_InvalidMessageLength",
        "inputs": []
    }
]
```

## File: symbiotic/client/evm/abi/OperatorRegistry.abi.json

```json
[
    {
        "type": "function",
        "name": "entity",
        "inputs": [
            {
                "name": "index",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isEntity",
        "inputs": [
            {
                "name": "entity_",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "registerOperator",
        "inputs": [],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "totalEntities",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "AddEntity",
        "inputs": [
            {
                "name": "entity",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "EntityNotExist",
        "inputs": []
    },
    {
        "type": "error",
        "name": "OperatorAlreadyRegistered",
        "inputs": []
    }
]
```

## File: symbiotic/client/evm/abi/Settlement.abi.json

```json
[
    {
        "type": "function",
        "name": "NETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK_IDENTIFIER",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint96",
                "internalType": "uint96"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "VALIDATOR_SET_VERSION",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "commitValSetHeader",
        "inputs": [
            {
                "name": "header",
                "type": "tuple",
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "extraData",
                "type": "tuple[]",
                "internalType": "struct ISettlement.ExtraData[]",
                "components": [
                    {
                        "name": "key",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    },
                    {
                        "name": "value",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "proof",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "eip712Domain",
        "inputs": [],
        "outputs": [
            {
                "name": "fields",
                "type": "bytes1",
                "internalType": "bytes1"
            },
            {
                "name": "name",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "chainId",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "verifyingContract",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "salt",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "extensions",
                "type": "uint256[]",
                "internalType": "uint256[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCaptureTimestampFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCaptureTimestampFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getExtraData",
        "inputs": [
            {
                "name": "key",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getExtraDataAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "key",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getLastCommittedHeaderEpoch",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getQuorumThresholdFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getQuorumThresholdFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredKeyTagFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredKeyTagFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSigVerifier",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSigVerifierAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getTotalVotingPowerFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getTotalVotingPowerFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "header",
                "type": "tuple",
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValSetHeaderHash",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValSetHeaderHashAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValidatorsSszMRootFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getValidatorsSszMRootFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVersionFromValSetHeader",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVersionFromValSetHeaderAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4CrossChain",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isValSetHeaderCommittedAt",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "setGenesis",
        "inputs": [
            {
                "name": "valSetHeader",
                "type": "tuple",
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "extraData",
                "type": "tuple[]",
                "internalType": "struct ISettlement.ExtraData[]",
                "components": [
                    {
                        "name": "key",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    },
                    {
                        "name": "value",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setSigVerifier",
        "inputs": [
            {
                "name": "sigVerifier",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "staticDelegateCall",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "verifyQuorumSig",
        "inputs": [
            {
                "name": "message",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "keyTag",
                "type": "uint8",
                "internalType": "uint8"
            },
            {
                "name": "quorumThreshold",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "proof",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "verifyQuorumSigAt",
        "inputs": [
            {
                "name": "message",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "keyTag",
                "type": "uint8",
                "internalType": "uint8"
            },
            {
                "name": "quorumThreshold",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "proof",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "CommitValSetHeader",
        "inputs": [
            {
                "name": "valSetHeader",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "extraData",
                "type": "tuple[]",
                "indexed": false,
                "internalType": "struct ISettlement.ExtraData[]",
                "components": [
                    {
                        "name": "key",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    },
                    {
                        "name": "value",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "EIP712DomainChanged",
        "inputs": [],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitEIP712",
        "inputs": [
            {
                "name": "name",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitSigVerifier",
        "inputs": [
            {
                "name": "sigVerifier",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitSubnetwork",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            },
            {
                "name": "subnetworkId",
                "type": "uint96",
                "indexed": false,
                "internalType": "uint96"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Initialized",
        "inputs": [
            {
                "name": "version",
                "type": "uint64",
                "indexed": false,
                "internalType": "uint64"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetGenesis",
        "inputs": [
            {
                "name": "valSetHeader",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct ISettlement.ValSetHeader",
                "components": [
                    {
                        "name": "version",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "requiredKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "epoch",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "captureTimestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "totalVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "validatorsSszMRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "extraData",
                "type": "tuple[]",
                "indexed": false,
                "internalType": "struct ISettlement.ExtraData[]",
                "components": [
                    {
                        "name": "key",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    },
                    {
                        "name": "value",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetSigVerifier",
        "inputs": [
            {
                "name": "sigVerifier",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "CheckpointUnorderedInsertion",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidInitialization",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidKeyTag",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NetworkManager_InvalidNetwork",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitializing",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_DuplicateExtraDataKey",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_InvalidCaptureTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_InvalidEpoch",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_InvalidSigVerifier",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_InvalidValidatorsSszMRoot",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_InvalidVersion",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_QuorumThresholdGtTotalVotingPower",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_ValSetHeaderAlreadyCommitted",
        "inputs": []
    },
    {
        "type": "error",
        "name": "Settlement_VerificationFailed",
        "inputs": []
    }
]
```

## File: symbiotic/client/evm/abi/ValSetDriver.abi.json

```json
[
    {
        "type": "function",
        "name": "MAX_QUORUM_THRESHOLD",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint248",
                "internalType": "uint248"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "NETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK_IDENTIFIER",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint96",
                "internalType": "uint96"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "addQuorumThreshold",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "addSettlement",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "addVotingPowerProvider",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "getCommitterSlotDuration",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCommitterSlotDurationAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getConfig",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IValSetDriver.Config",
                "components": [
                    {
                        "name": "numAggregators",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "numCommitters",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "committerSlotDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "votingPowerProviders",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.CrossChainAddress[]",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "keysProvider",
                        "type": "tuple",
                        "internalType": "struct IValSetDriver.CrossChainAddress",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "settlements",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.CrossChainAddress[]",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "maxVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "minInclusionVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "maxValidatorsCount",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "requiredKeyTags",
                        "type": "uint8[]",
                        "internalType": "uint8[]"
                    },
                    {
                        "name": "quorumThresholds",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.QuorumThreshold[]",
                        "components": [
                            {
                                "name": "keyTag",
                                "type": "uint8",
                                "internalType": "uint8"
                            },
                            {
                                "name": "quorumThreshold",
                                "type": "uint248",
                                "internalType": "uint248"
                            }
                        ]
                    },
                    {
                        "name": "requiredHeaderKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "verificationType",
                        "type": "uint32",
                        "internalType": "uint32"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getConfigAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IValSetDriver.Config",
                "components": [
                    {
                        "name": "numAggregators",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "numCommitters",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "committerSlotDuration",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "votingPowerProviders",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.CrossChainAddress[]",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "keysProvider",
                        "type": "tuple",
                        "internalType": "struct IValSetDriver.CrossChainAddress",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "settlements",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.CrossChainAddress[]",
                        "components": [
                            {
                                "name": "chainId",
                                "type": "uint64",
                                "internalType": "uint64"
                            },
                            {
                                "name": "addr",
                                "type": "address",
                                "internalType": "address"
                            }
                        ]
                    },
                    {
                        "name": "maxVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "minInclusionVotingPower",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "maxValidatorsCount",
                        "type": "uint208",
                        "internalType": "uint208"
                    },
                    {
                        "name": "requiredKeyTags",
                        "type": "uint8[]",
                        "internalType": "uint8[]"
                    },
                    {
                        "name": "quorumThresholds",
                        "type": "tuple[]",
                        "internalType": "struct IValSetDriver.QuorumThreshold[]",
                        "components": [
                            {
                                "name": "keyTag",
                                "type": "uint8",
                                "internalType": "uint8"
                            },
                            {
                                "name": "quorumThreshold",
                                "type": "uint248",
                                "internalType": "uint248"
                            }
                        ]
                    },
                    {
                        "name": "requiredHeaderKeyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "verificationType",
                        "type": "uint32",
                        "internalType": "uint32"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCurrentEpoch",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCurrentEpochDuration",
        "inputs": [],
        "outputs": [
            {
                "name": "epochDuration",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCurrentEpochStart",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getEpochDuration",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "epochDuration",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getEpochIndex",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getEpochStart",
        "inputs": [
            {
                "name": "epoch",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysProvider",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getKeysProviderAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMaxValidatorsCount",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMaxValidatorsCountAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMaxVotingPower",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMaxVotingPowerAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMinInclusionVotingPower",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getMinInclusionVotingPowerAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNextEpoch",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNextEpochDuration",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNextEpochStart",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNumAggregators",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNumAggregatorsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNumCommitters",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getNumCommittersAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getQuorumThresholds",
        "inputs": [],
        "outputs": [
            {
                "name": "quorumThresholds",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.QuorumThreshold[]",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getQuorumThresholdsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "quorumThresholds",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.QuorumThreshold[]",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredHeaderKeyTag",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredHeaderKeyTagAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredKeyTags",
        "inputs": [],
        "outputs": [
            {
                "name": "requiredKeyTags",
                "type": "uint8[]",
                "internalType": "uint8[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getRequiredKeyTagsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "requiredKeyTags",
                "type": "uint8[]",
                "internalType": "uint8[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSettlements",
        "inputs": [],
        "outputs": [
            {
                "name": "settlements",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.CrossChainAddress[]",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSettlementsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "settlements",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.CrossChainAddress[]",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVerificationType",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint32",
                "internalType": "uint32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVerificationTypeAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint32",
                "internalType": "uint32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVotingPowerProviders",
        "inputs": [],
        "outputs": [
            {
                "name": "votingPowerProviders",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.CrossChainAddress[]",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVotingPowerProvidersAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "votingPowerProviders",
                "type": "tuple[]",
                "internalType": "struct IValSetDriver.CrossChainAddress[]",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isQuorumThresholdRegistered",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isQuorumThresholdRegisteredAt",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSettlementRegistered",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSettlementRegisteredAt",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isVotingPowerProviderRegistered",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isVotingPowerProviderRegisteredAt",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "multicall",
        "inputs": [
            {
                "name": "data",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "outputs": [
            {
                "name": "results",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "removeQuorumThreshold",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "removeSettlement",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "removeVotingPowerProvider",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setCommitterSlotDuration",
        "inputs": [
            {
                "name": "slotDuration",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setEpochDuration",
        "inputs": [
            {
                "name": "epochDuration",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setKeysProvider",
        "inputs": [
            {
                "name": "keysProvider",
                "type": "tuple",
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setMaxValidatorsCount",
        "inputs": [
            {
                "name": "maxValidatorsCount",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setMaxVotingPower",
        "inputs": [
            {
                "name": "maxVotingPower",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setMinInclusionVotingPower",
        "inputs": [
            {
                "name": "minInclusionVotingPower",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setNumAggregators",
        "inputs": [
            {
                "name": "numAggregators",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setNumCommitters",
        "inputs": [
            {
                "name": "numCommitters",
                "type": "uint208",
                "internalType": "uint208"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setRequiredHeaderKeyTag",
        "inputs": [
            {
                "name": "requiredHeaderKeyTag",
                "type": "uint8",
                "internalType": "uint8"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setRequiredKeyTags",
        "inputs": [
            {
                "name": "requiredKeyTags",
                "type": "uint8[]",
                "internalType": "uint8[]"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setVerificationType",
        "inputs": [
            {
                "name": "verificationType",
                "type": "uint32",
                "internalType": "uint32"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "staticDelegateCall",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "AddQuorumThreshold",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "AddSettlement",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "AddVotingPowerProvider",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitEpochDuration",
        "inputs": [
            {
                "name": "epochDuration",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            },
            {
                "name": "epochDurationTimestamp",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitSubnetwork",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            },
            {
                "name": "subnetworkId",
                "type": "uint96",
                "indexed": false,
                "internalType": "uint96"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Initialized",
        "inputs": [
            {
                "name": "version",
                "type": "uint64",
                "indexed": false,
                "internalType": "uint64"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RemoveQuorumThreshold",
        "inputs": [
            {
                "name": "quorumThreshold",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.QuorumThreshold",
                "components": [
                    {
                        "name": "keyTag",
                        "type": "uint8",
                        "internalType": "uint8"
                    },
                    {
                        "name": "quorumThreshold",
                        "type": "uint248",
                        "internalType": "uint248"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RemoveSettlement",
        "inputs": [
            {
                "name": "settlement",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RemoveVotingPowerProvider",
        "inputs": [
            {
                "name": "votingPowerProvider",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetCommitterSlotDuration",
        "inputs": [
            {
                "name": "committerSlotDuration",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetEpochDuration",
        "inputs": [
            {
                "name": "epochDuration",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetKeysProvider",
        "inputs": [
            {
                "name": "keysProvider",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct IValSetDriver.CrossChainAddress",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "addr",
                        "type": "address",
                        "internalType": "address"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetMaxValidatorsCount",
        "inputs": [
            {
                "name": "maxValidatorsCount",
                "type": "uint208",
                "indexed": false,
                "internalType": "uint208"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetMaxVotingPower",
        "inputs": [
            {
                "name": "maxVotingPower",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetMinInclusionVotingPower",
        "inputs": [
            {
                "name": "minInclusionVotingPower",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetNumAggregators",
        "inputs": [
            {
                "name": "numAggregators",
                "type": "uint208",
                "indexed": false,
                "internalType": "uint208"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetNumCommitters",
        "inputs": [
            {
                "name": "numCommitters",
                "type": "uint208",
                "indexed": false,
                "internalType": "uint208"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetRequiredHeaderKeyTag",
        "inputs": [
            {
                "name": "requiredHeaderKeyTag",
                "type": "uint8",
                "indexed": false,
                "internalType": "uint8"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetRequiredKeyTags",
        "inputs": [
            {
                "name": "requiredKeyTags",
                "type": "uint8[]",
                "indexed": false,
                "internalType": "uint8[]"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetVerificationType",
        "inputs": [
            {
                "name": "verificationType",
                "type": "uint32",
                "indexed": false,
                "internalType": "uint32"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "AddressEmptyCode",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "CheckpointUnorderedInsertion",
        "inputs": []
    },
    {
        "type": "error",
        "name": "DuplicateKeyTag",
        "inputs": []
    },
    {
        "type": "error",
        "name": "EpochManager_InvalidEpochDuration",
        "inputs": []
    },
    {
        "type": "error",
        "name": "EpochManager_InvalidEpochDurationTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "EpochManager_TooOldTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "FailedCall",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidInitialization",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidKey",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidKeyTag",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NetworkManager_InvalidNetwork",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitializing",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_ChainAlreadyAdded",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_InvalidCrossChainAddress",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_InvalidMaxValidatorsCount",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_InvalidQuorumThreshold",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_KeyTagAlreadyAdded",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_NotAdded",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_ZeroCommitterSlotDuration",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_ZeroNumAggregators",
        "inputs": []
    },
    {
        "type": "error",
        "name": "ValSetDriver_ZeroNumCommitters",
        "inputs": []
    }
]
```

## File: symbiotic/client/evm/abi/VotingPowerProvider.abi.json

```json
[
    {
        "type": "function",
        "name": "NETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "OPERATOR_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "SUBNETWORK_IDENTIFIER",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint96",
                "internalType": "uint96"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "VAULT_FACTORY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "eip712Domain",
        "inputs": [],
        "outputs": [
            {
                "name": "fields",
                "type": "bytes1",
                "internalType": "bytes1"
            },
            {
                "name": "name",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "internalType": "string"
            },
            {
                "name": "chainId",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "verifyingContract",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "salt",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "extensions",
                "type": "uint256[]",
                "internalType": "uint256[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorStakes",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.VaultValue[]",
                "components": [
                    {
                        "name": "vault",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "value",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorStakesAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.VaultValue[]",
                "components": [
                    {
                        "name": "vault",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "value",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorVaults",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorVaultsAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorVotingPowers",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.VaultValue[]",
                "components": [
                    {
                        "name": "vault",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "value",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorVotingPowersAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.VaultValue[]",
                "components": [
                    {
                        "name": "vault",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "value",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperators",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSharedVaults",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSharedVaultsAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSlashingData",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getSlashingDataAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getTokens",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getTokensAt",
        "inputs": [
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address[]",
                "internalType": "address[]"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVotingPowers",
        "inputs": [
            {
                "name": "extraData",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.OperatorVotingPower[]",
                "components": [
                    {
                        "name": "operator",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "vaults",
                        "type": "tuple[]",
                        "internalType": "struct IVotingPowerProvider.VaultValue[]",
                        "components": [
                            {
                                "name": "vault",
                                "type": "address",
                                "internalType": "address"
                            },
                            {
                                "name": "value",
                                "type": "uint256",
                                "internalType": "uint256"
                            }
                        ]
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getVotingPowersAt",
        "inputs": [
            {
                "name": "extraData",
                "type": "bytes[]",
                "internalType": "bytes[]"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple[]",
                "internalType": "struct IVotingPowerProvider.OperatorVotingPower[]",
                "components": [
                    {
                        "name": "operator",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "vaults",
                        "type": "tuple[]",
                        "internalType": "struct IVotingPowerProvider.VaultValue[]",
                        "components": [
                            {
                                "name": "vault",
                                "type": "address",
                                "internalType": "address"
                            },
                            {
                                "name": "value",
                                "type": "uint256",
                                "internalType": "uint256"
                            }
                        ]
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "hashTypedDataV4CrossChain",
        "inputs": [
            {
                "name": "structHash",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "invalidateOldSignatures",
        "inputs": [],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "isOperatorRegistered",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOperatorRegisteredAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOperatorVaultRegistered",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOperatorVaultRegistered",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOperatorVaultRegisteredAt",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isOperatorVaultRegisteredAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSharedVaultRegistered",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isSharedVaultRegisteredAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isTokenRegistered",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "isTokenRegisteredAt",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "multicall",
        "inputs": [
            {
                "name": "data",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "outputs": [
            {
                "name": "results",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "nonces",
        "inputs": [
            {
                "name": "owner",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "registerOperator",
        "inputs": [],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "registerOperatorWithSignature",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "signature",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "stakeToVotingPower",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "stake",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "power",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "stakeToVotingPowerAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "stake",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            }
        ],
        "outputs": [
            {
                "name": "power",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "staticDelegateCall",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "unregisterOperator",
        "inputs": [],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "unregisterOperatorWithSignature",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "signature",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "EIP712DomainChanged",
        "inputs": [],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitEIP712",
        "inputs": [
            {
                "name": "name",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            },
            {
                "name": "version",
                "type": "string",
                "indexed": false,
                "internalType": "string"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "InitSubnetwork",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            },
            {
                "name": "subnetworkId",
                "type": "uint96",
                "indexed": false,
                "internalType": "uint96"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "Initialized",
        "inputs": [
            {
                "name": "version",
                "type": "uint64",
                "indexed": false,
                "internalType": "uint64"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RegisterOperator",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RegisterOperatorVault",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RegisterSharedVault",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "RegisterToken",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetSlashingData",
        "inputs": [
            {
                "name": "requireSlasher",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            },
            {
                "name": "minVaultEpochDuration",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "UnregisterOperator",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "UnregisterOperatorVault",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "UnregisterSharedVault",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "UnregisterToken",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "AddressEmptyCode",
        "inputs": [
            {
                "name": "target",
                "type": "address",
                "internalType": "address"
            }
        ]
    },
    {
        "type": "error",
        "name": "FailedCall",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidAccountNonce",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "currentNonce",
                "type": "uint256",
                "internalType": "uint256"
            }
        ]
    },
    {
        "type": "error",
        "name": "InvalidInitialization",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NetworkManager_InvalidNetwork",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotInitializing",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidOperator",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidOperatorVault",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidSharedVault",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidSignature",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidToken",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_InvalidVault",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_OperatorAlreadyRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_OperatorNotRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_OperatorVaultAlreadyIsRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_OperatorVaultNotRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_SharedVaultAlreadyIsRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_SharedVaultNotRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_TokenAlreadyIsRegistered",
        "inputs": []
    },
    {
        "type": "error",
        "name": "VotingPowerProvider_TokenNotRegistered",
        "inputs": []
    }
]
```

## File: symbiotic/client/evm/gen/keyRegistry.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// IKeyRegistryKey is an auto generated low-level Go binding around an user-defined struct.
type IKeyRegistryKey struct {
	Tag     uint8
	Payload []byte
}
⋮----
// IKeyRegistryKeyRegistryInitParams is an auto generated low-level Go binding around an user-defined struct.
type IKeyRegistryKeyRegistryInitParams struct {
	OzEip712InitParams IOzEIP712OzEIP712InitParams
}
⋮----
// IKeyRegistryOperatorWithKeys is an auto generated low-level Go binding around an user-defined struct.
type IKeyRegistryOperatorWithKeys struct {
	Operator common.Address
	Keys     []IKeyRegistryKey
}
⋮----
// IOzEIP712OzEIP712InitParams is an auto generated low-level Go binding around an user-defined struct.
type IOzEIP712OzEIP712InitParams struct {
	Name    string
	Version string
}
⋮----
// KeyRegistryMetaData contains all meta data concerning the KeyRegistry contract.
var KeyRegistryMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"__KeyRegistry_init\",\"inputs\":[{\"name\":\"keyRegistryInitParams\",\"type\":\"tuple\",\"internalType\":\"structIKeyRegistry.KeyRegistryInitParams\",\"components\":[{\"name\":\"ozEip712InitParams\",\"type\":\"tuple\",\"internalType\":\"structIOzEIP712.OzEIP712InitParams\",\"components\":[{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eip712Domain\",\"inputs\":[],\"outputs\":[{\"name\":\"fields\",\"type\":\"bytes1\",\"internalType\":\"bytes1\"},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extensions\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKey\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeyAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeys\",\"inputs\":[],\"outputs\":[{\"name\":\"operatorsKeys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.OperatorWithKeys[]\",\"components\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"keys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.Key[]\",\"components\":[{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"payload\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeys\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"keys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.Key[]\",\"components\":[{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"payload\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"operatorsKeys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.OperatorWithKeys[]\",\"components\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"keys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.Key[]\",\"components\":[{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"payload\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"keys\",\"type\":\"tuple[]\",\"internalType\":\"structIKeyRegistry.Key[]\",\"components\":[{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"payload\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysOperators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysOperatorsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysOperatorsLength\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperator\",\"inputs\":[{\"name\":\"key\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4CrossChain\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setKey\",\"inputs\":[{\"name\":\"tag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"key\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"EIP712DomainChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitEIP712\",\"inputs\":[{\"name\":\"name\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetKey\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tag\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"uint8\"},{\"name\":\"key\",\"type\":\"bytes\",\"indexed\":true,\"internalType\":\"bytes\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"CheckpointUnorderedInsertion\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDSTLength\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidKeyTag\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyBlsBls12381_InvalidBytes\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyBlsBls12381_InvalidKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyBlsBn254_InvalidBytes\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyBlsBn254_InvalidKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyEcdsaSecp256k1_InvalidBytes\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyRegistry_AlreadyUsed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyRegistry_InvalidKeySignature\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"KeyRegistry_InvalidKeyType\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SigBlsBls12381_InvalidMessageLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SigBlsBn254_InvalidMessageLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SigEcdsaSecp256k1_InvalidMessageLength\",\"inputs\":[]}]",
}
⋮----
// KeyRegistryABI is the input ABI used to generate the binding from.
// Deprecated: Use KeyRegistryMetaData.ABI instead.
var KeyRegistryABI = KeyRegistryMetaData.ABI
⋮----
// KeyRegistry is an auto generated Go binding around an Ethereum contract.
type KeyRegistry struct {
	KeyRegistryCaller     // Read-only binding to the contract
	KeyRegistryTransactor // Write-only binding to the contract
	KeyRegistryFilterer   // Log filterer for contract events
}
⋮----
KeyRegistryCaller     // Read-only binding to the contract
KeyRegistryTransactor // Write-only binding to the contract
KeyRegistryFilterer   // Log filterer for contract events
⋮----
// KeyRegistryCaller is an auto generated read-only Go binding around an Ethereum contract.
type KeyRegistryCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// KeyRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract.
type KeyRegistryTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// KeyRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type KeyRegistryFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// KeyRegistrySession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type KeyRegistrySession struct {
	Contract     *KeyRegistry      // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *KeyRegistry      // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// KeyRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type KeyRegistryCallerSession struct {
	Contract *KeyRegistryCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts      // Call options to use throughout this session
}
⋮----
Contract *KeyRegistryCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts      // Call options to use throughout this session
⋮----
// KeyRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type KeyRegistryTransactorSession struct {
	Contract     *KeyRegistryTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts      // Transaction auth options to use throughout this session
}
⋮----
Contract     *KeyRegistryTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts      // Transaction auth options to use throughout this session
⋮----
// KeyRegistryRaw is an auto generated low-level Go binding around an Ethereum contract.
type KeyRegistryRaw struct {
	Contract *KeyRegistry // Generic contract binding to access the raw methods on
}
⋮----
Contract *KeyRegistry // Generic contract binding to access the raw methods on
⋮----
// KeyRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type KeyRegistryCallerRaw struct {
	Contract *KeyRegistryCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *KeyRegistryCaller // Generic read-only contract binding to access the raw methods on
⋮----
// KeyRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type KeyRegistryTransactorRaw struct {
	Contract *KeyRegistryTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *KeyRegistryTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewKeyRegistry creates a new instance of KeyRegistry, bound to a specific deployed contract.
func NewKeyRegistry(address common.Address, backend bind.ContractBackend) (*KeyRegistry, error)
⋮----
// NewKeyRegistryCaller creates a new read-only instance of KeyRegistry, bound to a specific deployed contract.
func NewKeyRegistryCaller(address common.Address, caller bind.ContractCaller) (*KeyRegistryCaller, error)
⋮----
// NewKeyRegistryTransactor creates a new write-only instance of KeyRegistry, bound to a specific deployed contract.
func NewKeyRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*KeyRegistryTransactor, error)
⋮----
// NewKeyRegistryFilterer creates a new log filterer instance of KeyRegistry, bound to a specific deployed contract.
func NewKeyRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*KeyRegistryFilterer, error)
⋮----
// bindKeyRegistry binds a generic wrapper to an already deployed contract.
func bindKeyRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_KeyRegistry *KeyRegistryRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_KeyRegistry *KeyRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_KeyRegistry *KeyRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e.
//
// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)
func (_KeyRegistry *KeyRegistryCaller) Eip712Domain(opts *bind.CallOpts) (struct
⋮----
var out []interface{}
⋮----
// GetKey is a free data retrieval call binding the contract method 0xb6e1a1e2.
⋮----
// Solidity: function getKey(address operator, uint8 tag) view returns(bytes)
func (_KeyRegistry *KeyRegistryCaller) GetKey(opts *bind.CallOpts, operator common.Address, tag uint8) ([]byte, error)
⋮----
// GetKeyAt is a free data retrieval call binding the contract method 0xb1dab20f.
⋮----
// Solidity: function getKeyAt(address operator, uint8 tag, uint48 timestamp) view returns(bytes)
func (_KeyRegistry *KeyRegistryCaller) GetKeyAt(opts *bind.CallOpts, operator common.Address, tag uint8, timestamp *big.Int) ([]byte, error)
⋮----
// GetKeys is a free data retrieval call binding the contract method 0x2150c518.
⋮----
// Solidity: function getKeys() view returns((address,(uint8,bytes)[])[] operatorsKeys)
func (_KeyRegistry *KeyRegistryCaller) GetKeys(opts *bind.CallOpts) ([]IKeyRegistryOperatorWithKeys, error)
⋮----
// GetKeys0 is a free data retrieval call binding the contract method 0x34e80c34.
⋮----
// Solidity: function getKeys(address operator) view returns((uint8,bytes)[] keys)
func (_KeyRegistry *KeyRegistryCaller) GetKeys0(opts *bind.CallOpts, operator common.Address) ([]IKeyRegistryKey, error)
⋮----
// GetKeysAt is a free data retrieval call binding the contract method 0x256d1be5.
⋮----
// Solidity: function getKeysAt(uint48 timestamp) view returns((address,(uint8,bytes)[])[] operatorsKeys)
func (_KeyRegistry *KeyRegistryCaller) GetKeysAt(opts *bind.CallOpts, timestamp *big.Int) ([]IKeyRegistryOperatorWithKeys, error)
⋮----
// GetKeysAt0 is a free data retrieval call binding the contract method 0x26cb1f1c.
⋮----
// Solidity: function getKeysAt(address operator, uint48 timestamp) view returns((uint8,bytes)[] keys)
func (_KeyRegistry *KeyRegistryCaller) GetKeysAt0(opts *bind.CallOpts, operator common.Address, timestamp *big.Int) ([]IKeyRegistryKey, error)
⋮----
// GetKeysOperators is a free data retrieval call binding the contract method 0x20d268de.
⋮----
// Solidity: function getKeysOperators() view returns(address[])
func (_KeyRegistry *KeyRegistryCaller) GetKeysOperators(opts *bind.CallOpts) ([]common.Address, error)
⋮----
// GetKeysOperatorsAt is a free data retrieval call binding the contract method 0xf493b5f3.
⋮----
// Solidity: function getKeysOperatorsAt(uint48 timestamp) view returns(address[])
func (_KeyRegistry *KeyRegistryCaller) GetKeysOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetKeysOperatorsLength is a free data retrieval call binding the contract method 0xd201ab93.
⋮----
// Solidity: function getKeysOperatorsLength() view returns(uint256)
func (_KeyRegistry *KeyRegistryCaller) GetKeysOperatorsLength(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetOperator is a free data retrieval call binding the contract method 0x9eaffa96.
⋮----
// Solidity: function getOperator(bytes key) view returns(address)
func (_KeyRegistry *KeyRegistryCaller) GetOperator(opts *bind.CallOpts, key []byte) (common.Address, error)
⋮----
// HashTypedDataV4 is a free data retrieval call binding the contract method 0x4980f288.
⋮----
// Solidity: function hashTypedDataV4(bytes32 structHash) view returns(bytes32)
func (_KeyRegistry *KeyRegistryCaller) HashTypedDataV4(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// HashTypedDataV4CrossChain is a free data retrieval call binding the contract method 0x518dcf3b.
⋮----
// Solidity: function hashTypedDataV4CrossChain(bytes32 structHash) view returns(bytes32)
func (_KeyRegistry *KeyRegistryCaller) HashTypedDataV4CrossChain(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// KeyRegistryInit is a paid mutator transaction binding the contract method 0x529e712d.
⋮----
// Solidity: function __KeyRegistry_init(((string,string)) keyRegistryInitParams) returns()
func (_KeyRegistry *KeyRegistryTransactor) KeyRegistryInit(opts *bind.TransactOpts, keyRegistryInitParams IKeyRegistryKeyRegistryInitParams) (*types.Transaction, error)
⋮----
// Multicall is a paid mutator transaction binding the contract method 0xac9650d8.
⋮----
// Solidity: function multicall(bytes[] data) returns(bytes[] results)
func (_KeyRegistry *KeyRegistryTransactor) Multicall(opts *bind.TransactOpts, data [][]byte) (*types.Transaction, error)
⋮----
// SetKey is a paid mutator transaction binding the contract method 0xc1ef9aca.
⋮----
// Solidity: function setKey(uint8 tag, bytes key, bytes signature, bytes extraData) returns()
func (_KeyRegistry *KeyRegistryTransactor) SetKey(opts *bind.TransactOpts, tag uint8, key []byte, signature []byte, extraData []byte) (*types.Transaction, error)
⋮----
// KeyRegistryEIP712DomainChangedIterator is returned from FilterEIP712DomainChanged and is used to iterate over the raw logs and unpacked data for EIP712DomainChanged events raised by the KeyRegistry contract.
type KeyRegistryEIP712DomainChangedIterator struct {
	Event *KeyRegistryEIP712DomainChanged // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *KeyRegistryEIP712DomainChanged // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *KeyRegistryEIP712DomainChangedIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *KeyRegistryEIP712DomainChangedIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *KeyRegistryEIP712DomainChangedIterator) Close() error
⋮----
// KeyRegistryEIP712DomainChanged represents a EIP712DomainChanged event raised by the KeyRegistry contract.
type KeyRegistryEIP712DomainChanged struct {
	Raw types.Log // Blockchain specific contextual infos
}
⋮----
Raw types.Log // Blockchain specific contextual infos
⋮----
// FilterEIP712DomainChanged is a free log retrieval operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
// Solidity: event EIP712DomainChanged()
func (_KeyRegistry *KeyRegistryFilterer) FilterEIP712DomainChanged(opts *bind.FilterOpts) (*KeyRegistryEIP712DomainChangedIterator, error)
⋮----
// WatchEIP712DomainChanged is a free log subscription operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) WatchEIP712DomainChanged(opts *bind.WatchOpts, sink chan<- *KeyRegistryEIP712DomainChanged) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseEIP712DomainChanged is a log parse operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) ParseEIP712DomainChanged(log types.Log) (*KeyRegistryEIP712DomainChanged, error)
⋮----
// KeyRegistryInitEIP712Iterator is returned from FilterInitEIP712 and is used to iterate over the raw logs and unpacked data for InitEIP712 events raised by the KeyRegistry contract.
type KeyRegistryInitEIP712Iterator struct {
	Event *KeyRegistryInitEIP712 // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *KeyRegistryInitEIP712 // Event containing the contract specifics and raw log
⋮----
// KeyRegistryInitEIP712 represents a InitEIP712 event raised by the KeyRegistry contract.
type KeyRegistryInitEIP712 struct {
	Name    string
	Version string
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterInitEIP712 is a free log retrieval operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
// Solidity: event InitEIP712(string name, string version)
func (_KeyRegistry *KeyRegistryFilterer) FilterInitEIP712(opts *bind.FilterOpts) (*KeyRegistryInitEIP712Iterator, error)
⋮----
// WatchInitEIP712 is a free log subscription operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) WatchInitEIP712(opts *bind.WatchOpts, sink chan<- *KeyRegistryInitEIP712) (event.Subscription, error)
⋮----
// ParseInitEIP712 is a log parse operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) ParseInitEIP712(log types.Log) (*KeyRegistryInitEIP712, error)
⋮----
// KeyRegistryInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the KeyRegistry contract.
type KeyRegistryInitializedIterator struct {
	Event *KeyRegistryInitialized // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *KeyRegistryInitialized // Event containing the contract specifics and raw log
⋮----
// KeyRegistryInitialized represents a Initialized event raised by the KeyRegistry contract.
type KeyRegistryInitialized struct {
	Version uint64
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
// Solidity: event Initialized(uint64 version)
func (_KeyRegistry *KeyRegistryFilterer) FilterInitialized(opts *bind.FilterOpts) (*KeyRegistryInitializedIterator, error)
⋮----
// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *KeyRegistryInitialized) (event.Subscription, error)
⋮----
// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) ParseInitialized(log types.Log) (*KeyRegistryInitialized, error)
⋮----
// KeyRegistrySetKeyIterator is returned from FilterSetKey and is used to iterate over the raw logs and unpacked data for SetKey events raised by the KeyRegistry contract.
type KeyRegistrySetKeyIterator struct {
	Event *KeyRegistrySetKey // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *KeyRegistrySetKey // Event containing the contract specifics and raw log
⋮----
// KeyRegistrySetKey represents a SetKey event raised by the KeyRegistry contract.
type KeyRegistrySetKey struct {
	Operator  common.Address
	Tag       uint8
	Key       common.Hash
	ExtraData []byte
	Raw       types.Log // Blockchain specific contextual infos
}
⋮----
Raw       types.Log // Blockchain specific contextual infos
⋮----
// FilterSetKey is a free log retrieval operation binding the contract event 0x980cfe4e76cbf6d3ba24c2161089e5e1b2f98e31821b6afdf5a4d596bee91fcd.
⋮----
// Solidity: event SetKey(address indexed operator, uint8 indexed tag, bytes indexed key, bytes extraData)
func (_KeyRegistry *KeyRegistryFilterer) FilterSetKey(opts *bind.FilterOpts, operator []common.Address, tag []uint8, key [][]byte) (*KeyRegistrySetKeyIterator, error)
⋮----
var operatorRule []interface{}
⋮----
var tagRule []interface{}
⋮----
var keyRule []interface{}
⋮----
// WatchSetKey is a free log subscription operation binding the contract event 0x980cfe4e76cbf6d3ba24c2161089e5e1b2f98e31821b6afdf5a4d596bee91fcd.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) WatchSetKey(opts *bind.WatchOpts, sink chan<- *KeyRegistrySetKey, operator []common.Address, tag []uint8, key [][]byte) (event.Subscription, error)
⋮----
// ParseSetKey is a log parse operation binding the contract event 0x980cfe4e76cbf6d3ba24c2161089e5e1b2f98e31821b6afdf5a4d596bee91fcd.
⋮----
func (_KeyRegistry *KeyRegistryFilterer) ParseSetKey(log types.Log) (*KeyRegistrySetKey, error)
```

## File: symbiotic/client/evm/gen/multicall3.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// Multicall3Call is an auto generated low-level Go binding around an user-defined struct.
type Multicall3Call struct {
	Target   common.Address
	CallData []byte
}
⋮----
// Multicall3Call3 is an auto generated low-level Go binding around an user-defined struct.
type Multicall3Call3 struct {
	Target       common.Address
	AllowFailure bool
	CallData     []byte
}
⋮----
// Multicall3Call3Value is an auto generated low-level Go binding around an user-defined struct.
type Multicall3Call3Value struct {
	Target       common.Address
	AllowFailure bool
	Value        *big.Int
	CallData     []byte
}
⋮----
// Multicall3Result is an auto generated low-level Go binding around an user-defined struct.
type Multicall3Result struct {
	Success    bool
	ReturnData []byte
}
⋮----
// Multicall3MetaData contains all meta data concerning the Multicall3 contract.
var Multicall3MetaData = &bind.MetaData{
	ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
}
⋮----
// Multicall3ABI is the input ABI used to generate the binding from.
// Deprecated: Use Multicall3MetaData.ABI instead.
var Multicall3ABI = Multicall3MetaData.ABI
⋮----
// Multicall3 is an auto generated Go binding around an Ethereum contract.
type Multicall3 struct {
	Multicall3Caller     // Read-only binding to the contract
	Multicall3Transactor // Write-only binding to the contract
	Multicall3Filterer   // Log filterer for contract events
}
⋮----
Multicall3Caller     // Read-only binding to the contract
Multicall3Transactor // Write-only binding to the contract
Multicall3Filterer   // Log filterer for contract events
⋮----
// Multicall3Caller is an auto generated read-only Go binding around an Ethereum contract.
type Multicall3Caller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// Multicall3Transactor is an auto generated write-only Go binding around an Ethereum contract.
type Multicall3Transactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// Multicall3Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
type Multicall3Filterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// Multicall3Session is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type Multicall3Session struct {
	Contract     *Multicall3       // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *Multicall3       // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// Multicall3CallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type Multicall3CallerSession struct {
	Contract *Multicall3Caller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts     // Call options to use throughout this session
}
⋮----
Contract *Multicall3Caller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts     // Call options to use throughout this session
⋮----
// Multicall3TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type Multicall3TransactorSession struct {
	Contract     *Multicall3Transactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts     // Transaction auth options to use throughout this session
}
⋮----
Contract     *Multicall3Transactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts     // Transaction auth options to use throughout this session
⋮----
// Multicall3Raw is an auto generated low-level Go binding around an Ethereum contract.
type Multicall3Raw struct {
	Contract *Multicall3 // Generic contract binding to access the raw methods on
}
⋮----
Contract *Multicall3 // Generic contract binding to access the raw methods on
⋮----
// Multicall3CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type Multicall3CallerRaw struct {
	Contract *Multicall3Caller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *Multicall3Caller // Generic read-only contract binding to access the raw methods on
⋮----
// Multicall3TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type Multicall3TransactorRaw struct {
	Contract *Multicall3Transactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *Multicall3Transactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewMulticall3 creates a new instance of Multicall3, bound to a specific deployed contract.
func NewMulticall3(address common.Address, backend bind.ContractBackend) (*Multicall3, error)
⋮----
// NewMulticall3Caller creates a new read-only instance of Multicall3, bound to a specific deployed contract.
func NewMulticall3Caller(address common.Address, caller bind.ContractCaller) (*Multicall3Caller, error)
⋮----
// NewMulticall3Transactor creates a new write-only instance of Multicall3, bound to a specific deployed contract.
func NewMulticall3Transactor(address common.Address, transactor bind.ContractTransactor) (*Multicall3Transactor, error)
⋮----
// NewMulticall3Filterer creates a new log filterer instance of Multicall3, bound to a specific deployed contract.
func NewMulticall3Filterer(address common.Address, filterer bind.ContractFilterer) (*Multicall3Filterer, error)
⋮----
// bindMulticall3 binds a generic wrapper to an already deployed contract.
func bindMulticall3(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Multicall3 *Multicall3Raw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Multicall3 *Multicall3Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_Multicall3 *Multicall3Raw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// Aggregate is a free data retrieval call binding the contract method 0x252dba42.
//
// Solidity: function aggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes[] returnData)
func (_Multicall3 *Multicall3Caller) Aggregate(opts *bind.CallOpts, calls []Multicall3Call) (struct
⋮----
var out []interface{}
⋮----
// Aggregate3 is a free data retrieval call binding the contract method 0x82ad56cb.
⋮----
// Solidity: function aggregate3((address,bool,bytes)[] calls) view returns((bool,bytes)[] returnData)
func (_Multicall3 *Multicall3Caller) Aggregate3(opts *bind.CallOpts, calls []Multicall3Call3) ([]Multicall3Result, error)
⋮----
// Aggregate3Value is a free data retrieval call binding the contract method 0x174dea71.
⋮----
// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) view returns((bool,bytes)[] returnData)
func (_Multicall3 *Multicall3Caller) Aggregate3Value(opts *bind.CallOpts, calls []Multicall3Call3Value) ([]Multicall3Result, error)
⋮----
// BlockAndAggregate is a free data retrieval call binding the contract method 0xc3077fa9.
⋮----
// Solidity: function blockAndAggregate((address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData)
func (_Multicall3 *Multicall3Caller) BlockAndAggregate(opts *bind.CallOpts, calls []Multicall3Call) (struct
⋮----
// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696.
⋮----
// Solidity: function getBasefee() view returns(uint256 basefee)
func (_Multicall3 *Multicall3Caller) GetBasefee(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e.
⋮----
// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash)
func (_Multicall3 *Multicall3Caller) GetBlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error)
⋮----
// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c.
⋮----
// Solidity: function getBlockNumber() view returns(uint256 blockNumber)
func (_Multicall3 *Multicall3Caller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetChainId is a free data retrieval call binding the contract method 0x3408e470.
⋮----
// Solidity: function getChainId() view returns(uint256 chainid)
func (_Multicall3 *Multicall3Caller) GetChainId(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e.
⋮----
// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase)
func (_Multicall3 *Multicall3Caller) GetCurrentBlockCoinbase(opts *bind.CallOpts) (common.Address, error)
⋮----
// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d.
⋮----
// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty)
func (_Multicall3 *Multicall3Caller) GetCurrentBlockDifficulty(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8.
⋮----
// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit)
func (_Multicall3 *Multicall3Caller) GetCurrentBlockGasLimit(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d.
⋮----
// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp)
func (_Multicall3 *Multicall3Caller) GetCurrentBlockTimestamp(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc.
⋮----
// Solidity: function getEthBalance(address addr) view returns(uint256 balance)
func (_Multicall3 *Multicall3Caller) GetEthBalance(opts *bind.CallOpts, addr common.Address) (*big.Int, error)
⋮----
// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e.
⋮----
// Solidity: function getLastBlockHash() view returns(bytes32 blockHash)
func (_Multicall3 *Multicall3Caller) GetLastBlockHash(opts *bind.CallOpts) ([32]byte, error)
⋮----
// TryAggregate is a free data retrieval call binding the contract method 0xbce38bd7.
⋮----
// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) view returns((bool,bytes)[] returnData)
func (_Multicall3 *Multicall3Caller) TryAggregate(opts *bind.CallOpts, requireSuccess bool, calls []Multicall3Call) ([]Multicall3Result, error)
⋮----
// TryBlockAndAggregate is a free data retrieval call binding the contract method 0x399542e9.
⋮----
// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) view returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData)
func (_Multicall3 *Multicall3Caller) TryBlockAndAggregate(opts *bind.CallOpts, requireSuccess bool, calls []Multicall3Call) (struct
```

## File: symbiotic/client/evm/gen/operatorRegistry.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// OperatorRegistryMetaData contains all meta data concerning the OperatorRegistry contract.
var OperatorRegistryMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"entity\",\"inputs\":[{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isEntity\",\"inputs\":[{\"name\":\"entity_\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperator\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"totalEntities\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"AddEntity\",\"inputs\":[{\"name\":\"entity\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"EntityNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorAlreadyRegistered\",\"inputs\":[]}]",
}
⋮----
// OperatorRegistryABI is the input ABI used to generate the binding from.
// Deprecated: Use OperatorRegistryMetaData.ABI instead.
var OperatorRegistryABI = OperatorRegistryMetaData.ABI
⋮----
// OperatorRegistry is an auto generated Go binding around an Ethereum contract.
type OperatorRegistry struct {
	OperatorRegistryCaller     // Read-only binding to the contract
	OperatorRegistryTransactor // Write-only binding to the contract
	OperatorRegistryFilterer   // Log filterer for contract events
}
⋮----
OperatorRegistryCaller     // Read-only binding to the contract
OperatorRegistryTransactor // Write-only binding to the contract
OperatorRegistryFilterer   // Log filterer for contract events
⋮----
// OperatorRegistryCaller is an auto generated read-only Go binding around an Ethereum contract.
type OperatorRegistryCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// OperatorRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract.
type OperatorRegistryTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OperatorRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type OperatorRegistryFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// OperatorRegistrySession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type OperatorRegistrySession struct {
	Contract     *OperatorRegistry // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *OperatorRegistry // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// OperatorRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type OperatorRegistryCallerSession struct {
	Contract *OperatorRegistryCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts           // Call options to use throughout this session
}
⋮----
Contract *OperatorRegistryCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts           // Call options to use throughout this session
⋮----
// OperatorRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type OperatorRegistryTransactorSession struct {
	Contract     *OperatorRegistryTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts           // Transaction auth options to use throughout this session
}
⋮----
Contract     *OperatorRegistryTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts           // Transaction auth options to use throughout this session
⋮----
// OperatorRegistryRaw is an auto generated low-level Go binding around an Ethereum contract.
type OperatorRegistryRaw struct {
	Contract *OperatorRegistry // Generic contract binding to access the raw methods on
}
⋮----
Contract *OperatorRegistry // Generic contract binding to access the raw methods on
⋮----
// OperatorRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type OperatorRegistryCallerRaw struct {
	Contract *OperatorRegistryCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *OperatorRegistryCaller // Generic read-only contract binding to access the raw methods on
⋮----
// OperatorRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type OperatorRegistryTransactorRaw struct {
	Contract *OperatorRegistryTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *OperatorRegistryTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewOperatorRegistry creates a new instance of OperatorRegistry, bound to a specific deployed contract.
func NewOperatorRegistry(address common.Address, backend bind.ContractBackend) (*OperatorRegistry, error)
⋮----
// NewOperatorRegistryCaller creates a new read-only instance of OperatorRegistry, bound to a specific deployed contract.
func NewOperatorRegistryCaller(address common.Address, caller bind.ContractCaller) (*OperatorRegistryCaller, error)
⋮----
// NewOperatorRegistryTransactor creates a new write-only instance of OperatorRegistry, bound to a specific deployed contract.
func NewOperatorRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*OperatorRegistryTransactor, error)
⋮----
// NewOperatorRegistryFilterer creates a new log filterer instance of OperatorRegistry, bound to a specific deployed contract.
func NewOperatorRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*OperatorRegistryFilterer, error)
⋮----
// bindOperatorRegistry binds a generic wrapper to an already deployed contract.
func bindOperatorRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_OperatorRegistry *OperatorRegistryRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_OperatorRegistry *OperatorRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_OperatorRegistry *OperatorRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// Entity is a free data retrieval call binding the contract method 0xb42ba2a2.
//
// Solidity: function entity(uint256 index) view returns(address)
func (_OperatorRegistry *OperatorRegistryCaller) Entity(opts *bind.CallOpts, index *big.Int) (common.Address, error)
⋮----
var out []interface{}
⋮----
// IsEntity is a free data retrieval call binding the contract method 0x14887c58.
⋮----
// Solidity: function isEntity(address entity_) view returns(bool)
func (_OperatorRegistry *OperatorRegistryCaller) IsEntity(opts *bind.CallOpts, entity_ common.Address) (bool, error)
⋮----
// TotalEntities is a free data retrieval call binding the contract method 0x5cd8b15e.
⋮----
// Solidity: function totalEntities() view returns(uint256)
func (_OperatorRegistry *OperatorRegistryCaller) TotalEntities(opts *bind.CallOpts) (*big.Int, error)
⋮----
// RegisterOperator is a paid mutator transaction binding the contract method 0x2acde098.
⋮----
// Solidity: function registerOperator() returns()
func (_OperatorRegistry *OperatorRegistryTransactor) RegisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// OperatorRegistryAddEntityIterator is returned from FilterAddEntity and is used to iterate over the raw logs and unpacked data for AddEntity events raised by the OperatorRegistry contract.
type OperatorRegistryAddEntityIterator struct {
	Event *OperatorRegistryAddEntity // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *OperatorRegistryAddEntity // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *OperatorRegistryAddEntityIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *OperatorRegistryAddEntityIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *OperatorRegistryAddEntityIterator) Close() error
⋮----
// OperatorRegistryAddEntity represents a AddEntity event raised by the OperatorRegistry contract.
type OperatorRegistryAddEntity struct {
	Entity common.Address
	Raw    types.Log // Blockchain specific contextual infos
}
⋮----
Raw    types.Log // Blockchain specific contextual infos
⋮----
// FilterAddEntity is a free log retrieval operation binding the contract event 0xb919910dcefbf753bfd926ab3b1d3f85d877190c3d01ba1bd585047b99b99f0b.
⋮----
// Solidity: event AddEntity(address indexed entity)
func (_OperatorRegistry *OperatorRegistryFilterer) FilterAddEntity(opts *bind.FilterOpts, entity []common.Address) (*OperatorRegistryAddEntityIterator, error)
⋮----
var entityRule []interface{}
⋮----
// WatchAddEntity is a free log subscription operation binding the contract event 0xb919910dcefbf753bfd926ab3b1d3f85d877190c3d01ba1bd585047b99b99f0b.
⋮----
func (_OperatorRegistry *OperatorRegistryFilterer) WatchAddEntity(opts *bind.WatchOpts, sink chan<- *OperatorRegistryAddEntity, entity []common.Address) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseAddEntity is a log parse operation binding the contract event 0xb919910dcefbf753bfd926ab3b1d3f85d877190c3d01ba1bd585047b99b99f0b.
⋮----
func (_OperatorRegistry *OperatorRegistryFilterer) ParseAddEntity(log types.Log) (*OperatorRegistryAddEntity, error)
```

## File: symbiotic/client/evm/gen/settlement.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// ISettlementExtraData is an auto generated low-level Go binding around an user-defined struct.
type ISettlementExtraData struct {
	Key   [32]byte
	Value [32]byte
}
⋮----
// ISettlementValSetHeader is an auto generated low-level Go binding around an user-defined struct.
type ISettlementValSetHeader struct {
	Version            uint8
	RequiredKeyTag     uint8
	Epoch              *big.Int
	CaptureTimestamp   *big.Int
	QuorumThreshold    *big.Int
	TotalVotingPower   *big.Int
	ValidatorsSszMRoot [32]byte
}
⋮----
// SettlementMetaData contains all meta data concerning the Settlement contract.
var SettlementMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"NETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK_IDENTIFIER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint96\",\"internalType\":\"uint96\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VALIDATOR_SET_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"commitValSetHeader\",\"inputs\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"extraData\",\"type\":\"tuple[]\",\"internalType\":\"structISettlement.ExtraData[]\",\"components\":[{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"value\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"eip712Domain\",\"inputs\":[],\"outputs\":[{\"name\":\"fields\",\"type\":\"bytes1\",\"internalType\":\"bytes1\"},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extensions\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCaptureTimestampFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCaptureTimestampFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getExtraData\",\"inputs\":[{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getExtraDataAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getLastCommittedHeaderEpoch\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getQuorumThresholdFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getQuorumThresholdFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredKeyTagFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredKeyTagFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSigVerifier\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSigVerifierAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTotalVotingPowerFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTotalVotingPowerFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValSetHeaderHash\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValSetHeaderHashAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValidatorsSszMRootFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getValidatorsSszMRootFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVersionFromValSetHeader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVersionFromValSetHeaderAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4CrossChain\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isValSetHeaderCommittedAt\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setGenesis\",\"inputs\":[{\"name\":\"valSetHeader\",\"type\":\"tuple\",\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"extraData\",\"type\":\"tuple[]\",\"internalType\":\"structISettlement.ExtraData[]\",\"components\":[{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"value\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setSigVerifier\",\"inputs\":[{\"name\":\"sigVerifier\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"staticDelegateCall\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"verifyQuorumSig\",\"inputs\":[{\"name\":\"message\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyQuorumSigAt\",\"inputs\":[{\"name\":\"message\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CommitValSetHeader\",\"inputs\":[{\"name\":\"valSetHeader\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"extraData\",\"type\":\"tuple[]\",\"indexed\":false,\"internalType\":\"structISettlement.ExtraData[]\",\"components\":[{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"value\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"EIP712DomainChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitEIP712\",\"inputs\":[{\"name\":\"name\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitSigVerifier\",\"inputs\":[{\"name\":\"sigVerifier\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitSubnetwork\",\"inputs\":[{\"name\":\"network\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"subnetworkId\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetGenesis\",\"inputs\":[{\"name\":\"valSetHeader\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structISettlement.ValSetHeader\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"requiredKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"captureTimestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"quorumThreshold\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"totalVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"validatorsSszMRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"extraData\",\"type\":\"tuple[]\",\"indexed\":false,\"internalType\":\"structISettlement.ExtraData[]\",\"components\":[{\"name\":\"key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"value\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetSigVerifier\",\"inputs\":[{\"name\":\"sigVerifier\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CheckpointUnorderedInsertion\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidKeyTag\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NetworkManager_InvalidNetwork\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_DuplicateExtraDataKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_InvalidCaptureTimestamp\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_InvalidEpoch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_InvalidSigVerifier\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_InvalidValidatorsSszMRoot\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_InvalidVersion\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_QuorumThresholdGtTotalVotingPower\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_ValSetHeaderAlreadyCommitted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Settlement_VerificationFailed\",\"inputs\":[]}]",
}
⋮----
// SettlementABI is the input ABI used to generate the binding from.
// Deprecated: Use SettlementMetaData.ABI instead.
var SettlementABI = SettlementMetaData.ABI
⋮----
// Settlement is an auto generated Go binding around an Ethereum contract.
type Settlement struct {
	SettlementCaller     // Read-only binding to the contract
	SettlementTransactor // Write-only binding to the contract
	SettlementFilterer   // Log filterer for contract events
}
⋮----
SettlementCaller     // Read-only binding to the contract
SettlementTransactor // Write-only binding to the contract
SettlementFilterer   // Log filterer for contract events
⋮----
// SettlementCaller is an auto generated read-only Go binding around an Ethereum contract.
type SettlementCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// SettlementTransactor is an auto generated write-only Go binding around an Ethereum contract.
type SettlementTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// SettlementFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type SettlementFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// SettlementSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type SettlementSession struct {
	Contract     *Settlement       // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *Settlement       // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// SettlementCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type SettlementCallerSession struct {
	Contract *SettlementCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts     // Call options to use throughout this session
}
⋮----
Contract *SettlementCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts     // Call options to use throughout this session
⋮----
// SettlementTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type SettlementTransactorSession struct {
	Contract     *SettlementTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts     // Transaction auth options to use throughout this session
}
⋮----
Contract     *SettlementTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts     // Transaction auth options to use throughout this session
⋮----
// SettlementRaw is an auto generated low-level Go binding around an Ethereum contract.
type SettlementRaw struct {
	Contract *Settlement // Generic contract binding to access the raw methods on
}
⋮----
Contract *Settlement // Generic contract binding to access the raw methods on
⋮----
// SettlementCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type SettlementCallerRaw struct {
	Contract *SettlementCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *SettlementCaller // Generic read-only contract binding to access the raw methods on
⋮----
// SettlementTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type SettlementTransactorRaw struct {
	Contract *SettlementTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *SettlementTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewSettlement creates a new instance of Settlement, bound to a specific deployed contract.
func NewSettlement(address common.Address, backend bind.ContractBackend) (*Settlement, error)
⋮----
// NewSettlementCaller creates a new read-only instance of Settlement, bound to a specific deployed contract.
func NewSettlementCaller(address common.Address, caller bind.ContractCaller) (*SettlementCaller, error)
⋮----
// NewSettlementTransactor creates a new write-only instance of Settlement, bound to a specific deployed contract.
func NewSettlementTransactor(address common.Address, transactor bind.ContractTransactor) (*SettlementTransactor, error)
⋮----
// NewSettlementFilterer creates a new log filterer instance of Settlement, bound to a specific deployed contract.
func NewSettlementFilterer(address common.Address, filterer bind.ContractFilterer) (*SettlementFilterer, error)
⋮----
// bindSettlement binds a generic wrapper to an already deployed contract.
func bindSettlement(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Settlement *SettlementRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Settlement *SettlementRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_Settlement *SettlementRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// NETWORK is a free data retrieval call binding the contract method 0x8759e6d1.
//
// Solidity: function NETWORK() view returns(address)
func (_Settlement *SettlementCaller) NETWORK(opts *bind.CallOpts) (common.Address, error)
⋮----
var out []interface{}
⋮----
// SUBNETWORK is a free data retrieval call binding the contract method 0x773e6b54.
⋮----
// Solidity: function SUBNETWORK() view returns(bytes32)
func (_Settlement *SettlementCaller) SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
⋮----
// SUBNETWORKIDENTIFIER is a free data retrieval call binding the contract method 0xabacb807.
⋮----
// Solidity: function SUBNETWORK_IDENTIFIER() view returns(uint96)
func (_Settlement *SettlementCaller) SUBNETWORKIDENTIFIER(opts *bind.CallOpts) (*big.Int, error)
⋮----
// VALIDATORSETVERSION is a free data retrieval call binding the contract method 0x321d7b8d.
⋮----
// Solidity: function VALIDATOR_SET_VERSION() view returns(uint8)
func (_Settlement *SettlementCaller) VALIDATORSETVERSION(opts *bind.CallOpts) (uint8, error)
⋮----
// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e.
⋮----
// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)
func (_Settlement *SettlementCaller) Eip712Domain(opts *bind.CallOpts) (struct
⋮----
// GetCaptureTimestampFromValSetHeader is a free data retrieval call binding the contract method 0xf4935d39.
⋮----
// Solidity: function getCaptureTimestampFromValSetHeader() view returns(uint48)
func (_Settlement *SettlementCaller) GetCaptureTimestampFromValSetHeader(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCaptureTimestampFromValSetHeaderAt is a free data retrieval call binding the contract method 0x5485b549.
⋮----
// Solidity: function getCaptureTimestampFromValSetHeaderAt(uint48 epoch) view returns(uint48)
func (_Settlement *SettlementCaller) GetCaptureTimestampFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetExtraData is a free data retrieval call binding the contract method 0xecae6344.
⋮----
// Solidity: function getExtraData(bytes32 key) view returns(bytes32)
func (_Settlement *SettlementCaller) GetExtraData(opts *bind.CallOpts, key [32]byte) ([32]byte, error)
⋮----
// GetExtraDataAt is a free data retrieval call binding the contract method 0x52bb038a.
⋮----
// Solidity: function getExtraDataAt(uint48 epoch, bytes32 key) view returns(bytes32)
func (_Settlement *SettlementCaller) GetExtraDataAt(opts *bind.CallOpts, epoch *big.Int, key [32]byte) ([32]byte, error)
⋮----
// GetLastCommittedHeaderEpoch is a free data retrieval call binding the contract method 0x65b0849b.
⋮----
// Solidity: function getLastCommittedHeaderEpoch() view returns(uint48)
func (_Settlement *SettlementCaller) GetLastCommittedHeaderEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetQuorumThresholdFromValSetHeader is a free data retrieval call binding the contract method 0xe586b38e.
⋮----
// Solidity: function getQuorumThresholdFromValSetHeader() view returns(uint256)
func (_Settlement *SettlementCaller) GetQuorumThresholdFromValSetHeader(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetQuorumThresholdFromValSetHeaderAt is a free data retrieval call binding the contract method 0x1d86bd88.
⋮----
// Solidity: function getQuorumThresholdFromValSetHeaderAt(uint48 epoch) view returns(uint256)
func (_Settlement *SettlementCaller) GetQuorumThresholdFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetRequiredKeyTagFromValSetHeader is a free data retrieval call binding the contract method 0xb91a434a.
⋮----
// Solidity: function getRequiredKeyTagFromValSetHeader() view returns(uint8)
func (_Settlement *SettlementCaller) GetRequiredKeyTagFromValSetHeader(opts *bind.CallOpts) (uint8, error)
⋮----
// GetRequiredKeyTagFromValSetHeaderAt is a free data retrieval call binding the contract method 0xe4378ed2.
⋮----
// Solidity: function getRequiredKeyTagFromValSetHeaderAt(uint48 epoch) view returns(uint8)
func (_Settlement *SettlementCaller) GetRequiredKeyTagFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (uint8, error)
⋮----
// GetSigVerifier is a free data retrieval call binding the contract method 0x5b28556d.
⋮----
// Solidity: function getSigVerifier() view returns(address)
func (_Settlement *SettlementCaller) GetSigVerifier(opts *bind.CallOpts) (common.Address, error)
⋮----
// GetSigVerifierAt is a free data retrieval call binding the contract method 0xa54ce263.
⋮----
// Solidity: function getSigVerifierAt(uint48 epoch, bytes hint) view returns(address)
func (_Settlement *SettlementCaller) GetSigVerifierAt(opts *bind.CallOpts, epoch *big.Int, hint []byte) (common.Address, error)
⋮----
// GetTotalVotingPowerFromValSetHeader is a free data retrieval call binding the contract method 0xc38de37f.
⋮----
// Solidity: function getTotalVotingPowerFromValSetHeader() view returns(uint256)
func (_Settlement *SettlementCaller) GetTotalVotingPowerFromValSetHeader(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetTotalVotingPowerFromValSetHeaderAt is a free data retrieval call binding the contract method 0xf7e5b491.
⋮----
// Solidity: function getTotalVotingPowerFromValSetHeaderAt(uint48 epoch) view returns(uint256)
func (_Settlement *SettlementCaller) GetTotalVotingPowerFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetValSetHeader is a free data retrieval call binding the contract method 0xadc91fc8.
⋮----
// Solidity: function getValSetHeader() view returns((uint8,uint8,uint48,uint48,uint256,uint256,bytes32) header)
func (_Settlement *SettlementCaller) GetValSetHeader(opts *bind.CallOpts) (ISettlementValSetHeader, error)
⋮----
// GetValSetHeaderAt is a free data retrieval call binding the contract method 0x4addaee7.
⋮----
// Solidity: function getValSetHeaderAt(uint48 epoch) view returns((uint8,uint8,uint48,uint48,uint256,uint256,bytes32))
func (_Settlement *SettlementCaller) GetValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (ISettlementValSetHeader, error)
⋮----
// GetValSetHeaderHash is a free data retrieval call binding the contract method 0x32624bf3.
⋮----
// Solidity: function getValSetHeaderHash() view returns(bytes32)
func (_Settlement *SettlementCaller) GetValSetHeaderHash(opts *bind.CallOpts) ([32]byte, error)
⋮----
// GetValSetHeaderHashAt is a free data retrieval call binding the contract method 0xf35d12a3.
⋮----
// Solidity: function getValSetHeaderHashAt(uint48 epoch) view returns(bytes32)
func (_Settlement *SettlementCaller) GetValSetHeaderHashAt(opts *bind.CallOpts, epoch *big.Int) ([32]byte, error)
⋮----
// GetValidatorsSszMRootFromValSetHeader is a free data retrieval call binding the contract method 0x0167166e.
⋮----
// Solidity: function getValidatorsSszMRootFromValSetHeader() view returns(bytes32)
func (_Settlement *SettlementCaller) GetValidatorsSszMRootFromValSetHeader(opts *bind.CallOpts) ([32]byte, error)
⋮----
// GetValidatorsSszMRootFromValSetHeaderAt is a free data retrieval call binding the contract method 0x230ae408.
⋮----
// Solidity: function getValidatorsSszMRootFromValSetHeaderAt(uint48 epoch) view returns(bytes32)
func (_Settlement *SettlementCaller) GetValidatorsSszMRootFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) ([32]byte, error)
⋮----
// GetVersionFromValSetHeader is a free data retrieval call binding the contract method 0xd2df9fb6.
⋮----
// Solidity: function getVersionFromValSetHeader() view returns(uint8)
func (_Settlement *SettlementCaller) GetVersionFromValSetHeader(opts *bind.CallOpts) (uint8, error)
⋮----
// GetVersionFromValSetHeaderAt is a free data retrieval call binding the contract method 0x548202ad.
⋮----
// Solidity: function getVersionFromValSetHeaderAt(uint48 epoch) view returns(uint8)
func (_Settlement *SettlementCaller) GetVersionFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (uint8, error)
⋮----
// HashTypedDataV4 is a free data retrieval call binding the contract method 0x4980f288.
⋮----
// Solidity: function hashTypedDataV4(bytes32 structHash) view returns(bytes32)
func (_Settlement *SettlementCaller) HashTypedDataV4(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// HashTypedDataV4CrossChain is a free data retrieval call binding the contract method 0x518dcf3b.
⋮----
// Solidity: function hashTypedDataV4CrossChain(bytes32 structHash) view returns(bytes32)
func (_Settlement *SettlementCaller) HashTypedDataV4CrossChain(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// IsValSetHeaderCommittedAt is a free data retrieval call binding the contract method 0x5fa4bbd2.
⋮----
// Solidity: function isValSetHeaderCommittedAt(uint48 epoch) view returns(bool)
func (_Settlement *SettlementCaller) IsValSetHeaderCommittedAt(opts *bind.CallOpts, epoch *big.Int) (bool, error)
⋮----
// VerifyQuorumSig is a free data retrieval call binding the contract method 0x1dc1898b.
⋮----
// Solidity: function verifyQuorumSig(bytes message, uint8 keyTag, uint256 quorumThreshold, bytes proof) view returns(bool)
func (_Settlement *SettlementCaller) VerifyQuorumSig(opts *bind.CallOpts, message []byte, keyTag uint8, quorumThreshold *big.Int, proof []byte) (bool, error)
⋮----
// VerifyQuorumSigAt is a free data retrieval call binding the contract method 0xacaa2269.
⋮----
// Solidity: function verifyQuorumSigAt(bytes message, uint8 keyTag, uint256 quorumThreshold, bytes proof, uint48 epoch, bytes hint) view returns(bool)
func (_Settlement *SettlementCaller) VerifyQuorumSigAt(opts *bind.CallOpts, message []byte, keyTag uint8, quorumThreshold *big.Int, proof []byte, epoch *big.Int, hint []byte) (bool, error)
⋮----
// CommitValSetHeader is a paid mutator transaction binding the contract method 0x6f5f058e.
⋮----
// Solidity: function commitValSetHeader((uint8,uint8,uint48,uint48,uint256,uint256,bytes32) header, (bytes32,bytes32)[] extraData, bytes proof) returns()
func (_Settlement *SettlementTransactor) CommitValSetHeader(opts *bind.TransactOpts, header ISettlementValSetHeader, extraData []ISettlementExtraData, proof []byte) (*types.Transaction, error)
⋮----
// SetGenesis is a paid mutator transaction binding the contract method 0xec3be7e4.
⋮----
// Solidity: function setGenesis((uint8,uint8,uint48,uint48,uint256,uint256,bytes32) valSetHeader, (bytes32,bytes32)[] extraData) returns()
func (_Settlement *SettlementTransactor) SetGenesis(opts *bind.TransactOpts, valSetHeader ISettlementValSetHeader, extraData []ISettlementExtraData) (*types.Transaction, error)
⋮----
// SetSigVerifier is a paid mutator transaction binding the contract method 0xbd7e9980.
⋮----
// Solidity: function setSigVerifier(address sigVerifier) returns()
func (_Settlement *SettlementTransactor) SetSigVerifier(opts *bind.TransactOpts, sigVerifier common.Address) (*types.Transaction, error)
⋮----
// StaticDelegateCall is a paid mutator transaction binding the contract method 0x9f86fd85.
⋮----
// Solidity: function staticDelegateCall(address target, bytes data) returns()
func (_Settlement *SettlementTransactor) StaticDelegateCall(opts *bind.TransactOpts, target common.Address, data []byte) (*types.Transaction, error)
⋮----
// SettlementCommitValSetHeaderIterator is returned from FilterCommitValSetHeader and is used to iterate over the raw logs and unpacked data for CommitValSetHeader events raised by the Settlement contract.
type SettlementCommitValSetHeaderIterator struct {
	Event *SettlementCommitValSetHeader // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementCommitValSetHeader // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *SettlementCommitValSetHeaderIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *SettlementCommitValSetHeaderIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *SettlementCommitValSetHeaderIterator) Close() error
⋮----
// SettlementCommitValSetHeader represents a CommitValSetHeader event raised by the Settlement contract.
type SettlementCommitValSetHeader struct {
	ValSetHeader ISettlementValSetHeader
	ExtraData    []ISettlementExtraData
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
Raw          types.Log // Blockchain specific contextual infos
⋮----
// FilterCommitValSetHeader is a free log retrieval operation binding the contract event 0x9ed1f51eddfff95a70fd993c30da7d26fc67bda21c9145aafc7d0a510a405558.
⋮----
// Solidity: event CommitValSetHeader((uint8,uint8,uint48,uint48,uint256,uint256,bytes32) valSetHeader, (bytes32,bytes32)[] extraData)
func (_Settlement *SettlementFilterer) FilterCommitValSetHeader(opts *bind.FilterOpts) (*SettlementCommitValSetHeaderIterator, error)
⋮----
// WatchCommitValSetHeader is a free log subscription operation binding the contract event 0x9ed1f51eddfff95a70fd993c30da7d26fc67bda21c9145aafc7d0a510a405558.
⋮----
func (_Settlement *SettlementFilterer) WatchCommitValSetHeader(opts *bind.WatchOpts, sink chan<- *SettlementCommitValSetHeader) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseCommitValSetHeader is a log parse operation binding the contract event 0x9ed1f51eddfff95a70fd993c30da7d26fc67bda21c9145aafc7d0a510a405558.
⋮----
func (_Settlement *SettlementFilterer) ParseCommitValSetHeader(log types.Log) (*SettlementCommitValSetHeader, error)
⋮----
// SettlementEIP712DomainChangedIterator is returned from FilterEIP712DomainChanged and is used to iterate over the raw logs and unpacked data for EIP712DomainChanged events raised by the Settlement contract.
type SettlementEIP712DomainChangedIterator struct {
	Event *SettlementEIP712DomainChanged // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementEIP712DomainChanged // Event containing the contract specifics and raw log
⋮----
// SettlementEIP712DomainChanged represents a EIP712DomainChanged event raised by the Settlement contract.
type SettlementEIP712DomainChanged struct {
	Raw types.Log // Blockchain specific contextual infos
}
⋮----
Raw types.Log // Blockchain specific contextual infos
⋮----
// FilterEIP712DomainChanged is a free log retrieval operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
// Solidity: event EIP712DomainChanged()
func (_Settlement *SettlementFilterer) FilterEIP712DomainChanged(opts *bind.FilterOpts) (*SettlementEIP712DomainChangedIterator, error)
⋮----
// WatchEIP712DomainChanged is a free log subscription operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_Settlement *SettlementFilterer) WatchEIP712DomainChanged(opts *bind.WatchOpts, sink chan<- *SettlementEIP712DomainChanged) (event.Subscription, error)
⋮----
// ParseEIP712DomainChanged is a log parse operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_Settlement *SettlementFilterer) ParseEIP712DomainChanged(log types.Log) (*SettlementEIP712DomainChanged, error)
⋮----
// SettlementInitEIP712Iterator is returned from FilterInitEIP712 and is used to iterate over the raw logs and unpacked data for InitEIP712 events raised by the Settlement contract.
type SettlementInitEIP712Iterator struct {
	Event *SettlementInitEIP712 // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementInitEIP712 // Event containing the contract specifics and raw log
⋮----
// SettlementInitEIP712 represents a InitEIP712 event raised by the Settlement contract.
type SettlementInitEIP712 struct {
	Name    string
	Version string
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterInitEIP712 is a free log retrieval operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
// Solidity: event InitEIP712(string name, string version)
func (_Settlement *SettlementFilterer) FilterInitEIP712(opts *bind.FilterOpts) (*SettlementInitEIP712Iterator, error)
⋮----
// WatchInitEIP712 is a free log subscription operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_Settlement *SettlementFilterer) WatchInitEIP712(opts *bind.WatchOpts, sink chan<- *SettlementInitEIP712) (event.Subscription, error)
⋮----
// ParseInitEIP712 is a log parse operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_Settlement *SettlementFilterer) ParseInitEIP712(log types.Log) (*SettlementInitEIP712, error)
⋮----
// SettlementInitSigVerifierIterator is returned from FilterInitSigVerifier and is used to iterate over the raw logs and unpacked data for InitSigVerifier events raised by the Settlement contract.
type SettlementInitSigVerifierIterator struct {
	Event *SettlementInitSigVerifier // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementInitSigVerifier // Event containing the contract specifics and raw log
⋮----
// SettlementInitSigVerifier represents a InitSigVerifier event raised by the Settlement contract.
type SettlementInitSigVerifier struct {
	SigVerifier common.Address
	Raw         types.Log // Blockchain specific contextual infos
}
⋮----
Raw         types.Log // Blockchain specific contextual infos
⋮----
// FilterInitSigVerifier is a free log retrieval operation binding the contract event 0x8c698070f0c9ef92ff032a24e5c83ef7783fd360fde9c6af8ed5fca9fa5abbb7.
⋮----
// Solidity: event InitSigVerifier(address sigVerifier)
func (_Settlement *SettlementFilterer) FilterInitSigVerifier(opts *bind.FilterOpts) (*SettlementInitSigVerifierIterator, error)
⋮----
// WatchInitSigVerifier is a free log subscription operation binding the contract event 0x8c698070f0c9ef92ff032a24e5c83ef7783fd360fde9c6af8ed5fca9fa5abbb7.
⋮----
func (_Settlement *SettlementFilterer) WatchInitSigVerifier(opts *bind.WatchOpts, sink chan<- *SettlementInitSigVerifier) (event.Subscription, error)
⋮----
// ParseInitSigVerifier is a log parse operation binding the contract event 0x8c698070f0c9ef92ff032a24e5c83ef7783fd360fde9c6af8ed5fca9fa5abbb7.
⋮----
func (_Settlement *SettlementFilterer) ParseInitSigVerifier(log types.Log) (*SettlementInitSigVerifier, error)
⋮----
// SettlementInitSubnetworkIterator is returned from FilterInitSubnetwork and is used to iterate over the raw logs and unpacked data for InitSubnetwork events raised by the Settlement contract.
type SettlementInitSubnetworkIterator struct {
	Event *SettlementInitSubnetwork // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementInitSubnetwork // Event containing the contract specifics and raw log
⋮----
// SettlementInitSubnetwork represents a InitSubnetwork event raised by the Settlement contract.
type SettlementInitSubnetwork struct {
	Network      common.Address
	SubnetworkId *big.Int
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
// FilterInitSubnetwork is a free log retrieval operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
// Solidity: event InitSubnetwork(address network, uint96 subnetworkId)
func (_Settlement *SettlementFilterer) FilterInitSubnetwork(opts *bind.FilterOpts) (*SettlementInitSubnetworkIterator, error)
⋮----
// WatchInitSubnetwork is a free log subscription operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_Settlement *SettlementFilterer) WatchInitSubnetwork(opts *bind.WatchOpts, sink chan<- *SettlementInitSubnetwork) (event.Subscription, error)
⋮----
// ParseInitSubnetwork is a log parse operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_Settlement *SettlementFilterer) ParseInitSubnetwork(log types.Log) (*SettlementInitSubnetwork, error)
⋮----
// SettlementInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Settlement contract.
type SettlementInitializedIterator struct {
	Event *SettlementInitialized // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementInitialized // Event containing the contract specifics and raw log
⋮----
// SettlementInitialized represents a Initialized event raised by the Settlement contract.
type SettlementInitialized struct {
	Version uint64
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
// Solidity: event Initialized(uint64 version)
func (_Settlement *SettlementFilterer) FilterInitialized(opts *bind.FilterOpts) (*SettlementInitializedIterator, error)
⋮----
// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_Settlement *SettlementFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *SettlementInitialized) (event.Subscription, error)
⋮----
// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_Settlement *SettlementFilterer) ParseInitialized(log types.Log) (*SettlementInitialized, error)
⋮----
// SettlementSetGenesisIterator is returned from FilterSetGenesis and is used to iterate over the raw logs and unpacked data for SetGenesis events raised by the Settlement contract.
type SettlementSetGenesisIterator struct {
	Event *SettlementSetGenesis // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementSetGenesis // Event containing the contract specifics and raw log
⋮----
// SettlementSetGenesis represents a SetGenesis event raised by the Settlement contract.
type SettlementSetGenesis struct {
	ValSetHeader ISettlementValSetHeader
	ExtraData    []ISettlementExtraData
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetGenesis is a free log retrieval operation binding the contract event 0xd4b7365d7a7dd369f40b249f48684bd7e51524b3ab56a9eb188ac339d574bbc0.
⋮----
// Solidity: event SetGenesis((uint8,uint8,uint48,uint48,uint256,uint256,bytes32) valSetHeader, (bytes32,bytes32)[] extraData)
func (_Settlement *SettlementFilterer) FilterSetGenesis(opts *bind.FilterOpts) (*SettlementSetGenesisIterator, error)
⋮----
// WatchSetGenesis is a free log subscription operation binding the contract event 0xd4b7365d7a7dd369f40b249f48684bd7e51524b3ab56a9eb188ac339d574bbc0.
⋮----
func (_Settlement *SettlementFilterer) WatchSetGenesis(opts *bind.WatchOpts, sink chan<- *SettlementSetGenesis) (event.Subscription, error)
⋮----
// ParseSetGenesis is a log parse operation binding the contract event 0xd4b7365d7a7dd369f40b249f48684bd7e51524b3ab56a9eb188ac339d574bbc0.
⋮----
func (_Settlement *SettlementFilterer) ParseSetGenesis(log types.Log) (*SettlementSetGenesis, error)
⋮----
// SettlementSetSigVerifierIterator is returned from FilterSetSigVerifier and is used to iterate over the raw logs and unpacked data for SetSigVerifier events raised by the Settlement contract.
type SettlementSetSigVerifierIterator struct {
	Event *SettlementSetSigVerifier // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *SettlementSetSigVerifier // Event containing the contract specifics and raw log
⋮----
// SettlementSetSigVerifier represents a SetSigVerifier event raised by the Settlement contract.
type SettlementSetSigVerifier struct {
	SigVerifier common.Address
	Raw         types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetSigVerifier is a free log retrieval operation binding the contract event 0x3cb2fcfd41e182e933eb967bdeaac4f8ff69c80b6fd24fea9561dfbdec127942.
⋮----
// Solidity: event SetSigVerifier(address sigVerifier)
func (_Settlement *SettlementFilterer) FilterSetSigVerifier(opts *bind.FilterOpts) (*SettlementSetSigVerifierIterator, error)
⋮----
// WatchSetSigVerifier is a free log subscription operation binding the contract event 0x3cb2fcfd41e182e933eb967bdeaac4f8ff69c80b6fd24fea9561dfbdec127942.
⋮----
func (_Settlement *SettlementFilterer) WatchSetSigVerifier(opts *bind.WatchOpts, sink chan<- *SettlementSetSigVerifier) (event.Subscription, error)
⋮----
// ParseSetSigVerifier is a log parse operation binding the contract event 0x3cb2fcfd41e182e933eb967bdeaac4f8ff69c80b6fd24fea9561dfbdec127942.
⋮----
func (_Settlement *SettlementFilterer) ParseSetSigVerifier(log types.Log) (*SettlementSetSigVerifier, error)
```

## File: symbiotic/client/evm/gen/valsetDriver.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// IValSetDriverConfig is an auto generated low-level Go binding around an user-defined struct.
type IValSetDriverConfig struct {
	NumAggregators          *big.Int
	NumCommitters           *big.Int
	CommitterSlotDuration   *big.Int
	VotingPowerProviders    []IValSetDriverCrossChainAddress
	KeysProvider            IValSetDriverCrossChainAddress
	Settlements             []IValSetDriverCrossChainAddress
	MaxVotingPower          *big.Int
	MinInclusionVotingPower *big.Int
	MaxValidatorsCount      *big.Int
	RequiredKeyTags         []uint8
	QuorumThresholds        []IValSetDriverQuorumThreshold
	RequiredHeaderKeyTag    uint8
	VerificationType        uint32
}
⋮----
// IValSetDriverCrossChainAddress is an auto generated low-level Go binding around an user-defined struct.
type IValSetDriverCrossChainAddress struct {
	ChainId uint64
	Addr    common.Address
}
⋮----
// IValSetDriverQuorumThreshold is an auto generated low-level Go binding around an user-defined struct.
type IValSetDriverQuorumThreshold struct {
	KeyTag          uint8
	QuorumThreshold *big.Int
}
⋮----
// ValSetDriverMetaData contains all meta data concerning the ValSetDriver contract.
var ValSetDriverMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"MAX_QUORUM_THRESHOLD\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint248\",\"internalType\":\"uint248\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK_IDENTIFIER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint96\",\"internalType\":\"uint96\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addQuorumThreshold\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addSettlement\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addVotingPowerProvider\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getCommitterSlotDuration\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCommitterSlotDurationAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.Config\",\"components\":[{\"name\":\"numAggregators\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"numCommitters\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"committerSlotDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"votingPowerProviders\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"keysProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"settlements\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"maxVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minInclusionVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxValidatorsCount\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"internalType\":\"uint8[]\"},{\"name\":\"quorumThresholds\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.QuorumThreshold[]\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]},{\"name\":\"requiredHeaderKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"verificationType\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getConfigAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.Config\",\"components\":[{\"name\":\"numAggregators\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"numCommitters\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"committerSlotDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"votingPowerProviders\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"keysProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"settlements\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"maxVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minInclusionVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxValidatorsCount\",\"type\":\"uint208\",\"internalType\":\"uint208\"},{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"internalType\":\"uint8[]\"},{\"name\":\"quorumThresholds\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.QuorumThreshold[]\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]},{\"name\":\"requiredHeaderKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"verificationType\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentEpoch\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentEpochDuration\",\"inputs\":[],\"outputs\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCurrentEpochStart\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getEpochDuration\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getEpochIndex\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getEpochStart\",\"inputs\":[{\"name\":\"epoch\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysProvider\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getKeysProviderAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMaxValidatorsCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMaxValidatorsCountAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMaxVotingPower\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMaxVotingPowerAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMinInclusionVotingPower\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getMinInclusionVotingPowerAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNextEpoch\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNextEpochDuration\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNextEpochStart\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNumAggregators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNumAggregatorsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNumCommitters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNumCommittersAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getQuorumThresholds\",\"inputs\":[],\"outputs\":[{\"name\":\"quorumThresholds\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.QuorumThreshold[]\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getQuorumThresholdsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"quorumThresholds\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.QuorumThreshold[]\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredHeaderKeyTag\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredHeaderKeyTagAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredKeyTags\",\"inputs\":[],\"outputs\":[{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"internalType\":\"uint8[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredKeyTagsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"internalType\":\"uint8[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSettlements\",\"inputs\":[],\"outputs\":[{\"name\":\"settlements\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSettlementsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"settlements\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVerificationType\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVerificationTypeAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotingPowerProviders\",\"inputs\":[],\"outputs\":[{\"name\":\"votingPowerProviders\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotingPowerProvidersAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"votingPowerProviders\",\"type\":\"tuple[]\",\"internalType\":\"structIValSetDriver.CrossChainAddress[]\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isQuorumThresholdRegistered\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isQuorumThresholdRegisteredAt\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSettlementRegistered\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSettlementRegisteredAt\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isVotingPowerProviderRegistered\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isVotingPowerProviderRegisteredAt\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeQuorumThreshold\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeSettlement\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeVotingPowerProvider\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setCommitterSlotDuration\",\"inputs\":[{\"name\":\"slotDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setEpochDuration\",\"inputs\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setKeysProvider\",\"inputs\":[{\"name\":\"keysProvider\",\"type\":\"tuple\",\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxValidatorsCount\",\"inputs\":[{\"name\":\"maxValidatorsCount\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxVotingPower\",\"inputs\":[{\"name\":\"maxVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinInclusionVotingPower\",\"inputs\":[{\"name\":\"minInclusionVotingPower\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNumAggregators\",\"inputs\":[{\"name\":\"numAggregators\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNumCommitters\",\"inputs\":[{\"name\":\"numCommitters\",\"type\":\"uint208\",\"internalType\":\"uint208\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRequiredHeaderKeyTag\",\"inputs\":[{\"name\":\"requiredHeaderKeyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setRequiredKeyTags\",\"inputs\":[{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"internalType\":\"uint8[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setVerificationType\",\"inputs\":[{\"name\":\"verificationType\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"staticDelegateCall\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AddQuorumThreshold\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AddSettlement\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AddVotingPowerProvider\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitEpochDuration\",\"inputs\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"},{\"name\":\"epochDurationTimestamp\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitSubnetwork\",\"inputs\":[{\"name\":\"network\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"subnetworkId\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemoveQuorumThreshold\",\"inputs\":[{\"name\":\"quorumThreshold\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.QuorumThreshold\",\"components\":[{\"name\":\"keyTag\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"quorumThreshold\",\"type\":\"uint248\",\"internalType\":\"uint248\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemoveSettlement\",\"inputs\":[{\"name\":\"settlement\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RemoveVotingPowerProvider\",\"inputs\":[{\"name\":\"votingPowerProvider\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetCommitterSlotDuration\",\"inputs\":[{\"name\":\"committerSlotDuration\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetEpochDuration\",\"inputs\":[{\"name\":\"epochDuration\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetKeysProvider\",\"inputs\":[{\"name\":\"keysProvider\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIValSetDriver.CrossChainAddress\",\"components\":[{\"name\":\"chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"addr\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetMaxValidatorsCount\",\"inputs\":[{\"name\":\"maxValidatorsCount\",\"type\":\"uint208\",\"indexed\":false,\"internalType\":\"uint208\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetMaxVotingPower\",\"inputs\":[{\"name\":\"maxVotingPower\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetMinInclusionVotingPower\",\"inputs\":[{\"name\":\"minInclusionVotingPower\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetNumAggregators\",\"inputs\":[{\"name\":\"numAggregators\",\"type\":\"uint208\",\"indexed\":false,\"internalType\":\"uint208\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetNumCommitters\",\"inputs\":[{\"name\":\"numCommitters\",\"type\":\"uint208\",\"indexed\":false,\"internalType\":\"uint208\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetRequiredHeaderKeyTag\",\"inputs\":[{\"name\":\"requiredHeaderKeyTag\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetRequiredKeyTags\",\"inputs\":[{\"name\":\"requiredKeyTags\",\"type\":\"uint8[]\",\"indexed\":false,\"internalType\":\"uint8[]\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetVerificationType\",\"inputs\":[{\"name\":\"verificationType\",\"type\":\"uint32\",\"indexed\":false,\"internalType\":\"uint32\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"CheckpointUnorderedInsertion\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DuplicateKeyTag\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EpochManager_InvalidEpochDuration\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EpochManager_InvalidEpochDurationTimestamp\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EpochManager_TooOldTimestamp\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidKeyTag\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NetworkManager_InvalidNetwork\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_ChainAlreadyAdded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_InvalidCrossChainAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_InvalidMaxValidatorsCount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_InvalidQuorumThreshold\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_KeyTagAlreadyAdded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_NotAdded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_ZeroCommitterSlotDuration\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_ZeroNumAggregators\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValSetDriver_ZeroNumCommitters\",\"inputs\":[]}]",
}
⋮----
// ValSetDriverABI is the input ABI used to generate the binding from.
// Deprecated: Use ValSetDriverMetaData.ABI instead.
var ValSetDriverABI = ValSetDriverMetaData.ABI
⋮----
// ValSetDriver is an auto generated Go binding around an Ethereum contract.
type ValSetDriver struct {
	ValSetDriverCaller     // Read-only binding to the contract
	ValSetDriverTransactor // Write-only binding to the contract
	ValSetDriverFilterer   // Log filterer for contract events
}
⋮----
ValSetDriverCaller     // Read-only binding to the contract
ValSetDriverTransactor // Write-only binding to the contract
ValSetDriverFilterer   // Log filterer for contract events
⋮----
// ValSetDriverCaller is an auto generated read-only Go binding around an Ethereum contract.
type ValSetDriverCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// ValSetDriverTransactor is an auto generated write-only Go binding around an Ethereum contract.
type ValSetDriverTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// ValSetDriverFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type ValSetDriverFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// ValSetDriverSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type ValSetDriverSession struct {
	Contract     *ValSetDriver     // Generic contract binding to set the session for
	CallOpts     bind.CallOpts     // Call options to use throughout this session
	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
⋮----
Contract     *ValSetDriver     // Generic contract binding to set the session for
CallOpts     bind.CallOpts     // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
⋮----
// ValSetDriverCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type ValSetDriverCallerSession struct {
	Contract *ValSetDriverCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts       // Call options to use throughout this session
}
⋮----
Contract *ValSetDriverCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts       // Call options to use throughout this session
⋮----
// ValSetDriverTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type ValSetDriverTransactorSession struct {
	Contract     *ValSetDriverTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts       // Transaction auth options to use throughout this session
}
⋮----
Contract     *ValSetDriverTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts       // Transaction auth options to use throughout this session
⋮----
// ValSetDriverRaw is an auto generated low-level Go binding around an Ethereum contract.
type ValSetDriverRaw struct {
	Contract *ValSetDriver // Generic contract binding to access the raw methods on
}
⋮----
Contract *ValSetDriver // Generic contract binding to access the raw methods on
⋮----
// ValSetDriverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type ValSetDriverCallerRaw struct {
	Contract *ValSetDriverCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *ValSetDriverCaller // Generic read-only contract binding to access the raw methods on
⋮----
// ValSetDriverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type ValSetDriverTransactorRaw struct {
	Contract *ValSetDriverTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *ValSetDriverTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewValSetDriver creates a new instance of ValSetDriver, bound to a specific deployed contract.
func NewValSetDriver(address common.Address, backend bind.ContractBackend) (*ValSetDriver, error)
⋮----
// NewValSetDriverCaller creates a new read-only instance of ValSetDriver, bound to a specific deployed contract.
func NewValSetDriverCaller(address common.Address, caller bind.ContractCaller) (*ValSetDriverCaller, error)
⋮----
// NewValSetDriverTransactor creates a new write-only instance of ValSetDriver, bound to a specific deployed contract.
func NewValSetDriverTransactor(address common.Address, transactor bind.ContractTransactor) (*ValSetDriverTransactor, error)
⋮----
// NewValSetDriverFilterer creates a new log filterer instance of ValSetDriver, bound to a specific deployed contract.
func NewValSetDriverFilterer(address common.Address, filterer bind.ContractFilterer) (*ValSetDriverFilterer, error)
⋮----
// bindValSetDriver binds a generic wrapper to an already deployed contract.
func bindValSetDriver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_ValSetDriver *ValSetDriverRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_ValSetDriver *ValSetDriverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_ValSetDriver *ValSetDriverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// MAXQUORUMTHRESHOLD is a free data retrieval call binding the contract method 0x127ec283.
//
// Solidity: function MAX_QUORUM_THRESHOLD() view returns(uint248)
func (_ValSetDriver *ValSetDriverCaller) MAXQUORUMTHRESHOLD(opts *bind.CallOpts) (*big.Int, error)
⋮----
var out []interface{}
⋮----
// NETWORK is a free data retrieval call binding the contract method 0x8759e6d1.
⋮----
// Solidity: function NETWORK() view returns(address)
func (_ValSetDriver *ValSetDriverCaller) NETWORK(opts *bind.CallOpts) (common.Address, error)
⋮----
// SUBNETWORK is a free data retrieval call binding the contract method 0x773e6b54.
⋮----
// Solidity: function SUBNETWORK() view returns(bytes32)
func (_ValSetDriver *ValSetDriverCaller) SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
⋮----
// SUBNETWORKIDENTIFIER is a free data retrieval call binding the contract method 0xabacb807.
⋮----
// Solidity: function SUBNETWORK_IDENTIFIER() view returns(uint96)
func (_ValSetDriver *ValSetDriverCaller) SUBNETWORKIDENTIFIER(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCommitterSlotDuration is a free data retrieval call binding the contract method 0xcdad0bb6.
⋮----
// Solidity: function getCommitterSlotDuration() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetCommitterSlotDuration(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCommitterSlotDurationAt is a free data retrieval call binding the contract method 0x490be3bd.
⋮----
// Solidity: function getCommitterSlotDurationAt(uint48 timestamp) view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetCommitterSlotDurationAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetConfig is a free data retrieval call binding the contract method 0xc3f909d4.
⋮----
// Solidity: function getConfig() view returns((uint208,uint208,uint48,(uint64,address)[],(uint64,address),(uint64,address)[],uint256,uint256,uint208,uint8[],(uint8,uint248)[],uint8,uint32))
func (_ValSetDriver *ValSetDriverCaller) GetConfig(opts *bind.CallOpts) (IValSetDriverConfig, error)
⋮----
// GetConfigAt is a free data retrieval call binding the contract method 0x13fb0877.
⋮----
// Solidity: function getConfigAt(uint48 timestamp) view returns((uint208,uint208,uint48,(uint64,address)[],(uint64,address),(uint64,address)[],uint256,uint256,uint208,uint8[],(uint8,uint248)[],uint8,uint32))
func (_ValSetDriver *ValSetDriverCaller) GetConfigAt(opts *bind.CallOpts, timestamp *big.Int) (IValSetDriverConfig, error)
⋮----
// GetCurrentEpoch is a free data retrieval call binding the contract method 0xb97dd9e2.
⋮----
// Solidity: function getCurrentEpoch() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetCurrentEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCurrentEpochDuration is a free data retrieval call binding the contract method 0x558e2eb6.
⋮----
// Solidity: function getCurrentEpochDuration() view returns(uint48 epochDuration)
func (_ValSetDriver *ValSetDriverCaller) GetCurrentEpochDuration(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetCurrentEpochStart is a free data retrieval call binding the contract method 0xa6e16c4d.
⋮----
// Solidity: function getCurrentEpochStart() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetCurrentEpochStart(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetEpochDuration is a free data retrieval call binding the contract method 0xf6fd6f14.
⋮----
// Solidity: function getEpochDuration(uint48 epoch) view returns(uint48 epochDuration)
func (_ValSetDriver *ValSetDriverCaller) GetEpochDuration(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetEpochIndex is a free data retrieval call binding the contract method 0xccafd209.
⋮----
// Solidity: function getEpochIndex(uint48 timestamp) view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetEpochIndex(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetEpochStart is a free data retrieval call binding the contract method 0x246e158f.
⋮----
// Solidity: function getEpochStart(uint48 epoch) view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetEpochStart(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetKeysProvider is a free data retrieval call binding the contract method 0x297d29b8.
⋮----
// Solidity: function getKeysProvider() view returns((uint64,address))
func (_ValSetDriver *ValSetDriverCaller) GetKeysProvider(opts *bind.CallOpts) (IValSetDriverCrossChainAddress, error)
⋮----
// GetKeysProviderAt is a free data retrieval call binding the contract method 0x10a49295.
⋮----
// Solidity: function getKeysProviderAt(uint48 timestamp) view returns((uint64,address))
func (_ValSetDriver *ValSetDriverCaller) GetKeysProviderAt(opts *bind.CallOpts, timestamp *big.Int) (IValSetDriverCrossChainAddress, error)
⋮----
// GetMaxValidatorsCount is a free data retrieval call binding the contract method 0x06ce894d.
⋮----
// Solidity: function getMaxValidatorsCount() view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetMaxValidatorsCount(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetMaxValidatorsCountAt is a free data retrieval call binding the contract method 0x4f938edc.
⋮----
// Solidity: function getMaxValidatorsCountAt(uint48 timestamp) view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetMaxValidatorsCountAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetMaxVotingPower is a free data retrieval call binding the contract method 0x9f9c3080.
⋮----
// Solidity: function getMaxVotingPower() view returns(uint256)
func (_ValSetDriver *ValSetDriverCaller) GetMaxVotingPower(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetMaxVotingPowerAt is a free data retrieval call binding the contract method 0x848b3040.
⋮----
// Solidity: function getMaxVotingPowerAt(uint48 timestamp) view returns(uint256)
func (_ValSetDriver *ValSetDriverCaller) GetMaxVotingPowerAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetMinInclusionVotingPower is a free data retrieval call binding the contract method 0xb6a94695.
⋮----
// Solidity: function getMinInclusionVotingPower() view returns(uint256)
func (_ValSetDriver *ValSetDriverCaller) GetMinInclusionVotingPower(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetMinInclusionVotingPowerAt is a free data retrieval call binding the contract method 0x456705a2.
⋮----
// Solidity: function getMinInclusionVotingPowerAt(uint48 timestamp) view returns(uint256)
func (_ValSetDriver *ValSetDriverCaller) GetMinInclusionVotingPowerAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetNextEpoch is a free data retrieval call binding the contract method 0xefe97d05.
⋮----
// Solidity: function getNextEpoch() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetNextEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetNextEpochDuration is a free data retrieval call binding the contract method 0x038cf1c0.
⋮----
// Solidity: function getNextEpochDuration() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetNextEpochDuration(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetNextEpochStart is a free data retrieval call binding the contract method 0x65c5f94a.
⋮----
// Solidity: function getNextEpochStart() view returns(uint48)
func (_ValSetDriver *ValSetDriverCaller) GetNextEpochStart(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetNumAggregators is a free data retrieval call binding the contract method 0x21fbfe0d.
⋮----
// Solidity: function getNumAggregators() view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetNumAggregators(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetNumAggregatorsAt is a free data retrieval call binding the contract method 0x6bb7e08a.
⋮----
// Solidity: function getNumAggregatorsAt(uint48 timestamp) view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetNumAggregatorsAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetNumCommitters is a free data retrieval call binding the contract method 0x7861db16.
⋮----
// Solidity: function getNumCommitters() view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetNumCommitters(opts *bind.CallOpts) (*big.Int, error)
⋮----
// GetNumCommittersAt is a free data retrieval call binding the contract method 0xe0078c64.
⋮----
// Solidity: function getNumCommittersAt(uint48 timestamp) view returns(uint208)
func (_ValSetDriver *ValSetDriverCaller) GetNumCommittersAt(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error)
⋮----
// GetQuorumThresholds is a free data retrieval call binding the contract method 0x5796148c.
⋮----
// Solidity: function getQuorumThresholds() view returns((uint8,uint248)[] quorumThresholds)
func (_ValSetDriver *ValSetDriverCaller) GetQuorumThresholds(opts *bind.CallOpts) ([]IValSetDriverQuorumThreshold, error)
⋮----
// GetQuorumThresholdsAt is a free data retrieval call binding the contract method 0xf2f46b83.
⋮----
// Solidity: function getQuorumThresholdsAt(uint48 timestamp) view returns((uint8,uint248)[] quorumThresholds)
func (_ValSetDriver *ValSetDriverCaller) GetQuorumThresholdsAt(opts *bind.CallOpts, timestamp *big.Int) ([]IValSetDriverQuorumThreshold, error)
⋮----
// GetRequiredHeaderKeyTag is a free data retrieval call binding the contract method 0x6582e9f7.
⋮----
// Solidity: function getRequiredHeaderKeyTag() view returns(uint8)
func (_ValSetDriver *ValSetDriverCaller) GetRequiredHeaderKeyTag(opts *bind.CallOpts) (uint8, error)
⋮----
// GetRequiredHeaderKeyTagAt is a free data retrieval call binding the contract method 0xbc12e1fd.
⋮----
// Solidity: function getRequiredHeaderKeyTagAt(uint48 timestamp) view returns(uint8)
func (_ValSetDriver *ValSetDriverCaller) GetRequiredHeaderKeyTagAt(opts *bind.CallOpts, timestamp *big.Int) (uint8, error)
⋮----
// GetRequiredKeyTags is a free data retrieval call binding the contract method 0xf9bfa78a.
⋮----
// Solidity: function getRequiredKeyTags() view returns(uint8[] requiredKeyTags)
func (_ValSetDriver *ValSetDriverCaller) GetRequiredKeyTags(opts *bind.CallOpts) ([]uint8, error)
⋮----
// GetRequiredKeyTagsAt is a free data retrieval call binding the contract method 0x1161fc83.
⋮----
// Solidity: function getRequiredKeyTagsAt(uint48 timestamp) view returns(uint8[] requiredKeyTags)
func (_ValSetDriver *ValSetDriverCaller) GetRequiredKeyTagsAt(opts *bind.CallOpts, timestamp *big.Int) ([]uint8, error)
⋮----
// GetSettlements is a free data retrieval call binding the contract method 0xa0c2bc25.
⋮----
// Solidity: function getSettlements() view returns((uint64,address)[] settlements)
func (_ValSetDriver *ValSetDriverCaller) GetSettlements(opts *bind.CallOpts) ([]IValSetDriverCrossChainAddress, error)
⋮----
// GetSettlementsAt is a free data retrieval call binding the contract method 0x763d255a.
⋮----
// Solidity: function getSettlementsAt(uint48 timestamp) view returns((uint64,address)[] settlements)
func (_ValSetDriver *ValSetDriverCaller) GetSettlementsAt(opts *bind.CallOpts, timestamp *big.Int) ([]IValSetDriverCrossChainAddress, error)
⋮----
// GetVerificationType is a free data retrieval call binding the contract method 0x24acc119.
⋮----
// Solidity: function getVerificationType() view returns(uint32)
func (_ValSetDriver *ValSetDriverCaller) GetVerificationType(opts *bind.CallOpts) (uint32, error)
⋮----
// GetVerificationTypeAt is a free data retrieval call binding the contract method 0x3a0ad9ec.
⋮----
// Solidity: function getVerificationTypeAt(uint48 timestamp) view returns(uint32)
func (_ValSetDriver *ValSetDriverCaller) GetVerificationTypeAt(opts *bind.CallOpts, timestamp *big.Int) (uint32, error)
⋮----
// GetVotingPowerProviders is a free data retrieval call binding the contract method 0x3e39b8db.
⋮----
// Solidity: function getVotingPowerProviders() view returns((uint64,address)[] votingPowerProviders)
func (_ValSetDriver *ValSetDriverCaller) GetVotingPowerProviders(opts *bind.CallOpts) ([]IValSetDriverCrossChainAddress, error)
⋮----
// GetVotingPowerProvidersAt is a free data retrieval call binding the contract method 0x09bba5ca.
⋮----
// Solidity: function getVotingPowerProvidersAt(uint48 timestamp) view returns((uint64,address)[] votingPowerProviders)
func (_ValSetDriver *ValSetDriverCaller) GetVotingPowerProvidersAt(opts *bind.CallOpts, timestamp *big.Int) ([]IValSetDriverCrossChainAddress, error)
⋮----
// IsQuorumThresholdRegistered is a free data retrieval call binding the contract method 0x79a4c359.
⋮----
// Solidity: function isQuorumThresholdRegistered((uint8,uint248) quorumThreshold) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsQuorumThresholdRegistered(opts *bind.CallOpts, quorumThreshold IValSetDriverQuorumThreshold) (bool, error)
⋮----
// IsQuorumThresholdRegisteredAt is a free data retrieval call binding the contract method 0x80c2fc48.
⋮----
// Solidity: function isQuorumThresholdRegisteredAt((uint8,uint248) quorumThreshold, uint48 timestamp) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsQuorumThresholdRegisteredAt(opts *bind.CallOpts, quorumThreshold IValSetDriverQuorumThreshold, timestamp *big.Int) (bool, error)
⋮----
// IsSettlementRegistered is a free data retrieval call binding the contract method 0x965c0768.
⋮----
// Solidity: function isSettlementRegistered((uint64,address) settlement) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsSettlementRegistered(opts *bind.CallOpts, settlement IValSetDriverCrossChainAddress) (bool, error)
⋮----
// IsSettlementRegisteredAt is a free data retrieval call binding the contract method 0x01749b26.
⋮----
// Solidity: function isSettlementRegisteredAt((uint64,address) settlement, uint48 timestamp) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsSettlementRegisteredAt(opts *bind.CallOpts, settlement IValSetDriverCrossChainAddress, timestamp *big.Int) (bool, error)
⋮----
// IsVotingPowerProviderRegistered is a free data retrieval call binding the contract method 0x1265b3be.
⋮----
// Solidity: function isVotingPowerProviderRegistered((uint64,address) votingPowerProvider) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsVotingPowerProviderRegistered(opts *bind.CallOpts, votingPowerProvider IValSetDriverCrossChainAddress) (bool, error)
⋮----
// IsVotingPowerProviderRegisteredAt is a free data retrieval call binding the contract method 0xc16ccb73.
⋮----
// Solidity: function isVotingPowerProviderRegisteredAt((uint64,address) votingPowerProvider, uint48 timestamp) view returns(bool)
func (_ValSetDriver *ValSetDriverCaller) IsVotingPowerProviderRegisteredAt(opts *bind.CallOpts, votingPowerProvider IValSetDriverCrossChainAddress, timestamp *big.Int) (bool, error)
⋮----
// AddQuorumThreshold is a paid mutator transaction binding the contract method 0x0fe5e0c2.
⋮----
// Solidity: function addQuorumThreshold((uint8,uint248) quorumThreshold) returns()
func (_ValSetDriver *ValSetDriverTransactor) AddQuorumThreshold(opts *bind.TransactOpts, quorumThreshold IValSetDriverQuorumThreshold) (*types.Transaction, error)
⋮----
// AddSettlement is a paid mutator transaction binding the contract method 0x52ab8872.
⋮----
// Solidity: function addSettlement((uint64,address) settlement) returns()
func (_ValSetDriver *ValSetDriverTransactor) AddSettlement(opts *bind.TransactOpts, settlement IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// AddVotingPowerProvider is a paid mutator transaction binding the contract method 0x6940ed80.
⋮----
// Solidity: function addVotingPowerProvider((uint64,address) votingPowerProvider) returns()
func (_ValSetDriver *ValSetDriverTransactor) AddVotingPowerProvider(opts *bind.TransactOpts, votingPowerProvider IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// Multicall is a paid mutator transaction binding the contract method 0xac9650d8.
⋮----
// Solidity: function multicall(bytes[] data) returns(bytes[] results)
func (_ValSetDriver *ValSetDriverTransactor) Multicall(opts *bind.TransactOpts, data [][]byte) (*types.Transaction, error)
⋮----
// RemoveQuorumThreshold is a paid mutator transaction binding the contract method 0xf388db18.
⋮----
// Solidity: function removeQuorumThreshold((uint8,uint248) quorumThreshold) returns()
func (_ValSetDriver *ValSetDriverTransactor) RemoveQuorumThreshold(opts *bind.TransactOpts, quorumThreshold IValSetDriverQuorumThreshold) (*types.Transaction, error)
⋮----
// RemoveSettlement is a paid mutator transaction binding the contract method 0x502bb1ad.
⋮----
// Solidity: function removeSettlement((uint64,address) settlement) returns()
func (_ValSetDriver *ValSetDriverTransactor) RemoveSettlement(opts *bind.TransactOpts, settlement IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// RemoveVotingPowerProvider is a paid mutator transaction binding the contract method 0x325234d5.
⋮----
// Solidity: function removeVotingPowerProvider((uint64,address) votingPowerProvider) returns()
func (_ValSetDriver *ValSetDriverTransactor) RemoveVotingPowerProvider(opts *bind.TransactOpts, votingPowerProvider IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// SetCommitterSlotDuration is a paid mutator transaction binding the contract method 0xf86b8fa1.
⋮----
// Solidity: function setCommitterSlotDuration(uint48 slotDuration) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetCommitterSlotDuration(opts *bind.TransactOpts, slotDuration *big.Int) (*types.Transaction, error)
⋮----
// SetEpochDuration is a paid mutator transaction binding the contract method 0x2f53d5ff.
⋮----
// Solidity: function setEpochDuration(uint48 epochDuration) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetEpochDuration(opts *bind.TransactOpts, epochDuration *big.Int) (*types.Transaction, error)
⋮----
// SetKeysProvider is a paid mutator transaction binding the contract method 0xdd08bbff.
⋮----
// Solidity: function setKeysProvider((uint64,address) keysProvider) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetKeysProvider(opts *bind.TransactOpts, keysProvider IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// SetMaxValidatorsCount is a paid mutator transaction binding the contract method 0xd2384cd3.
⋮----
// Solidity: function setMaxValidatorsCount(uint208 maxValidatorsCount) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetMaxValidatorsCount(opts *bind.TransactOpts, maxValidatorsCount *big.Int) (*types.Transaction, error)
⋮----
// SetMaxVotingPower is a paid mutator transaction binding the contract method 0xf6af258c.
⋮----
// Solidity: function setMaxVotingPower(uint256 maxVotingPower) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetMaxVotingPower(opts *bind.TransactOpts, maxVotingPower *big.Int) (*types.Transaction, error)
⋮----
// SetMinInclusionVotingPower is a paid mutator transaction binding the contract method 0xfaae42d7.
⋮----
// Solidity: function setMinInclusionVotingPower(uint256 minInclusionVotingPower) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetMinInclusionVotingPower(opts *bind.TransactOpts, minInclusionVotingPower *big.Int) (*types.Transaction, error)
⋮----
// SetNumAggregators is a paid mutator transaction binding the contract method 0x0dec288b.
⋮----
// Solidity: function setNumAggregators(uint208 numAggregators) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetNumAggregators(opts *bind.TransactOpts, numAggregators *big.Int) (*types.Transaction, error)
⋮----
// SetNumCommitters is a paid mutator transaction binding the contract method 0x15ddbbe8.
⋮----
// Solidity: function setNumCommitters(uint208 numCommitters) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetNumCommitters(opts *bind.TransactOpts, numCommitters *big.Int) (*types.Transaction, error)
⋮----
// SetRequiredHeaderKeyTag is a paid mutator transaction binding the contract method 0xd9736e12.
⋮----
// Solidity: function setRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetRequiredHeaderKeyTag(opts *bind.TransactOpts, requiredHeaderKeyTag uint8) (*types.Transaction, error)
⋮----
// SetRequiredKeyTags is a paid mutator transaction binding the contract method 0x4678a284.
⋮----
// Solidity: function setRequiredKeyTags(uint8[] requiredKeyTags) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetRequiredKeyTags(opts *bind.TransactOpts, requiredKeyTags []uint8) (*types.Transaction, error)
⋮----
// SetVerificationType is a paid mutator transaction binding the contract method 0x7b8ef42d.
⋮----
// Solidity: function setVerificationType(uint32 verificationType) returns()
func (_ValSetDriver *ValSetDriverTransactor) SetVerificationType(opts *bind.TransactOpts, verificationType uint32) (*types.Transaction, error)
⋮----
// StaticDelegateCall is a paid mutator transaction binding the contract method 0x9f86fd85.
⋮----
// Solidity: function staticDelegateCall(address target, bytes data) returns()
func (_ValSetDriver *ValSetDriverTransactor) StaticDelegateCall(opts *bind.TransactOpts, target common.Address, data []byte) (*types.Transaction, error)
⋮----
// ValSetDriverAddQuorumThresholdIterator is returned from FilterAddQuorumThreshold and is used to iterate over the raw logs and unpacked data for AddQuorumThreshold events raised by the ValSetDriver contract.
type ValSetDriverAddQuorumThresholdIterator struct {
	Event *ValSetDriverAddQuorumThreshold // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverAddQuorumThreshold // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *ValSetDriverAddQuorumThresholdIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *ValSetDriverAddQuorumThresholdIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *ValSetDriverAddQuorumThresholdIterator) Close() error
⋮----
// ValSetDriverAddQuorumThreshold represents a AddQuorumThreshold event raised by the ValSetDriver contract.
type ValSetDriverAddQuorumThreshold struct {
	QuorumThreshold IValSetDriverQuorumThreshold
	Raw             types.Log // Blockchain specific contextual infos
}
⋮----
Raw             types.Log // Blockchain specific contextual infos
⋮----
// FilterAddQuorumThreshold is a free log retrieval operation binding the contract event 0x88ee37bfc079201d8493557f757c8ff6b14222ae13a8393747fb3c74b8ddf06f.
⋮----
// Solidity: event AddQuorumThreshold((uint8,uint248) quorumThreshold)
func (_ValSetDriver *ValSetDriverFilterer) FilterAddQuorumThreshold(opts *bind.FilterOpts) (*ValSetDriverAddQuorumThresholdIterator, error)
⋮----
// WatchAddQuorumThreshold is a free log subscription operation binding the contract event 0x88ee37bfc079201d8493557f757c8ff6b14222ae13a8393747fb3c74b8ddf06f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchAddQuorumThreshold(opts *bind.WatchOpts, sink chan<- *ValSetDriverAddQuorumThreshold) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseAddQuorumThreshold is a log parse operation binding the contract event 0x88ee37bfc079201d8493557f757c8ff6b14222ae13a8393747fb3c74b8ddf06f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseAddQuorumThreshold(log types.Log) (*ValSetDriverAddQuorumThreshold, error)
⋮----
// ValSetDriverAddSettlementIterator is returned from FilterAddSettlement and is used to iterate over the raw logs and unpacked data for AddSettlement events raised by the ValSetDriver contract.
type ValSetDriverAddSettlementIterator struct {
	Event *ValSetDriverAddSettlement // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverAddSettlement // Event containing the contract specifics and raw log
⋮----
// ValSetDriverAddSettlement represents a AddSettlement event raised by the ValSetDriver contract.
type ValSetDriverAddSettlement struct {
	Settlement IValSetDriverCrossChainAddress
	Raw        types.Log // Blockchain specific contextual infos
}
⋮----
Raw        types.Log // Blockchain specific contextual infos
⋮----
// FilterAddSettlement is a free log retrieval operation binding the contract event 0xd66c27144960b789ff7b5514538e3d85a3623c1669b8d6db4eb85658df2aad57.
⋮----
// Solidity: event AddSettlement((uint64,address) settlement)
func (_ValSetDriver *ValSetDriverFilterer) FilterAddSettlement(opts *bind.FilterOpts) (*ValSetDriverAddSettlementIterator, error)
⋮----
// WatchAddSettlement is a free log subscription operation binding the contract event 0xd66c27144960b789ff7b5514538e3d85a3623c1669b8d6db4eb85658df2aad57.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchAddSettlement(opts *bind.WatchOpts, sink chan<- *ValSetDriverAddSettlement) (event.Subscription, error)
⋮----
// ParseAddSettlement is a log parse operation binding the contract event 0xd66c27144960b789ff7b5514538e3d85a3623c1669b8d6db4eb85658df2aad57.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseAddSettlement(log types.Log) (*ValSetDriverAddSettlement, error)
⋮----
// ValSetDriverAddVotingPowerProviderIterator is returned from FilterAddVotingPowerProvider and is used to iterate over the raw logs and unpacked data for AddVotingPowerProvider events raised by the ValSetDriver contract.
type ValSetDriverAddVotingPowerProviderIterator struct {
	Event *ValSetDriverAddVotingPowerProvider // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverAddVotingPowerProvider // Event containing the contract specifics and raw log
⋮----
// ValSetDriverAddVotingPowerProvider represents a AddVotingPowerProvider event raised by the ValSetDriver contract.
type ValSetDriverAddVotingPowerProvider struct {
	VotingPowerProvider IValSetDriverCrossChainAddress
	Raw                 types.Log // Blockchain specific contextual infos
}
⋮----
Raw                 types.Log // Blockchain specific contextual infos
⋮----
// FilterAddVotingPowerProvider is a free log retrieval operation binding the contract event 0xa8ba28fa43d2ebdcd4f5c29ee4f5e5fb568e9986ae8be7c6ae54540176d6147f.
⋮----
// Solidity: event AddVotingPowerProvider((uint64,address) votingPowerProvider)
func (_ValSetDriver *ValSetDriverFilterer) FilterAddVotingPowerProvider(opts *bind.FilterOpts) (*ValSetDriverAddVotingPowerProviderIterator, error)
⋮----
// WatchAddVotingPowerProvider is a free log subscription operation binding the contract event 0xa8ba28fa43d2ebdcd4f5c29ee4f5e5fb568e9986ae8be7c6ae54540176d6147f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchAddVotingPowerProvider(opts *bind.WatchOpts, sink chan<- *ValSetDriverAddVotingPowerProvider) (event.Subscription, error)
⋮----
// ParseAddVotingPowerProvider is a log parse operation binding the contract event 0xa8ba28fa43d2ebdcd4f5c29ee4f5e5fb568e9986ae8be7c6ae54540176d6147f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseAddVotingPowerProvider(log types.Log) (*ValSetDriverAddVotingPowerProvider, error)
⋮----
// ValSetDriverInitEpochDurationIterator is returned from FilterInitEpochDuration and is used to iterate over the raw logs and unpacked data for InitEpochDuration events raised by the ValSetDriver contract.
type ValSetDriverInitEpochDurationIterator struct {
	Event *ValSetDriverInitEpochDuration // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverInitEpochDuration // Event containing the contract specifics and raw log
⋮----
// ValSetDriverInitEpochDuration represents a InitEpochDuration event raised by the ValSetDriver contract.
type ValSetDriverInitEpochDuration struct {
	EpochDuration          *big.Int
	EpochDurationTimestamp *big.Int
	Raw                    types.Log // Blockchain specific contextual infos
}
⋮----
Raw                    types.Log // Blockchain specific contextual infos
⋮----
// FilterInitEpochDuration is a free log retrieval operation binding the contract event 0xf688b7b02a20c2dda7d7de03a41637b274af7706eb975ea4af45858648370f55.
⋮----
// Solidity: event InitEpochDuration(uint48 epochDuration, uint48 epochDurationTimestamp)
func (_ValSetDriver *ValSetDriverFilterer) FilterInitEpochDuration(opts *bind.FilterOpts) (*ValSetDriverInitEpochDurationIterator, error)
⋮----
// WatchInitEpochDuration is a free log subscription operation binding the contract event 0xf688b7b02a20c2dda7d7de03a41637b274af7706eb975ea4af45858648370f55.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchInitEpochDuration(opts *bind.WatchOpts, sink chan<- *ValSetDriverInitEpochDuration) (event.Subscription, error)
⋮----
// ParseInitEpochDuration is a log parse operation binding the contract event 0xf688b7b02a20c2dda7d7de03a41637b274af7706eb975ea4af45858648370f55.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseInitEpochDuration(log types.Log) (*ValSetDriverInitEpochDuration, error)
⋮----
// ValSetDriverInitSubnetworkIterator is returned from FilterInitSubnetwork and is used to iterate over the raw logs and unpacked data for InitSubnetwork events raised by the ValSetDriver contract.
type ValSetDriverInitSubnetworkIterator struct {
	Event *ValSetDriverInitSubnetwork // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverInitSubnetwork // Event containing the contract specifics and raw log
⋮----
// ValSetDriverInitSubnetwork represents a InitSubnetwork event raised by the ValSetDriver contract.
type ValSetDriverInitSubnetwork struct {
	Network      common.Address
	SubnetworkId *big.Int
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
Raw          types.Log // Blockchain specific contextual infos
⋮----
// FilterInitSubnetwork is a free log retrieval operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
// Solidity: event InitSubnetwork(address network, uint96 subnetworkId)
func (_ValSetDriver *ValSetDriverFilterer) FilterInitSubnetwork(opts *bind.FilterOpts) (*ValSetDriverInitSubnetworkIterator, error)
⋮----
// WatchInitSubnetwork is a free log subscription operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchInitSubnetwork(opts *bind.WatchOpts, sink chan<- *ValSetDriverInitSubnetwork) (event.Subscription, error)
⋮----
// ParseInitSubnetwork is a log parse operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseInitSubnetwork(log types.Log) (*ValSetDriverInitSubnetwork, error)
⋮----
// ValSetDriverInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the ValSetDriver contract.
type ValSetDriverInitializedIterator struct {
	Event *ValSetDriverInitialized // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverInitialized // Event containing the contract specifics and raw log
⋮----
// ValSetDriverInitialized represents a Initialized event raised by the ValSetDriver contract.
type ValSetDriverInitialized struct {
	Version uint64
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
// Solidity: event Initialized(uint64 version)
func (_ValSetDriver *ValSetDriverFilterer) FilterInitialized(opts *bind.FilterOpts) (*ValSetDriverInitializedIterator, error)
⋮----
// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *ValSetDriverInitialized) (event.Subscription, error)
⋮----
// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseInitialized(log types.Log) (*ValSetDriverInitialized, error)
⋮----
// ValSetDriverRemoveQuorumThresholdIterator is returned from FilterRemoveQuorumThreshold and is used to iterate over the raw logs and unpacked data for RemoveQuorumThreshold events raised by the ValSetDriver contract.
type ValSetDriverRemoveQuorumThresholdIterator struct {
	Event *ValSetDriverRemoveQuorumThreshold // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverRemoveQuorumThreshold // Event containing the contract specifics and raw log
⋮----
// ValSetDriverRemoveQuorumThreshold represents a RemoveQuorumThreshold event raised by the ValSetDriver contract.
type ValSetDriverRemoveQuorumThreshold struct {
	QuorumThreshold IValSetDriverQuorumThreshold
	Raw             types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRemoveQuorumThreshold is a free log retrieval operation binding the contract event 0xb321a5a0425badf1acf0a0b21b7984fa61e1e6405ae9011d4dcdb29b0e2f43ec.
⋮----
// Solidity: event RemoveQuorumThreshold((uint8,uint248) quorumThreshold)
func (_ValSetDriver *ValSetDriverFilterer) FilterRemoveQuorumThreshold(opts *bind.FilterOpts) (*ValSetDriverRemoveQuorumThresholdIterator, error)
⋮----
// WatchRemoveQuorumThreshold is a free log subscription operation binding the contract event 0xb321a5a0425badf1acf0a0b21b7984fa61e1e6405ae9011d4dcdb29b0e2f43ec.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchRemoveQuorumThreshold(opts *bind.WatchOpts, sink chan<- *ValSetDriverRemoveQuorumThreshold) (event.Subscription, error)
⋮----
// ParseRemoveQuorumThreshold is a log parse operation binding the contract event 0xb321a5a0425badf1acf0a0b21b7984fa61e1e6405ae9011d4dcdb29b0e2f43ec.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseRemoveQuorumThreshold(log types.Log) (*ValSetDriverRemoveQuorumThreshold, error)
⋮----
// ValSetDriverRemoveSettlementIterator is returned from FilterRemoveSettlement and is used to iterate over the raw logs and unpacked data for RemoveSettlement events raised by the ValSetDriver contract.
type ValSetDriverRemoveSettlementIterator struct {
	Event *ValSetDriverRemoveSettlement // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverRemoveSettlement // Event containing the contract specifics and raw log
⋮----
// ValSetDriverRemoveSettlement represents a RemoveSettlement event raised by the ValSetDriver contract.
type ValSetDriverRemoveSettlement struct {
	Settlement IValSetDriverCrossChainAddress
	Raw        types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRemoveSettlement is a free log retrieval operation binding the contract event 0x6307047e2a245d2a5867f7667a4a48687593b73e3b2f95d2204256cbff350cf3.
⋮----
// Solidity: event RemoveSettlement((uint64,address) settlement)
func (_ValSetDriver *ValSetDriverFilterer) FilterRemoveSettlement(opts *bind.FilterOpts) (*ValSetDriverRemoveSettlementIterator, error)
⋮----
// WatchRemoveSettlement is a free log subscription operation binding the contract event 0x6307047e2a245d2a5867f7667a4a48687593b73e3b2f95d2204256cbff350cf3.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchRemoveSettlement(opts *bind.WatchOpts, sink chan<- *ValSetDriverRemoveSettlement) (event.Subscription, error)
⋮----
// ParseRemoveSettlement is a log parse operation binding the contract event 0x6307047e2a245d2a5867f7667a4a48687593b73e3b2f95d2204256cbff350cf3.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseRemoveSettlement(log types.Log) (*ValSetDriverRemoveSettlement, error)
⋮----
// ValSetDriverRemoveVotingPowerProviderIterator is returned from FilterRemoveVotingPowerProvider and is used to iterate over the raw logs and unpacked data for RemoveVotingPowerProvider events raised by the ValSetDriver contract.
type ValSetDriverRemoveVotingPowerProviderIterator struct {
	Event *ValSetDriverRemoveVotingPowerProvider // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverRemoveVotingPowerProvider // Event containing the contract specifics and raw log
⋮----
// ValSetDriverRemoveVotingPowerProvider represents a RemoveVotingPowerProvider event raised by the ValSetDriver contract.
type ValSetDriverRemoveVotingPowerProvider struct {
	VotingPowerProvider IValSetDriverCrossChainAddress
	Raw                 types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRemoveVotingPowerProvider is a free log retrieval operation binding the contract event 0x2a2103a52b9c3907936be3fea265a7bd34fdfc0c8c09cc3b8e3938b7deda761f.
⋮----
// Solidity: event RemoveVotingPowerProvider((uint64,address) votingPowerProvider)
func (_ValSetDriver *ValSetDriverFilterer) FilterRemoveVotingPowerProvider(opts *bind.FilterOpts) (*ValSetDriverRemoveVotingPowerProviderIterator, error)
⋮----
// WatchRemoveVotingPowerProvider is a free log subscription operation binding the contract event 0x2a2103a52b9c3907936be3fea265a7bd34fdfc0c8c09cc3b8e3938b7deda761f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchRemoveVotingPowerProvider(opts *bind.WatchOpts, sink chan<- *ValSetDriverRemoveVotingPowerProvider) (event.Subscription, error)
⋮----
// ParseRemoveVotingPowerProvider is a log parse operation binding the contract event 0x2a2103a52b9c3907936be3fea265a7bd34fdfc0c8c09cc3b8e3938b7deda761f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseRemoveVotingPowerProvider(log types.Log) (*ValSetDriverRemoveVotingPowerProvider, error)
⋮----
// ValSetDriverSetCommitterSlotDurationIterator is returned from FilterSetCommitterSlotDuration and is used to iterate over the raw logs and unpacked data for SetCommitterSlotDuration events raised by the ValSetDriver contract.
type ValSetDriverSetCommitterSlotDurationIterator struct {
	Event *ValSetDriverSetCommitterSlotDuration // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetCommitterSlotDuration // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetCommitterSlotDuration represents a SetCommitterSlotDuration event raised by the ValSetDriver contract.
type ValSetDriverSetCommitterSlotDuration struct {
	CommitterSlotDuration *big.Int
	Raw                   types.Log // Blockchain specific contextual infos
}
⋮----
Raw                   types.Log // Blockchain specific contextual infos
⋮----
// FilterSetCommitterSlotDuration is a free log retrieval operation binding the contract event 0x853ac7224393856467cf1f4981ef9fa5d586d71783e6f66221f7af0a987f7d51.
⋮----
// Solidity: event SetCommitterSlotDuration(uint48 committerSlotDuration)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetCommitterSlotDuration(opts *bind.FilterOpts) (*ValSetDriverSetCommitterSlotDurationIterator, error)
⋮----
// WatchSetCommitterSlotDuration is a free log subscription operation binding the contract event 0x853ac7224393856467cf1f4981ef9fa5d586d71783e6f66221f7af0a987f7d51.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetCommitterSlotDuration(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetCommitterSlotDuration) (event.Subscription, error)
⋮----
// ParseSetCommitterSlotDuration is a log parse operation binding the contract event 0x853ac7224393856467cf1f4981ef9fa5d586d71783e6f66221f7af0a987f7d51.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetCommitterSlotDuration(log types.Log) (*ValSetDriverSetCommitterSlotDuration, error)
⋮----
// ValSetDriverSetEpochDurationIterator is returned from FilterSetEpochDuration and is used to iterate over the raw logs and unpacked data for SetEpochDuration events raised by the ValSetDriver contract.
type ValSetDriverSetEpochDurationIterator struct {
	Event *ValSetDriverSetEpochDuration // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetEpochDuration // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetEpochDuration represents a SetEpochDuration event raised by the ValSetDriver contract.
type ValSetDriverSetEpochDuration struct {
	EpochDuration *big.Int
	Raw           types.Log // Blockchain specific contextual infos
}
⋮----
Raw           types.Log // Blockchain specific contextual infos
⋮----
// FilterSetEpochDuration is a free log retrieval operation binding the contract event 0xc950f06b73b224f8b32d39245a5905020aebfc426a15833a70ac2e4e2ebe098c.
⋮----
// Solidity: event SetEpochDuration(uint48 epochDuration)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetEpochDuration(opts *bind.FilterOpts) (*ValSetDriverSetEpochDurationIterator, error)
⋮----
// WatchSetEpochDuration is a free log subscription operation binding the contract event 0xc950f06b73b224f8b32d39245a5905020aebfc426a15833a70ac2e4e2ebe098c.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetEpochDuration(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetEpochDuration) (event.Subscription, error)
⋮----
// ParseSetEpochDuration is a log parse operation binding the contract event 0xc950f06b73b224f8b32d39245a5905020aebfc426a15833a70ac2e4e2ebe098c.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetEpochDuration(log types.Log) (*ValSetDriverSetEpochDuration, error)
⋮----
// ValSetDriverSetKeysProviderIterator is returned from FilterSetKeysProvider and is used to iterate over the raw logs and unpacked data for SetKeysProvider events raised by the ValSetDriver contract.
type ValSetDriverSetKeysProviderIterator struct {
	Event *ValSetDriverSetKeysProvider // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetKeysProvider // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetKeysProvider represents a SetKeysProvider event raised by the ValSetDriver contract.
type ValSetDriverSetKeysProvider struct {
	KeysProvider IValSetDriverCrossChainAddress
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetKeysProvider is a free log retrieval operation binding the contract event 0x15ceb492f5dd0988720d5f2258f4de98a2ac5df85b25ed2f33eda91e90e07321.
⋮----
// Solidity: event SetKeysProvider((uint64,address) keysProvider)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetKeysProvider(opts *bind.FilterOpts) (*ValSetDriverSetKeysProviderIterator, error)
⋮----
// WatchSetKeysProvider is a free log subscription operation binding the contract event 0x15ceb492f5dd0988720d5f2258f4de98a2ac5df85b25ed2f33eda91e90e07321.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetKeysProvider(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetKeysProvider) (event.Subscription, error)
⋮----
// ParseSetKeysProvider is a log parse operation binding the contract event 0x15ceb492f5dd0988720d5f2258f4de98a2ac5df85b25ed2f33eda91e90e07321.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetKeysProvider(log types.Log) (*ValSetDriverSetKeysProvider, error)
⋮----
// ValSetDriverSetMaxValidatorsCountIterator is returned from FilterSetMaxValidatorsCount and is used to iterate over the raw logs and unpacked data for SetMaxValidatorsCount events raised by the ValSetDriver contract.
type ValSetDriverSetMaxValidatorsCountIterator struct {
	Event *ValSetDriverSetMaxValidatorsCount // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetMaxValidatorsCount // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetMaxValidatorsCount represents a SetMaxValidatorsCount event raised by the ValSetDriver contract.
type ValSetDriverSetMaxValidatorsCount struct {
	MaxValidatorsCount *big.Int
	Raw                types.Log // Blockchain specific contextual infos
}
⋮----
Raw                types.Log // Blockchain specific contextual infos
⋮----
// FilterSetMaxValidatorsCount is a free log retrieval operation binding the contract event 0x37ca3532b507cfa33b11765ae8b499cb6830421b982a7f8837ee71ca5a3119c8.
⋮----
// Solidity: event SetMaxValidatorsCount(uint208 maxValidatorsCount)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetMaxValidatorsCount(opts *bind.FilterOpts) (*ValSetDriverSetMaxValidatorsCountIterator, error)
⋮----
// WatchSetMaxValidatorsCount is a free log subscription operation binding the contract event 0x37ca3532b507cfa33b11765ae8b499cb6830421b982a7f8837ee71ca5a3119c8.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetMaxValidatorsCount(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetMaxValidatorsCount) (event.Subscription, error)
⋮----
// ParseSetMaxValidatorsCount is a log parse operation binding the contract event 0x37ca3532b507cfa33b11765ae8b499cb6830421b982a7f8837ee71ca5a3119c8.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetMaxValidatorsCount(log types.Log) (*ValSetDriverSetMaxValidatorsCount, error)
⋮----
// ValSetDriverSetMaxVotingPowerIterator is returned from FilterSetMaxVotingPower and is used to iterate over the raw logs and unpacked data for SetMaxVotingPower events raised by the ValSetDriver contract.
type ValSetDriverSetMaxVotingPowerIterator struct {
	Event *ValSetDriverSetMaxVotingPower // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetMaxVotingPower // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetMaxVotingPower represents a SetMaxVotingPower event raised by the ValSetDriver contract.
type ValSetDriverSetMaxVotingPower struct {
	MaxVotingPower *big.Int
	Raw            types.Log // Blockchain specific contextual infos
}
⋮----
Raw            types.Log // Blockchain specific contextual infos
⋮----
// FilterSetMaxVotingPower is a free log retrieval operation binding the contract event 0xe891886eac9e583940fb0844098689693a4d105206ec1f789d119b4314383b95.
⋮----
// Solidity: event SetMaxVotingPower(uint256 maxVotingPower)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetMaxVotingPower(opts *bind.FilterOpts) (*ValSetDriverSetMaxVotingPowerIterator, error)
⋮----
// WatchSetMaxVotingPower is a free log subscription operation binding the contract event 0xe891886eac9e583940fb0844098689693a4d105206ec1f789d119b4314383b95.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetMaxVotingPower(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetMaxVotingPower) (event.Subscription, error)
⋮----
// ParseSetMaxVotingPower is a log parse operation binding the contract event 0xe891886eac9e583940fb0844098689693a4d105206ec1f789d119b4314383b95.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetMaxVotingPower(log types.Log) (*ValSetDriverSetMaxVotingPower, error)
⋮----
// ValSetDriverSetMinInclusionVotingPowerIterator is returned from FilterSetMinInclusionVotingPower and is used to iterate over the raw logs and unpacked data for SetMinInclusionVotingPower events raised by the ValSetDriver contract.
type ValSetDriverSetMinInclusionVotingPowerIterator struct {
	Event *ValSetDriverSetMinInclusionVotingPower // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetMinInclusionVotingPower // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetMinInclusionVotingPower represents a SetMinInclusionVotingPower event raised by the ValSetDriver contract.
type ValSetDriverSetMinInclusionVotingPower struct {
	MinInclusionVotingPower *big.Int
	Raw                     types.Log // Blockchain specific contextual infos
}
⋮----
Raw                     types.Log // Blockchain specific contextual infos
⋮----
// FilterSetMinInclusionVotingPower is a free log retrieval operation binding the contract event 0x7ea1f11872caff0567f050bd06f29f128a1407e56e3272abbadef87f6cbb6188.
⋮----
// Solidity: event SetMinInclusionVotingPower(uint256 minInclusionVotingPower)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetMinInclusionVotingPower(opts *bind.FilterOpts) (*ValSetDriverSetMinInclusionVotingPowerIterator, error)
⋮----
// WatchSetMinInclusionVotingPower is a free log subscription operation binding the contract event 0x7ea1f11872caff0567f050bd06f29f128a1407e56e3272abbadef87f6cbb6188.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetMinInclusionVotingPower(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetMinInclusionVotingPower) (event.Subscription, error)
⋮----
// ParseSetMinInclusionVotingPower is a log parse operation binding the contract event 0x7ea1f11872caff0567f050bd06f29f128a1407e56e3272abbadef87f6cbb6188.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetMinInclusionVotingPower(log types.Log) (*ValSetDriverSetMinInclusionVotingPower, error)
⋮----
// ValSetDriverSetNumAggregatorsIterator is returned from FilterSetNumAggregators and is used to iterate over the raw logs and unpacked data for SetNumAggregators events raised by the ValSetDriver contract.
type ValSetDriverSetNumAggregatorsIterator struct {
	Event *ValSetDriverSetNumAggregators // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetNumAggregators // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetNumAggregators represents a SetNumAggregators event raised by the ValSetDriver contract.
type ValSetDriverSetNumAggregators struct {
	NumAggregators *big.Int
	Raw            types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetNumAggregators is a free log retrieval operation binding the contract event 0xa47e6808a463c6134cf3bb23d54ee0ccb5c8056ab8c8b5fd5277fc83cc2f25f3.
⋮----
// Solidity: event SetNumAggregators(uint208 numAggregators)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetNumAggregators(opts *bind.FilterOpts) (*ValSetDriverSetNumAggregatorsIterator, error)
⋮----
// WatchSetNumAggregators is a free log subscription operation binding the contract event 0xa47e6808a463c6134cf3bb23d54ee0ccb5c8056ab8c8b5fd5277fc83cc2f25f3.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetNumAggregators(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetNumAggregators) (event.Subscription, error)
⋮----
// ParseSetNumAggregators is a log parse operation binding the contract event 0xa47e6808a463c6134cf3bb23d54ee0ccb5c8056ab8c8b5fd5277fc83cc2f25f3.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetNumAggregators(log types.Log) (*ValSetDriverSetNumAggregators, error)
⋮----
// ValSetDriverSetNumCommittersIterator is returned from FilterSetNumCommitters and is used to iterate over the raw logs and unpacked data for SetNumCommitters events raised by the ValSetDriver contract.
type ValSetDriverSetNumCommittersIterator struct {
	Event *ValSetDriverSetNumCommitters // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetNumCommitters // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetNumCommitters represents a SetNumCommitters event raised by the ValSetDriver contract.
type ValSetDriverSetNumCommitters struct {
	NumCommitters *big.Int
	Raw           types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetNumCommitters is a free log retrieval operation binding the contract event 0x931a819f63102a134c17aeb8b67a254fc3e215c35487041ff43fd3225b272b5f.
⋮----
// Solidity: event SetNumCommitters(uint208 numCommitters)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetNumCommitters(opts *bind.FilterOpts) (*ValSetDriverSetNumCommittersIterator, error)
⋮----
// WatchSetNumCommitters is a free log subscription operation binding the contract event 0x931a819f63102a134c17aeb8b67a254fc3e215c35487041ff43fd3225b272b5f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetNumCommitters(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetNumCommitters) (event.Subscription, error)
⋮----
// ParseSetNumCommitters is a log parse operation binding the contract event 0x931a819f63102a134c17aeb8b67a254fc3e215c35487041ff43fd3225b272b5f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetNumCommitters(log types.Log) (*ValSetDriverSetNumCommitters, error)
⋮----
// ValSetDriverSetRequiredHeaderKeyTagIterator is returned from FilterSetRequiredHeaderKeyTag and is used to iterate over the raw logs and unpacked data for SetRequiredHeaderKeyTag events raised by the ValSetDriver contract.
type ValSetDriverSetRequiredHeaderKeyTagIterator struct {
	Event *ValSetDriverSetRequiredHeaderKeyTag // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetRequiredHeaderKeyTag // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetRequiredHeaderKeyTag represents a SetRequiredHeaderKeyTag event raised by the ValSetDriver contract.
type ValSetDriverSetRequiredHeaderKeyTag struct {
	RequiredHeaderKeyTag uint8
	Raw                  types.Log // Blockchain specific contextual infos
}
⋮----
Raw                  types.Log // Blockchain specific contextual infos
⋮----
// FilterSetRequiredHeaderKeyTag is a free log retrieval operation binding the contract event 0xba7887224500eabdaa5bddd0e0210aec811345379939ffbbc4bc87bdfb673b70.
⋮----
// Solidity: event SetRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetRequiredHeaderKeyTag(opts *bind.FilterOpts) (*ValSetDriverSetRequiredHeaderKeyTagIterator, error)
⋮----
// WatchSetRequiredHeaderKeyTag is a free log subscription operation binding the contract event 0xba7887224500eabdaa5bddd0e0210aec811345379939ffbbc4bc87bdfb673b70.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetRequiredHeaderKeyTag(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetRequiredHeaderKeyTag) (event.Subscription, error)
⋮----
// ParseSetRequiredHeaderKeyTag is a log parse operation binding the contract event 0xba7887224500eabdaa5bddd0e0210aec811345379939ffbbc4bc87bdfb673b70.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetRequiredHeaderKeyTag(log types.Log) (*ValSetDriverSetRequiredHeaderKeyTag, error)
⋮----
// ValSetDriverSetRequiredKeyTagsIterator is returned from FilterSetRequiredKeyTags and is used to iterate over the raw logs and unpacked data for SetRequiredKeyTags events raised by the ValSetDriver contract.
type ValSetDriverSetRequiredKeyTagsIterator struct {
	Event *ValSetDriverSetRequiredKeyTags // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetRequiredKeyTags // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetRequiredKeyTags represents a SetRequiredKeyTags event raised by the ValSetDriver contract.
type ValSetDriverSetRequiredKeyTags struct {
	RequiredKeyTags []uint8
	Raw             types.Log // Blockchain specific contextual infos
}
⋮----
// FilterSetRequiredKeyTags is a free log retrieval operation binding the contract event 0x14f8998266f37e593027a05efebf63b8710681d1cdbd39e6d7a156ff7e1485cd.
⋮----
// Solidity: event SetRequiredKeyTags(uint8[] requiredKeyTags)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetRequiredKeyTags(opts *bind.FilterOpts) (*ValSetDriverSetRequiredKeyTagsIterator, error)
⋮----
// WatchSetRequiredKeyTags is a free log subscription operation binding the contract event 0x14f8998266f37e593027a05efebf63b8710681d1cdbd39e6d7a156ff7e1485cd.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetRequiredKeyTags(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetRequiredKeyTags) (event.Subscription, error)
⋮----
// ParseSetRequiredKeyTags is a log parse operation binding the contract event 0x14f8998266f37e593027a05efebf63b8710681d1cdbd39e6d7a156ff7e1485cd.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetRequiredKeyTags(log types.Log) (*ValSetDriverSetRequiredKeyTags, error)
⋮----
// ValSetDriverSetVerificationTypeIterator is returned from FilterSetVerificationType and is used to iterate over the raw logs and unpacked data for SetVerificationType events raised by the ValSetDriver contract.
type ValSetDriverSetVerificationTypeIterator struct {
	Event *ValSetDriverSetVerificationType // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *ValSetDriverSetVerificationType // Event containing the contract specifics and raw log
⋮----
// ValSetDriverSetVerificationType represents a SetVerificationType event raised by the ValSetDriver contract.
type ValSetDriverSetVerificationType struct {
	VerificationType uint32
	Raw              types.Log // Blockchain specific contextual infos
}
⋮----
Raw              types.Log // Blockchain specific contextual infos
⋮----
// FilterSetVerificationType is a free log retrieval operation binding the contract event 0x2acc7be3ff5df4b911488f72502071dcf3f4a8f778a8abc351af3220bcd15b7f.
⋮----
// Solidity: event SetVerificationType(uint32 verificationType)
func (_ValSetDriver *ValSetDriverFilterer) FilterSetVerificationType(opts *bind.FilterOpts) (*ValSetDriverSetVerificationTypeIterator, error)
⋮----
// WatchSetVerificationType is a free log subscription operation binding the contract event 0x2acc7be3ff5df4b911488f72502071dcf3f4a8f778a8abc351af3220bcd15b7f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) WatchSetVerificationType(opts *bind.WatchOpts, sink chan<- *ValSetDriverSetVerificationType) (event.Subscription, error)
⋮----
// ParseSetVerificationType is a log parse operation binding the contract event 0x2acc7be3ff5df4b911488f72502071dcf3f4a8f778a8abc351af3220bcd15b7f.
⋮----
func (_ValSetDriver *ValSetDriverFilterer) ParseSetVerificationType(log types.Log) (*ValSetDriverSetVerificationType, error)
```

## File: symbiotic/client/evm/gen/votingPowerProvider.go

```go
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
⋮----
package gen
⋮----
import (
	"errors"
	"math/big"
	"strings"

	ethereum "github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/event"
)
⋮----
"errors"
"math/big"
"strings"
⋮----
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
⋮----
// Reference imports to suppress errors if they are not otherwise used.
var (
	_ = errors.New
	_ = big.NewInt
	_ = strings.NewReader
	_ = ethereum.NotFound
	_ = bind.Bind
	_ = common.Big1
	_ = types.BloomLookup
	_ = event.NewSubscription
	_ = abi.ConvertType
)
⋮----
// IVotingPowerProviderOperatorVotingPower is an auto generated low-level Go binding around an user-defined struct.
type IVotingPowerProviderOperatorVotingPower struct {
	Operator common.Address
	Vaults   []IVotingPowerProviderVaultValue
}
⋮----
// IVotingPowerProviderVaultValue is an auto generated low-level Go binding around an user-defined struct.
type IVotingPowerProviderVaultValue struct {
	Vault common.Address
	Value *big.Int
}
⋮----
// VotingPowerProviderMetaData contains all meta data concerning the VotingPowerProvider contract.
var VotingPowerProviderMetaData = &bind.MetaData{
	ABI: "[{\"type\":\"function\",\"name\":\"NETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPERATOR_REGISTRY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SUBNETWORK_IDENTIFIER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint96\",\"internalType\":\"uint96\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VAULT_FACTORY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip712Domain\",\"inputs\":[],\"outputs\":[{\"name\":\"fields\",\"type\":\"bytes1\",\"internalType\":\"bytes1\"},{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extensions\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorStakes\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorStakesAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorVaults\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorVaultsAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorVotingPowers\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorVotingPowersAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperators\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperatorsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSharedVaults\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSharedVaultsAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSlashingData\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getSlashingDataAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"hint\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTokens\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTokensAt\",\"inputs\":[{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address[]\",\"internalType\":\"address[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotingPowers\",\"inputs\":[{\"name\":\"extraData\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.OperatorVotingPower[]\",\"components\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"vaults\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getVotingPowersAt\",\"inputs\":[{\"name\":\"extraData\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.OperatorVotingPower[]\",\"components\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"vaults\",\"type\":\"tuple[]\",\"internalType\":\"structIVotingPowerProvider.VaultValue[]\",\"components\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"hashTypedDataV4CrossChain\",\"inputs\":[{\"name\":\"structHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"invalidateOldSignatures\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isOperatorRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperatorRegisteredAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperatorVaultRegistered\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperatorVaultRegistered\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperatorVaultRegisteredAt\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isOperatorVaultRegisteredAt\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSharedVaultRegistered\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isSharedVaultRegisteredAt\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegisteredAt\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"nonces\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerOperator\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"registerOperatorWithSignature\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stakeToVotingPower\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"power\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"stakeToVotingPowerAt\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"stake\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"extraData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"timestamp\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[{\"name\":\"power\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"staticDelegateCall\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unregisterOperator\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unregisterOperatorWithSignature\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"EIP712DomainChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitEIP712\",\"inputs\":[{\"name\":\"name\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InitSubnetwork\",\"inputs\":[{\"name\":\"network\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"subnetworkId\",\"type\":\"uint96\",\"indexed\":false,\"internalType\":\"uint96\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RegisterOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RegisterOperatorVault\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"vault\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RegisterSharedVault\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RegisterToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SetSlashingData\",\"inputs\":[{\"name\":\"requireSlasher\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"},{\"name\":\"minVaultEpochDuration\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnregisterOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnregisterOperatorVault\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"vault\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnregisterSharedVault\",\"inputs\":[{\"name\":\"vault\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UnregisterToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidAccountNonce\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"currentNonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NetworkManager_InvalidNetwork\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidOperator\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidOperatorVault\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidSharedVault\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidSignature\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_InvalidVault\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_OperatorAlreadyRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_OperatorNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_OperatorVaultAlreadyIsRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_OperatorVaultNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_SharedVaultAlreadyIsRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_SharedVaultNotRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_TokenAlreadyIsRegistered\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"VotingPowerProvider_TokenNotRegistered\",\"inputs\":[]}]",
}
⋮----
// VotingPowerProviderABI is the input ABI used to generate the binding from.
// Deprecated: Use VotingPowerProviderMetaData.ABI instead.
var VotingPowerProviderABI = VotingPowerProviderMetaData.ABI
⋮----
// VotingPowerProvider is an auto generated Go binding around an Ethereum contract.
type VotingPowerProvider struct {
	VotingPowerProviderCaller     // Read-only binding to the contract
	VotingPowerProviderTransactor // Write-only binding to the contract
	VotingPowerProviderFilterer   // Log filterer for contract events
}
⋮----
VotingPowerProviderCaller     // Read-only binding to the contract
VotingPowerProviderTransactor // Write-only binding to the contract
VotingPowerProviderFilterer   // Log filterer for contract events
⋮----
// VotingPowerProviderCaller is an auto generated read-only Go binding around an Ethereum contract.
type VotingPowerProviderCaller struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
contract *bind.BoundContract // Generic contract wrapper for the low level calls
⋮----
// VotingPowerProviderTransactor is an auto generated write-only Go binding around an Ethereum contract.
type VotingPowerProviderTransactor struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// VotingPowerProviderFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type VotingPowerProviderFilterer struct {
	contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
⋮----
// VotingPowerProviderSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type VotingPowerProviderSession struct {
	Contract     *VotingPowerProvider // Generic contract binding to set the session for
	CallOpts     bind.CallOpts        // Call options to use throughout this session
	TransactOpts bind.TransactOpts    // Transaction auth options to use throughout this session
}
⋮----
Contract     *VotingPowerProvider // Generic contract binding to set the session for
CallOpts     bind.CallOpts        // Call options to use throughout this session
TransactOpts bind.TransactOpts    // Transaction auth options to use throughout this session
⋮----
// VotingPowerProviderCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type VotingPowerProviderCallerSession struct {
	Contract *VotingPowerProviderCaller // Generic contract caller binding to set the session for
	CallOpts bind.CallOpts              // Call options to use throughout this session
}
⋮----
Contract *VotingPowerProviderCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts              // Call options to use throughout this session
⋮----
// VotingPowerProviderTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type VotingPowerProviderTransactorSession struct {
	Contract     *VotingPowerProviderTransactor // Generic contract transactor binding to set the session for
	TransactOpts bind.TransactOpts              // Transaction auth options to use throughout this session
}
⋮----
Contract     *VotingPowerProviderTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts              // Transaction auth options to use throughout this session
⋮----
// VotingPowerProviderRaw is an auto generated low-level Go binding around an Ethereum contract.
type VotingPowerProviderRaw struct {
	Contract *VotingPowerProvider // Generic contract binding to access the raw methods on
}
⋮----
Contract *VotingPowerProvider // Generic contract binding to access the raw methods on
⋮----
// VotingPowerProviderCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type VotingPowerProviderCallerRaw struct {
	Contract *VotingPowerProviderCaller // Generic read-only contract binding to access the raw methods on
}
⋮----
Contract *VotingPowerProviderCaller // Generic read-only contract binding to access the raw methods on
⋮----
// VotingPowerProviderTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type VotingPowerProviderTransactorRaw struct {
	Contract *VotingPowerProviderTransactor // Generic write-only contract binding to access the raw methods on
}
⋮----
Contract *VotingPowerProviderTransactor // Generic write-only contract binding to access the raw methods on
⋮----
// NewVotingPowerProvider creates a new instance of VotingPowerProvider, bound to a specific deployed contract.
func NewVotingPowerProvider(address common.Address, backend bind.ContractBackend) (*VotingPowerProvider, error)
⋮----
// NewVotingPowerProviderCaller creates a new read-only instance of VotingPowerProvider, bound to a specific deployed contract.
func NewVotingPowerProviderCaller(address common.Address, caller bind.ContractCaller) (*VotingPowerProviderCaller, error)
⋮----
// NewVotingPowerProviderTransactor creates a new write-only instance of VotingPowerProvider, bound to a specific deployed contract.
func NewVotingPowerProviderTransactor(address common.Address, transactor bind.ContractTransactor) (*VotingPowerProviderTransactor, error)
⋮----
// NewVotingPowerProviderFilterer creates a new log filterer instance of VotingPowerProvider, bound to a specific deployed contract.
func NewVotingPowerProviderFilterer(address common.Address, filterer bind.ContractFilterer) (*VotingPowerProviderFilterer, error)
⋮----
// bindVotingPowerProvider binds a generic wrapper to an already deployed contract.
func bindVotingPowerProvider(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error)
⋮----
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_VotingPowerProvider *VotingPowerProviderRaw) Call(opts *bind.CallOpts, result *[]interface
⋮----
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_VotingPowerProvider *VotingPowerProviderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Transact invokes the (paid) contract method with params as input values.
func (_VotingPowerProvider *VotingPowerProviderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface
⋮----
// NETWORK is a free data retrieval call binding the contract method 0x8759e6d1.
//
// Solidity: function NETWORK() view returns(address)
func (_VotingPowerProvider *VotingPowerProviderCaller) NETWORK(opts *bind.CallOpts) (common.Address, error)
⋮----
var out []interface{}
⋮----
// OPERATORREGISTRY is a free data retrieval call binding the contract method 0x83ce0322.
⋮----
// Solidity: function OPERATOR_REGISTRY() view returns(address)
func (_VotingPowerProvider *VotingPowerProviderCaller) OPERATORREGISTRY(opts *bind.CallOpts) (common.Address, error)
⋮----
// SUBNETWORK is a free data retrieval call binding the contract method 0x773e6b54.
⋮----
// Solidity: function SUBNETWORK() view returns(bytes32)
func (_VotingPowerProvider *VotingPowerProviderCaller) SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
⋮----
// SUBNETWORKIDENTIFIER is a free data retrieval call binding the contract method 0xabacb807.
⋮----
// Solidity: function SUBNETWORK_IDENTIFIER() view returns(uint96)
func (_VotingPowerProvider *VotingPowerProviderCaller) SUBNETWORKIDENTIFIER(opts *bind.CallOpts) (*big.Int, error)
⋮----
// VAULTFACTORY is a free data retrieval call binding the contract method 0x103f2907.
⋮----
// Solidity: function VAULT_FACTORY() view returns(address)
func (_VotingPowerProvider *VotingPowerProviderCaller) VAULTFACTORY(opts *bind.CallOpts) (common.Address, error)
⋮----
// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e.
⋮----
// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)
func (_VotingPowerProvider *VotingPowerProviderCaller) Eip712Domain(opts *bind.CallOpts) (struct
⋮----
// GetOperatorStakes is a free data retrieval call binding the contract method 0x93816a13.
⋮----
// Solidity: function getOperatorStakes(address operator) view returns((address,uint256)[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorStakes(opts *bind.CallOpts, operator common.Address) ([]IVotingPowerProviderVaultValue, error)
⋮----
// GetOperatorStakesAt is a free data retrieval call binding the contract method 0xa54e116e.
⋮----
// Solidity: function getOperatorStakesAt(address operator, uint48 timestamp) view returns((address,uint256)[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorStakesAt(opts *bind.CallOpts, operator common.Address, timestamp *big.Int) ([]IVotingPowerProviderVaultValue, error)
⋮----
// GetOperatorVaults is a free data retrieval call binding the contract method 0x14d7e25b.
⋮----
// Solidity: function getOperatorVaults(address operator) view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorVaults(opts *bind.CallOpts, operator common.Address) ([]common.Address, error)
⋮----
// GetOperatorVaultsAt is a free data retrieval call binding the contract method 0x49f993ec.
⋮----
// Solidity: function getOperatorVaultsAt(address operator, uint48 timestamp) view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorVaultsAt(opts *bind.CallOpts, operator common.Address, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetOperatorVotingPowers is a free data retrieval call binding the contract method 0x63ff1140.
⋮----
// Solidity: function getOperatorVotingPowers(address operator, bytes extraData) view returns((address,uint256)[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorVotingPowers(opts *bind.CallOpts, operator common.Address, extraData []byte) ([]IVotingPowerProviderVaultValue, error)
⋮----
// GetOperatorVotingPowersAt is a free data retrieval call binding the contract method 0x380f9945.
⋮----
// Solidity: function getOperatorVotingPowersAt(address operator, bytes extraData, uint48 timestamp) view returns((address,uint256)[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorVotingPowersAt(opts *bind.CallOpts, operator common.Address, extraData []byte, timestamp *big.Int) ([]IVotingPowerProviderVaultValue, error)
⋮----
// GetOperators is a free data retrieval call binding the contract method 0x27a099d8.
⋮----
// Solidity: function getOperators() view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperators(opts *bind.CallOpts) ([]common.Address, error)
⋮----
// GetOperatorsAt is a free data retrieval call binding the contract method 0xa2e33009.
⋮----
// Solidity: function getOperatorsAt(uint48 timestamp) view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetSharedVaults is a free data retrieval call binding the contract method 0xc28474cd.
⋮----
// Solidity: function getSharedVaults() view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetSharedVaults(opts *bind.CallOpts) ([]common.Address, error)
⋮----
// GetSharedVaultsAt is a free data retrieval call binding the contract method 0x4a0c7c17.
⋮----
// Solidity: function getSharedVaultsAt(uint48 timestamp) view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetSharedVaultsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetSlashingData is a free data retrieval call binding the contract method 0xf7dfb974.
⋮----
// Solidity: function getSlashingData() view returns(bool, uint48)
func (_VotingPowerProvider *VotingPowerProviderCaller) GetSlashingData(opts *bind.CallOpts) (bool, *big.Int, error)
⋮----
// GetSlashingDataAt is a free data retrieval call binding the contract method 0x7a74c7fd.
⋮----
// Solidity: function getSlashingDataAt(uint48 timestamp, bytes hint) view returns(bool, uint48)
func (_VotingPowerProvider *VotingPowerProviderCaller) GetSlashingDataAt(opts *bind.CallOpts, timestamp *big.Int, hint []byte) (bool, *big.Int, error)
⋮----
// GetTokens is a free data retrieval call binding the contract method 0xaa6ca808.
⋮----
// Solidity: function getTokens() view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetTokens(opts *bind.CallOpts) ([]common.Address, error)
⋮----
// GetTokensAt is a free data retrieval call binding the contract method 0x1796df1b.
⋮----
// Solidity: function getTokensAt(uint48 timestamp) view returns(address[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetTokensAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetVotingPowers is a free data retrieval call binding the contract method 0xff7cd71c.
⋮----
// Solidity: function getVotingPowers(bytes[] extraData) view returns((address,(address,uint256)[])[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetVotingPowers(opts *bind.CallOpts, extraData [][]byte) ([]IVotingPowerProviderOperatorVotingPower, error)
⋮----
// GetVotingPowersAt is a free data retrieval call binding the contract method 0x77adea5f.
⋮----
// Solidity: function getVotingPowersAt(bytes[] extraData, uint48 timestamp) view returns((address,(address,uint256)[])[])
func (_VotingPowerProvider *VotingPowerProviderCaller) GetVotingPowersAt(opts *bind.CallOpts, extraData [][]byte, timestamp *big.Int) ([]IVotingPowerProviderOperatorVotingPower, error)
⋮----
// HashTypedDataV4 is a free data retrieval call binding the contract method 0x4980f288.
⋮----
// Solidity: function hashTypedDataV4(bytes32 structHash) view returns(bytes32)
func (_VotingPowerProvider *VotingPowerProviderCaller) HashTypedDataV4(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// HashTypedDataV4CrossChain is a free data retrieval call binding the contract method 0x518dcf3b.
⋮----
// Solidity: function hashTypedDataV4CrossChain(bytes32 structHash) view returns(bytes32)
func (_VotingPowerProvider *VotingPowerProviderCaller) HashTypedDataV4CrossChain(opts *bind.CallOpts, structHash [32]byte) ([32]byte, error)
⋮----
// IsOperatorRegistered is a free data retrieval call binding the contract method 0x6b1906f8.
⋮----
// Solidity: function isOperatorRegistered(address operator) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorRegistered(opts *bind.CallOpts, operator common.Address) (bool, error)
⋮----
// IsOperatorRegisteredAt is a free data retrieval call binding the contract method 0x8a5aef51.
⋮----
// Solidity: function isOperatorRegisteredAt(address operator, uint48 timestamp) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorRegisteredAt(opts *bind.CallOpts, operator common.Address, timestamp *big.Int) (bool, error)
⋮----
// IsOperatorVaultRegistered is a free data retrieval call binding the contract method 0x0f6e0743.
⋮----
// Solidity: function isOperatorVaultRegistered(address vault) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorVaultRegistered(opts *bind.CallOpts, vault common.Address) (bool, error)
⋮----
// IsOperatorVaultRegistered0 is a free data retrieval call binding the contract method 0x669fa8c7.
⋮----
// Solidity: function isOperatorVaultRegistered(address operator, address vault) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorVaultRegistered0(opts *bind.CallOpts, operator common.Address, vault common.Address) (bool, error)
⋮----
// IsOperatorVaultRegisteredAt is a free data retrieval call binding the contract method 0xdae8f803.
⋮----
// Solidity: function isOperatorVaultRegisteredAt(address operator, address vault, uint48 timestamp) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorVaultRegisteredAt(opts *bind.CallOpts, operator common.Address, vault common.Address, timestamp *big.Int) (bool, error)
⋮----
// IsOperatorVaultRegisteredAt0 is a free data retrieval call binding the contract method 0xf6c011de.
⋮----
// Solidity: function isOperatorVaultRegisteredAt(address vault, uint48 timestamp) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsOperatorVaultRegisteredAt0(opts *bind.CallOpts, vault common.Address, timestamp *big.Int) (bool, error)
⋮----
// IsSharedVaultRegistered is a free data retrieval call binding the contract method 0x9a1ebee9.
⋮----
// Solidity: function isSharedVaultRegistered(address vault) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsSharedVaultRegistered(opts *bind.CallOpts, vault common.Address) (bool, error)
⋮----
// IsSharedVaultRegisteredAt is a free data retrieval call binding the contract method 0xe66e1ed2.
⋮----
// Solidity: function isSharedVaultRegisteredAt(address vault, uint48 timestamp) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsSharedVaultRegisteredAt(opts *bind.CallOpts, vault common.Address, timestamp *big.Int) (bool, error)
⋮----
// IsTokenRegistered is a free data retrieval call binding the contract method 0x26aa101f.
⋮----
// Solidity: function isTokenRegistered(address token) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsTokenRegistered(opts *bind.CallOpts, token common.Address) (bool, error)
⋮----
// IsTokenRegisteredAt is a free data retrieval call binding the contract method 0x6a496108.
⋮----
// Solidity: function isTokenRegisteredAt(address token, uint48 timestamp) view returns(bool)
func (_VotingPowerProvider *VotingPowerProviderCaller) IsTokenRegisteredAt(opts *bind.CallOpts, token common.Address, timestamp *big.Int) (bool, error)
⋮----
// Nonces is a free data retrieval call binding the contract method 0x7ecebe00.
⋮----
// Solidity: function nonces(address owner) view returns(uint256)
func (_VotingPowerProvider *VotingPowerProviderCaller) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error)
⋮----
// StakeToVotingPower is a free data retrieval call binding the contract method 0x039b8dd0.
⋮----
// Solidity: function stakeToVotingPower(address vault, uint256 stake, bytes extraData) view returns(uint256 power)
func (_VotingPowerProvider *VotingPowerProviderCaller) StakeToVotingPower(opts *bind.CallOpts, vault common.Address, stake *big.Int, extraData []byte) (*big.Int, error)
⋮----
// StakeToVotingPowerAt is a free data retrieval call binding the contract method 0x52936362.
⋮----
// Solidity: function stakeToVotingPowerAt(address vault, uint256 stake, bytes extraData, uint48 timestamp) view returns(uint256 power)
func (_VotingPowerProvider *VotingPowerProviderCaller) StakeToVotingPowerAt(opts *bind.CallOpts, vault common.Address, stake *big.Int, extraData []byte, timestamp *big.Int) (*big.Int, error)
⋮----
// InvalidateOldSignatures is a paid mutator transaction binding the contract method 0x622e4dba.
⋮----
// Solidity: function invalidateOldSignatures() returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) InvalidateOldSignatures(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// Multicall is a paid mutator transaction binding the contract method 0xac9650d8.
⋮----
// Solidity: function multicall(bytes[] data) returns(bytes[] results)
func (_VotingPowerProvider *VotingPowerProviderTransactor) Multicall(opts *bind.TransactOpts, data [][]byte) (*types.Transaction, error)
⋮----
// RegisterOperator is a paid mutator transaction binding the contract method 0x2acde098.
⋮----
// Solidity: function registerOperator() returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) RegisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// RegisterOperatorWithSignature is a paid mutator transaction binding the contract method 0xeb5e940d.
⋮----
// Solidity: function registerOperatorWithSignature(address operator, bytes signature) returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) RegisterOperatorWithSignature(opts *bind.TransactOpts, operator common.Address, signature []byte) (*types.Transaction, error)
⋮----
// StaticDelegateCall is a paid mutator transaction binding the contract method 0x9f86fd85.
⋮----
// Solidity: function staticDelegateCall(address target, bytes data) returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) StaticDelegateCall(opts *bind.TransactOpts, target common.Address, data []byte) (*types.Transaction, error)
⋮----
// UnregisterOperator is a paid mutator transaction binding the contract method 0xa876b89a.
⋮----
// Solidity: function unregisterOperator() returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) UnregisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// UnregisterOperatorWithSignature is a paid mutator transaction binding the contract method 0xf96d1946.
⋮----
// Solidity: function unregisterOperatorWithSignature(address operator, bytes signature) returns()
func (_VotingPowerProvider *VotingPowerProviderTransactor) UnregisterOperatorWithSignature(opts *bind.TransactOpts, operator common.Address, signature []byte) (*types.Transaction, error)
⋮----
// VotingPowerProviderEIP712DomainChangedIterator is returned from FilterEIP712DomainChanged and is used to iterate over the raw logs and unpacked data for EIP712DomainChanged events raised by the VotingPowerProvider contract.
type VotingPowerProviderEIP712DomainChangedIterator struct {
	Event *VotingPowerProviderEIP712DomainChanged // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderEIP712DomainChanged // Event containing the contract specifics and raw log
⋮----
contract *bind.BoundContract // Generic contract to use for unpacking event data
event    string              // Event name to use for unpacking event data
⋮----
logs chan types.Log        // Log channel receiving the found contract events
sub  ethereum.Subscription // Subscription for errors, completion and termination
done bool                  // Whether the subscription completed delivering logs
fail error                 // Occurred error to stop iteration
⋮----
// Next advances the iterator to the subsequent event, returning whether there
// are any more events found. In case of a retrieval or parsing error, false is
// returned and Error() can be queried for the exact failure.
func (it *VotingPowerProviderEIP712DomainChangedIterator) Next() bool
⋮----
// If the iterator failed, stop iterating
⋮----
// If the iterator completed, deliver directly whatever's available
⋮----
// Iterator still in progress, wait for either a data or an error event
⋮----
// Error returns any retrieval or parsing error occurred during filtering.
func (it *VotingPowerProviderEIP712DomainChangedIterator) Error() error
⋮----
// Close terminates the iteration process, releasing any pending underlying
// resources.
func (it *VotingPowerProviderEIP712DomainChangedIterator) Close() error
⋮----
// VotingPowerProviderEIP712DomainChanged represents a EIP712DomainChanged event raised by the VotingPowerProvider contract.
type VotingPowerProviderEIP712DomainChanged struct {
	Raw types.Log // Blockchain specific contextual infos
}
⋮----
Raw types.Log // Blockchain specific contextual infos
⋮----
// FilterEIP712DomainChanged is a free log retrieval operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
// Solidity: event EIP712DomainChanged()
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterEIP712DomainChanged(opts *bind.FilterOpts) (*VotingPowerProviderEIP712DomainChangedIterator, error)
⋮----
// WatchEIP712DomainChanged is a free log subscription operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchEIP712DomainChanged(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderEIP712DomainChanged) (event.Subscription, error)
⋮----
// New log arrived, parse the event and forward to the user
⋮----
// ParseEIP712DomainChanged is a log parse operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseEIP712DomainChanged(log types.Log) (*VotingPowerProviderEIP712DomainChanged, error)
⋮----
// VotingPowerProviderInitEIP712Iterator is returned from FilterInitEIP712 and is used to iterate over the raw logs and unpacked data for InitEIP712 events raised by the VotingPowerProvider contract.
type VotingPowerProviderInitEIP712Iterator struct {
	Event *VotingPowerProviderInitEIP712 // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderInitEIP712 // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderInitEIP712 represents a InitEIP712 event raised by the VotingPowerProvider contract.
type VotingPowerProviderInitEIP712 struct {
	Name    string
	Version string
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
Raw     types.Log // Blockchain specific contextual infos
⋮----
// FilterInitEIP712 is a free log retrieval operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
// Solidity: event InitEIP712(string name, string version)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterInitEIP712(opts *bind.FilterOpts) (*VotingPowerProviderInitEIP712Iterator, error)
⋮----
// WatchInitEIP712 is a free log subscription operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchInitEIP712(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderInitEIP712) (event.Subscription, error)
⋮----
// ParseInitEIP712 is a log parse operation binding the contract event 0x98790bb3996c909e6f4279ffabdfe70fa6c0d49b8fa04656d6161decfc442e0a.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseInitEIP712(log types.Log) (*VotingPowerProviderInitEIP712, error)
⋮----
// VotingPowerProviderInitSubnetworkIterator is returned from FilterInitSubnetwork and is used to iterate over the raw logs and unpacked data for InitSubnetwork events raised by the VotingPowerProvider contract.
type VotingPowerProviderInitSubnetworkIterator struct {
	Event *VotingPowerProviderInitSubnetwork // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderInitSubnetwork // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderInitSubnetwork represents a InitSubnetwork event raised by the VotingPowerProvider contract.
type VotingPowerProviderInitSubnetwork struct {
	Network      common.Address
	SubnetworkId *big.Int
	Raw          types.Log // Blockchain specific contextual infos
}
⋮----
Raw          types.Log // Blockchain specific contextual infos
⋮----
// FilterInitSubnetwork is a free log retrieval operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
// Solidity: event InitSubnetwork(address network, uint96 subnetworkId)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterInitSubnetwork(opts *bind.FilterOpts) (*VotingPowerProviderInitSubnetworkIterator, error)
⋮----
// WatchInitSubnetwork is a free log subscription operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchInitSubnetwork(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderInitSubnetwork) (event.Subscription, error)
⋮----
// ParseInitSubnetwork is a log parse operation binding the contract event 0x469c2e982e7d76d34cf5d1e72abee29749bb9971942c180e9023cea09f5f8e83.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseInitSubnetwork(log types.Log) (*VotingPowerProviderInitSubnetwork, error)
⋮----
// VotingPowerProviderInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the VotingPowerProvider contract.
type VotingPowerProviderInitializedIterator struct {
	Event *VotingPowerProviderInitialized // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderInitialized // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderInitialized represents a Initialized event raised by the VotingPowerProvider contract.
type VotingPowerProviderInitialized struct {
	Version uint64
	Raw     types.Log // Blockchain specific contextual infos
}
⋮----
// FilterInitialized is a free log retrieval operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
// Solidity: event Initialized(uint64 version)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterInitialized(opts *bind.FilterOpts) (*VotingPowerProviderInitializedIterator, error)
⋮----
// WatchInitialized is a free log subscription operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderInitialized) (event.Subscription, error)
⋮----
// ParseInitialized is a log parse operation binding the contract event 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseInitialized(log types.Log) (*VotingPowerProviderInitialized, error)
⋮----
// VotingPowerProviderRegisterOperatorIterator is returned from FilterRegisterOperator and is used to iterate over the raw logs and unpacked data for RegisterOperator events raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterOperatorIterator struct {
	Event *VotingPowerProviderRegisterOperator // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderRegisterOperator // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderRegisterOperator represents a RegisterOperator event raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterOperator struct {
	Operator common.Address
	Raw      types.Log // Blockchain specific contextual infos
}
⋮----
Raw      types.Log // Blockchain specific contextual infos
⋮----
// FilterRegisterOperator is a free log retrieval operation binding the contract event 0xdfd9e0392912bee97777ec588d2ff7ae010ea24202d153a0bff1b30aed643daa.
⋮----
// Solidity: event RegisterOperator(address indexed operator)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterRegisterOperator(opts *bind.FilterOpts, operator []common.Address) (*VotingPowerProviderRegisterOperatorIterator, error)
⋮----
var operatorRule []interface{}
⋮----
// WatchRegisterOperator is a free log subscription operation binding the contract event 0xdfd9e0392912bee97777ec588d2ff7ae010ea24202d153a0bff1b30aed643daa.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchRegisterOperator(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderRegisterOperator, operator []common.Address) (event.Subscription, error)
⋮----
// ParseRegisterOperator is a log parse operation binding the contract event 0xdfd9e0392912bee97777ec588d2ff7ae010ea24202d153a0bff1b30aed643daa.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseRegisterOperator(log types.Log) (*VotingPowerProviderRegisterOperator, error)
⋮----
// VotingPowerProviderRegisterOperatorVaultIterator is returned from FilterRegisterOperatorVault and is used to iterate over the raw logs and unpacked data for RegisterOperatorVault events raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterOperatorVaultIterator struct {
	Event *VotingPowerProviderRegisterOperatorVault // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderRegisterOperatorVault // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderRegisterOperatorVault represents a RegisterOperatorVault event raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterOperatorVault struct {
	Operator common.Address
	Vault    common.Address
	Raw      types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRegisterOperatorVault is a free log retrieval operation binding the contract event 0x6db8d1ad7903329250db9b7a653d3aa009807c85daa2281a75e063808bceefdc.
⋮----
// Solidity: event RegisterOperatorVault(address indexed operator, address indexed vault)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterRegisterOperatorVault(opts *bind.FilterOpts, operator []common.Address, vault []common.Address) (*VotingPowerProviderRegisterOperatorVaultIterator, error)
⋮----
var vaultRule []interface{}
⋮----
// WatchRegisterOperatorVault is a free log subscription operation binding the contract event 0x6db8d1ad7903329250db9b7a653d3aa009807c85daa2281a75e063808bceefdc.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchRegisterOperatorVault(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderRegisterOperatorVault, operator []common.Address, vault []common.Address) (event.Subscription, error)
⋮----
// ParseRegisterOperatorVault is a log parse operation binding the contract event 0x6db8d1ad7903329250db9b7a653d3aa009807c85daa2281a75e063808bceefdc.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseRegisterOperatorVault(log types.Log) (*VotingPowerProviderRegisterOperatorVault, error)
⋮----
// VotingPowerProviderRegisterSharedVaultIterator is returned from FilterRegisterSharedVault and is used to iterate over the raw logs and unpacked data for RegisterSharedVault events raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterSharedVaultIterator struct {
	Event *VotingPowerProviderRegisterSharedVault // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderRegisterSharedVault // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderRegisterSharedVault represents a RegisterSharedVault event raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterSharedVault struct {
	Vault common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
Raw   types.Log // Blockchain specific contextual infos
⋮----
// FilterRegisterSharedVault is a free log retrieval operation binding the contract event 0x99528065e654d6d4b95447d6787148a84b7e98a95e752784e99da056b403b25c.
⋮----
// Solidity: event RegisterSharedVault(address indexed vault)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterRegisterSharedVault(opts *bind.FilterOpts, vault []common.Address) (*VotingPowerProviderRegisterSharedVaultIterator, error)
⋮----
// WatchRegisterSharedVault is a free log subscription operation binding the contract event 0x99528065e654d6d4b95447d6787148a84b7e98a95e752784e99da056b403b25c.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchRegisterSharedVault(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderRegisterSharedVault, vault []common.Address) (event.Subscription, error)
⋮----
// ParseRegisterSharedVault is a log parse operation binding the contract event 0x99528065e654d6d4b95447d6787148a84b7e98a95e752784e99da056b403b25c.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseRegisterSharedVault(log types.Log) (*VotingPowerProviderRegisterSharedVault, error)
⋮----
// VotingPowerProviderRegisterTokenIterator is returned from FilterRegisterToken and is used to iterate over the raw logs and unpacked data for RegisterToken events raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterTokenIterator struct {
	Event *VotingPowerProviderRegisterToken // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderRegisterToken // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderRegisterToken represents a RegisterToken event raised by the VotingPowerProvider contract.
type VotingPowerProviderRegisterToken struct {
	Token common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
// FilterRegisterToken is a free log retrieval operation binding the contract event 0xf7fe8023cb2e36bde1d59a88ac5763a8c11be6d25e6819f71bb7e23e5bf0dc16.
⋮----
// Solidity: event RegisterToken(address indexed token)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterRegisterToken(opts *bind.FilterOpts, token []common.Address) (*VotingPowerProviderRegisterTokenIterator, error)
⋮----
var tokenRule []interface{}
⋮----
// WatchRegisterToken is a free log subscription operation binding the contract event 0xf7fe8023cb2e36bde1d59a88ac5763a8c11be6d25e6819f71bb7e23e5bf0dc16.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchRegisterToken(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderRegisterToken, token []common.Address) (event.Subscription, error)
⋮----
// ParseRegisterToken is a log parse operation binding the contract event 0xf7fe8023cb2e36bde1d59a88ac5763a8c11be6d25e6819f71bb7e23e5bf0dc16.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseRegisterToken(log types.Log) (*VotingPowerProviderRegisterToken, error)
⋮----
// VotingPowerProviderSetSlashingDataIterator is returned from FilterSetSlashingData and is used to iterate over the raw logs and unpacked data for SetSlashingData events raised by the VotingPowerProvider contract.
type VotingPowerProviderSetSlashingDataIterator struct {
	Event *VotingPowerProviderSetSlashingData // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderSetSlashingData // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderSetSlashingData represents a SetSlashingData event raised by the VotingPowerProvider contract.
type VotingPowerProviderSetSlashingData struct {
	RequireSlasher        bool
	MinVaultEpochDuration *big.Int
	Raw                   types.Log // Blockchain specific contextual infos
}
⋮----
Raw                   types.Log // Blockchain specific contextual infos
⋮----
// FilterSetSlashingData is a free log retrieval operation binding the contract event 0xfa31c1b97ed96532301949e5fd34d2e059500b0de599195245ddf8fbfbb36db0.
⋮----
// Solidity: event SetSlashingData(bool requireSlasher, uint48 minVaultEpochDuration)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterSetSlashingData(opts *bind.FilterOpts) (*VotingPowerProviderSetSlashingDataIterator, error)
⋮----
// WatchSetSlashingData is a free log subscription operation binding the contract event 0xfa31c1b97ed96532301949e5fd34d2e059500b0de599195245ddf8fbfbb36db0.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchSetSlashingData(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderSetSlashingData) (event.Subscription, error)
⋮----
// ParseSetSlashingData is a log parse operation binding the contract event 0xfa31c1b97ed96532301949e5fd34d2e059500b0de599195245ddf8fbfbb36db0.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseSetSlashingData(log types.Log) (*VotingPowerProviderSetSlashingData, error)
⋮----
// VotingPowerProviderUnregisterOperatorIterator is returned from FilterUnregisterOperator and is used to iterate over the raw logs and unpacked data for UnregisterOperator events raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterOperatorIterator struct {
	Event *VotingPowerProviderUnregisterOperator // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderUnregisterOperator // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderUnregisterOperator represents a UnregisterOperator event raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterOperator struct {
	Operator common.Address
	Raw      types.Log // Blockchain specific contextual infos
}
⋮----
// FilterUnregisterOperator is a free log retrieval operation binding the contract event 0xd1b48d1e49885298af5dc8adc7777836ef804b38af88eabf4e079c04ee1538a7.
⋮----
// Solidity: event UnregisterOperator(address indexed operator)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterUnregisterOperator(opts *bind.FilterOpts, operator []common.Address) (*VotingPowerProviderUnregisterOperatorIterator, error)
⋮----
// WatchUnregisterOperator is a free log subscription operation binding the contract event 0xd1b48d1e49885298af5dc8adc7777836ef804b38af88eabf4e079c04ee1538a7.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchUnregisterOperator(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderUnregisterOperator, operator []common.Address) (event.Subscription, error)
⋮----
// ParseUnregisterOperator is a log parse operation binding the contract event 0xd1b48d1e49885298af5dc8adc7777836ef804b38af88eabf4e079c04ee1538a7.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseUnregisterOperator(log types.Log) (*VotingPowerProviderUnregisterOperator, error)
⋮----
// VotingPowerProviderUnregisterOperatorVaultIterator is returned from FilterUnregisterOperatorVault and is used to iterate over the raw logs and unpacked data for UnregisterOperatorVault events raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterOperatorVaultIterator struct {
	Event *VotingPowerProviderUnregisterOperatorVault // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderUnregisterOperatorVault // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderUnregisterOperatorVault represents a UnregisterOperatorVault event raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterOperatorVault struct {
	Operator common.Address
	Vault    common.Address
	Raw      types.Log // Blockchain specific contextual infos
}
⋮----
// FilterUnregisterOperatorVault is a free log retrieval operation binding the contract event 0x3455b6128675eff843703027879cc9b52d6ce684ddc6077cbe0d191ad98b255e.
⋮----
// Solidity: event UnregisterOperatorVault(address indexed operator, address indexed vault)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterUnregisterOperatorVault(opts *bind.FilterOpts, operator []common.Address, vault []common.Address) (*VotingPowerProviderUnregisterOperatorVaultIterator, error)
⋮----
// WatchUnregisterOperatorVault is a free log subscription operation binding the contract event 0x3455b6128675eff843703027879cc9b52d6ce684ddc6077cbe0d191ad98b255e.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchUnregisterOperatorVault(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderUnregisterOperatorVault, operator []common.Address, vault []common.Address) (event.Subscription, error)
⋮----
// ParseUnregisterOperatorVault is a log parse operation binding the contract event 0x3455b6128675eff843703027879cc9b52d6ce684ddc6077cbe0d191ad98b255e.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseUnregisterOperatorVault(log types.Log) (*VotingPowerProviderUnregisterOperatorVault, error)
⋮----
// VotingPowerProviderUnregisterSharedVaultIterator is returned from FilterUnregisterSharedVault and is used to iterate over the raw logs and unpacked data for UnregisterSharedVault events raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterSharedVaultIterator struct {
	Event *VotingPowerProviderUnregisterSharedVault // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderUnregisterSharedVault // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderUnregisterSharedVault represents a UnregisterSharedVault event raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterSharedVault struct {
	Vault common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
// FilterUnregisterSharedVault is a free log retrieval operation binding the contract event 0xead83f8482d0fa5de2b5c28fb39ee288392076d150db7020e10a92954aea82ee.
⋮----
// Solidity: event UnregisterSharedVault(address indexed vault)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterUnregisterSharedVault(opts *bind.FilterOpts, vault []common.Address) (*VotingPowerProviderUnregisterSharedVaultIterator, error)
⋮----
// WatchUnregisterSharedVault is a free log subscription operation binding the contract event 0xead83f8482d0fa5de2b5c28fb39ee288392076d150db7020e10a92954aea82ee.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchUnregisterSharedVault(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderUnregisterSharedVault, vault []common.Address) (event.Subscription, error)
⋮----
// ParseUnregisterSharedVault is a log parse operation binding the contract event 0xead83f8482d0fa5de2b5c28fb39ee288392076d150db7020e10a92954aea82ee.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseUnregisterSharedVault(log types.Log) (*VotingPowerProviderUnregisterSharedVault, error)
⋮----
// VotingPowerProviderUnregisterTokenIterator is returned from FilterUnregisterToken and is used to iterate over the raw logs and unpacked data for UnregisterToken events raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterTokenIterator struct {
	Event *VotingPowerProviderUnregisterToken // Event containing the contract specifics and raw log

	contract *bind.BoundContract // Generic contract to use for unpacking event data
	event    string              // Event name to use for unpacking event data

	logs chan types.Log        // Log channel receiving the found contract events
	sub  ethereum.Subscription // Subscription for errors, completion and termination
	done bool                  // Whether the subscription completed delivering logs
	fail error                 // Occurred error to stop iteration
}
⋮----
Event *VotingPowerProviderUnregisterToken // Event containing the contract specifics and raw log
⋮----
// VotingPowerProviderUnregisterToken represents a UnregisterToken event raised by the VotingPowerProvider contract.
type VotingPowerProviderUnregisterToken struct {
	Token common.Address
	Raw   types.Log // Blockchain specific contextual infos
}
⋮----
// FilterUnregisterToken is a free log retrieval operation binding the contract event 0xca2a890939276223a9122217752c67608466faee388aff53f077d00a186a389b.
⋮----
// Solidity: event UnregisterToken(address indexed token)
func (_VotingPowerProvider *VotingPowerProviderFilterer) FilterUnregisterToken(opts *bind.FilterOpts, token []common.Address) (*VotingPowerProviderUnregisterTokenIterator, error)
⋮----
// WatchUnregisterToken is a free log subscription operation binding the contract event 0xca2a890939276223a9122217752c67608466faee388aff53f077d00a186a389b.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) WatchUnregisterToken(opts *bind.WatchOpts, sink chan<- *VotingPowerProviderUnregisterToken, token []common.Address) (event.Subscription, error)
⋮----
// ParseUnregisterToken is a log parse operation binding the contract event 0xca2a890939276223a9122217752c67608466faee388aff53f077d00a186a389b.
⋮----
func (_VotingPowerProvider *VotingPowerProviderFilterer) ParseUnregisterToken(log types.Log) (*VotingPowerProviderUnregisterToken, error)
```

## File: symbiotic/client/evm/mocks/eth.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/symbioticfi/relay/symbiotic/client/evm (interfaces: IEvmClient,conn,metrics,keyProvider,driverContract,settlementContract,votingPowerProviderContract,votingPowerProviderTransactor,keyRegistryContract,operatorRegistryContract)
//
// Generated by this command:
⋮----
//	mockgen -destination=mocks/eth.go -package=mocks github.com/symbioticfi/relay/symbiotic/client/evm IEvmClient,conn,metrics,keyProvider,driverContract,settlementContract,votingPowerProviderContract,votingPowerProviderTransactor,keyRegistryContract,operatorRegistryContract
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	big "math/big"
	reflect "reflect"
	time "time"

	ethereum "github.com/ethereum/go-ethereum"
	bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
	common "github.com/ethereum/go-ethereum/common"
	types "github.com/ethereum/go-ethereum/core/types"
	gen "github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	entity "github.com/symbioticfi/relay/symbiotic/entity"
	crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
big "math/big"
reflect "reflect"
time "time"
⋮----
ethereum "github.com/ethereum/go-ethereum"
bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
common "github.com/ethereum/go-ethereum/common"
types "github.com/ethereum/go-ethereum/core/types"
gen "github.com/symbioticfi/relay/symbiotic/client/evm/gen"
entity "github.com/symbioticfi/relay/symbiotic/entity"
crypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
gomock "go.uber.org/mock/gomock"
⋮----
// MockIEvmClient is a mock of IEvmClient interface.
type MockIEvmClient struct {
	ctrl     *gomock.Controller
	recorder *MockIEvmClientMockRecorder
	isgomock struct{}
⋮----
// MockIEvmClientMockRecorder is the mock recorder for MockIEvmClient.
type MockIEvmClientMockRecorder struct {
	mock *MockIEvmClient
}
⋮----
// NewMockIEvmClient creates a new mock instance.
func NewMockIEvmClient(ctrl *gomock.Controller) *MockIEvmClient
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockIEvmClient) EXPECT() *MockIEvmClientMockRecorder
⋮----
// CommitValsetHeader mocks base method.
func (m *MockIEvmClient) CommitValsetHeader(ctx context.Context, addr entity.CrossChainAddress, header entity.ValidatorSetHeader, extraData []entity.ExtraData, proof []byte) (entity.TxResult, error)
⋮----
// CommitValsetHeader indicates an expected call of CommitValsetHeader.
⋮----
// GetCaptureTimestampFromValsetHeaderAt mocks base method.
func (m *MockIEvmClient) GetCaptureTimestampFromValsetHeaderAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch) (uint64, error)
⋮----
// GetCaptureTimestampFromValsetHeaderAt indicates an expected call of GetCaptureTimestampFromValsetHeaderAt.
⋮----
// GetChains mocks base method.
func (m *MockIEvmClient) GetChains() []uint64
⋮----
// GetChains indicates an expected call of GetChains.
⋮----
// GetConfig mocks base method.
func (m *MockIEvmClient) GetConfig(ctx context.Context, timestamp entity.Timestamp, epoch entity.Epoch) (entity.NetworkConfig, error)
⋮----
// GetConfig indicates an expected call of GetConfig.
⋮----
// GetCurrentEpoch mocks base method.
func (m *MockIEvmClient) GetCurrentEpoch(ctx context.Context) (entity.Epoch, error)
⋮----
// GetCurrentEpoch indicates an expected call of GetCurrentEpoch.
⋮----
// GetCurrentEpochDuration mocks base method.
func (m *MockIEvmClient) GetCurrentEpochDuration(ctx context.Context) (uint64, error)
⋮----
// GetCurrentEpochDuration indicates an expected call of GetCurrentEpochDuration.
⋮----
// GetEip712Domain mocks base method.
func (m *MockIEvmClient) GetEip712Domain(ctx context.Context, addr entity.CrossChainAddress) (entity.Eip712Domain, error)
⋮----
// GetEip712Domain indicates an expected call of GetEip712Domain.
⋮----
// GetEpochDuration mocks base method.
func (m *MockIEvmClient) GetEpochDuration(ctx context.Context, epoch entity.Epoch) (uint64, error)
⋮----
// GetEpochDuration indicates an expected call of GetEpochDuration.
⋮----
// GetEpochStart mocks base method.
func (m *MockIEvmClient) GetEpochStart(ctx context.Context, epoch entity.Epoch) (entity.Timestamp, error)
⋮----
// GetEpochStart indicates an expected call of GetEpochStart.
⋮----
// GetHeaderHash mocks base method.
func (m *MockIEvmClient) GetHeaderHash(ctx context.Context, addr entity.CrossChainAddress) (common.Hash, error)
⋮----
// GetHeaderHash indicates an expected call of GetHeaderHash.
⋮----
// GetHeaderHashAt mocks base method.
func (m *MockIEvmClient) GetHeaderHashAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch) (common.Hash, error)
⋮----
// GetHeaderHashAt indicates an expected call of GetHeaderHashAt.
⋮----
// GetKeys mocks base method.
func (m *MockIEvmClient) GetKeys(ctx context.Context, address entity.CrossChainAddress, timestamp entity.Timestamp) ([]entity.OperatorWithKeys, error)
⋮----
// GetKeys indicates an expected call of GetKeys.
⋮----
// GetLastCommittedHeaderEpoch mocks base method.
func (m *MockIEvmClient) GetLastCommittedHeaderEpoch(ctx context.Context, addr entity.CrossChainAddress, evmOptions ...entity.EVMOption) (entity.Epoch, error)
⋮----
// GetLastCommittedHeaderEpoch indicates an expected call of GetLastCommittedHeaderEpoch.
⋮----
// GetNetworkAddress mocks base method.
func (m *MockIEvmClient) GetNetworkAddress(ctx context.Context) (common.Address, error)
⋮----
// GetNetworkAddress indicates an expected call of GetNetworkAddress.
⋮----
// GetOperatorNonce mocks base method.
func (m *MockIEvmClient) GetOperatorNonce(ctx context.Context, votingPowerProvider entity.CrossChainAddress, operator common.Address) (*big.Int, error)
⋮----
// GetOperatorNonce indicates an expected call of GetOperatorNonce.
⋮----
// GetSubnetwork mocks base method.
func (m *MockIEvmClient) GetSubnetwork(ctx context.Context) (common.Hash, error)
⋮----
// GetSubnetwork indicates an expected call of GetSubnetwork.
⋮----
// GetValSetHeader mocks base method.
func (m *MockIEvmClient) GetValSetHeader(ctx context.Context, addr entity.CrossChainAddress) (entity.ValidatorSetHeader, error)
⋮----
// GetValSetHeader indicates an expected call of GetValSetHeader.
⋮----
// GetValSetHeaderAt mocks base method.
func (m *MockIEvmClient) GetValSetHeaderAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch) (entity.ValidatorSetHeader, error)
⋮----
// GetValSetHeaderAt indicates an expected call of GetValSetHeaderAt.
⋮----
// GetVotingPowerProviderEip712Domain mocks base method.
func (m *MockIEvmClient) GetVotingPowerProviderEip712Domain(ctx context.Context, addr entity.CrossChainAddress) (entity.Eip712Domain, error)
⋮----
// GetVotingPowerProviderEip712Domain indicates an expected call of GetVotingPowerProviderEip712Domain.
⋮----
// GetVotingPowers mocks base method.
func (m *MockIEvmClient) GetVotingPowers(ctx context.Context, address entity.CrossChainAddress, timestamp entity.Timestamp) ([]entity.OperatorVotingPower, error)
⋮----
// GetVotingPowers indicates an expected call of GetVotingPowers.
⋮----
// InvalidateOldSignatures mocks base method.
func (m *MockIEvmClient) InvalidateOldSignatures(ctx context.Context, addr entity.CrossChainAddress) (entity.TxResult, error)
⋮----
// InvalidateOldSignatures indicates an expected call of InvalidateOldSignatures.
⋮----
// IsValsetHeaderCommittedAt mocks base method.
func (m *MockIEvmClient) IsValsetHeaderCommittedAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch, opts ...entity.EVMOption) (bool, error)
⋮----
// IsValsetHeaderCommittedAt indicates an expected call of IsValsetHeaderCommittedAt.
⋮----
// IsValsetHeaderCommittedAtEpochs mocks base method.
func (m *MockIEvmClient) IsValsetHeaderCommittedAtEpochs(ctx context.Context, addr entity.CrossChainAddress, epochs []entity.Epoch) ([]bool, error)
⋮----
// IsValsetHeaderCommittedAtEpochs indicates an expected call of IsValsetHeaderCommittedAtEpochs.
⋮----
// RegisterKey mocks base method.
func (m *MockIEvmClient) RegisterKey(ctx context.Context, addr entity.CrossChainAddress, keyTag entity.KeyTag, key entity.CompactPublicKey, signature entity.RawSignature, extraData []byte) (entity.TxResult, error)
⋮----
// RegisterKey indicates an expected call of RegisterKey.
⋮----
// RegisterOperator mocks base method.
func (m *MockIEvmClient) RegisterOperator(ctx context.Context, addr entity.CrossChainAddress) (entity.TxResult, error)
⋮----
// RegisterOperator indicates an expected call of RegisterOperator.
⋮----
// RegisterOperatorVotingPowerProvider mocks base method.
func (m *MockIEvmClient) RegisterOperatorVotingPowerProvider(ctx context.Context, addr entity.CrossChainAddress) (entity.TxResult, error)
⋮----
// RegisterOperatorVotingPowerProvider indicates an expected call of RegisterOperatorVotingPowerProvider.
⋮----
// SetGenesis mocks base method.
func (m *MockIEvmClient) SetGenesis(ctx context.Context, addr entity.CrossChainAddress, header entity.ValidatorSetHeader, extraData []entity.ExtraData) (entity.TxResult, error)
⋮----
// SetGenesis indicates an expected call of SetGenesis.
⋮----
// UnregisterOperatorVotingPowerProvider mocks base method.
func (m *MockIEvmClient) UnregisterOperatorVotingPowerProvider(ctx context.Context, addr entity.CrossChainAddress) (entity.TxResult, error)
⋮----
// UnregisterOperatorVotingPowerProvider indicates an expected call of UnregisterOperatorVotingPowerProvider.
⋮----
// VerifyQuorumSig mocks base method.
func (m *MockIEvmClient) VerifyQuorumSig(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch, message []byte, keyTag entity.KeyTag, threshold *big.Int, proof []byte) (bool, error)
⋮----
// VerifyQuorumSig indicates an expected call of VerifyQuorumSig.
⋮----
// Mockconn is a mock of conn interface.
type Mockconn struct {
	ctrl     *gomock.Controller
	recorder *MockconnMockRecorder
	isgomock struct{}
⋮----
// MockconnMockRecorder is the mock recorder for Mockconn.
type MockconnMockRecorder struct {
	mock *Mockconn
}
⋮----
// NewMockconn creates a new mock instance.
func NewMockconn(ctrl *gomock.Controller) *Mockconn
⋮----
// CallContract mocks base method.
func (m *Mockconn) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
⋮----
// CallContract indicates an expected call of CallContract.
⋮----
// CodeAt mocks base method.
func (m *Mockconn) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error)
⋮----
// CodeAt indicates an expected call of CodeAt.
⋮----
// EstimateGas mocks base method.
func (m *Mockconn) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error)
⋮----
// EstimateGas indicates an expected call of EstimateGas.
⋮----
// FilterLogs mocks base method.
func (m *Mockconn) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)
⋮----
// FilterLogs indicates an expected call of FilterLogs.
⋮----
// HeaderByNumber mocks base method.
func (m *Mockconn) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
⋮----
// HeaderByNumber indicates an expected call of HeaderByNumber.
⋮----
// PendingCodeAt mocks base method.
func (m *Mockconn) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error)
⋮----
// PendingCodeAt indicates an expected call of PendingCodeAt.
⋮----
// PendingNonceAt mocks base method.
func (m *Mockconn) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
⋮----
// PendingNonceAt indicates an expected call of PendingNonceAt.
⋮----
// SendTransaction mocks base method.
func (m *Mockconn) SendTransaction(ctx context.Context, tx *types.Transaction) error
⋮----
// SendTransaction indicates an expected call of SendTransaction.
⋮----
// SubscribeFilterLogs mocks base method.
func (m *Mockconn) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
⋮----
// SubscribeFilterLogs indicates an expected call of SubscribeFilterLogs.
⋮----
// SuggestGasPrice mocks base method.
func (m *Mockconn) SuggestGasPrice(ctx context.Context) (*big.Int, error)
⋮----
// SuggestGasPrice indicates an expected call of SuggestGasPrice.
⋮----
// SuggestGasTipCap mocks base method.
func (m *Mockconn) SuggestGasTipCap(ctx context.Context) (*big.Int, error)
⋮----
// SuggestGasTipCap indicates an expected call of SuggestGasTipCap.
⋮----
// TransactionReceipt mocks base method.
func (m *Mockconn) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
⋮----
// TransactionReceipt indicates an expected call of TransactionReceipt.
⋮----
// Mockmetrics is a mock of metrics interface.
type Mockmetrics struct {
	ctrl     *gomock.Controller
	recorder *MockmetricsMockRecorder
	isgomock struct{}
⋮----
// MockmetricsMockRecorder is the mock recorder for Mockmetrics.
type MockmetricsMockRecorder struct {
	mock *Mockmetrics
}
⋮----
// NewMockmetrics creates a new mock instance.
func NewMockmetrics(ctrl *gomock.Controller) *Mockmetrics
⋮----
// ObserveCommitValsetHeaderParams mocks base method.
func (m *Mockmetrics) ObserveCommitValsetHeaderParams(chainID, gasUsed uint64, effectiveGasPrice *big.Int)
⋮----
// ObserveCommitValsetHeaderParams indicates an expected call of ObserveCommitValsetHeaderParams.
⋮----
// ObserveEVMMethodCall mocks base method.
func (m *Mockmetrics) ObserveEVMMethodCall(method string, chainID uint64, status string, d time.Duration)
⋮----
// ObserveEVMMethodCall indicates an expected call of ObserveEVMMethodCall.
⋮----
// MockkeyProvider is a mock of keyProvider interface.
type MockkeyProvider struct {
	ctrl     *gomock.Controller
	recorder *MockkeyProviderMockRecorder
	isgomock struct{}
⋮----
// MockkeyProviderMockRecorder is the mock recorder for MockkeyProvider.
type MockkeyProviderMockRecorder struct {
	mock *MockkeyProvider
}
⋮----
// NewMockkeyProvider creates a new mock instance.
func NewMockkeyProvider(ctrl *gomock.Controller) *MockkeyProvider
⋮----
// GetPrivateKeyByNamespaceTypeId mocks base method.
func (m *MockkeyProvider) GetPrivateKeyByNamespaceTypeId(namespace string, keyType entity.KeyType, id int) (crypto.PrivateKey, error)
⋮----
// GetPrivateKeyByNamespaceTypeId indicates an expected call of GetPrivateKeyByNamespaceTypeId.
⋮----
// MockdriverContract is a mock of driverContract interface.
type MockdriverContract struct {
	ctrl     *gomock.Controller
	recorder *MockdriverContractMockRecorder
	isgomock struct{}
⋮----
// MockdriverContractMockRecorder is the mock recorder for MockdriverContract.
type MockdriverContractMockRecorder struct {
	mock *MockdriverContract
}
⋮----
// NewMockdriverContract creates a new mock instance.
func NewMockdriverContract(ctrl *gomock.Controller) *MockdriverContract
⋮----
// AddSettlement mocks base method.
func (m *MockdriverContract) AddSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// AddSettlement indicates an expected call of AddSettlement.
⋮----
// GetConfigAt mocks base method.
func (m *MockdriverContract) GetConfigAt(opts *bind.CallOpts, timestamp *big.Int) (gen.IValSetDriverConfig, error)
⋮----
// GetConfigAt indicates an expected call of GetConfigAt.
⋮----
// NETWORK mocks base method.
func (m *MockdriverContract) NETWORK(opts *bind.CallOpts) (common.Address, error)
⋮----
// NETWORK indicates an expected call of NETWORK.
⋮----
// RemoveSettlement mocks base method.
func (m *MockdriverContract) RemoveSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
// RemoveSettlement indicates an expected call of RemoveSettlement.
⋮----
// SUBNETWORK mocks base method.
func (m *MockdriverContract) SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
⋮----
// SUBNETWORK indicates an expected call of SUBNETWORK.
⋮----
// MocksettlementContract is a mock of settlementContract interface.
type MocksettlementContract struct {
	ctrl     *gomock.Controller
	recorder *MocksettlementContractMockRecorder
	isgomock struct{}
⋮----
// MocksettlementContractMockRecorder is the mock recorder for MocksettlementContract.
type MocksettlementContractMockRecorder struct {
	mock *MocksettlementContract
}
⋮----
// NewMocksettlementContract creates a new mock instance.
func NewMocksettlementContract(ctrl *gomock.Controller) *MocksettlementContract
⋮----
// CommitValSetHeader mocks base method.
func (m *MocksettlementContract) CommitValSetHeader(opts *bind.TransactOpts, header gen.ISettlementValSetHeader, extraData []gen.ISettlementExtraData, proof []byte) (*types.Transaction, error)
⋮----
// CommitValSetHeader indicates an expected call of CommitValSetHeader.
⋮----
// Eip712Domain mocks base method.
func (m *MocksettlementContract) Eip712Domain(opts *bind.CallOpts) (entity.Eip712Domain, error)
⋮----
// Eip712Domain indicates an expected call of Eip712Domain.
⋮----
// GetCaptureTimestampFromValSetHeaderAt mocks base method.
func (m *MocksettlementContract) GetCaptureTimestampFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
// GetCaptureTimestampFromValSetHeaderAt indicates an expected call of GetCaptureTimestampFromValSetHeaderAt.
⋮----
// GetValSetHeaderHash mocks base method.
func (m *MocksettlementContract) GetValSetHeaderHash(opts *bind.CallOpts) ([32]byte, error)
⋮----
// GetValSetHeaderHash indicates an expected call of GetValSetHeaderHash.
⋮----
// GetValSetHeaderHashAt mocks base method.
func (m *MocksettlementContract) GetValSetHeaderHashAt(opts *bind.CallOpts, epoch *big.Int) ([32]byte, error)
⋮----
// GetValSetHeaderHashAt indicates an expected call of GetValSetHeaderHashAt.
⋮----
// IsValSetHeaderCommittedAt mocks base method.
func (m *MocksettlementContract) IsValSetHeaderCommittedAt(opts *bind.CallOpts, epoch *big.Int) (bool, error)
⋮----
// IsValSetHeaderCommittedAt indicates an expected call of IsValSetHeaderCommittedAt.
⋮----
// VerifyQuorumSigAt mocks base method.
func (m *MocksettlementContract) VerifyQuorumSigAt(opts *bind.CallOpts, message []byte, keyTag uint8, quorumThreshold *big.Int, proof []byte, epoch *big.Int, hint []byte) (bool, error)
⋮----
// VerifyQuorumSigAt indicates an expected call of VerifyQuorumSigAt.
⋮----
// MockvotingPowerProviderContract is a mock of votingPowerProviderContract interface.
type MockvotingPowerProviderContract struct {
	ctrl     *gomock.Controller
	recorder *MockvotingPowerProviderContractMockRecorder
	isgomock struct{}
⋮----
// MockvotingPowerProviderContractMockRecorder is the mock recorder for MockvotingPowerProviderContract.
type MockvotingPowerProviderContractMockRecorder struct {
	mock *MockvotingPowerProviderContract
}
⋮----
// NewMockvotingPowerProviderContract creates a new mock instance.
func NewMockvotingPowerProviderContract(ctrl *gomock.Controller) *MockvotingPowerProviderContract
⋮----
// GetOperatorsAt mocks base method.
func (m *MockvotingPowerProviderContract) GetOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetOperatorsAt indicates an expected call of GetOperatorsAt.
⋮----
// GetVotingPowersAt mocks base method.
func (m *MockvotingPowerProviderContract) GetVotingPowersAt(opts *bind.CallOpts, extraData [][]byte, timestamp *big.Int) ([]gen.IVotingPowerProviderOperatorVotingPower, error)
⋮----
// GetVotingPowersAt indicates an expected call of GetVotingPowersAt.
⋮----
// IsOperatorRegistered mocks base method.
func (m *MockvotingPowerProviderContract) IsOperatorRegistered(opts *bind.CallOpts, operator common.Address) (bool, error)
⋮----
// IsOperatorRegistered indicates an expected call of IsOperatorRegistered.
⋮----
// Nonces mocks base method.
func (m *MockvotingPowerProviderContract) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error)
⋮----
// Nonces indicates an expected call of Nonces.
⋮----
// MockvotingPowerProviderTransactor is a mock of votingPowerProviderTransactor interface.
type MockvotingPowerProviderTransactor struct {
	ctrl     *gomock.Controller
	recorder *MockvotingPowerProviderTransactorMockRecorder
	isgomock struct{}
⋮----
// MockvotingPowerProviderTransactorMockRecorder is the mock recorder for MockvotingPowerProviderTransactor.
type MockvotingPowerProviderTransactorMockRecorder struct {
	mock *MockvotingPowerProviderTransactor
}
⋮----
// NewMockvotingPowerProviderTransactor creates a new mock instance.
func NewMockvotingPowerProviderTransactor(ctrl *gomock.Controller) *MockvotingPowerProviderTransactor
⋮----
// UnregisterOperator mocks base method.
func (m *MockvotingPowerProviderTransactor) UnregisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
// UnregisterOperator indicates an expected call of UnregisterOperator.
⋮----
// MockkeyRegistryContract is a mock of keyRegistryContract interface.
type MockkeyRegistryContract struct {
	ctrl     *gomock.Controller
	recorder *MockkeyRegistryContractMockRecorder
	isgomock struct{}
⋮----
// MockkeyRegistryContractMockRecorder is the mock recorder for MockkeyRegistryContract.
type MockkeyRegistryContractMockRecorder struct {
	mock *MockkeyRegistryContract
}
⋮----
// NewMockkeyRegistryContract creates a new mock instance.
func NewMockkeyRegistryContract(ctrl *gomock.Controller) *MockkeyRegistryContract
⋮----
// GetKeysAt mocks base method.
func (m *MockkeyRegistryContract) GetKeysAt(opts *bind.CallOpts, timestamp *big.Int) ([]gen.IKeyRegistryOperatorWithKeys, error)
⋮----
// GetKeysAt indicates an expected call of GetKeysAt.
⋮----
// GetKeysOperatorsAt mocks base method.
func (m *MockkeyRegistryContract) GetKeysOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
// GetKeysOperatorsAt indicates an expected call of GetKeysOperatorsAt.
⋮----
// SetKey mocks base method.
func (m *MockkeyRegistryContract) SetKey(opts *bind.TransactOpts, tag uint8, key, signature, extraData []byte) (*types.Transaction, error)
⋮----
// SetKey indicates an expected call of SetKey.
⋮----
// MockoperatorRegistryContract is a mock of operatorRegistryContract interface.
type MockoperatorRegistryContract struct {
	ctrl     *gomock.Controller
	recorder *MockoperatorRegistryContractMockRecorder
	isgomock struct{}
⋮----
// MockoperatorRegistryContractMockRecorder is the mock recorder for MockoperatorRegistryContract.
type MockoperatorRegistryContractMockRecorder struct {
	mock *MockoperatorRegistryContract
}
⋮----
// NewMockoperatorRegistryContract creates a new mock instance.
func NewMockoperatorRegistryContract(ctrl *gomock.Controller) *MockoperatorRegistryContract
```

## File: symbiotic/client/evm/eth_commit_valset.go

```go
package evm
⋮----
import (
	"context"
	"log/slog"
	"math/big"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"log/slog"
"math/big"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (e *Client) CommitValsetHeader(
	ctx context.Context,
	addr symbiotic.CrossChainAddress,
	header symbiotic.ValidatorSetHeader,
	extraData []symbiotic.ExtraData,
	proof []byte,
) (_ symbiotic.TxResult, err error)
```

## File: symbiotic/client/evm/eth_operator.go

```go
package evm
⋮----
import (
	"context"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"time"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (e *Client) RegisterOperator(
	ctx context.Context,
	opRegistryAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) RegisterKey(
	ctx context.Context,
	keyRegistryAddr symbiotic.CrossChainAddress,
	keyTag symbiotic.KeyTag,
	key symbiotic.CompactPublicKey,
	signature symbiotic.RawSignature,
	extraData []byte,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) InvalidateOldSignatures(
	ctx context.Context,
	votingPowerProviderAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) RegisterOperatorVotingPowerProvider(
	ctx context.Context,
	votingPowerProviderAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) IsOperatorRegistered(
	ctx context.Context,
	votingPowerProviderAddr, operator symbiotic.CrossChainAddress,
) (_ bool, err error)
⋮----
func (e *Client) UnregisterOperatorVotingPowerProvider(
	ctx context.Context,
	votingPowerProviderAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
```

## File: symbiotic/client/evm/eth_set_genesis_test.go

```go
package evm
⋮----
import (
	"context"
	"crypto/ecdsa"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"crypto/ecdsa"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type mockPrivateKey struct {
	key *ecdsa.PrivateKey
}
⋮----
func (m *mockPrivateKey) Bytes() []byte
⋮----
func (m *mockPrivateKey) Sign(msg []byte) (symbiotic.RawSignature, symbiotic.MessageHash, error)
⋮----
func (m *mockPrivateKey) PublicKey() symbiotic.PublicKey
⋮----
func TestSetGenesis_NoSettlementContract_ReturnsError(t *testing.T)
⋮----
func TestSetGenesis_KeyProviderFails_ReturnsError(t *testing.T)
⋮----
func TestSetGenesis_InvalidECDSAKey_ReturnsError(t *testing.T)
⋮----
func TestSetGenesis_InvalidChainID_ReturnsError(t *testing.T)
⋮----
func TestSetGenesis_PartialHappyPath_ValidatesDataPreparation(t *testing.T)
```

## File: symbiotic/client/evm/eth_set_genesis.go

```go
package evm
⋮----
import (
	"context"
	"math/big"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (e *Client) SetGenesis(
	ctx context.Context,
	addr symbiotic.CrossChainAddress,
	header symbiotic.ValidatorSetHeader,
	extraData []symbiotic.ExtraData,
) (_ symbiotic.TxResult, err error)
```

## File: symbiotic/client/evm/eth_settlement.go

```go
package evm
⋮----
import (
	"context"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"

	keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"time"
⋮----
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (e *Client) RemoveSettlement(
	ctx context.Context,
	settlementAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) AddSettlement(
	ctx context.Context,
	settlementAddr symbiotic.CrossChainAddress,
) (_ symbiotic.TxResult, err error)
⋮----
func (e *Client) doTransaction(ctx context.Context, method string, addr symbiotic.CrossChainAddress, f func(opts *bind.TransactOpts) (*types.Transaction, error), opts ...symbiotic.EVMOption) (symbiotic.TxResult, error)
⋮----
gasPrice = 2_000_000_000 // default: 2 GWei
⋮----
// If GasLimitMultiplier is set, estimate gas and apply multiplier
```

## File: symbiotic/client/evm/eth_test.go

```go
package evm
⋮----
import (
	"context"
	"errors"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"errors"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestGetChains_WithMultipleChains_ReturnsAllChainIDs(t *testing.T)
⋮----
func TestGetChains_WithNoChains_ReturnsEmptySlice(t *testing.T)
⋮----
func TestGetChains_WithSingleChain_ReturnsSingleChainID(t *testing.T)
⋮----
func TestObserveMetrics_WithMetricsEnabled_CallsObserveEVMMethodCall(t *testing.T)
⋮----
func TestObserveMetrics_WithError_CallsWithErrorStatus(t *testing.T)
⋮----
func TestObserveMetrics_WithNilMetrics_DoesNotPanic(t *testing.T)
⋮----
func TestIsValsetHeaderCommittedAt_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetHeaderHash_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetHeaderHashAt_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetLastCommittedHeaderEpoch_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetCaptureTimestampFromValsetHeaderAt_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetValSetHeaderAt_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetValSetHeader_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetEip712Domain_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetVotingPowerProviderEip712Domain_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetOperatorNonce_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetVotingPowers_MulticallCheckFails_ReturnsError(t *testing.T)
⋮----
func TestGetOperators_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetKeysOperators_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetKeys_MulticallCheckFails_ReturnsError(t *testing.T)
⋮----
func TestIsValsetHeaderCommittedAtEpochs_MulticallCheckFails_ReturnsError(t *testing.T)
⋮----
func TestGetSubnetwork_Success_ReturnsSubnetworkHash(t *testing.T)
⋮----
func TestGetSubnetwork_DriverError_ReturnsError(t *testing.T)
⋮----
func TestGetNetworkAddress_Success_ReturnsNetworkAddress(t *testing.T)
⋮----
func TestGetNetworkAddress_DriverError_ReturnsError(t *testing.T)
⋮----
func TestFormatEVMContractError_WithNonJSONError_ReturnsOriginalError(t *testing.T)
⋮----
func TestGetVotingPowers_WithNoMulticall_ReturnsError(t *testing.T)
⋮----
func TestGetKeys_WithNoMulticall_ReturnsError(t *testing.T)
⋮----
func TestGetSettlementContract_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetSettlementContract_WithConnection_ReturnsContract(t *testing.T)
⋮----
func TestGetVotingPowerProviderContract_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetVotingPowerProviderContract_WithConnection_ReturnsContract(t *testing.T)
⋮----
func TestGetVotingPowerProviderContractTransactor_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetVotingPowerProviderContractTransactor_WithConnection_ReturnsContract(t *testing.T)
⋮----
func TestGetKeyRegistryContract_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetKeyRegistryContract_WithConnection_ReturnsContract(t *testing.T)
⋮----
func TestGetOperatorRegistryContract_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestGetOperatorRegistryContract_WithConnection_ReturnsContract(t *testing.T)
⋮----
func TestGetCurrentEpoch_Success_ReturnsEpoch(t *testing.T)
⋮----
func TestGetCurrentEpoch_DriverError_ReturnsError(t *testing.T)
⋮----
func TestGetCurrentEpochDuration_Success_ReturnsDuration(t *testing.T)
⋮----
func TestGetCurrentEpochDuration_DriverError_ReturnsError(t *testing.T)
⋮----
func TestGetEpochDuration_Success_ReturnsDuration(t *testing.T)
⋮----
func TestGetEpochDuration_DriverError_ReturnsError(t *testing.T)
⋮----
func TestGetEpochStart_Success_ReturnsTimestamp(t *testing.T)
⋮----
func TestGetEpochStart_DriverError_ReturnsError(t *testing.T)
⋮----
func TestGetConfig_Success_ReturnsConfig(t *testing.T)
⋮----
func TestGetConfig_GetConfigAtError_ReturnsError(t *testing.T)
⋮----
func TestGetConfig_GetEpochDurationError_ReturnsError(t *testing.T)
```

## File: symbiotic/client/evm/eth_tracing.go

```go
package evm
⋮----
import (
	"context"
	"fmt"
	"math/big"
	"strconv"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/pkg/tracing"
	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"fmt"
"math/big"
"strconv"
⋮----
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/pkg/tracing"
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type tracingDriver struct {
	base driverContract
}
⋮----
type tracingConn struct {
	base    conn
	chainID uint64
}
⋮----
var (
	_ conn                         = (*tracingConn)(nil)
⋮----
func newTracingConn(chainID uint64, base conn) conn
⋮----
func (t *tracingConn) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error)
⋮----
func (t *tracingConn) CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error)
⋮----
func (t *tracingConn) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
⋮----
func (t *tracingConn) CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error)
⋮----
func (t *tracingConn) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
⋮----
func (t *tracingConn) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
⋮----
func (t *tracingConn) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error)
⋮----
func (t *tracingConn) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
⋮----
func (t *tracingConn) SuggestGasPrice(ctx context.Context) (*big.Int, error)
⋮----
func (t *tracingConn) SuggestGasTipCap(ctx context.Context) (*big.Int, error)
⋮----
func (t *tracingConn) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error)
⋮----
func (t *tracingConn) SendTransaction(ctx context.Context, tx *types.Transaction) error
⋮----
func (t *tracingConn) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)
⋮----
func (t *tracingConn) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
⋮----
func (t *tracingConn) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
⋮----
func (t *tracingConn) spanAttributes(method string, extra ...attribute.KeyValue) []attribute.KeyValue
⋮----
func blockNumberValue(blockNumber *big.Int) string
⋮----
func bigIntValue(value *big.Int) string
⋮----
func callMsgAttributes(call ethereum.CallMsg) []attribute.KeyValue
⋮----
func filterQueryAttributes(q ethereum.FilterQuery) []attribute.KeyValue
⋮----
func optionalAddressHex(addr *common.Address) string
⋮----
func (t tracingDriver) GetConfigAt(opts *bind.CallOpts, timestamp *big.Int) (gen.IValSetDriverConfig, error)
⋮----
func (t tracingDriver) GetCurrentEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
func (t tracingDriver) GetCurrentEpochDuration(opts *bind.CallOpts) (*big.Int, error)
⋮----
func (t tracingDriver) GetEpochDuration(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
func (t tracingDriver) GetEpochStart(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
func (t tracingDriver) SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
⋮----
func (t tracingDriver) NETWORK(opts *bind.CallOpts) (common.Address, error)
⋮----
func (t tracingDriver) RemoveSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
func (t tracingDriver) AddSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
⋮----
type tracingSettlement struct {
	base settlementContract
}
⋮----
func (t tracingSettlement) IsValSetHeaderCommittedAt(opts *bind.CallOpts, epoch *big.Int) (bool, error)
⋮----
func (t tracingSettlement) GetValSetHeaderHash(opts *bind.CallOpts) ([32]byte, error)
⋮----
func (t tracingSettlement) GetValSetHeaderHashAt(opts *bind.CallOpts, epoch *big.Int) ([32]byte, error)
⋮----
func (t tracingSettlement) GetLastCommittedHeaderEpoch(opts *bind.CallOpts) (*big.Int, error)
⋮----
func (t tracingSettlement) GetCaptureTimestampFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
⋮----
func (t tracingSettlement) GetValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (gen.ISettlementValSetHeader, error)
⋮----
func (t tracingSettlement) GetValSetHeader(opts *bind.CallOpts) (gen.ISettlementValSetHeader, error)
⋮----
func (t tracingSettlement) Eip712Domain(opts *bind.CallOpts) (symbiotic.Eip712Domain, error)
⋮----
func (t tracingSettlement) CommitValSetHeader(opts *bind.TransactOpts, header gen.ISettlementValSetHeader, extraData []gen.ISettlementExtraData, proof []byte) (*types.Transaction, error)
⋮----
func (t tracingSettlement) SetGenesis(opts *bind.TransactOpts, valSetHeader gen.ISettlementValSetHeader, extraData []gen.ISettlementExtraData) (*types.Transaction, error)
⋮----
func (t tracingSettlement) VerifyQuorumSigAt(opts *bind.CallOpts, message []byte, keyTag uint8, quorumThreshold *big.Int, proof []byte, epoch *big.Int, hint []byte) (bool, error)
⋮----
type tracingVotingPowerProvider struct {
	base votingPowerProviderContract
}
⋮----
func (t tracingVotingPowerProvider) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error)
⋮----
func (t tracingVotingPowerProvider) GetVotingPowersAt(opts *bind.CallOpts, extraData [][]byte, timestamp *big.Int) ([]gen.IVotingPowerProviderOperatorVotingPower, error)
⋮----
func (t tracingVotingPowerProvider) GetOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
func (t tracingVotingPowerProvider) IsOperatorRegistered(opts *bind.CallOpts, operator common.Address) (bool, error)
⋮----
type tracingVotingPowerProviderTransactor struct {
	base votingPowerProviderTransactor
}
⋮----
func (t tracingVotingPowerProviderTransactor) InvalidateOldSignatures(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
func (t tracingVotingPowerProviderTransactor) RegisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
func (t tracingVotingPowerProviderTransactor) UnregisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
⋮----
type tracingKeyRegistry struct {
	base keyRegistryContract
}
⋮----
func (t tracingKeyRegistry) GetKeysOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
⋮----
func (t tracingKeyRegistry) GetKeysAt(opts *bind.CallOpts, timestamp *big.Int) ([]gen.IKeyRegistryOperatorWithKeys, error)
⋮----
func (t tracingKeyRegistry) SetKey(opts *bind.TransactOpts, tag uint8, key []byte, signature []byte, extraData []byte) (*types.Transaction, error)
⋮----
type tracingOperatorRegistry struct {
	base operatorRegistryContract
}
```

## File: symbiotic/client/evm/eth_verify_quorum_sig_test.go

```go
package evm
⋮----
import (
	"context"
	"math/big"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestVerifyQuorumSig_NoSettlementContract_ReturnsError(t *testing.T)
⋮----
func TestVerifyQuorumSig_ContextTimeout_ReturnsError(t *testing.T)
⋮----
func TestVerifyQuorumSig_InvalidChainID_ReturnsError(t *testing.T)
⋮----
func TestVerifyQuorumSig_EmptyProof_HandlesCorrectly(t *testing.T)
⋮----
func TestVerifyQuorumSig_EmptyMessage_HandlesCorrectly(t *testing.T)
⋮----
func TestVerifyQuorumSig_NilThreshold_HandlesCorrectly(t *testing.T)
⋮----
func TestVerifyQuorumSig_ZeroEpoch_HandlesCorrectly(t *testing.T)
```

## File: symbiotic/client/evm/eth_verify_quorum_sig.go

```go
package evm
⋮----
import (
	"context"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"time"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/rpc"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func (e *Client) VerifyQuorumSig(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, message []byte, keyTag symbiotic.KeyTag, threshold *big.Int, proof []byte) (_ bool, err error)
```

## File: symbiotic/client/evm/eth.go

```go
package evm
⋮----
import (
	"context"
	_ "embed"
	"encoding/hex"
	"log/slog"
	"math/big"
	"net/http"
	"regexp"
	"time"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/samber/lo"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/go-errors/errors"
	"github.com/go-playground/validator/v10"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	cryptoSym "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
)
⋮----
"context"
_ "embed"
"encoding/hex"
"log/slog"
"math/big"
"net/http"
"regexp"
"time"
⋮----
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
"github.com/samber/lo"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
cryptoSym "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
//go:generate mockgen -destination=mocks/eth.go -package=mocks github.com/symbioticfi/relay/symbiotic/client/evm IEvmClient,conn,metrics,keyProvider,driverContract,settlementContract,votingPowerProviderContract,votingPowerProviderTransactor,keyRegistryContract,operatorRegistryContract
⋮----
type metrics interface {
	ObserveEVMMethodCall(method string, chainID uint64, status string, d time.Duration)
	ObserveCommitValsetHeaderParams(chainID uint64, gasUsed uint64, effectiveGasPrice *big.Int)
}
⋮----
// IEvmClient defines the interface for EVM client operations
type IEvmClient interface {
	GetChains() []uint64
	GetSubnetwork(ctx context.Context) (common.Hash, error)
	GetNetworkAddress(ctx context.Context) (common.Address, error)
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.Eip712Domain, error)
	GetVotingPowerProviderEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.Eip712Domain, error)
	GetOperatorNonce(ctx context.Context, votingPowerProvider symbiotic.CrossChainAddress, operator common.Address) (*big.Int, error)
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetCurrentEpochDuration(ctx context.Context) (uint64, error)
	GetEpochDuration(ctx context.Context, epoch symbiotic.Epoch) (uint64, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	IsValsetHeaderCommittedAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, opts ...symbiotic.EVMOption) (bool, error)
	GetHeaderHash(ctx context.Context, addr symbiotic.CrossChainAddress) (common.Hash, error)
	GetHeaderHashAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (common.Hash, error)
	GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, evmOptions ...symbiotic.EVMOption) (symbiotic.Epoch, error)
	GetCaptureTimestampFromValsetHeaderAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (uint64, error)
	GetValSetHeaderAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (symbiotic.ValidatorSetHeader, error)
	GetValSetHeader(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.ValidatorSetHeader, error)
	GetVotingPowers(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorVotingPower, error)
	GetKeys(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorWithKeys, error)
	CommitValsetHeader(ctx context.Context, addr symbiotic.CrossChainAddress, header symbiotic.ValidatorSetHeader, extraData []symbiotic.ExtraData, proof []byte) (symbiotic.TxResult, error)
	RegisterOperator(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.TxResult, error)
	RegisterKey(ctx context.Context, addr symbiotic.CrossChainAddress, keyTag symbiotic.KeyTag, key symbiotic.CompactPublicKey, signature symbiotic.RawSignature, extraData []byte) (symbiotic.TxResult, error)
	InvalidateOldSignatures(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.TxResult, error)
	RegisterOperatorVotingPowerProvider(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.TxResult, error)
	UnregisterOperatorVotingPowerProvider(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.TxResult, error)
	SetGenesis(ctx context.Context, addr symbiotic.CrossChainAddress, header symbiotic.ValidatorSetHeader, extraData []symbiotic.ExtraData) (symbiotic.TxResult, error)
	VerifyQuorumSig(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, message []byte, keyTag symbiotic.KeyTag, threshold *big.Int, proof []byte) (bool, error)
	IsValsetHeaderCommittedAtEpochs(ctx context.Context, addr symbiotic.CrossChainAddress, epochs []symbiotic.Epoch) ([]bool, error)
}
⋮----
type keyProvider interface {
	GetPrivateKeyByNamespaceTypeId(namespace string, keyType symbiotic.KeyType, id int) (cryptoSym.PrivateKey, error)
}
⋮----
// conn defines the interface for Ethereum client operations
// ethclient.Client implements this interface
type conn interface {
	bind.ContractBackend
	bind.DeployBackend
}
⋮----
var _ driverContract = (*gen.ValSetDriver)(nil)
⋮----
// driverContract defines the interface for driver contract operations
// gen.ValSetDriverCaller implements this interface
type driverContract interface {
	// read-only methods
	GetConfigAt(opts *bind.CallOpts, timestamp *big.Int) (gen.IValSetDriverConfig, error)
	GetCurrentEpoch(opts *bind.CallOpts) (*big.Int, error)
	GetCurrentEpochDuration(opts *bind.CallOpts) (*big.Int, error)
	GetEpochDuration(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
	GetEpochStart(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
	SUBNETWORK(opts *bind.CallOpts) ([32]byte, error)
	NETWORK(opts *bind.CallOpts) (common.Address, error)

	// write-only methods
	RemoveSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
	AddSettlement(opts *bind.TransactOpts, settlement gen.IValSetDriverCrossChainAddress) (*types.Transaction, error)
}
⋮----
// read-only methods
⋮----
// write-only methods
⋮----
type settlementContract interface {
	IsValSetHeaderCommittedAt(opts *bind.CallOpts, epoch *big.Int) (bool, error)
	GetValSetHeaderHash(opts *bind.CallOpts) ([32]byte, error)
	GetValSetHeaderHashAt(opts *bind.CallOpts, epoch *big.Int) ([32]byte, error)
	GetLastCommittedHeaderEpoch(opts *bind.CallOpts) (*big.Int, error)
	GetCaptureTimestampFromValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (*big.Int, error)
	GetValSetHeaderAt(opts *bind.CallOpts, epoch *big.Int) (gen.ISettlementValSetHeader, error)
	GetValSetHeader(opts *bind.CallOpts) (gen.ISettlementValSetHeader, error)
	Eip712Domain(opts *bind.CallOpts) (symbiotic.Eip712Domain, error)

	CommitValSetHeader(opts *bind.TransactOpts, header gen.ISettlementValSetHeader, extraData []gen.ISettlementExtraData, proof []byte) (*types.Transaction, error)
	SetGenesis(opts *bind.TransactOpts, valSetHeader gen.ISettlementValSetHeader, extraData []gen.ISettlementExtraData) (*types.Transaction, error)
	VerifyQuorumSigAt(opts *bind.CallOpts, message []byte, keyTag uint8, quorumThreshold *big.Int, proof []byte, epoch *big.Int, hint []byte) (bool, error)
}
⋮----
type votingPowerProviderContract interface {
	Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error)
	GetVotingPowersAt(opts *bind.CallOpts, extraData [][]byte, timestamp *big.Int) ([]gen.IVotingPowerProviderOperatorVotingPower, error)
	GetOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
	Eip712Domain(opts *bind.CallOpts) (symbiotic.Eip712Domain, error)
	IsOperatorRegistered(opts *bind.CallOpts, operator common.Address) (bool, error)
}
⋮----
type votingPowerProviderTransactor interface {
	InvalidateOldSignatures(opts *bind.TransactOpts) (*types.Transaction, error)
	RegisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
	UnregisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
}
⋮----
type keyRegistryContract interface {
	GetKeysOperatorsAt(opts *bind.CallOpts, timestamp *big.Int) ([]common.Address, error)
	GetKeysAt(opts *bind.CallOpts, timestamp *big.Int) ([]gen.IKeyRegistryOperatorWithKeys, error)
	SetKey(opts *bind.TransactOpts, tag uint8, key []byte, signature []byte, extraData []byte) (*types.Transaction, error)
}
⋮----
type operatorRegistryContract interface {
	RegisterOperator(opts *bind.TransactOpts) (*types.Transaction, error)
}
⋮----
type Config struct {
	ChainURLs         []string                    `validate:"required"`
	DriverAddress     symbiotic.CrossChainAddress `validate:"required"`
	RequestTimeout    time.Duration               `validate:"required,gt=0"`
	KeyProvider       keyProvider
	Metrics           metrics
	MaxCalls          int
	FallbackGasPrices map[uint64]uint64 // Per-chain gas price in wei when eth_maxPriorityFeePerGas is not supported (default: 2 GWei)
}
⋮----
FallbackGasPrices map[uint64]uint64 // Per-chain gas price in wei when eth_maxPriorityFeePerGas is not supported (default: 2 GWei)
⋮----
func (c Config) Validate() error
⋮----
type Client struct {
	cfg Config

	conns         map[uint64]clientWithInfo
	driver        driverContract
	driverChainID uint64

	metrics metrics
}
⋮----
type clientWithInfo struct {
	conn

	hasMaxPriorityFeePerGasMethod bool
}
⋮----
func NewEvmClient(ctx context.Context, cfg Config) (*Client, error)
⋮----
var tip *hexutil.Big
⋮----
var httpError rpc.HTTPError
⋮----
func (e *Client) GetChains() []uint64
⋮----
func (e *Client) GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (_ symbiotic.NetworkConfig, err error)
⋮----
func (e *Client) GetCurrentEpoch(ctx context.Context) (_ symbiotic.Epoch, err error)
⋮----
func (e *Client) GetCurrentEpochDuration(ctx context.Context) (_ uint64, err error)
⋮----
func (e *Client) GetEpochDuration(ctx context.Context, epoch symbiotic.Epoch) (_ uint64, err error)
⋮----
func (e *Client) GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (_ symbiotic.Timestamp, err error)
⋮----
func (e *Client) GetSubnetwork(ctx context.Context) (_ common.Hash, err error)
⋮----
func (e *Client) GetNetworkAddress(ctx context.Context) (_ common.Address, err error)
⋮----
func (e *Client) IsValsetHeaderCommittedAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, opts ...symbiotic.EVMOption) (_ bool, err error)
⋮----
func (e *Client) GetHeaderHash(ctx context.Context, addr symbiotic.CrossChainAddress) (_ common.Hash, err error)
⋮----
func (e *Client) GetHeaderHashAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (_ common.Hash, err error)
⋮----
func (e *Client) GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, opts ...symbiotic.EVMOption) (_ symbiotic.Epoch, err error)
⋮----
// todo if zero epoch need to check if it's committed or not
⋮----
func getRPCBlockNumber(number symbiotic.BlockNumber) *big.Int
⋮----
func (e *Client) GetCaptureTimestampFromValsetHeaderAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (_ uint64, err error)
⋮----
func (e *Client) GetValSetHeaderAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (_ symbiotic.ValidatorSetHeader, err error)
⋮----
func (e *Client) GetValSetHeader(ctx context.Context, addr symbiotic.CrossChainAddress) (_ symbiotic.ValidatorSetHeader, err error)
⋮----
func (e *Client) GetEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (_ symbiotic.Eip712Domain, err error)
⋮----
func (e *Client) GetVotingPowerProviderEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (_ symbiotic.Eip712Domain, err error)
⋮----
func (e *Client) GetOperatorNonce(ctx context.Context, votingPowerProvider symbiotic.CrossChainAddress, operator common.Address) (_ *big.Int, err error)
⋮----
func (e *Client) GetVotingPowers(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) (_ []symbiotic.OperatorVotingPower, err error)
⋮----
func (e *Client) GetOperators(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) (_ []common.Address, err error)
⋮----
func (e *Client) GetKeysOperators(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) (_ []common.Address, err error)
⋮----
func (e *Client) GetKeys(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) (_ []symbiotic.OperatorWithKeys, err error)
⋮----
func (e *Client) IsValsetHeaderCommittedAtEpochs(ctx context.Context, addr symbiotic.CrossChainAddress, epochs []symbiotic.Epoch) (_ []bool, err error)
⋮----
var res bool
⋮----
var customErrRegExp = regexp.MustCompile(`0x[0-9a-fA-F]{8}`)
⋮----
type metadata interface {
	GetAbi() (*abi.ABI, error)
}
⋮----
func (e *Client) formatEVMContractError(meta metadata, originalErr error) error
⋮----
type jsonError interface {
		Error() string
		ErrorData() interface{}
var errData jsonError
⋮----
func (e *Client) formatEVMError(err error) error
⋮----
func (e *Client) getSettlementContract(addr symbiotic.CrossChainAddress) (settlementContract, error)
⋮----
func (e *Client) getVotingPowerProviderContract(addr symbiotic.CrossChainAddress) (votingPowerProviderContract, error)
⋮----
func (e *Client) getVotingPowerProviderContractTransactor(addr symbiotic.CrossChainAddress) (votingPowerProviderTransactor, error)
⋮----
func (e *Client) getKeyRegistryContract(addr symbiotic.CrossChainAddress) (keyRegistryContract, error)
⋮----
func (e *Client) getOperatorRegistryContract(addr symbiotic.CrossChainAddress) (operatorRegistryContract, error)
⋮----
func findErrorBySelector(errSelector string) (abi.Error, bool)
⋮----
func (e *Client) observeMetrics(method string, chainID uint64, err error, start time.Time)
```

## File: symbiotic/client/evm/multicall_test.go

```go
package evm
⋮----
import (
	"context"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
)
⋮----
"context"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm/mocks"
⋮----
func TestMulticallExists_NoConnection_ReturnsError(t *testing.T)
⋮----
func TestMulticallExists_CodeAtFails_ReturnsError(t *testing.T)
⋮----
func TestMulticallExists_CodeExists_ReturnsTrue(t *testing.T)
⋮----
func TestMulticallExists_NoCode_ReturnsFalse(t *testing.T)
⋮----
func TestMulticall_NoConnection_ReturnsError(t *testing.T)
```

## File: symbiotic/client/evm/multicall.go

```go
package evm
⋮----
import (
	"context"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind/v2"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/go-errors/errors"
	"github.com/samber/lo"

	"github.com/symbioticfi/relay/internal/entity"
	"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"time"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi/bind/v2"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
"github.com/symbioticfi/relay/internal/entity"
"github.com/symbioticfi/relay/symbiotic/client/evm/gen"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const Multicall3 = "0xcA11bde05977b3631167028862bE2a173976CA11"
⋮----
func (e *Client) multicallExists(ctx context.Context, chainId uint64) (bool, error)
⋮----
func (e *Client) multicall(ctx context.Context, chainId uint64, calls []Call) (_ []Result, err error)
⋮----
func (e *Client) getVotingPowersMulticall(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorVotingPower, error)
⋮----
var res []gen.IVotingPowerProviderVaultValue
⋮----
func (e *Client) getKeysMulticall(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) (_ []symbiotic.OperatorWithKeys, err error)
⋮----
var res []gen.IKeyRegistryKey
```

## File: symbiotic/client/votingpower/chainid_domain_test.go

```go
package votingpower
⋮----
import "testing"
⋮----
func TestIsExternalVotingPowerChainID(t *testing.T)
```

## File: symbiotic/client/votingpower/chainid_domain.go

```go
package votingpower
⋮----
const (
	ExternalVotingPowerChainIDMin uint64 = 4_000_000_000
	ExternalVotingPowerChainIDMax uint64 = 4_100_000_000
)
⋮----
func IsExternalVotingPowerChainID(chainID uint64) bool
```

## File: symbiotic/client/votingpower/client_test.go

```go
package votingpower
⋮----
import (
	"context"
	"math/big"
	"net"
	"sync"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/metadata"

	votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"net"
"sync"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/metadata"
⋮----
votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type testServer struct {
	votingpowerv1.UnimplementedVotingPowerProviderServiceServer

	mu     sync.Mutex
	calls  int
	lastMD metadata.MD

	fn func(ctx context.Context, req *votingpowerv1.GetVotingPowersAtRequest, call int) (*votingpowerv1.GetVotingPowersAtResponse, error)
}
⋮----
func (s *testServer) GetVotingPowersAt(ctx context.Context, req *votingpowerv1.GetVotingPowersAtRequest) (*votingpowerv1.GetVotingPowersAtResponse, error)
⋮----
func (s *testServer) callCount() int
⋮----
func (s *testServer) metadata() metadata.MD
⋮----
func startTestServer(t *testing.T, srv *testServer) (string, *health.Server)
⋮----
func testProviderID() ProviderID
⋮----
func providerAddress(id ProviderID) symbiotic.CrossChainAddress
⋮----
var addr common.Address
⋮----
func TestNewClient_DuplicateProviderID(t *testing.T)
⋮----
func TestClient_GetVotingPowers_HappyPathAndSorting(t *testing.T)
⋮----
func TestClient_GetVotingPowers_DuplicateOperatorsMerged(t *testing.T)
⋮----
func TestClient_GetVotingPowers_EmptyResponse(t *testing.T)
⋮----
func TestClient_GetVotingPowers_InvalidOperator(t *testing.T)
⋮----
func TestClient_GetVotingPowers_InvalidVotingPower(t *testing.T)
⋮----
func TestClient_GetVotingPowers_UnknownProvider(t *testing.T)
⋮----
func TestClient_GetVotingPowers_UsesProviderIDRouting(t *testing.T)
⋮----
// Provider address prefix should be the routing key, chain ID is not.
⋮----
func TestClient_GetVotingPowers_NoRetry(t *testing.T)
⋮----
func TestClient_NewClient_DoesNotRequireHealthCheckOnInit(t *testing.T)
⋮----
func TestClient_GetVotingPowers_Headers(t *testing.T)
⋮----
func TestClient_Close(t *testing.T)
```

## File: symbiotic/client/votingpower/client.go

```go
package votingpower
⋮----
import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"encoding/hex"
	"log/slog"
	"math/big"
	"os"
	"slices"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"

	votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"log/slog"
"math/big"
"os"
"slices"
"strings"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
⋮----
votingpowerv1 "github.com/symbioticfi/relay/internal/gen/votingpower/v1"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
// maxVotingPower is 2^256 - 1, the largest value that fits in the 32-byte SSZ field.
var maxVotingPower = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
⋮----
const (
	defaultTimeout = 5 * time.Second
)
⋮----
type ProviderID [10]byte
⋮----
// ProviderConfig describes one external voting power provider.
type ProviderConfig struct {
	ID         string            `mapstructure:"id"`
	URL        string            `mapstructure:"url"`
	Secure     bool              `mapstructure:"secure"`
	CACertFile string            `mapstructure:"ca-cert-file"`
	ServerName string            `mapstructure:"server-name"`
	Headers    map[string]string `mapstructure:"headers"`
	Timeout    time.Duration     `mapstructure:"timeout"`
}
⋮----
// Client routes GetVotingPowers calls to configured external providers.
type Client struct {
	providers map[ProviderID]provider
}
⋮----
type provider struct {
	cfg    ProviderConfig
	conn   *grpc.ClientConn
	client votingpowerv1.VotingPowerProviderServiceClient
}
⋮----
// NewClient creates a new external voting power client and validates provider connectivity.
func NewClient(ctx context.Context, cfgs []ProviderConfig) (*Client, error)
⋮----
// Public API stays the same.
func (c *Client) GetVotingPowers(
	ctx context.Context,
	address symbiotic.CrossChainAddress,
	timestamp symbiotic.Timestamp,
) ([]symbiotic.OperatorVotingPower, error)
⋮----
func (c *Client) Close() error
⋮----
var firstErr error
⋮----
func ParseProviderID(input string) (ProviderID, error)
⋮----
var id ProviderID
⋮----
func dial(ctx context.Context, cfg ProviderConfig) (*grpc.ClientConn, error)
⋮----
func buildTLSConfig(cfg ProviderConfig) (*tls.Config, error)
⋮----
func providerIDFromAddress(addr common.Address) ProviderID
⋮----
func providerIDString(id ProviderID) string
```

## File: symbiotic/entity/entity_test.go

```go
package entity
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/require"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
⋮----
func TestValidatorSet_FindValidatorsBySignatures(t *testing.T)
⋮----
// Test data setup
⋮----
// Create validators
⋮----
{Tag: KeyTag(2), Payload: publicKey3}, // Different key tag
⋮----
// Check that we found the right validators
⋮----
// Validator3 has publicKey3 but for different tag
⋮----
func TestValidatorSet_IsActiveCommitter(t *testing.T)
⋮----
// Create test validators with keys
⋮----
{ // Index 0 - committer
⋮----
{ // Index 1 - committer
⋮----
{ // Index 2 - committer
⋮----
{ // Index 3 - not a committer
⋮----
CommitterIndices: []uint32{0, 1, 2}, // Only first three are committers
⋮----
// Test with non-committer key
⋮----
// Test with unknown key
⋮----
// When duration is 0, any committer should always be active
⋮----
CommitterIndices: []uint32{1}, // Only one committer
⋮----
// Single committer should always be active after capture time (no time slot rotation needed)
⋮----
// but capture time is in the future, so before that it should be false
⋮----
// But non-committer key should still return false
⋮----
// No committer should be active before capture timestamp
⋮----
CommitterIndices: []uint32{0, 1, 2}, // Three committers
⋮----
// Test first slot (1000-1099): committer 0 should be active
⋮----
// Test second slot (1100-1199): committer 1 should be active
⋮----
// Test third slot (1200-1299): committer 2 should be active
⋮----
// Test fourth slot (1300-1399): wraps back to committer 0
⋮----
// Test fifth slot (1400-1499): committer 1 again
⋮----
// Test sixth slot (1500-1599): committer 2 again
⋮----
// Test grace period at end of slot 0 (time 1095, grace brings us to 1105 which is slot 1)
⋮----
// Test grace period at end of slot 1 (time 1195, grace brings us to 1205 which is slot 2)
⋮----
// Test grace period at end of slot 2 (time 1295, grace brings us to 1305 which is slot 3, wraps to committer 0)
⋮----
// Test grace period that doesn't cross slot boundary
⋮----
CommitterIndices: []uint32{2, 0, 1}, // Different order to test proper indexing
⋮----
// First slot should go to validator at index 2 (first in CommitterIndices)
⋮----
// Second slot should go to validator at index 0 (second in CommitterIndices)
⋮----
// Third slot should go to validator at index 1 (third in CommitterIndices)
⋮----
// Fourth slot wraps back to validator at index 2
⋮----
CaptureTimestamp: 1000000000, // 1 billion
⋮----
slotDuration := uint64(1000000) // 1 million seconds per slot
⋮----
// Test first slot
⋮----
// Test second slot
⋮----
// Test wrap-around with large values
⋮----
// Test exact boundary between slot 0 and slot 1
⋮----
// Test exact boundary between slot 1 and slot 2
⋮----
CommitterIndices: []uint32{}, // No committers
⋮----
// No one should be active if there are no committers
⋮----
func TestPaddedUint64(t *testing.T)
⋮----
input:    65535, // 0xFFFF
⋮----
input:    4294967295, // 0xFFFFFFFF
⋮----
input:    18446744073709551615, // 0xFFFFFFFFFFFFFFFF
⋮----
input:    1640995200, // Typical epoch timestamp
```

## File: symbiotic/entity/entity.go

```go
package entity
⋮----
import (
	"bytes"
	"context"
	"encoding/binary"
	"fmt"
	"log/slog"
	"math/big"
	"slices"

	"github.com/symbioticfi/relay/symbiotic/usecase/ssz"

	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
)
⋮----
"bytes"
"context"
"encoding/binary"
"fmt"
"log/slog"
"math/big"
"slices"
⋮----
"github.com/symbioticfi/relay/symbiotic/usecase/ssz"
⋮----
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/samber/lo"
⋮----
type VerificationType uint32
type AggregationPolicyType uint32
⋮----
const (
	VerificationTypeBlsBn254ZK     VerificationType = 0
	VerificationTypeBlsBn254Simple VerificationType = 1

	AggregationPolicyLowLatency AggregationPolicyType = 0
	AggregationPolicyLowCost    AggregationPolicyType = 1
)
⋮----
var (
	ExtraDataKeyTagPrefixHash = crypto.Keccak256Hash([]byte("keyTag."))
⋮----
var (
	ZkVerificationTotalActiveValidatorsHash = crypto.Keccak256Hash([]byte("totalActiveValidators"))
⋮----
var (
	SimpleVerificationValidatorSetHashKeccak256Hash = crypto.Keccak256Hash([]byte("validatorSetHashKeccak256"))
⋮----
type ValidatorSetStatus uint8
⋮----
const (
	HeaderDerived ValidatorSetStatus = iota
	HeaderAggregated
	HeaderCommitted
)
⋮----
type RawSignature []byte
type RawMessageHash []byte
type RawPublicKey []byte
type CompactPublicKey []byte
type RawMessage []byte
type RawProof []byte
type VotingPower struct {
	*big.Int
}
type QuorumThresholdPct struct {
	*big.Int
}
⋮----
func ToVotingPower(val *big.Int) VotingPower
⋮----
func ToQuorumThresholdPct(val *big.Int) QuorumThresholdPct
⋮----
type Epoch uint64
type Timestamp uint64
⋮----
// Bytes returns the epoch as a BigEndian encoded byte slice for use in database keys.
// BigEndian encoding ensures that lexicographic byte ordering matches numeric ordering,
// which is crucial for proper sorting in key-value stores like Badger.
// Example: Epoch(51).Bytes() < Epoch(501).Bytes() when comparing bytes lexicographically.
func (e Epoch) Bytes() []byte
⋮----
// EpochFromBytes decodes a BigEndian encoded byte slice back to an Epoch.
// This is the inverse operation of Epoch.Bytes().
// Returns an error if the input is not exactly 8 bytes long.
func EpochFromBytes(b []byte) (Epoch, error)
⋮----
func (raw RawSignature) MarshalText() ([]byte, error)
⋮----
func (vp VotingPower) MarshalJSON() ([]byte, error)
⋮----
// dirty hack to force using string instead of float in json
⋮----
// SignatureRequest signature request message
type SignatureRequest struct {
	KeyTag        KeyTag
	RequiredEpoch Epoch
	Message       RawMessage
}
⋮----
type SignatureRequestWithID struct {
	SignatureRequest

	RequestID common.Hash
}
⋮----
// Signature signer.sign() -> Signature
type Signature struct {
	MessageHash RawMessageHash // scheme depends on KeyTag
	KeyTag      KeyTag         // Key tag for validation
	Epoch       Epoch          // Epoch for validation
	PublicKey   PublicKey      // parse based on KeyTag (for bls will contain g1+g2)
	Signature   RawSignature   // parse based on KeyTag
}
⋮----
MessageHash RawMessageHash // scheme depends on KeyTag
KeyTag      KeyTag         // Key tag for validation
Epoch       Epoch          // Epoch for validation
PublicKey   PublicKey      // parse based on KeyTag (for bls will contain g1+g2)
Signature   RawSignature   // parse based on KeyTag
⋮----
// RequestID calculates the request id based on Hash(MessageHash, KeyTag, Epoch)
func (s Signature) RequestID() common.Hash
⋮----
func requestID(keyTag KeyTag, epoch Epoch, messageHash RawMessageHash) common.Hash
⋮----
func paddedUint64(value uint64) []byte
⋮----
// AggregationProof aggregator.proof(signatures []Signature) -> AggregationProof
type AggregationProof struct {
	MessageHash RawMessageHash // scheme depends on KeyTag
	KeyTag      KeyTag         // Key tag for validation
	Epoch       Epoch          // Epoch for validation
	Proof       RawProof       // parse based on KeyTag
}
⋮----
Proof       RawProof       // parse based on KeyTag
⋮----
// ProofCommitKey represents a proof commit key with its parsed epoch and hash for sorting
type ProofCommitKey struct {
	Epoch     Epoch
	RequestID common.Hash
}
⋮----
func (vt VerificationType) String() string
⋮----
type CrossChainAddress struct {
	ChainId uint64
	Address common.Address
}
⋮----
type QuorumThreshold struct {
	KeyTag          KeyTag
	QuorumThreshold QuorumThresholdPct
}
⋮----
type NetworkConfig struct {
	VotingPowerProviders    []CrossChainAddress
	KeysProvider            CrossChainAddress
	Settlements             []CrossChainAddress
	VerificationType        VerificationType
	MaxVotingPower          VotingPower
	MinInclusionVotingPower VotingPower
	MaxValidatorsCount      VotingPower
	RequiredKeyTags         []KeyTag
	RequiredHeaderKeyTag    KeyTag
	QuorumThresholds        []QuorumThreshold
	EpochDuration           uint64 // in seconds
	// scheduler config
	NumAggregators        uint64
	NumCommitters         uint64
	CommitterSlotDuration uint64 // in seconds
}
⋮----
EpochDuration           uint64 // in seconds
// scheduler config
⋮----
CommitterSlotDuration uint64 // in seconds
⋮----
func maxThreshold() *big.Int
⋮----
// 10^18 is the maximum threshold value
⋮----
func (nc NetworkConfig) CalcQuorumThreshold(totalVP VotingPower) (VotingPower, error)
⋮----
// add 1 to apply up rounding
⋮----
type NetworkData struct {
	Address    common.Address
	Subnetwork common.Hash
	Eip712Data Eip712Domain
}
⋮----
type VaultVotingPower struct {
	Vault       common.Address
	VotingPower VotingPower
}
⋮----
type OperatorVotingPower struct {
	Operator common.Address
	Vaults   []VaultVotingPower
}
⋮----
type OperatorWithKeys struct {
	Operator common.Address
	Keys     []ValidatorKey
}
⋮----
type ValidatorKey struct {
	Tag     KeyTag
	Payload CompactPublicKey
}
⋮----
type ValidatorVault struct {
	ChainID     uint64         `json:"chainId"`
	Vault       common.Address `json:"vault"`
	VotingPower VotingPower    `json:"votingPower"`
}
⋮----
type Validators []Validator
⋮----
func (va Validators) SortByVotingPowerDescAndOperatorAddressAsc()
⋮----
func (va Validators) FindValidatorByKey(keyTag KeyTag, publicKey []byte) (Validator, bool)
⋮----
func (va Validators) SortByOperatorAddressAsc()
⋮----
func (va Validators) CheckIsSortedByOperatorAddressAsc() error
⋮----
type Vaults []ValidatorVault
⋮----
func (v Vaults) SortByAddressAsc()
⋮----
func (v Vaults) SortVaultsByVotingPowerDescAndAddressAsc()
⋮----
func (va Validators) GetTotalActiveVotingPower() VotingPower
⋮----
func (va Validators) GetActiveValidators() Validators
⋮----
var activeValidators Validators
⋮----
type Validator struct {
	Operator    common.Address `json:"operator"`
	VotingPower VotingPower    `json:"votingPower"`
	IsActive    bool           `json:"isActive"`
	Keys        []ValidatorKey `json:"keys"`
	Vaults      Vaults         `json:"vaults"`
}
⋮----
func (v Validator) FindKeyByKeyTag(keyTag KeyTag) ([]byte, bool)
⋮----
type ValidatorSet struct {
	Version          uint8
	RequiredKeyTag   KeyTag      // key tag required to commit next valset
	Epoch            Epoch       // valset epoch
	CaptureTimestamp Timestamp   // epoch capture timestamp
	QuorumThreshold  VotingPower // absolute number now, not a percent
	Validators       Validators
	Status           ValidatorSetStatus

	// Scheduler info for current validator set, completely offchain not included in header
	AggregatorIndices []uint32
	CommitterIndices  []uint32
}
⋮----
RequiredKeyTag   KeyTag      // key tag required to commit next valset
Epoch            Epoch       // valset epoch
CaptureTimestamp Timestamp   // epoch capture timestamp
QuorumThreshold  VotingPower // absolute number now, not a percent
⋮----
// Scheduler info for current validator set, completely offchain not included in header
⋮----
func (v ValidatorSet) IsAggregator(requiredKey CompactPublicKey) bool
⋮----
func (v ValidatorSet) IsCommitter(requiredKey CompactPublicKey) bool
⋮----
func (v ValidatorSet) ValidatorIndex(requiredKey CompactPublicKey) int
⋮----
func (v ValidatorSet) IsSigner(requiredKey CompactPublicKey) bool
⋮----
func (v ValidatorSet) findMembership(indexArray []uint32, requiredKey []byte) (uint32, bool)
⋮----
// Unreachable in normal operation: scheduler picks indices in [0, len(activeValidators))
// at derivation, and the (Validators, AggregatorIndices, CommitterIndices) tuple is
// stored together — so a violation means data corruption or a scheduler bug.
⋮----
// IsActiveCommitter determines if the current time falls within the time slot
// of the current node based on the network configuration and validator set.
// Each committer has a dedicated time slot of CommitterSlotDuration seconds,
// starting from the CaptureTimestamp. If the node's slot is about to start
// i.e. if currentTime + graceSeconds moves us to the next slot, it will also return true.
func (v ValidatorSet) IsActiveCommitter(
	ctx context.Context,
	committerSlotDuration uint64,
	currentTime Timestamp,
	graceSeconds uint64,
	requiredKey []byte,
) bool
⋮----
// If current time is before capture timestamp, we're not in any slot yet
⋮----
// single committer no need to check time slots
⋮----
// Calculate elapsed time since capture
⋮----
// Calculate which slot we're currently in
⋮----
// Calculate which committer should be active for current slot (round-robin)
⋮----
// Check if the required key matches the current slot's committer
⋮----
// Check if adding grace period moves us to the next slot
⋮----
// If grace period moves us to a different slot, check that slot's committer too
⋮----
func (v ValidatorSet) FindValidatorByKey(keyTag KeyTag, publicKey []byte) (Validator, bool) { // DON'T USE INSIDE LOOPS
⋮----
type ValidatorSetHash struct {
	KeyTag KeyTag
	Hash   common.Hash
}
⋮----
// ValidatorSetHeader represents the input for validator set header
type ValidatorSetHeader struct {
	Version            uint8
	RequiredKeyTag     KeyTag
	Epoch              Epoch
	CaptureTimestamp   Timestamp
	QuorumThreshold    VotingPower
	TotalVotingPower   VotingPower
	ValidatorsSszMRoot common.Hash
}
⋮----
type ValidatorSetMetadata struct {
	RequestID      common.Hash
	ExtraData      []ExtraData
	Epoch          Epoch
	CommitmentData []byte
}
⋮----
type ExtraData struct {
	Key   common.Hash
	Value common.Hash
}
⋮----
type ExtraDataList []ExtraData
⋮----
func (e ExtraDataList) Hash() ([]byte, error)
⋮----
func (e ExtraDataList) AbiEncode() ([]byte, error)
⋮----
func (v ValidatorSet) GetTotalActiveValidators() int64
⋮----
func (v ValidatorSet) GetHeader() (ValidatorSetHeader, error)
⋮----
func (v ValidatorSet) FindValidatorsByKeys(keyTag KeyTag, publicKeys []CompactPublicKey) (Validators, error)
⋮----
// Build lookup map: publicKey -> validator
⋮----
// Find validators for each public key
⋮----
func sszTreeRoot(v *ValidatorSet) (common.Hash, error)
⋮----
func keyPayloadHash(k ValidatorKey) common.Hash
⋮----
func validatorSetToSszValidators(v *ValidatorSet) ssz.SszValidatorSet
⋮----
type TxResult struct {
	TxHash            common.Hash
	GasUsed           uint64
	EffectiveGasPrice *big.Int
}
⋮----
type ChainURL struct {
	ChainID uint64
	RPCURL  string
}
⋮----
type AggregationStatus struct {
	VotingPower VotingPower
	Validators  []Validator
}
```

## File: symbiotic/entity/evm_entity.go

```go
package entity
⋮----
type BlockNumber string
⋮----
const (
	BlockNumberFinalized BlockNumber = "finalized"
	BlockNumberLatest    BlockNumber = "latest"
)
⋮----
type EVMOptions struct {
	BlockNumber        BlockNumber
	GasLimitMultiplier float64
}
⋮----
func AppliedEVMOptions(opts ...EVMOption) *EVMOptions
⋮----
type EVMOption func(options *EVMOptions)
⋮----
func WithEVMBlockNumber(blockNumber BlockNumber) EVMOption
⋮----
func WithGasLimitMultiplier(multiplier float64) EVMOption
```

## File: symbiotic/entity/key_tag_entity_test.go

```go
package entity
⋮----
import (
	"strings"
	"testing"
)
⋮----
"strings"
"testing"
⋮----
func TestKeyTag_Type(t *testing.T)
⋮----
func TestKeyTag_MarshalText(t *testing.T)
⋮----
func TestKeyTag_String(t *testing.T)
⋮----
func TestKeyType_String(t *testing.T)
⋮----
func TestKeyTypeFromString(t *testing.T)
```

## File: symbiotic/entity/key_tag_entity.go

```go
package entity
⋮----
import (
	"fmt"

	"github.com/go-errors/errors"
)
⋮----
"fmt"
⋮----
"github.com/go-errors/errors"
⋮----
type KeyType uint8
⋮----
const (
	KeyTypeBlsBn254       KeyType = 0
	KeyTypeEcdsaSecp256k1 KeyType = 1
	KeyTypeBls12381       KeyType = 2
	KeyTypeInvalid        KeyType = 255

	BLS_BN254_TYPE       = "bls_bn254"
	ECDSA_SECP256K1_TYPE = "ecdsa_secp256k1"
	BLS12_381_TYPE       = "bls12_381"
	INVALID_TYPE         = "invalid"
)
⋮----
type KeyTag uint8
⋮----
func (kt KeyTag) Type() KeyType
⋮----
return KeyTypeInvalid // Invalid key type
⋮----
func (kt KeyTag) MarshalText() (text []byte, err error)
⋮----
func (kt KeyTag) String() string
⋮----
// SignerKey returns true if the key type can be used for signing
func (kt KeyType) SignerKey() bool
⋮----
// AggregationKey returns true if the key type can be used for aggregation
func (kt KeyType) AggregationKey() bool
⋮----
func KeyTypeFromString(typeStr string) (KeyType, error)
⋮----
func KeyTagFromTypeAndId(keyType KeyType, keyId uint8) (KeyTag, error)
```

## File: symbiotic/entity/key.go

```go
package entity
⋮----
type PublicKey interface {
	Verify(msg Message, sig RawSignature) error
	VerifyWithHash(msgHash MessageHash, sig RawSignature) error
	OnChain() CompactPublicKey
	Raw() RawPublicKey
	MarshalText() (text []byte, err error)
}
⋮----
type PrivateKey interface {
	Bytes() []byte
	Sign(msg []byte) (RawSignature, MessageHash, error)
	PublicKey() PublicKey
}
```

## File: symbiotic/usecase/aggregator/aggregator-types/aggregator.go

```go
package aggregator_types
⋮----
import (
	"context"

	"github.com/symbioticfi/relay/pkg/proof"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"

	"github.com/ethereum/go-ethereum/common"
)
⋮----
"context"
⋮----
"github.com/symbioticfi/relay/pkg/proof"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
type Aggregator interface {
	Aggregate(ctx context.Context, valset symbiotic.ValidatorSet, signatures []symbiotic.Signature) (symbiotic.AggregationProof, error)
	Verify(ctx context.Context, valset symbiotic.ValidatorSet, keyTag symbiotic.KeyTag, aggregationProof symbiotic.AggregationProof) (bool, error)
	GenerateExtraData(ctx context.Context, valset symbiotic.ValidatorSet, keyTags []symbiotic.KeyTag) ([]symbiotic.ExtraData, error)
}
⋮----
type Prover interface {
	Prove(ctx context.Context, proveInput proof.ProveInput) (proof.ProofData, error)
	Verify(ctx context.Context, valsetLen int, publicInputHash common.Hash, proofBytes []byte) (bool, error)
}
```

## File: symbiotic/usecase/aggregator/blsBn254Simple/aggregator_test.go

```go
package blsBn254Simple
⋮----
import (
	"math/big"
	"testing"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestNewAggregator_Success(t *testing.T)
⋮----
func TestCompress_WithValidG1Point_ReturnsCompressedHash(t *testing.T)
⋮----
func TestCompress_WithZeroPoint_ReturnsHash(t *testing.T)
⋮----
func TestCompress_WithDifferentPoints_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestDecompress_WithValidCompressedPoint_ReturnsG1Point(t *testing.T)
⋮----
func TestCompress_Decompress_RoundTrip_PreservesPoint(t *testing.T)
⋮----
func TestFindYFromX_WithValidX_ReturnsY(t *testing.T)
⋮----
assert.Greater(t, y.Cmp(big.NewInt(0)), 0) //nolint:testifylint // assert.Positive doesn't work with *big.Int
⋮----
func TestFindYFromX_WithZeroX_ReturnsY(t *testing.T)
⋮----
func TestFindYFromX_WithLargeX_ReturnsY(t *testing.T)
⋮----
func TestProcessValidators_WithNoValidators_ReturnsEmpty(t *testing.T)
⋮----
func TestProcessValidators_WithInactiveValidators_ReturnsEmpty(t *testing.T)
⋮----
func TestProcessValidators_WithActiveValidators_ReturnsValidatorData(t *testing.T)
⋮----
func TestProcessValidators_WithMultipleValidators_ReturnsSortedData(t *testing.T)
⋮----
func TestProcessValidators_WithMissingKeyTag_ReturnsError(t *testing.T)
⋮----
func TestCalcAlpha_WithValidInputs_ReturnsAlpha(t *testing.T)
⋮----
assert.Greater(t, alpha.Cmp(big.NewInt(0)), 0) //nolint:testifylint // assert.Positive doesn't work with *big.Int
⋮----
func TestCalcAlpha_WithDifferentInputs_ReturnsDifferentAlphas(t *testing.T)
⋮----
func TestCalcAlpha_WithSameInputs_ReturnsSameAlpha(t *testing.T)
⋮----
func TestAggregator_Aggregate_WithEmptySignatures_Fail(t *testing.T)
⋮----
func TestAggregator_Aggregate_WithMismatchedMessageHashes_ReturnsError(t *testing.T)
⋮----
func TestAggregator_Verify_WithInvalidMessageHashLength_ReturnsError(t *testing.T)
⋮----
func TestAggregator_Verify_WithShortProof_ReturnsError(t *testing.T)
⋮----
func TestAggregator_PackValidatorsData_WithValidData_ReturnsBytes(t *testing.T)
⋮----
func TestAggregator_PackValidatorsData_WithEmptyData_ReturnsBytes(t *testing.T)
⋮----
func TestAggregator_CalculateValidatorsKeccak_WithValidData_ReturnsHash(t *testing.T)
⋮----
func TestAggregator_CalculateValidatorsKeccak_WithSameData_ReturnsSameHash(t *testing.T)
⋮----
func TestAggregator_CalculateValidatorsKeccak_WithDifferentData_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_WithValidValidatorSet_ReturnsExtraData(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_WithMultipleKeyTags_ReturnsMultipleExtraData(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_ReturnsSortedData(t *testing.T)
```

## File: symbiotic/usecase/aggregator/blsBn254Simple/aggregator.go

```go
package blsBn254Simple
⋮----
import (
	"bytes"
	"context"
	"encoding/binary"
	"math/big"
	"sort"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/consensys/gnark-crypto/ecc/bn254/fp"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/pkg/tracing"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/helpers"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
)
⋮----
"bytes"
"context"
"encoding/binary"
"math/big"
"sort"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark-crypto/ecc/bn254/fp"
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/pkg/tracing"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/helpers"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
⋮----
const maxValidators = 65_536
⋮----
// MinProofSize is the smallest valid Simple aggregation proof:
// 64 (sigBytes) + 64 (apkBytes) + 64 (apkG2BytesFirstHalf) + 32 (nonSignersLength) = 224.
// Anything shorter cannot be parsed and would panic on fixed-offset slicing below.
const MinProofSize = 224
⋮----
type abiTypes struct {
	g1Type             abi.Type
	g2Type             abi.Type
	validatorsDataType abi.Type
	g1Args             abi.Arguments
	g2Args             abi.Arguments
	validatorsArgs     abi.Arguments
}
⋮----
type Aggregator struct {
	abiTypes abiTypes
}
⋮----
type ValidatorData struct {
	KeySerialized common.Hash
	VotingPower   *big.Int
}
⋮----
func NewAggregator() (*Aggregator, error)
⋮----
// createABITypes creates and returns all ABI types
func createABITypes() (abiTypes, error)
⋮----
func (a Aggregator) Aggregate(
	ctx context.Context,
	valset symbiotic.ValidatorSet,
	signatures []symbiotic.Signature,
) (symbiotic.AggregationProof, error)
⋮----
//nolint:gosec // we have already checked that signatures length is > 0
⋮----
aggG2Key.X.A1.BigInt(new(big.Int)), // index 0
aggG2Key.X.A0.BigInt(new(big.Int)), // index 1
⋮----
aggG2Key.Y.A1.BigInt(new(big.Int)), // index 0
aggG2Key.Y.A0.BigInt(new(big.Int)), // index 1
⋮----
// Pack validators data with anonymous structs
⋮----
// Encode non-signers indices
⋮----
// Assemble proof
⋮----
func (a Aggregator) Verify(
	ctx context.Context,
	valset symbiotic.ValidatorSet,
	keyTag symbiotic.KeyTag,
	aggregationProof symbiotic.AggregationProof,
) (bool, error)
⋮----
// Check key tag type
⋮----
// Parse proof components
⋮----
// Parse validators data length
⋮----
// Calculate non-signers offset
⋮----
// Verify validators data hash matches
⋮----
// Parse non-signers with proper validation
⋮----
// Validate proof length matches expected non-signers data
⋮----
// Parse and validate non-signers with ordering check
⋮----
var nonSignersVotingPower big.Int
var nonSignersPublicKeyG1 *bn254.G1Affine
nonSignersPublicKeyG1 = new(bn254.G1Affine) // Initialize to zero point
⋮----
var prevNonSignerIndex uint16
⋮----
// Validate non-signer index
⋮----
// Check ordering (must be ascending)
⋮----
// Add non-signer's voting power
⋮----
// Add non-signer's public key
⋮----
// Verify validators match expected
⋮----
// Verify validator data matches
⋮----
// Check quorum using the same logic as Solidity
⋮----
// Get aggregated public key from valset (equivalent to extra data in Solidity)
⋮----
// Calculate effective public key: aggPubKeyG1 - nonSignersPublicKeyG1
// This matches the Solidity logic: aggPubKeyG1.plus(nonSignersPublicKeyG1.negate())
⋮----
// Verify signature using BLS verification
⋮----
// Prepare bytes for alpha calculation
⋮----
func calcAlpha(aggPubKeyG1 *bn254.G1Affine, aggPubKeyG2 *bn254.G2Affine, aggSig *bn254.G1Affine, messageHash []byte) *big.Int
⋮----
// G1 public key bytes
⋮----
// G2 public key bytes
⋮----
// Signature bytes
⋮----
func (a Aggregator) GenerateExtraData(ctx context.Context, valset symbiotic.ValidatorSet, keyTags []symbiotic.KeyTag) ([]symbiotic.ExtraData, error)
⋮----
// Pack aggregated keys
⋮----
// sort extra data by key to ensure deterministic order
⋮----
func (a Aggregator) packValidatorsData(validatorsData []ValidatorData) ([]byte, error)
⋮----
func processValidators(validators []symbiotic.Validator, keyTag symbiotic.KeyTag) ([]ValidatorData, error)
⋮----
func (a Aggregator) calculateValidatorsKeccak(validatorsData []ValidatorData) (common.Hash, error)
⋮----
func compress(g1 *bn254.G1Affine) (common.Hash, error)
⋮----
func decompress(compressed [32]byte) (*bn254.G1Affine, error)
⋮----
func findYFromX(x *big.Int) (y *big.Int, err error)
⋮----
// Calculate beta = x^3 + 3 mod p
beta := new(big.Int).Exp(x, big.NewInt(3), fpModulus) // x^3
beta.Add(beta, big.NewInt(3))                         // x^3 + 3
beta.Mod(beta, fpModulus)                             // (x^3 + 3) mod p
⋮----
// Calculate y = beta^((p+1)/4) mod p
```

## File: symbiotic/usecase/aggregator/blsBn254ZK/aggregator_test.go

```go
package blsBn254ZK
⋮----
import (
	"context"
	"math/big"
	"testing"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/pkg/proof"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"context"
"math/big"
"testing"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/pkg/proof"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
type mockProver struct{}
⋮----
func (m *mockProver) Prove(ctx context.Context, proveInput proof.ProveInput) (proof.ProofData, error)
⋮----
func (m *mockProver) Verify(ctx context.Context, valsetLen int, publicInputHash common.Hash, proofBytes []byte) (bool, error)
⋮----
func TestNewAggregator_WithProver_Success(t *testing.T)
⋮----
func TestNewAggregator_WithNilProver_Success(t *testing.T)
⋮----
func TestAggregator_Aggregate_WithMismatchedMessageHashes_ReturnsError(t *testing.T)
⋮----
func TestValidatorSetMimcAccumulator_WithNoValidators_ReturnsZeroHash(t *testing.T)
⋮----
func TestValidatorSetMimcAccumulator_WithActiveValidators_ReturnsHash(t *testing.T)
⋮----
func TestValidatorSetMimcAccumulator_WithSameValidators_ReturnsSameHash(t *testing.T)
⋮----
func TestValidatorSetMimcAccumulator_WithDifferentValidators_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestToValidatorsData_WithNoValidators_ReturnsNormalizedData(t *testing.T)
⋮----
func TestToValidatorsData_WithInactiveValidators_ReturnsNormalizedData(t *testing.T)
⋮----
func TestToValidatorsData_WithActiveValidators_ReturnsData(t *testing.T)
⋮----
func TestToValidatorsData_WithSigners_MarksSignersCorrectly(t *testing.T)
⋮----
func TestToValidatorsData_WithMixedSignersAndNonSigners_MarksCorrectly(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_WithValidValidators_ReturnsExtraData(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_WithMultipleKeyTags_ReturnsMultipleExtraData(t *testing.T)
⋮----
func TestAggregator_GenerateExtraData_ReturnsSortedData(t *testing.T)
⋮----
func TestAggregator_Verify_WithInvalidMessageHash_ReturnsError(t *testing.T)
⋮----
func TestAggregator_Verify_WithInsufficientVotingPower_ReturnsError(t *testing.T)
```

## File: symbiotic/usecase/aggregator/blsBn254ZK/aggregator.go

```go
package blsBn254ZK
⋮----
import (
	"bytes"
	"context"
	"math/big"
	"sort"

	"go.opentelemetry.io/otel/attribute"

	"github.com/symbioticfi/relay/pkg/proof"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	types "github.com/symbioticfi/relay/symbiotic/usecase/aggregator/aggregator-types"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/helpers"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"

	"github.com/symbioticfi/relay/pkg/tracing"
)
⋮----
"bytes"
"context"
"math/big"
"sort"
⋮----
"go.opentelemetry.io/otel/attribute"
⋮----
"github.com/symbioticfi/relay/pkg/proof"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
types "github.com/symbioticfi/relay/symbiotic/usecase/aggregator/aggregator-types"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/helpers"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
"github.com/symbioticfi/relay/pkg/tracing"
⋮----
// MinProofSize is the minimum byte length of a valid ZK aggregation proof:
// 256 bytes of proof data + 128 bytes of public inputs. Anything shorter
// cannot be parsed and would panic on the fixed-offset slicing below.
const MinProofSize = 384
⋮----
type Aggregator struct {
	prover types.Prover
}
⋮----
func NewAggregator(prover types.Prover) (*Aggregator, error)
⋮----
func (a Aggregator) Aggregate(
	ctx context.Context,
	valset symbiotic.ValidatorSet,
	signatures []symbiotic.Signature,
) (symbiotic.AggregationProof, error)
⋮----
var validatorsData []proof.ValidatorData
⋮----
func (a Aggregator) Verify(
	ctx context.Context,
	valset symbiotic.ValidatorSet,
	keyTag symbiotic.KeyTag,
	aggregationProof symbiotic.AggregationProof,
) (bool, error)
⋮----
// last 32 bytes is aggVotingPowerBytes
⋮----
messageG1Bytes := messageG1.RawBytes() // non compressed
⋮----
func (a Aggregator) GenerateExtraData(ctx context.Context, valset symbiotic.ValidatorSet, keyTags []symbiotic.KeyTag) ([]symbiotic.ExtraData, error)
⋮----
// sort extra data by key to ensure deterministic order
⋮----
func validatorSetMimcAccumulator(valset []symbiotic.Validator, requiredKeyTag symbiotic.KeyTag) (common.Hash, error)
⋮----
func toValidatorsData(signerValidators []symbiotic.Validator, allValidators symbiotic.Validators, requiredKeyTag symbiotic.KeyTag) ([]proof.ValidatorData, error)
```

## File: symbiotic/usecase/aggregator/helpers/helpers_test.go

```go
package helpers
⋮----
import (
	"math/big"
	"testing"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"math/big"
"testing"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func TestCompareMessageHasher_WithMatchingHashes_ReturnsTrue(t *testing.T)
⋮----
func TestCompareMessageHasher_WithDifferentHash_ReturnsFalse(t *testing.T)
⋮----
func TestCompareMessageHasher_WithEmptySignatures_ReturnsTrue(t *testing.T)
⋮----
func TestCompareMessageHasher_WithSingleSignature_ReturnsCorrectResult(t *testing.T)
⋮----
func TestGetExtraDataKey_WithValidInputs_ReturnsHash(t *testing.T)
⋮----
func TestGetExtraDataKey_WithDifferentVerificationTypes_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestGetExtraDataKey_WithDifferentNameHashes_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestGetExtraDataKey_WithSameInputs_ReturnsSameHash(t *testing.T)
⋮----
func TestGetExtraDataKeyTagged_WithValidInputs_ReturnsHash(t *testing.T)
⋮----
func TestGetExtraDataKeyTagged_WithDifferentKeyTags_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestGetExtraDataKeyTagged_WithDifferentVerificationTypes_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestGetExtraDataKeyTagged_WithSameInputs_ReturnsSameHash(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithNoValidators_ReturnsZeroPoint(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithInactiveValidators_ReturnsZeroPoint(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithSingleActiveValidator_ReturnsAggregatedKey(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithMultipleActiveValidators_ReturnsAggregatedKey(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithMixedActiveInactive_ReturnsOnlyActiveAggregation(t *testing.T)
⋮----
func TestGetAggregatedPubKeys_WithMultipleKeyTags_ReturnsMultipleAggregations(t *testing.T)
⋮----
func TestGetExtraDataKeyIndexed_WithValidInputs_ReturnsHash(t *testing.T)
⋮----
func TestGetExtraDataKeyIndexed_WithZeroIndex_EqualsBaseHash(t *testing.T)
⋮----
func TestGetExtraDataKeyIndexed_WithDifferentIndexes_ReturnsDifferentHashes(t *testing.T)
⋮----
func TestGetExtraDataKeyIndexed_WithLargeIndex_ReturnsHash(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithNoValidators_ReturnsEmptyMap(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithInactiveValidators_ReturnsEmptyMap(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithSingleActiveValidator_ReturnsMapWithOneEntry(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithMultipleActiveValidators_ReturnsMapWithAllEntries(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithMixedActiveInactive_ReturnsOnlyActiveValidators(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithNonMatchingKeyTag_ReturnsEmptyMap(t *testing.T)
⋮----
func TestGetActiveValidatorsIndexesMapByKey_WithValidatorHavingMultipleKeys_OnlyMapsMatchingKeyTag(t *testing.T)
```

## File: symbiotic/usecase/aggregator/helpers/helpers.go

```go
package helpers
⋮----
import (
	"bytes"
	"math/big"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"bytes"
"math/big"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
func CheckSignaturesHaveSameTagAndMessageHash(signatures []symbiotic.Signature) error
⋮----
func GetExtraDataKey(verificationType symbiotic.VerificationType, nameHash common.Hash) (common.Hash, error)
⋮----
func GetExtraDataKeyTagged(verificationType symbiotic.VerificationType, keyTag symbiotic.KeyTag, nameHash common.Hash) (common.Hash, error)
⋮----
func GetAggregatedPubKeys(
	valset symbiotic.ValidatorSet,
	keyTags []symbiotic.KeyTag,
) []symbiotic.ValidatorKey
⋮----
// only bn254 bls for now
⋮----
// aggregate and save in map
⋮----
var aggregatedPubKeys []symbiotic.ValidatorKey
⋮----
// pack g1 point to bytes and add to list
⋮----
// will be used later
func GetExtraDataKeyIndexed(
	verificationType symbiotic.VerificationType,
	keyTag symbiotic.KeyTag,
	nameHash common.Hash,
	index *big.Int,
) (common.Hash, error)
⋮----
var out common.Hash
⋮----
func GetActiveValidatorsIndexesMapByKey(valset symbiotic.ValidatorSet, keyTag symbiotic.KeyTag) map[string]int
```

## File: symbiotic/usecase/aggregator/aggregators_test.go

```go
package aggregator
⋮----
import (
	"context"
	"encoding/hex"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/common"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/symbioticfi/relay/pkg/proof"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"

	crypto2 "github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
)
⋮----
"context"
"encoding/hex"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
⋮----
"github.com/symbioticfi/relay/pkg/proof"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
crypto2 "github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
type mockProver struct{}
⋮----
func (m *mockProver) Prove(ctx context.Context, proveInput proof.ProveInput) (proof.ProofData, error)
⋮----
func (m *mockProver) Verify(ctx context.Context, valsetLen int, publicInputHash common.Hash, proofBytes []byte) (bool, error)
⋮----
func TestSimpleAggregator(t *testing.T)
⋮----
func TestInvalidSimpleAggregator(t *testing.T)
⋮----
func TestSimpleAggregatorExtraData(t *testing.T)
⋮----
func TestAggregatorZKExtraData(t *testing.T)
⋮----
func TestZkAggregator(t *testing.T)
⋮----
func genExtraDataTest(t *testing.T) (symbiotic.ValidatorSet, symbiotic.KeyTag)
⋮----
var err error
⋮----
func genCorrectTest(numValidators int, nonSigners []int) (symbiotic.ValidatorSet, []symbiotic.Signature, symbiotic.KeyTag)
⋮----
func TestNewAggregator_WithBlsBn254Simple_ReturnsAggregator(t *testing.T)
⋮----
func TestNewAggregator_WithBlsBn254ZK_ReturnsAggregator(t *testing.T)
⋮----
func TestNewAggregator_WithUnsupportedType_ReturnsError(t *testing.T)
⋮----
func TestNewAggregator_WithDifferentTypes_ReturnsDifferentImplementations(t *testing.T)
```

## File: symbiotic/usecase/aggregator/aggregators.go

```go
package aggregator
⋮----
import (
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	types "github.com/symbioticfi/relay/symbiotic/usecase/aggregator/aggregator-types"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"

	"github.com/go-errors/errors"
)
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
types "github.com/symbioticfi/relay/symbiotic/usecase/aggregator/aggregator-types"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254Simple"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator/blsBn254ZK"
⋮----
"github.com/go-errors/errors"
⋮----
func NewAggregator(verificationType symbiotic.VerificationType, prover Prover) (Aggregator, error)
```

## File: symbiotic/usecase/crypto/bls12381/key_test.go

```go
package bls12381
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"

	"github.com/stretchr/testify/require"
)
⋮----
"crypto/rand"
"math/big"
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
func TestBLS12381Keys(t *testing.T)
⋮----
func TestCheckPrivateKeyBytes(t *testing.T)
⋮----
func TestMarshalText(t *testing.T)
⋮----
func TestInvalidVerification(t *testing.T)
⋮----
func TestFromRaw(t *testing.T)
⋮----
func randData(t *testing.T) []byte
```

## File: symbiotic/usecase/crypto/bls12381/key.go

```go
package bls12381
⋮----
import (
	"fmt"
	"math/big"

	bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
	"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"fmt"
"math/big"
⋮----
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	RawKeyLength      int = bls12381.SizeOfG1AffineCompressed + bls12381.SizeOfG2AffineCompressed
	MessageHashLength int = 32
	hashToG1Domain        = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"
)
⋮----
type PublicKey struct {
	g1PubKey bls12381.G1Affine
	g2PubKey bls12381.G2Affine
}
⋮----
type PrivateKey struct {
	privateKey *big.Int
}
⋮----
func NewPrivateKey(b []byte) (*PrivateKey, error)
⋮----
func HashMessage(msg []byte) MessageHash
⋮----
func GenerateKey() (*PrivateKey, error)
⋮----
var err error
⋮----
func (k *PrivateKey) Bytes() []byte
⋮----
func (k *PrivateKey) Sign(msg []byte) (Signature, MessageHash, error)
⋮----
// symbiotic using keccak256 for hashing in bls12381-bn254
⋮----
var g1Sig bls12381.G1Affine
⋮----
func HashToG1(data []byte) (*bls12381.G1Affine, error)
⋮----
func (k *PrivateKey) PublicKey() symbiotic.PublicKey
⋮----
func NewPublicKey(g1PubKey bls12381.G1Affine, g2PubKey bls12381.G2Affine) *PublicKey
⋮----
func (k *PublicKey) Verify(msg Message, sig Signature) error
⋮----
func (k *PublicKey) VerifyWithHash(msgHash MessageHash, sig Signature) error
⋮----
var negSig bls12381.G1Affine
⋮----
// OnChain might be one way operation, meaning that it's impossible to reconstruct PublicKey from compact
func (k *PublicKey) OnChain() CompactPublicKey
⋮----
// DEV: g1PubKey Marshalled is 96 bytes in total, x and y each 48bytes
// but onchain we need to pad each field to 64 bytes, hence we manually pad it here
⋮----
copy(paddedPk[16:64], pk[0:48])   // x coordinate
copy(paddedPk[80:128], pk[48:96]) // y coordinate
⋮----
func (k *PublicKey) Raw() RawPublicKey
⋮----
// combined g1 and g2 [compressed]
⋮----
func (k *PublicKey) G2() *bls12381.G2Affine
⋮----
func (k *PublicKey) MarshalText() ([]byte, error)
⋮----
func FromRaw(rawKey RawPublicKey) (*PublicKey, error)
⋮----
var g1 bls12381.G1Affine
var g2 bls12381.G2Affine
⋮----
func FromPrivateKey(privateKey *PrivateKey) symbiotic.PublicKey
```

## File: symbiotic/usecase/crypto/blsBn254/key_test.go

```go
package blsBn254
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"

	"github.com/stretchr/testify/require"
)
⋮----
"crypto/rand"
"math/big"
"testing"
⋮----
"github.com/stretchr/testify/require"
⋮----
func TestBLSKeys(t *testing.T)
⋮----
func TestCheckPrivateKeyBytes(t *testing.T)
⋮----
func TestMarshallText(t *testing.T)
⋮----
func TestInvalidVerification(t *testing.T)
⋮----
func TestFromRaw(t *testing.T)
⋮----
func randData(t *testing.T) []byte
```

## File: symbiotic/usecase/crypto/blsBn254/key.go

```go
package blsBn254
⋮----
import (
	"fmt"
	"math/big"

	"github.com/consensys/gnark-crypto/ecc/bn254"
	"github.com/consensys/gnark-crypto/ecc/bn254/fp"
	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"fmt"
"math/big"
⋮----
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark-crypto/ecc/bn254/fp"
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	RawKeyLength      int = 96
	MessageHashLength int = 32
)
⋮----
type PublicKey struct {
	g1PubKey bn254.G1Affine
	g2PubKey bn254.G2Affine
}
⋮----
type PrivateKey struct {
	privateKey *big.Int
}
⋮----
func NewPrivateKey(b []byte) (*PrivateKey, error)
⋮----
func HashMessage(msg []byte) MessageHash
⋮----
func GenerateKey() (*PrivateKey, error)
⋮----
var err error
⋮----
func (k *PrivateKey) Bytes() []byte
⋮----
func (k *PrivateKey) Sign(msg []byte) (Signature, MessageHash, error)
⋮----
// symbiotic using keccak256 for hashing in bls-bn254
⋮----
// returns non compressed G1 point
⋮----
func HashToG1(data []byte) (*bn254.G1Affine, error)
⋮----
// Convert data to a big integer
⋮----
// Ensure x is within the field
⋮----
// Find y coordinate for the current x
⋮----
// Check if y^2 == beta
⋮----
// Create a G1 point with the found coordinates
var point bn254.G1Affine
⋮----
// Increment x and try again
⋮----
// FindYFromX calculates the y coordinate for a given x on the BN254 curve
// Returns (beta, y) where beta = x^3 + 3 (mod p) and y = sqrt(beta) if it exists
func findYFromX(x *big.Int) (beta *big.Int, y *big.Int, err error)
⋮----
// Calculate beta = x^3 + 3 mod p
beta = new(big.Int).Exp(x, big.NewInt(3), fpModulus) // x^3
beta.Add(beta, big.NewInt(3))                        // x^3 + 3
beta.Mod(beta, fpModulus)                            // (x^3 + 3) mod p
⋮----
// Calculate y = beta^((p+1)/4) mod p
// The exponent (p+1)/4 for BN254 is 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52
⋮----
func (k *PrivateKey) PublicKey() symbiotic.PublicKey
⋮----
// Get the generators for G1 and G2
⋮----
// Compute public keys by scalar multiplication with generators
⋮----
func NewPublicKey(g1PubKey bn254.G1Affine, g2PubKey bn254.G2Affine) *PublicKey
⋮----
func (k *PublicKey) Verify(msg Message, sig Signature) error
⋮----
// Hash the message to a point on G1
⋮----
// Get the G2 generator
⋮----
var negSig bn254.G1Affine
⋮----
func (k *PublicKey) VerifyWithHash(msgHash MessageHash, sig Signature) error
⋮----
// OnChain might be one way operation, meaning that it's impossible to reconstruct PublicKey from compact
func (k *PublicKey) OnChain() CompactPublicKey
⋮----
func (k *PublicKey) Raw() RawPublicKey
⋮----
// combined g1 and g2 [compressed]
⋮----
func (k *PublicKey) G2() *bn254.G2Affine
⋮----
func (k *PublicKey) MarshalText() (text []byte, err error)
⋮----
func FromRaw(rawKey RawPublicKey) (*PublicKey, error)
⋮----
func FromPrivateKey(privateKey *PrivateKey) symbiotic.PublicKey
```

## File: symbiotic/usecase/crypto/ecdsaSecp256k1/key_test.go

```go
package ecdsaSecp256k1
⋮----
import (
	"crypto/rand"
	"math/big"
	"testing"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/stretchr/testify/require"
)
⋮----
"crypto/rand"
"math/big"
"testing"
⋮----
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
⋮----
func TestECDSAKeys(t *testing.T)
⋮----
func TestCheckPrivateKeyBytes(t *testing.T)
⋮----
func TestMakePrivateFromNumber(t *testing.T)
⋮----
func TestMarshallText(t *testing.T)
⋮----
func TestInvalidVerification(t *testing.T)
⋮----
func TestFromRaw(t *testing.T)
⋮----
func randData(t *testing.T) []byte
```

## File: symbiotic/usecase/crypto/ecdsaSecp256k1/key.go

```go
package ecdsaSecp256k1
⋮----
import (
	"crypto/ecdsa"
	"math/big"

	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
)
⋮----
"crypto/ecdsa"
"math/big"
⋮----
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
const (
	RawKeyLength      int = 33
	MessageHashLength int = 32
)
⋮----
type PublicKey struct {
	pubKey ecdsa.PublicKey
}
⋮----
type PrivateKey struct {
	privateKey ecdsa.PrivateKey
}
⋮----
func NewPrivateKey(b []byte) (*PrivateKey, error)
⋮----
if kInt.BitLen() > 32*8 { // 32 bytes = 256 bits
⋮----
func HashMessage(msg []byte) MessageHash
⋮----
func GenerateKey() (*PrivateKey, error)
⋮----
func (k *PrivateKey) Bytes() []byte
⋮----
func (k *PrivateKey) Sign(msg []byte) (Signature, MessageHash, error)
⋮----
// symbiotic using keccak256 for hashing in ecdsaSecp256k1
⋮----
func (k *PrivateKey) PublicKey() symbiotic.PublicKey
⋮----
func NewPublicKey(x *big.Int, y *big.Int) *PublicKey
⋮----
func (k *PublicKey) Verify(msg Message, sig Signature) error
⋮----
func (k *PublicKey) VerifyWithHash(msgHash MessageHash, sig Signature) error
⋮----
// Remove recovery ID from signature for verification
⋮----
// OnChain might be one way operation, meaning that it's impossible to reconstruct PublicKey from compact
func (k *PublicKey) OnChain() CompactPublicKey
⋮----
// returns eth address in this case, left-padded to 32 bytes to match logic in contracts
// see https://github.com/symbioticfi/relay-contracts/blob/abcf4d7bb151780094d3a67cce7431300ecd5e31/src/contracts/libraries/keys/KeyEcdsaSecp256k1.sol#L41
⋮----
func (k *PublicKey) Raw() RawPublicKey
⋮----
// returns 33 bytes compressed pubKey
⋮----
func (k *PublicKey) MarshalText() (text []byte, err error)
⋮----
func FromRaw(rawKey RawPublicKey) (*PublicKey, error)
⋮----
func FromPrivateKey(privateKey *PrivateKey) symbiotic.PublicKey
```

## File: symbiotic/usecase/crypto/keys.go

```go
package crypto
⋮----
import (
	"sync"

	"github.com/go-errors/errors"
	"github.com/symbioticfi/relay/internal/client/repository/cache"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto/ecdsaSecp256k1"
)
⋮----
"sync"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/internal/client/repository/cache"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/ecdsaSecp256k1"
⋮----
var (
	pubKeyCache   cache.Cache[pubKeyCacheKey, symbiotic.PublicKey]
	initCacheOnce sync.Once
)
⋮----
// InitializePubkeyCache initializes the public key cache with the given size.
// Dev: Should be called only once during application startup.
func InitializePubkeyCache(cacheSize int) (err error)
⋮----
// FNV-1a 32-bit hash
const (
					offset32 = uint32(2166136261)
⋮----
// Process each byte of the key string
⋮----
type pubKeyCacheKey struct {
	keyTag symbiotic.KeyType
	key    string
}
⋮----
func NewPublicKey(keyType symbiotic.KeyType, keyBytes symbiotic.RawPublicKey) (PublicKey, error)
⋮----
// Try cache first
⋮----
var (
		pubkey PublicKey
		err    error
	)
⋮----
func NewPrivateKey(keyType symbiotic.KeyType, keyBytes []byte) (PrivateKey, error)
⋮----
func HashMessage(keyType symbiotic.KeyType, msg []byte) (symbiotic.RawMessageHash, error)
⋮----
func GeneratePrivateKey(keyType symbiotic.KeyType) (PrivateKey, error)
```

## File: symbiotic/usecase/ssz/ssz.go

```go
// Hash: 8c67e0de1079a95336f540c6c73e42f4633fd2cb9841d83ab84b052439e4f3c7
// Version: 0.1.3
package ssz
⋮----
import (
	"math/big"
	"sort"

	ssz "github.com/ferranbt/fastssz"
	"github.com/go-errors/errors"

	"github.com/ethereum/go-ethereum/common"
)
⋮----
"math/big"
"sort"
⋮----
ssz "github.com/ferranbt/fastssz"
"github.com/go-errors/errors"
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
const (
	ValidatorsListLocalPosition       = 0
	OperatorLocalPosition             = 0
	ValidatorVotingPowerLocalPosition = 1
	IsActiveLocalPosition             = 2
	KeysListLocalPosition             = 3
	VaultsListLocalPosition           = 4
	TagLocalPosition                  = 0
	PayloadHashLocalPosition          = 1
	ChainIdLocalPosition              = 0
	VaultLocalPosition                = 1
	VaultVotingPowerLocalPosition     = 2
)
⋮----
const (
	ValidatorSetElements      = 1
	ValidatorSetTreeHeight    = 0 // ceil(log2(ValidatorSetElements))
⋮----
ValidatorSetTreeHeight    = 0 // ceil(log2(ValidatorSetElements))
⋮----
ValidatorTreeHeight       = 3 // ceil(log2(ValidatorElements))
⋮----
VaultTreeHeight           = 2 // ceil(log2(VaultElements))
⋮----
KeyTreeHeight             = 1 // ceil(log2(KeyElements))
⋮----
ValidatorsListTreeHeight  = 20 // ceil(log2(ValidatorsListMaxElements))
⋮----
KeysListTreeHeight        = 7 // ceil(log2(KeysListMaxElements))
⋮----
VaultsListTreeHeight      = 10 // ceil(log2(VaultsListMaxElements))
⋮----
// MarshalSSZ ssz marshals the Key object
func (k *SszKey) MarshalSSZ() ([]byte, error)
⋮----
// MarshalSSZTo ssz marshals the Key object to a target array
func (k *SszKey) MarshalSSZTo(buf []byte) ([]byte, error)
⋮----
// Field (0) 'Tag'
⋮----
// Field (1) 'PayloadHash'
⋮----
// UnmarshalSSZ ssz unmarshals the Key object
func (k *SszKey) UnmarshalSSZ(buf []byte) error
⋮----
var err error
⋮----
// SizeSSZ returns the ssz encoded size in bytes for the Key object
func (k *SszKey) SizeSSZ() int
⋮----
// HashTreeRoot ssz hashes the Key object
func (k *SszKey) HashTreeRoot() ([32]byte, error)
⋮----
// HashTreeRootWith ssz hashes the Key object with a hasher
func (k *SszKey) HashTreeRootWith(hh ssz.HashWalker) error
⋮----
// GetTree ssz hashes the Key object
func (k *SszKey) GetTree() (*ssz.Node, error)
⋮----
// MarshalSSZ ssz marshals the Vault object
⋮----
// MarshalSSZTo ssz marshals the Vault object to a target array
⋮----
// Field (0) 'ChainId'
⋮----
// Field (1) 'OperatorVault'
⋮----
// Field (2) 'VotingPower'
⋮----
// UnmarshalSSZ ssz unmarshals the Vault object
⋮----
// SizeSSZ returns the ssz encoded size in bytes for the Vault object
⋮----
// HashTreeRoot ssz hashes the Vault object
⋮----
// HashTreeRootWith ssz hashes the Vault object with a hasher
⋮----
// GetTree ssz hashes the Vault object
⋮----
// MarshalSSZ ssz marshals the Validator object
⋮----
// MarshalSSZTo ssz marshals the Validator object to a target array
⋮----
// Field (0) 'Operator'
⋮----
// Field (1) 'VotingPower'
⋮----
// Field (2) 'IsActive'
⋮----
// Offset (3) 'Keys'
⋮----
// Offset (4) 'Vaults'
⋮----
// Field (3) 'Keys'
⋮----
// Field (4) 'Vaults'
⋮----
// UnmarshalSSZ ssz unmarshals the Validator object
⋮----
var o3, o4 uint64
⋮----
// SizeSSZ returns the ssz encoded size in bytes for the Validator object
⋮----
// HashTreeRoot ssz hashes the Validator object
⋮----
// HashTreeRootWith ssz hashes the Validator object with a hasher
⋮----
// GetTree ssz hashes the Validator object
⋮----
// MarshalSSZ ssz marshals the SszValidatorSet object
⋮----
// MarshalSSZTo ssz marshals the SszValidatorSet object to a target array
⋮----
// Offset (0) 'Validators'
⋮----
// Field (0) 'Validators'
⋮----
// UnmarshalSSZ ssz unmarshalls the SszValidatorSet object
⋮----
var o0 uint64
⋮----
// SizeSSZ returns the ssz encoded size in bytes for the SszValidatorSet object
⋮----
// HashTreeRoot ssz hashes the SszValidatorSet object
⋮----
// HashTreeRootWith ssz hashes the SszValidatorSet object with a hasher
⋮----
// GetTree ssz hashes the SszValidatorSet object
⋮----
//revive:disable-next-line:function-result-limit // This proof helper returns value, index and proof together.
func (v *SszValidatorSet) ProveValidatorRoot(operator common.Address) (*SszValidator, int, *ssz.Proof, error)
⋮----
// go to SszValidatorSet.Validators
⋮----
// consider List's length mix-in
⋮----
// go to SszValidatorSet.Validators[validatorIndex]
⋮----
func (v *SszValidator) ProveValidatorOperator() (*ssz.Proof, error)
⋮----
// go to Validator.Operator
⋮----
func (v *SszValidator) ProveValidatorVotingPower() (*ssz.Proof, error)
⋮----
// go to Validator.VotingPower
⋮----
func (v *SszValidator) ProveValidatorIsActive() (*ssz.Proof, error)
⋮----
// go to Validator.IsActive
⋮----
func (v *SszValidator) ProveKeyRoot(keyTag uint8) (*SszKey, int, *ssz.Proof, error)
⋮----
// go to Validator.Keys
⋮----
// go to Validator.Keys[keyIndex]
⋮----
func (k *SszKey) ProveKeyTag() (*ssz.Proof, error)
⋮----
// go to Key.Tag
⋮----
func (k *SszKey) ProveKeyPayloadHash() (*ssz.Proof, error)
⋮----
// go to Key.PayloadHash
⋮----
func (v *SszValidator) ProveVaultRoot(vault common.Address) (*SszVault, int, *ssz.Proof, error)
⋮----
// go to Validator.Vaults
⋮----
// go to Validator.Vaults[vaultIndex]
⋮----
func (v *SszVault) ProveVaultChainId() (*ssz.Proof, error)
⋮----
// go to Vault.ChainId
⋮----
func (v *SszVault) ProveVaultVault() (*ssz.Proof, error)
⋮----
// go to Vault.Vault
⋮----
func (v *SszVault) ProveVaultVotingPower() (*ssz.Proof, error)
⋮----
// go to Vault.VotingPower
```

## File: symbiotic/usecase/ssz/types.go

```go
package ssz
⋮----
import (
	"math/big"

	"github.com/ethereum/go-ethereum/common"
)
⋮----
"math/big"
⋮----
"github.com/ethereum/go-ethereum/common"
⋮----
type SszKey struct {
	Tag         uint8 `ssz-size:"1"`
	Payload     []byte
	PayloadHash [32]byte `ssz-size:"32"`
}
⋮----
type SszVault struct {
	ChainId     uint64         `ssz-size:"8"`
	Vault       common.Address `ssz-size:"20"`
	VotingPower *big.Int       `ssz-size:"32"`
}
⋮----
type SszValidator struct {
	Operator    common.Address `ssz-size:"20"`
	VotingPower *big.Int       `ssz-size:"32"`
	IsActive    bool           `ssz-size:"1"`
	Keys        []*SszKey      `ssz-max:"128"`
	Vaults      []*SszVault    `ssz-max:"1024"`
}
⋮----
type SszValidatorSet struct {
	Version    uint8
	Validators []*SszValidator `ssz-max:"1048576"`
}
```

## File: symbiotic/usecase/valset-deriver/mocks/deriver.go

```go
// Code generated by MockGen. DO NOT EDIT.
// Source: valset_deriver.go
//
// Generated by this command:
⋮----
//	mockgen -source=valset_deriver.go -destination=mocks/deriver.go -package=mocks -mock_names=evmClient=MockEvmClient
⋮----
// Package mocks is a generated GoMock package.
package mocks
⋮----
import (
	context "context"
	reflect "reflect"

	common "github.com/ethereum/go-ethereum/common"
	entity "github.com/symbioticfi/relay/symbiotic/entity"
	gomock "go.uber.org/mock/gomock"
)
⋮----
context "context"
reflect "reflect"
⋮----
common "github.com/ethereum/go-ethereum/common"
entity "github.com/symbioticfi/relay/symbiotic/entity"
gomock "go.uber.org/mock/gomock"
⋮----
// MockEvmClient is a mock of evmClient interface.
type MockEvmClient struct {
	ctrl     *gomock.Controller
	recorder *MockEvmClientMockRecorder
	isgomock struct{}
⋮----
// MockEvmClientMockRecorder is the mock recorder for MockEvmClient.
type MockEvmClientMockRecorder struct {
	mock *MockEvmClient
}
⋮----
// NewMockEvmClient creates a new mock instance.
func NewMockEvmClient(ctrl *gomock.Controller) *MockEvmClient
⋮----
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockEvmClient) EXPECT() *MockEvmClientMockRecorder
⋮----
// GetConfig mocks base method.
func (m *MockEvmClient) GetConfig(ctx context.Context, timestamp entity.Timestamp, epoch entity.Epoch) (entity.NetworkConfig, error)
⋮----
// GetConfig indicates an expected call of GetConfig.
⋮----
// GetCurrentEpoch mocks base method.
func (m *MockEvmClient) GetCurrentEpoch(ctx context.Context) (entity.Epoch, error)
⋮----
// GetCurrentEpoch indicates an expected call of GetCurrentEpoch.
⋮----
// GetEip712Domain mocks base method.
func (m *MockEvmClient) GetEip712Domain(ctx context.Context, addr entity.CrossChainAddress) (entity.Eip712Domain, error)
⋮----
// GetEip712Domain indicates an expected call of GetEip712Domain.
⋮----
// GetEpochStart mocks base method.
func (m *MockEvmClient) GetEpochStart(ctx context.Context, epoch entity.Epoch) (entity.Timestamp, error)
⋮----
// GetEpochStart indicates an expected call of GetEpochStart.
⋮----
// GetHeaderHash mocks base method.
func (m *MockEvmClient) GetHeaderHash(ctx context.Context, addr entity.CrossChainAddress) (common.Hash, error)
⋮----
// GetHeaderHash indicates an expected call of GetHeaderHash.
⋮----
// GetHeaderHashAt mocks base method.
func (m *MockEvmClient) GetHeaderHashAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch) (common.Hash, error)
⋮----
// GetHeaderHashAt indicates an expected call of GetHeaderHashAt.
⋮----
// GetKeys mocks base method.
func (m *MockEvmClient) GetKeys(ctx context.Context, address entity.CrossChainAddress, timestamp entity.Timestamp) ([]entity.OperatorWithKeys, error)
⋮----
// GetKeys indicates an expected call of GetKeys.
⋮----
// GetLastCommittedHeaderEpoch mocks base method.
func (m *MockEvmClient) GetLastCommittedHeaderEpoch(ctx context.Context, addr entity.CrossChainAddress, opts ...entity.EVMOption) (entity.Epoch, error)
⋮----
// GetLastCommittedHeaderEpoch indicates an expected call of GetLastCommittedHeaderEpoch.
⋮----
// GetNetworkAddress mocks base method.
func (m *MockEvmClient) GetNetworkAddress(ctx context.Context) (common.Address, error)
⋮----
// GetNetworkAddress indicates an expected call of GetNetworkAddress.
⋮----
// GetOperators mocks base method.
func (m *MockEvmClient) GetOperators(ctx context.Context, address entity.CrossChainAddress, timestamp entity.Timestamp) ([]common.Address, error)
⋮----
// GetOperators indicates an expected call of GetOperators.
⋮----
// GetSubnetwork mocks base method.
func (m *MockEvmClient) GetSubnetwork(ctx context.Context) (common.Hash, error)
⋮----
// GetSubnetwork indicates an expected call of GetSubnetwork.
⋮----
// GetVotingPowers mocks base method.
func (m *MockEvmClient) GetVotingPowers(ctx context.Context, address entity.CrossChainAddress, timestamp entity.Timestamp) ([]entity.OperatorVotingPower, error)
⋮----
// GetVotingPowers indicates an expected call of GetVotingPowers.
⋮----
// IsValsetHeaderCommittedAt mocks base method.
func (m *MockEvmClient) IsValsetHeaderCommittedAt(ctx context.Context, addr entity.CrossChainAddress, epoch entity.Epoch, opts ...entity.EVMOption) (bool, error)
⋮----
// IsValsetHeaderCommittedAt indicates an expected call of IsValsetHeaderCommittedAt.
⋮----
// MockexternalVotingPowerClient is a mock of externalVotingPowerClient interface.
type MockexternalVotingPowerClient struct {
	ctrl     *gomock.Controller
	recorder *MockexternalVotingPowerClientMockRecorder
	isgomock struct{}
⋮----
// MockexternalVotingPowerClientMockRecorder is the mock recorder for MockexternalVotingPowerClient.
type MockexternalVotingPowerClientMockRecorder struct {
	mock *MockexternalVotingPowerClient
}
⋮----
// NewMockexternalVotingPowerClient creates a new mock instance.
func NewMockexternalVotingPowerClient(ctrl *gomock.Controller) *MockexternalVotingPowerClient
```

## File: symbiotic/usecase/valset-deriver/valset_deriver_test.go

```go
package valsetDeriver
⋮----
import (
	"context"
	"fmt"
	"math/big"
	"slices"
	"sync/atomic"
	"testing"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/go-errors/errors"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/ssz"
	"github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
)
⋮----
"context"
"fmt"
"math/big"
"slices"
"sync/atomic"
"testing"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/ssz"
"github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver/mocks"
⋮----
type testExternalVotingPowerClient struct {
	getVotingPowers func(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorVotingPower, error)
}
⋮----
func (t *testExternalVotingPowerClient) GetVotingPowers(
	ctx context.Context,
	address symbiotic.CrossChainAddress,
	timestamp symbiotic.Timestamp,
) ([]symbiotic.OperatorVotingPower, error)
⋮----
func TestDeriver_calcQuorumThreshold(t *testing.T)
⋮----
QuorumThreshold: symbiotic.ToQuorumThresholdPct(big.NewInt(670000000000000000)), // 67%
⋮----
expectedQuorum: big.NewInt(1000*.67 + 1), // (1000 * 67% + 1)
⋮----
QuorumThreshold: symbiotic.ToQuorumThresholdPct(big.NewInt(750000000000000000)), // 75%
⋮----
expectedQuorum: big.NewInt(2000*.75 + 1), // (2000 * 75% + 1)
⋮----
func TestDeriver_fillValidators(t *testing.T)
⋮----
func TestDeriver_fillValidatorsActive(t *testing.T)
⋮----
expectedActiveValidators   []common.Address    // operator addresses that should be active
expectedInactiveValidators []common.Address    // operator addresses that should be inactive
expectedVotingPowers       map[string]*big.Int // operator -> expected voting power after capping
⋮----
MaxVotingPower:          symbiotic.ToVotingPower(big.NewInt(0)), // no max limit
MaxValidatorsCount:      symbiotic.ToVotingPower(big.NewInt(0)), // no max count
⋮----
expectedTotalVotingPower:   big.NewInt(700), // 500 + 200
⋮----
expectedInactiveValidators: []common.Address{common.HexToAddress("0x789")}, // below minimum
⋮----
"0x789": big.NewInt(50), // unchanged but inactive
⋮----
Keys:        []symbiotic.ValidatorKey{}, // no keys
⋮----
expectedInactiveValidators: []common.Address{common.HexToAddress("0x456")}, // no keys
⋮----
expectedTotalVotingPower: big.NewInt(600), // 400 (capped) + 200
⋮----
"0x123": big.NewInt(400), // capped from 600
⋮----
expectedTotalVotingPower:   big.NewInt(900), // 500 + 400 (only first 2 validators)
⋮----
expectedInactiveValidators: []common.Address{common.HexToAddress("0x789")}, // exceeds max count
⋮----
expectedTotalVotingPower:   big.NewInt(550), // 350 (capped from 500) + 200
⋮----
expectedInactiveValidators: []common.Address{common.HexToAddress("0x789"), common.HexToAddress("0xabc")}, // 0x789 exceeds max count, 0xabc below min power
⋮----
"0x123": big.NewInt(350), // capped from 500
⋮----
// Make a copy of validators to avoid modifying the test data
⋮----
// Check total voting power
⋮----
// Check active validators
var activeValidators []common.Address
var inactiveValidators []common.Address
⋮----
// Check voting power (capping)
⋮----
func TestDeriver_GetNetworkData(t *testing.T)
⋮----
func TestDeriver_fillValidators_VaultLimitExceeded(t *testing.T)
⋮----
// This test verifies vault truncation when exceeding ssz.VaultsListMaxElements (1024)
// Expected behavior:
// 1. Sort vaults by voting power DESC, then vault address ASC
// 2. Truncate to keep only top 1024 vaults
// 3. Re-sort remaining vaults by vault address ASC only
⋮----
const (
		highPowerVaults   = 5
		mediumPowerVaults = 5
		extraVaults       = 10 // Create more than the 1024 limit
		highPower         = 2000
		mediumPower       = 1500
		lowPower          = 1000
	)
⋮----
extraVaults       = 10 // Create more than the 1024 limit
⋮----
// Create test vaults with different voting powers
⋮----
var power int64
⋮----
// Setup test data
⋮----
// Execute
⋮----
// Verify results
⋮----
// All high and medium power vaults should be kept
⋮----
// Remaining slots filled with low power vaults
⋮----
func TestDeriver_getVotingPowersFromProviders_MixedRouting(t *testing.T)
⋮----
func TestDeriver_getVotingPowersFromProviders_ChainIDZeroUsesEVM(t *testing.T)
⋮----
func TestDeriver_getVotingPowersFromProviders_NoExternalClient(t *testing.T)
⋮----
func TestDeriver_getVotingPowersFromProviders_TypedNilExternalClient(t *testing.T)
⋮----
var typedNilExternalClient *testExternalVotingPowerClient
⋮----
var gotErr error
⋮----
func TestDeriver_getVotingPowersFromProviders_ErrorPropagation(t *testing.T)
⋮----
func TestDeriver_getVotingPowersFromProviders_ConcurrencyLimit(t *testing.T)
⋮----
var inFlight int64
var maxInFlight int64
⋮----
func TestDeriver_GetSchedulerInfo(t *testing.T)
⋮----
// These expected values are deterministic based on the hash calculation
expectedAggIndices:  []uint32{2, 0}, // Calculated deterministically from hash
expectedCommIndices: []uint32{1},    // Calculated deterministically from hash
⋮----
func TestDeriver_GetSchedulerInfo_Deterministic(t *testing.T)
⋮----
// Test that GetSchedulerInfo returns consistent results for the same inputs
⋮----
// Run the same calculation multiple times
const iterations = 10
var firstAggIndices, firstCommIndices []uint32
⋮----
func TestDeriver_GetSchedulerInfo_VerifyRandomness(t *testing.T)
⋮----
// Test that different inputs produce different results
⋮----
// Get results for original valset
⋮----
// Test with different epoch
⋮----
// Note: Different epochs might produce the same results due to hash collisions,
// but we can verify they run without error
⋮----
// Test with different timestamp
⋮----
// Results should be different for different timestamps (high probability)
⋮----
func TestDeriver_findNextAvailableIndex(t *testing.T)
⋮----
// Verify the result is not in usedIndices
⋮----
// Verify the result is within bounds
⋮----
func TestDeriver_findNextAvailableIndex_Panic(t *testing.T)
⋮----
// Test that the function panics when no indices are available
⋮----
// Create a scenario where all indices are taken
```

## File: symbiotic/usecase/valset-deriver/valset_deriver.go

```go
package valsetDeriver
⋮----
import (
	"context"
	"log/slog"
	"maps"
	"math/big"
	"reflect"
	"slices"
	"strconv"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/go-errors/errors"
	"github.com/samber/lo"
	"golang.org/x/sync/errgroup"

	"github.com/symbioticfi/relay/symbiotic/client/votingpower"
	symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
	"github.com/symbioticfi/relay/symbiotic/usecase/ssz"
)
⋮----
"context"
"log/slog"
"maps"
"math/big"
"reflect"
"slices"
"strconv"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-errors/errors"
"github.com/samber/lo"
"golang.org/x/sync/errgroup"
⋮----
"github.com/symbioticfi/relay/symbiotic/client/votingpower"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/ssz"
⋮----
const (
	valsetVersion      = 1
	aggregatorRoleType = "AGGREGATOR"
	committerRoleType  = "COMMITTER"
)
⋮----
//go:generate mockgen -source=valset_deriver.go -destination=mocks/deriver.go -package=mocks -mock_names=evmClient=MockEvmClient
type evmClient interface {
	GetConfig(ctx context.Context, timestamp symbiotic.Timestamp, epoch symbiotic.Epoch) (symbiotic.NetworkConfig, error)
	GetEpochStart(ctx context.Context, epoch symbiotic.Epoch) (symbiotic.Timestamp, error)
	GetVotingPowers(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorVotingPower, error)
	GetKeys(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorWithKeys, error)
	GetEip712Domain(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.Eip712Domain, error)
	GetCurrentEpoch(ctx context.Context) (symbiotic.Epoch, error)
	GetSubnetwork(ctx context.Context) (common.Hash, error)
	GetNetworkAddress(ctx context.Context) (common.Address, error)
	GetHeaderHash(ctx context.Context, addr symbiotic.CrossChainAddress) (common.Hash, error)
	IsValsetHeaderCommittedAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch, opts ...symbiotic.EVMOption) (bool, error)
	GetHeaderHashAt(ctx context.Context, addr symbiotic.CrossChainAddress, epoch symbiotic.Epoch) (common.Hash, error)
	GetLastCommittedHeaderEpoch(ctx context.Context, addr symbiotic.CrossChainAddress, opts ...symbiotic.EVMOption) (symbiotic.Epoch, error)
	GetOperators(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]common.Address, error)
}
⋮----
type externalVotingPowerClient interface {
	GetVotingPowers(ctx context.Context, address symbiotic.CrossChainAddress, timestamp symbiotic.Timestamp) ([]symbiotic.OperatorVotingPower, error)
}
⋮----
// Deriver coordinates the ETH services
type Deriver struct {
	evmClient        evmClient
	externalVPClient externalVotingPowerClient
}
⋮----
// NewDeriver creates a new valset deriver
func NewDeriver(evmClient evmClient, externalVPClient externalVotingPowerClient) (*Deriver, error)
⋮----
func normalizeExternalVotingPowerClient(client externalVotingPowerClient) externalVotingPowerClient
⋮----
func (v *Deriver) GetNetworkData(ctx context.Context, addr symbiotic.CrossChainAddress) (symbiotic.NetworkData, error)
⋮----
type dtoOperatorVotingPower struct {
	chainId      uint64
	votingPowers []symbiotic.OperatorVotingPower
}
⋮----
func (v *Deriver) GetValidatorSet(ctx context.Context, epoch symbiotic.Epoch, config symbiotic.NetworkConfig) (symbiotic.ValidatorSet, error)
⋮----
// Get voting powers from all voting power providers.
⋮----
// Get keys from the keys provider
⋮----
// form validators list from voting powers and keys using config
⋮----
// calc new quorum threshold
⋮----
AggregatorIndices: nil, // will be initialized later
CommitterIndices:  nil, // will be initialized later
⋮----
func (v *Deriver) getVotingPowersFromProviders(
	ctx context.Context,
	providers []symbiotic.CrossChainAddress,
	timestamp symbiotic.Timestamp,
) ([]dtoOperatorVotingPower, error)
⋮----
var (
				votingPowers []symbiotic.OperatorVotingPower
				err          error
			)
⋮----
func GetSchedulerInfo(_ context.Context, valset symbiotic.ValidatorSet, config symbiotic.NetworkConfig) (aggIndices []uint32, commIndices []uint32, err error)
⋮----
// header.Hash() is computed over the full validator set, so the full slice
// must be in a deterministic order across nodes — otherwise scheduler
// assignments diverge silently.
⋮----
// need to return sorted ascending order indices because serialization uses bitmap which only returns sorted values when unpacking
⋮----
// Helper function for wrap-around search
func findNextAvailableIndex(startIndex uint32, validatorCount int, usedIndices map[uint32]struct
⋮----
// This should never happen if we don't request more roles than available validators
⋮----
func (v *Deriver) formValidators(
	config symbiotic.NetworkConfig,
	votingPowers []dtoOperatorVotingPower,
	keys []symbiotic.OperatorWithKeys,
) symbiotic.Validators
⋮----
func markValidatorsActive(config symbiotic.NetworkConfig, validators symbiotic.Validators)
⋮----
// Check minimum voting power if configured
⋮----
// Validators must have at least one key, and when configured,
// they must include every required key tag.
⋮----
func hasRequiredKeys(validator symbiotic.Validator, requiredKeyTags []symbiotic.KeyTag) bool
⋮----
func fillValidators(votingPowers []dtoOperatorVotingPower, keys []symbiotic.OperatorWithKeys) symbiotic.Validators
⋮----
// Create validators map to consolidate voting powers and keys
⋮----
// Process voting powers
⋮----
IsActive:    false, // Default to active, will filter later
⋮----
// Add vaults and their voting powers
⋮----
// Add vault to validator's vaults
⋮----
// filter by ssz max-vaults limit
⋮----
// Process required keys
for _, rk := range keys { // TODO: get required key tags from validator set config and fill with nils if needed
⋮----
// Add all keys for this operator
⋮----
// filter by ssz max-validators limit
```

## File: symbiotic/symbiotic.go

```go
package symbiotic
⋮----
import (
	"github.com/symbioticfi/relay/symbiotic/client/evm"
	"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
	"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
	valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"github.com/symbioticfi/relay/symbiotic/client/evm"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
```

## File: votingpower/proto/v1/votingpower.proto

```protobuf
syntax = "proto3";

package votingpower.v1;

option go_package = "github.com/symbioticfi/relay/internal/gen/votingpower/v1;votingpowerv1";

// VotingPowerProviderService is implemented by external voting power providers.
service VotingPowerProviderService {
  // GetVotingPowersAt returns voting power for operators at a specific timestamp.
  rpc GetVotingPowersAt(GetVotingPowersAtRequest) returns (GetVotingPowersAtResponse);
}

message GetVotingPowersAtRequest {
  // Unix timestamp in seconds.
  uint64 timestamp = 1;
}

message GetVotingPowersAtResponse {
  repeated OperatorVotingPower voting_powers = 1;
}

message OperatorVotingPower {
  // Operator address as hex string.
  string operator = 1;

  // Decimal string voting power.
  string voting_power = 2;
}
```

## File: .env.example

```
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
ETH_RPC_URL_MASTER=http://127.0.0.1:8545
EPOCH_DURATION=60
DEPLOYMENT_BUFFER=600
SLASHING_WINDOW=1200
BLOCK_TIME=1
OPERATORS=4
VERIFICATION_TYPE=1
```

## File: .gitmodules

```
[submodule "relay-bn254-example-circuit-keys"]
	path = circuits
	url = git@github.com:symbioticfi/relay-bn254-example-circuit-keys.git
```

## File: .golangci.yml

```yaml
version: "2"
run:
    go: "1.26"
    build-tags:
        - integration
    tests: true
linters:
    default: none
    enable:
        - asasalint
        - asciicheck
        - bidichk
        - bodyclose
        - contextcheck
        - copyloopvar
        - decorder
        #    - dogsled
        - durationcheck
        - embeddedstructfieldcheck
        - errchkjson
        - errname
        - errorlint
        - exhaustive
        - exhaustruct
        - exptostd
        - fatcontext
        - forbidigo
        - funcorder
        - gocheckcompilerdirectives
        - gochecknoinits
        - gochecksumtype
        - goconst
        - gocritic
        #    - godox
        - gomoddirectives
        - gomodguard
        - goprintffuncname
        - gosec
        - govet
        - grouper
        - importas
        - inamedparam
        - ineffassign
        - iotamixing
        - loggercheck
        - makezero
        - modernize
        - mirror
        - misspell
        - musttag
        - nakedret
        - nilerr
        - nilnesserr
        - noctx
        - nolintlint
        - nosprintfhostport
        - perfsprint
        - prealloc
        - predeclared
        - protogetter
        - reassign
        - revive
        - rowserrcheck
        - sloglint
        - spancheck
        - sqlclosecheck
        - staticcheck
        - testableexamples
        - testifylint
        - thelper
        - tparallel
        - unconvert
        - unparam
        - unused
        - usestdlibvars
        - usetesting
        - wastedassign
        - whitespace
    #    - wrapcheck
    settings:
        gomoddirectives:
            replace-allow-list:
                - github.com/consensys/gnark
                - github.com/consensys/gnark-crypto
        importas:
            alias:
                - pkg: github.com/symbioticfi/relay/internal/gen/api/v1
                  alias: apiv1
        cyclop:
            max-complexity: 30
            package-average: 10
        errcheck:
            check-type-assertions: true
        exhaustive:
            check:
                - switch
                - map
        exhaustruct:
            allow-empty-returns: true
            allow-empty: true
            include:
                - ^github.com/symbioticfi/relay/internal/client/repository/.*$
                - ^github.com/symbioticfi/relay/internal/client/p2p/proto/.*$
                - ^github.com/symbioticfi/relay/internal/gen/.*$
                - ^github.com/symbioticfi/relay/internal/entity/.*$
                - ^github.com/symbioticfi/relay/symbiotic/entity/.*$
                - ^github.com/symbioticfi/relay/core/entity/.*$
                - ^github.com/symbioticfi/relay/core/entity/.*$
            exclude:
                - ^github.com/symbioticfi/relay/internal/client/repository/badger.Repository$
                - ^github.com/ethereum/go-ethereum.CallMsg$
        funlen:
            lines: 100
            statements: 50
            ignore-comments: true
        gocognit:
            min-complexity: 20
        gocritic:
            disabled-checks:
                - commentFormatting
                - ifElseChain
                - appendAssign
            settings:
                captLocal:
                    paramsOnly: false
                underef:
                    skipRecvDeref: false
        gomodguard:
            blocked:
                modules:
                    - github.com/golang/protobuf:
                          recommendations:
                              - google.golang.org/protobuf
                          reason: see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules
                    - github.com/satori/go.uuid:
                          recommendations:
                              - github.com/google/uuid
                          reason: satori's package is not maintained
                    - github.com/gofrs/uuid:
                          recommendations:
                              - github.com/gofrs/uuid/v5
                          reason: gofrs' package was not go module before v5
        govet:
            disable:
                - fieldalignment
            enable-all: true
            settings:
                shadow:
                    strict: true
        inamedparam:
            skip-single-param: true
        mnd:
            ignored-functions:
                - args.Error
                - flag.Arg
                - flag.Duration.*
                - flag.Float.*
                - flag.Int.*
                - flag.Uint.*
                - os.Chmod
                - os.Mkdir.*
                - os.OpenFile
                - os.WriteFile
                - prometheus.ExponentialBuckets.*
                - prometheus.LinearBuckets
        nolintlint:
            require-explanation: true
            require-specific: true
            allow-no-explanation:
                - funlen
                - gocognit
                - lll
        perfsprint:
            strconcat: false
        revive:
            severity: warning
            rules:
                - name: atomic
                - name: banned-characters
                - name: bare-return
                - name: bool-literal-in-expr
                - name: call-to-gc
                - name: comments-density
                - name: confusing-results
                - name: constant-logical-expr
                - name: context-as-argument
                - name: context-keys-type
                - name: datarace
                - name: deep-exit
                - name: defer
                - name: dot-imports
                - name: duplicated-imports
                - name: early-return
                - name: empty-block
                - name: empty-lines
                - name: enforce-map-style
                - name: enforce-repeated-arg-type-style
                - name: enforce-slice-style
                - name: error-naming
                - name: error-return
                - name: error-strings
                - name: errorf
                - name: file-header
                - name: forbidden-call-in-wg-go
                #        - name: flag-parameter
                - name: function-result-limit
                - name: identical-branches
                - name: imports-blocklist
                - name: inefficient-map-lookup
                - name: increment-decrement
                - name: indent-error-flow
                - name: modifies-parameter
                - name: modifies-value-receiver
                - name: nested-structs
                - name: optimize-operands-order
                - name: range-val-address
                - name: range-val-in-closure
                - name: range
                - name: receiver-naming
                - name: redefines-builtin-id
                - name: redundant-import-alias
                - name: string-format
                - name: string-of-int
                - name: struct-tag
                - name: superfluous-else
                - name: time-equal
                - name: time-naming
                - name: unconditional-recursion
                - name: unexported-naming
                - name: unexported-return
                - name: unnecessary-if
                - name: unnecessary-stmt
                - name: unreachable-code
                - name: useless-break
                - name: var-declaration
                - name: waitgroup-by-value
        rowserrcheck:
            packages:
                - github.com/jmoiron/sqlx
        sloglint:
            no-global: ""
            context: scope
        wrapcheck:
            ignore-package-globs:
                - github.com/symbioticfi/relay/internal/*
                - golang.org/x/sync/errgroup
        modernize:
            disable:
                - any
        funcorder:
            constructor: true
            struct-method: false
        forbidigo:
            forbid:
                - pattern: ^fmt\.Errorf$
                  msg: "use errors.Errorf instead of fmt.Errorf"
    exclusions:
        generated: lax
        presets:
            - comments
            - common-false-positives
            - legacy
            - std-error-handling
        rules:
            - linters:
                  - goconst
                  - exhaustruct
                  - wrapcheck
                  - prealloc
                  - modernize
              path: _test\.go
            - path: _test\.go
              text: "subtests should call t.Parallel"
            - path: (.+)\.go$
              text: ST1003
            - path: (.+)\.go$
              text: 'shadow: declaration of "err" shadows declaration at line'
            - path: (.+)\.go$
              text: G115
            - path: (.+)\.go$
              text: G706
            - path: cmd/utils/
              text: "use of `fmt.Printf` forbidden"
        paths:
            - third_party$
            - builtin$
            - examples$
            - hack/
issues:
    max-issues-per-linter: 500
    max-same-issues: 500
formatters:
    enable:
        - gofmt
        - goimports
    exclusions:
        generated: lax
        paths:
            - third_party$
            - builtin$
            - examples$
```

## File: buf.badger.gen.yaml

```yaml
version: v2
inputs:
    - directory: internal/client/repository/badger/proto
managed:
    enabled: true
plugins:
    - local: protoc-gen-go
      out: internal/client/repository/badger/proto
      opt:
          - paths=source_relative
```

## File: buf.gen.yaml

```yaml
version: v2
inputs:
    - directory: api/proto
managed:
    enabled: true
plugins:
    - local: protoc-gen-doc
      out: docs/api/v1
      opt:
          - "html,index.html"
    - local: protoc-gen-doc
      out: docs/api/v1
      opt:
          - "markdown,doc.md"
    - local: protoc-gen-go
      out: internal/gen/api
      opt:
          - paths=source_relative
    - local: protoc-gen-go-grpc
      out: internal/gen/api
      opt:
          - paths=source_relative
    - local: protoc-gen-grpc-gateway
      out: internal/gen/api
      opt:
          - paths=source_relative
          - generate_unbound_methods=true
    - local: protoc-gen-openapiv2
      out: docs/api
      opt:
          - openapi_naming_strategy=simple
```

## File: buf.lock

```
# Generated by buf. DO NOT EDIT.
version: v2
deps:
  - name: buf.build/googleapis/googleapis
    commit: 72c8614f3bd0466ea67931ef2c43d608
    digest: b5:13efeea24e633fd45327390bdee941207a8727e96cf01affb84c1e4100fd8f48a42bbd508df11930cd2884629bafad685df1ac3111bc78cdaefcd38c9371c6b1
```

## File: buf.p2p.gen.yaml

```yaml
version: v2
inputs:
    - directory: internal/client/p2p/proto
managed:
    enabled: true
plugins:
    - local: protoc-gen-go
      out: internal/client/p2p/proto
      opt:
          - paths=source_relative
    - local: protoc-gen-go-grpc
      out: internal/client/p2p/proto
      opt:
          - paths=source_relative
```

## File: buf.votingpower.gen.yaml

```yaml
version: v2
inputs:
    - directory: votingpower/proto
managed:
    enabled: true
plugins:
    - local: protoc-gen-go
      out: internal/gen/votingpower
      opt:
          - paths=source_relative
    - local: protoc-gen-go-grpc
      out: internal/gen/votingpower
      opt:
          - paths=source_relative
    - local: protoc-gen-openapiv2
      strategy: all
      out: docs/votingpower
      opt:
          - openapi_naming_strategy=simple
    - local: protoc-gen-doc
      strategy: all
      out: docs/votingpower/v1
      opt:
          - "html,index.html"
    - local: protoc-gen-doc
      strategy: all
      out: docs/votingpower/v1
      opt:
          - "markdown,doc.md"
```

## File: buf.yaml

```yaml
version: v2
modules:
    - path: api/proto
    - path: votingpower/proto
deps:
    - buf.build/googleapis/googleapis
lint:
    use:
        - STANDARD
    except:
        - PACKAGE_DIRECTORY_MATCH
```

## File: CONTRIBUTING.md

```markdown
# Contributing Guidelines

We welcome contributions from the community! Please read the following guidelines carefully to ensure a smooth development workflow and consistent project quality.

For detailed development setup, testing, and API change management, see the [Development Guide](DEVELOPMENT.md).

---

## Branching Strategy

We use a trunk-based development model with the following branches:

- **`main`**: The primary development branch. All active development happens here, and it contains the latest code.
- **`release-x.y`**: Release branches created for each new minor version (e.g., `release-1.0`, `release-1.1`). These branches are used to:
    - Tag stable releases (`vx.y.0`, `vx.y.1`, etc.)
    - Backport critical fixes from `main`
    - Create patch releases for older versions

### Branch Naming Conventions

Please name your branches according to the purpose of the work:

- `feature/your-short-description` — for new features
- `fix/your-bug-description` — for bug fixes
- `chore/your-task` — for maintenance or tooling updates
- `docs/your-doc-change` — for documentation-only changes

> **Note**: Release branches (`release-x.y`) are created and managed by maintainers only.

---

## Pull Request Process

- 🔀 **Always create pull requests targeting the `main` branch** (unless backporting fixes to a release branch).
- ✅ Make sure your branch is up to date with `main` (or the target `release-x.y` branch) before opening a PR.
- ✅ Ensure your code builds and passes all tests.
- ✅ Follow Go best practices and run a linter by running `make lint`.
- 📝 Use clear and descriptive PR titles.
- 📌 Link related issues in the PR description (`Fixes #123`, `Closes #456`, etc.).

> **Note**: CI workflows (tests, linting, code quality checks) run automatically on all PRs to `main` and `release-*` branches, as well as on direct commits to these branches.

### PR Checklist

Before submitting, make sure your PR meets the following:

- [ ] Target branch is `main` (or appropriate `release-x.y` branch for backports)
- [ ] All tests pass
- [ ] Lint checks pass
- [ ] Code is covered with tests where applicable
- [ ] Documentation is updated if needed

---

## Releases

Releases are created by maintainers using the following process:

1. A new `release-x.y` branch is created from `main` for each minor version (e.g., `release-1.0`, `release-1.1`)
2. Releases are tagged from the `release-x.y` branch using semantic versioning:
    - `vx.y.0` — initial release for the minor version
    - `vx.y.1`, `vx.y.2`, etc. — patch releases with backported fixes
3. Critical fixes can be cherry-picked from `main` to release branches for patch releases

This branching strategy allows us to:

- Continue active development on `main` without blocking releases
- Backport important fixes to older stable versions
- Maintain multiple supported versions simultaneously

> 🚫 Do not create release branches or tag releases manually unless you are a core maintainer.

---

## Commit Style

We encourage using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages, e.g.:
```

## File: DEVELOPMENT.md

````markdown
# Symbiotic Relay - Development Guide

## Table of Contents

1. [Introduction](#introduction)
2. [Architecture Overview](#architecture-overview)
3. [Development Setup](#development-setup)
4. [Running Tests](#running-tests)
5. [Local Environment](#local-environment)
6. [Managing API/Configuration Changes](#managing-api-changes)
7. [Code Generation](#code-generation)
8. [Linting](#linting)
9. [Logging Conventions](#logging-conventions)
10. [Building Docker Images](#building-docker-images)
11. [Contributing](#contributing)
12. [Additional Resources](#additional-resources)

---

## Introduction

The Symbiotic Relay is a distributed middleware layer that facilitates cross-chain coordination, validator set management, and signature aggregation. This guide provides comprehensive information for developers working on the relay codebase, including setup, testing, and managing changes across the ecosystem.

## Architecture Overview

### Core Components

The Symbiotic Relay consists of several key components working together:

#### 1. **P2P Layer** (`internal/client/p2p/`)

The peer-to-peer networking layer handles decentralized communication between relay nodes:

- **GossipSub Protocol**: Uses libp2p's GossipSub for message broadcasting
- **Topic-based Communication**:
    - `/relay/v1/signature/ready` - Signature ready notifications
    - `/relay/v1/proof/ready` - Aggregation proof ready notifications
- **gRPC over P2P**: Direct node-to-node sync requests using gRPC over libp2p streams
- **Discovery**:
    - mDNS for local network discovery
    - Kademlia DHT for distributed peer discovery
    - Static peer support for known bootstrap nodes

#### 2. **Node Logic & Applications**

The relay operates in multiple modes, configurable per node:

- **Signer Nodes** (`internal/usecase/signer-app/`):
    - Listen for signature requests
    - Sign messages using BLS/Ecdsa keys
    - Broadcast signatures to the P2P network
- **Aggregator Nodes** (`internal/usecase/aggregator-app/`):
    - Collect signatures from multiple signers
    - Apply aggregation policies
    - Generate BLS aggregated signatures or ZK proofs
    - Broadcast aggregation proofs

- **Committer Nodes** (`internal/usecase/valset-listener/`):
    - Monitor validator set state on-chain
    - Submit aggregated proofs to settlement chains
    - Track epoch transitions

#### 3. **API Layer** (`internal/usecase/api-server/`)

Exposes gRPC API for external clients to create signature requests, query proofs/signatures and get validator/epoch info. Defined in `api/proto/v1/api.proto`

#### 4. **Storage Layer** (`internal/client/repository/badger/`)

- BadgerDB for persistent state storage
- Caches for high-performance reads
- Stores signatures, aggregation proofs, validator sets, and epochs

#### 5. **Symbiotic Integration** (`symbiotic/`)

- EVM client for on-chain interactions
- Validator set derivation logic
- Cryptographic primitives (BLS signatures, ZK proofs)

---

## Development Setup

### Prerequisites

- **Go 1.26.1 or later**
- **Node.js** (for contract compilation in E2E tests)
- **Foundry/Forge** (for Solidity contracts)
- **Docker & Docker Compose** (for E2E testing)
- **Buf CLI** (installed via `make install-tools`)

### Initial Setup

1. **Clone the repository**:

    ```bash
    git clone https://github.com/symbioticfi/relay.git
    cd relay
    ```

2. **Install development tools**:

    ```bash
    make install-tools
    ```

    This installs:
    - `buf` - Protocol buffer compiler
    - `protoc-gen-go` and `protoc-gen-go-grpc` - Go protobuf generators
    - `mockgen` - Mock generation for testing
    - `protoc-gen-doc` - API documentation generator

3. **Generate code**:

    ```bash
    make generate
    ```

    This generates:
    - API types from proto files
    - P2P message types
    - BadgerDB repository types
    - Client types
    - Mock implementations
    - Contract ABI bindings

4. **Build the relay sidecar binary**:

    ```bash
    make build-relay-sidecar OS=linux ARCH=amd64
    ```

    or for macOS ARM:

    ```bash
    make build-relay-sidecar OS=darwin ARCH=arm64
    ```

5. **Build the relay utils CLI binary**:
    ```bash
    make build-relay-utils OS=linux ARCH=amd64
    ```

---

## Running Tests

### Unit Tests

Run all unit tests with coverage:

```bash
make unit-test
```

To run tests for a specific package:

```bash
go test -v ./internal/usecase/signer-app/
```

### End-to-End (E2E) Tests

E2E tests spin up a complete relay network with blockchain nodes.

#### Quick E2E Test Run

```bash
# Setup the E2E environment (only needed once or after cleanup)
cd e2e
./setup.sh

# Start the network
cd temp-network
docker compose up -d
cd ../..

# Run the tests
make e2e-test
```

#### Custom E2E Configuration

You can customize the E2E network topology using environment variables, see the setup.sh script for more envs:

```bash
# Configure network before setup
export OPERATORS=6          # Number of relay operator nodes (default: 4)
export COMMITERS=2          # Number of committer nodes (default: 1)
export AGGREGATORS=1        # Number of aggregator nodes (default: 1)
export VERIFICATION_TYPE=1  # 0=ZK proofs, 1=BLS simple (default: 1)
export EPOCH_TIME=30        # Epoch duration in seconds (default: 30)
export BLOCK_TIME=2         # Block time in seconds (default: 1)
export FINALITY_BLOCKS=2    # Blocks until finality (default: 2)

# Run setup with custom config
cd e2e
./setup.sh
```

#### Cleanup E2E Environment

```bash
# Stop and remove containers
cd e2e/temp-network
docker compose down
```

---

## Local Environment

### Setting Up Local Development Network

For local development and testing:

```bash
make local-setup
```

This command takes the same envs as the e2e setup for configuration.

This command:

1. Generates relay sidecar configurations
2. Sets up a local blockchain network (Anvil)
3. Deploys contracts
4. Starts relay nodes in Docker

---

## Managing API/Configuration Changes

### Overview

When you make changes to the API proto file (`api/proto/v1/api.proto`), those changes must be propagated across multiple repositories and examples to maintain consistency across the ecosystem.

### Step 1: Update Proto Definition

1. Make your changes to `api/proto/v1/api.proto`
2. Regenerate Go code and Docs:
    ```bash
    make generate
    ```

### Step 2: Update Local Examples and E2E Tests

**Update Go Client Examples:**

```bash
cd api/client/examples
# Update main.go to reflect API changes
vim main.go
# Test the example, follow the readme and test
go run main.go
```

**Update E2E Tests and Configuration:**

If API changes affect the relay sidecar configuration or client usage:

**E2E Test Files** (`e2e/tests/`):

- Update client instantiation in test setup files
- Update test cases that use the changed RPC methods
- Update `sidecar.yaml` if new configuration fields are required

**E2E Scripts** (`e2e/scripts/`):

- Update sidecar startup scripts if config template needs new fields
- Update genesis generation script if relay utils CLI commands changed
- Update network generation script if new environment variables are needed

**Common changes:**

- **New RPC methods** → Add corresponding test cases
- **Config field changes** → Update sidecar configuration files and startup templates
- **CLI command changes** → Update scripts that invoke relay utils commands
- **Client interface changes** → Update test setup and client instantiation code

### Step 3: Update External Client Repositories

#### TypeScript Client ([relay-client-ts](https://github.com/symbioticfi/relay-client-ts))

The TypeScript client has an automated workflow that regenerates the gRPC client when the proto file changes. However, you still need to:

1. **Wait for/Trigger the workflow** that updates the generated client code
2. **Update examples manually**:
    ```bash
    cd examples/
    # Update example files to use new API
    vim basic-usage.ts
    npm run build
    npm run basic-usage
    ```

#### Rust Client ([relay-client-rs](https://github.com/symbioticfi/relay-client-rs))

Similar to TypeScript, the Rust client auto-generates the gRPC implementation:

1. **Wait for/Trigger the workflow** that updates the generated client code
2. **Update examples manually**:
    ```bash
    cd examples/
    # Update example files to use new API
    vim basic_usage.rs
    cargo build
    cargo run --example basic_usage
    ```

### Step 4: Update Symbiotic Super Sum Example

The [symbiotic-super-sum](https://github.com/symbioticfi/symbiotic-super-sum) repository provides a comprehensive task-based example.

**What to update:**

1. **Go Client Package Version**:

    ```bash
    cd off-chain
    # Update go.mod to use latest relay client
    go get github.com/symbioticfi/relay@<commit/tag>
    go mod tidy
    ```

2. **Network Configuration**:
    - Check if any configuration changes are needed in network setup
    - The `generate_network.sh` script in symbiotic-super-sum is similar to the E2E setup
    - Update environment variables or config files if the relay now requires new settings

3. **Example Application Code**:
    - Update any client usage in the off-chain application
    - Test the example end-to-end

4. **Documentation**:
    - Update README if API usage patterns have changed

### Step 5: Update Cosmos Relay SDK

The [cosmos-relay-sdk](https://github.com/symbioticfi/cosmos-relay-sdk) integrates the relay with Cosmos SDK chains.

**What to update:**

1. **Go Client Package**:

    ```bash
    # Update the client package version
    go get github.com/symbioticfi/relay/api/client/v1@latest
    go mod tidy
    ```

2. **Mock Relay Client** (`x/symstaking/types/mock_relay.go`):

    The mock relay client must match the updated client interface:

    Example of what needs updating:
    - If you added a new RPC method, add it to the mock
    - If you changed method signatures, update them in the mock
    - If you changed request/response types, update the mock accordingly

3. **Documentation**:
    - Update SDK docs to reflect new API capabilities

---

## Code Generation

The project uses code generation extensively. Here's what each target generates:

### Generate All

```bash
make generate
```

This runs all generation targets that need codegen, including mocks, proto messages, etc.

---

## Linting

### Run All Linters

```bash
make lint
```

This runs:

- `buf lint` for proto files
- `golangci-lint` for Go code

### Auto-fix Linting Issues

```bash
make go-lint-fix
```

---

## Logging Conventions

### Overview

The Symbiotic Relay uses Go's standard `log/slog` (structured logging) with a custom wrapper located in `pkg/log/`. This provides:

- **Structured logging** with type-safe fields
- **Context propagation** for automatic field inheritance
- **Component-based tagging** for filtering and debugging
- **Multiple output modes**: pretty (colored), text, and JSON

**Configuration:**
Set log level and mode in `sidecar.yaml`:

```yaml
log:
    level: debug # debug, info, warn, error
    mode: pretty # pretty, text, json
```

### Log Levels - When to Use

| Level                   | When to Use                                                           | Examples                                                                                     |
| ----------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| **Debug**               | Flow tracing, detailed decisions, skipped operations, variable values | "Skipped signing (not in validator set)", "Checked for missing epochs"                       |
| **Info** (prod default) | Key state changes, service lifecycle events, completed operations     | "Signature aggregation completed", "Started P2P listener", "Submitted proof to chain"        |
| **Warn**                | Recoverable issues, unusual but handled situations, security concerns | "Message signing disabled", "Retrying after temporary failure", "Invalid signature received" |
| **Error**               | Unrecoverable failures, critical problems requiring attention         | "Failed to load validator set", "Database connection lost", "Contract call failed"           |

**Important:** Log errors only at high-level error handlers (API handlers, main event loops, service entry points), not at every location where an error occurs. Internal functions should return errors without logging them, allowing the top-level handler to log once with full context.

### Context Propagation Pattern

**Always use context-aware logging variants** (`slog.InfoContext`, `slog.DebugContext`, etc.) when context is available.

```go
func (s *Service) HandleRequest(ctx context.Context, req *Request) error {
    // 1. Add component tag (required)
    ctx = log.WithComponent(ctx, "aggregator")

    // 2. Add request-specific context (if applicable)
    ctx = log.WithAttrs(ctx,
        slog.Uint64("epoch", uint64(req.Epoch)),
        slog.String("requestId", req.RequestID.Hex()),
    )

    // 3. All subsequent logs automatically include these fields
    slog.InfoContext(ctx, "Started processing request")

    // ... rest of implementation
    return nil
}

```

### Standard Field Names

All field names **must** use `camelCase` notation. Use these standard field names consistently:

#### Request Context

- `requestId` - Unique request identifier (use for cross-service correlation)
- `epoch` - Epoch number (uint64)

#### Identifiers

- `keyTag` - Key tag identifier
- `operator` - Operator address/ID
- `publicKey` - Public key (formatted as hex)
- `address` - Ethereum address
- `validatorIndex` - Validator index in the set

#### Operation Tracking

- `error` - Error message/object (always use "error", not "err")
- `duration` - Operation duration (use `time.Since()`)
- `attempt` - Current retry attempt number
- `maxRetries` - Maximum retry attempts

#### Network/P2P

- `topic` - P2P topic name
- `sender` - Message sender identifier
- `peer` - Peer identifier
- `peerId` - Libp2p peer ID

#### Component/Method

- `component` - Component name (auto-added via `log.WithComponent()`)
- `method` - gRPC method name or function identifier

#### Blockchain

- `chainId` - Chain identifier
- `blockNumber` - Block number
- `txHash` - Transaction hash
- `contractAddress` - Smart contract address

#### Custom Fields

When adding custom fields not in this list:

- Use descriptive `camelCase` names
- Prefer specific names over generic ones (`validatorCount` not `count`)
- Document new commonly-used fields by updating this list

### Error Logging Standards

**1. Error Wrapping (Internal Functions):**

Always wrap errors using `github.com/go-errors/errors` to capture stacktrace in the place of error:

```go
import "github.com/go-errors/errors"

func (s *Service) loadData(id string) error {
    data, err := s.repo.Get(id)
    if err != nil {
        // Wrap with context, preserve stack trace
        return errors.Errorf("failed to load data for id=%s: %w", id, err)
    }
    return nil
}
```

**2. Error Logging (Boundaries Only):**

Log errors at **boundaries** (API handlers, main loops, service entry points):

**3. Always use `"error"` as the field name** (not "err"):

```go
// ❌ Incorrect: Using "err" as field name
slog.ErrorContext(ctx, "Failed to process request", "err", err)
slog.WarnContext(ctx, "Retry attempt failed", "err", retryErr)

// ✅ Correct: Always use "error" for consistency
slog.ErrorContext(ctx, "Failed to process request", "error", err)
slog.WarnContext(ctx, "Retry attempt failed", "error", retryErr)
```

### Duration Tracking

Always track and log operation durations for performance monitoring:

```go
func (s *Service) ProcessSignature(ctx context.Context, sig *Signature) error {
    start := time.Now()

    // ... perform operation ...

    slog.InfoContext(ctx, "Signature processed successfully",
        "duration", time.Since(start),
        "requestId", sig.RequestID,
    )
    return nil
}
```

### Log Message Format

Log messages **must** follow these conventions:

**1. Start with past tense verb:**

```go
// ✅ Correct: Past tense verbs indicating completed actions
slog.InfoContext(ctx, "Signature received")
slog.InfoContext(ctx, "Validator set loaded")
slog.InfoContext(ctx, "Proof submitted to chain")
slog.DebugContext(ctx, "Checked for missing epochs")

// ❌ Incorrect
slog.InfoContext(ctx, "Receiving signature")      // present continuous
slog.InfoContext(ctx, "Load validator set")       // imperative
slog.InfoContext(ctx, "Signature receive")        // noun only
```

**Note:** Present continuous tense ("Processing...", "Aggregating signatures...") may be valid for long-running operations where you want to communicate progress and show that the process is active, not stuck. However, always pair these with a past tense completion log:

```go
// ✅ Acceptable for long-running operations
slog.DebugContext(ctx, "Aggregating signatures from validators", "count", validatorCount)
// ... long operation ...
slog.InfoContext(ctx, "Aggregation completed", "duration", time.Since(start))
```

**2. Use consistent terminology:**

- "Started" / "Completed" for long operations
- "Received" / "Sent" for messages
- "Loaded" / "Stored" for data operations
- "Failed" for errors (not "Error:", the log level indicates it's an error)

### Component Naming Conventions

Use these standard component names with `log.WithComponent()`:

| Component         | Usage                      |
| ----------------- | -------------------------- |
| `"grpc"`          | gRPC handlers              |
| `"signer"`        | Signer application         |
| `"aggregator"`    | Aggregator application     |
| `"sign_listener"` | Signature listener service |
| `"listener"`      | Validator set listener     |
| `"p2p"`           | P2P network layer          |
| `"evm"`           | EVM client interactions    |

Keep component names:

- Lowercase
- Short and recognizable
- Consistent across the codebase

### \*Prefer context-aware logging variants whenever possible

```go
// ✅ Preferred (context-aware)
slog.InfoContext(ctx, "Message processed", "count", count)
slog.ErrorContext(ctx, "Failed to process", "error", err)

// ⚠️ Avoid when context is available (legacy pattern)
slog.Info("Message processed", "count", count)
slog.Error("Failed to process", "error", err)
```

---

## Building Docker Images

Build the relay sidecar Docker image:

```bash
make image
```

To build and push multi-architecture images:

```bash
PUSH_IMAGE=true PUSH_LATEST=true make image
```

---

## Contributing

Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for our branching strategy, PR process, and commit conventions.

### Key Points:

- **Target branch**: Always create PRs against `main` (unless backporting to a release branch)
- **Tests**: Ensure all tests pass before submitting PR
- **Linting**: Run `make lint` and fix all issues
- **Documentation**: Update docs when changing APIs or behavior

---

## Additional Resources

- **API Documentation**: [docs/api/v1/doc.md](docs/api/v1/doc.md)
- **Main README**: [README.md](README.md)
- **Contributing Guide**: [CONTRIBUTING.md](CONTRIBUTING.md)
- **Official Docs**: https://docs.symbiotic.fi/category/relay-sdk
- **Example Client Usage**: [api/client/examples/README.md](api/client/examples/README.md)
````

## File: Dockerfile

```dockerfile
FROM golang:1.26 AS builder

WORKDIR /app

# Cache go mod dependencies
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    go mod download

COPY . ./

ARG APP_VERSION
ARG BUILD_TIME
ARG TARGETOS
ENV GOOS=$TARGETOS
ARG TARGETARCH
ENV GOARCH=$TARGETARCH

# Cache build artifacts
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=0 go build -ldflags "-extldflags '-static' -X 'github.com/symbioticfi/relay/cmd/utils/root.Version=${APP_VERSION}' -X 'github.com/symbioticfi/relay/cmd/utils/root.BuildTime=${BUILD_TIME}'" -o relay_utils ./cmd/utils && \
    chmod a+x relay_utils

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=0 go build -ldflags "-extldflags '-static' -X 'github.com/symbioticfi/relay/cmd/relay/root.Version=${APP_VERSION}' -X 'github.com/symbioticfi/relay/cmd/relay/root.BuildTime=${BUILD_TIME}'" -o relay_sidecar ./cmd/relay && \
    chmod a+x relay_sidecar

FROM alpine:latest

WORKDIR /app

COPY --from=builder /app/relay_utils .
COPY --from=builder /app/relay_sidecar .
COPY --from=builder /app/docs ./docs
```

## File: example.config.yaml

```yaml
# Relay Sidecar Configuration Example

# Logging
log:
    level: "debug"
    mode: "pretty"

# Storage
storage-dir: ".data"
# storage-type: "bbolt"  # Storage backend: "bbolt" (default) or "badger"
# circuits-dir: ""  # Optional: Path to ZK circuits directory

# API Server Configuration
api:
    listen: ":8080"
    verbose-logging: false
    http-gateway: false # Enable HTTP/JSON REST API gateway (default: false)

# Metrics Configuration (optional)
metrics:
    listen: ":9090"
    pprof: false

# Driver Contract
driver:
    chain-id: 31337
    address: "0x4826533B4897376654Bb4d4AD88B7faFD0C98528"

# Secret Keys
secret-keys:
    - namespace: "symb"
      key-type: 0
      key-id: 15
      secret: "0xde0b6b3a7640000"
    - namespace: "evm"
      key-type: 1
      key-id: 31337
      secret: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"

# Signal Configuration
signal:
    worker-count: 10
    buffer-size: 20

# Cache Configuration
cache:
    network-config-size: 10
    validator-set-size: 10

# Sync Configuration
sync:
    enabled: true
    period: 5s
    timeout: 1m
    epochs: 5

# Key Cache
key-cache:
    size: 100
    enabled: true

# P2P Configuration
p2p:
    listen: "/ip4/0.0.0.0/tcp/8880"
    bootnodes: []
    dht-mode: "disabled"
    mdns: true
    publish-timeout: 10s # Maximum time a single pubsub publish may block

# EVM Configuration
evm:
    chains:
        - "http://127.0.0.1:8545"
    max-calls: 30
    # Per-chain gas prices in wei when eth_maxPriorityFeePerGas is not supported
    # Key is chain ID, value is gas price in wei
    # Default: 2000000000 (2 GWei) if chain is not specified
    # fallback-gas-prices:
    #   "31337": 2000000000    # Local chain: 2 GWei
    #   "11155420": 1000000000 # OP Sepolia: 1 GWei

# External Voting Power Providers (optional)
# Used when a voting power provider in on-chain config has chain-id in
# reserved external range [4_000_000_000..4_100_000_000].
# Provider ID is read from the first 10 bytes of provider address.
# external-voting-power-providers:
#   - id: "0x11223344556677889900"
#     url: "dns:///beacon-vp:50051"
#     secure: false
#     # ca-cert-file: "/path/to/ca.pem"
#     # server-name: "beacon-vp.internal"
#     # timeout: 5s
#     # headers:
#     #   authorization: "Bearer <token>"

# Aggregation Policy
aggregation-policy-max-unsigners: 50

# Data Retention Configuration (optional)
# Controls how much historical data to keep on this node
retention:
    # Maximum number of historical validator set epochs to sync on fresh node startup
    # - 0 (default): Unlimited - sync from genesis epoch
    # - N > 0: Sync only the most recent N epochs
    # Note: Only applies to fresh nodes. Existing nodes continue from last synced epoch.
    # Should match your pruning retention period to avoid re-syncing pruned data.
    valset-epochs: 0

# Automatic Pruning Configuration (optional)
# Periodically deletes old epoch data to prevent unbounded storage growth
pruner:
    # Enable automatic pruning (default: false for safety)
    enabled: false

    # How often to run the pruning process (default: 1h)
    # Examples: 30m, 1h, 6h, 24h
    interval: 1h

    # Number of request IDs to delete per database transaction during pruning
    # Lower values = shorter write lock durations, higher values = fewer transactions
    # 0 = process all request IDs in a single transaction (not recommended for large datasets)
    batch-size: 100

    # Pause between prune batches to yield to live writers (default: 100ms; 0 = no pause)
    # bbolt only — badger has no batching and ignores this value
    batch-pause: 100ms

# Aggregation Configuration
aggregation:
    # Max simultaneous proof aggregations (default: 10)
    worker-count: 10

    # Catch-up: periodically retries aggregation for requests that don't have a proof yet
    catchup:
        # Enable periodic catch-up loop (default: true)
        enabled: true

        # How often to run catch-up cycles (default: 1m)
        interval: 1m

        # Number of recent epochs to scan per cycle (default: 20)
        epochs-to-check: 20

        # How many epochs back from latest to start scanning (default: 0)
        # 0 = start from latest epoch
        epochs-offset: 0

        # Max requests to check per cycle, 0 = unlimited (default: 0)
        max-requests-per-cycle: 0

        # Max proofs to generate per cycle, 0 = unlimited (default: 100)
        max-proofs-per-cycle: 100

# bbolt Storage Engine Tuning (default, only used when storage-type: "bbolt")
# bbolt uses a B+tree with single-writer model for predictable write latency
# bbolt:
#   initial-mmap-size: 0        # Initial mmap size in bytes (0 = default)
#   compact-on-startup: true    # Compact database on startup to reclaim free pages (default: true)
#   no-freelist-sync: false     # Skip writing freelist to disk on every commit (faster writes, slower startup)
#   max-batch-delay: 2ms        # Max delay before flushing a batch write (default: 2ms; 0 = bbolt default 10ms)
#   max-batch-size: 0           # Max operations per batch write (0 = bbolt default 1000)
#   stats-log-interval: 0       # Interval for logging database stats (default: 0 = disabled)

# BadgerDB Storage Engine Tuning (optional, only used when storage-type: "badger")
# See https://github.com/dgraph-io/badger/blob/main/options.go#L123 for details
# badger:
#   block-cache-size: 134217728     # 128 MB (badger default: 256 MB)
#   mem-table-size: 33554432        # 32 MB (badger default: 64 MB)
#   num-memtables: 3                # (badger default: 5)
#   num-level-zero-tables: 3        # (badger default: 5)
#   num-level-zero-tables-stall: 8  # (badger default: 15)
#   compact-l0-on-close: true       # (badger default: false)
#   num-compactors: 2               # concurrent compaction goroutines (badger default: 4)
#   value-log-file-size: 536870912  # 512 MB (badger default: ~1 GB)
#   value-log-gc-interval: 5m      # how often to run value log GC, 0 = disabled (default: 5m)
#   value-log-gc-discard-ratio: 0.5 # discard ratio threshold for GC (default: 0.5)

tracing:
    enabled: false
    endpoint: "localhost:4317"
    sample-rate: 1.0
```

## File: go.mod

```
module github.com/symbioticfi/relay

go 1.26.1

require (
	github.com/RoaringBitmap/roaring/v2 v2.18.0
	github.com/consensys/gnark v0.0.0-00010101000000-000000000000 // pinned with replace
	github.com/consensys/gnark-crypto v0.20.1 // pinned with replace
	github.com/dgraph-io/badger/v4 v4.9.1
	github.com/elastic/go-freelru v0.16.0
	github.com/ethereum/go-ethereum v1.17.3
	github.com/ferranbt/fastssz v1.0.0
	github.com/go-chi/chi/v5 v5.2.5
	github.com/go-errors/errors v1.5.1
	github.com/go-playground/validator/v10 v10.30.2
	github.com/google/uuid v1.6.0
	github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3
	github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
	github.com/kelseyhightower/envconfig v1.4.0
	github.com/libp2p/go-libp2p v0.48.0
	github.com/libp2p/go-libp2p-gostream v0.6.0
	github.com/libp2p/go-libp2p-kad-dht v0.39.2
	github.com/libp2p/go-libp2p-pubsub v0.16.0
	github.com/multiformats/go-multiaddr v0.16.1
	github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0
	github.com/pelletier/go-toml/v2 v2.3.1
	github.com/prometheus/client_golang v1.23.2
	github.com/pterm/pterm v0.12.83
	github.com/samber/lo v1.53.0
	github.com/samber/slog-multi v1.8.0
	github.com/spf13/cobra v1.10.2
	github.com/spf13/pflag v1.0.10
	github.com/spf13/viper v1.21.0
	github.com/stretchr/testify v1.11.1
	go.etcd.io/bbolt v1.4.3
	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0
	go.opentelemetry.io/otel v1.43.0
	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0
	go.opentelemetry.io/otel/sdk v1.43.0
	go.opentelemetry.io/otel/trace v1.43.0
	go.uber.org/mock v0.6.0
	golang.org/x/net v0.53.0
	golang.org/x/sync v0.20.0
	golang.org/x/term v0.43.0
	google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348
	google.golang.org/grpc v1.81.0
	google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af
	gopkg.in/yaml.v2 v2.4.0
	k8s.io/client-go v0.36.0
)

require (
	atomicgo.dev/cursor v0.2.0 // indirect
	atomicgo.dev/keyboard v0.2.10 // indirect
	atomicgo.dev/schedule v0.1.0 // indirect
	filippo.io/bigmod v0.1.1-0.20260103110540-f8a47775ebe5 // indirect
	filippo.io/keygen v0.0.0-20260114151900-8e2790ea4c5b // indirect
	github.com/Microsoft/go-winio v0.6.2 // indirect
	github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260416073033-7c2071eaa8d4 // indirect
	github.com/benbjohnson/clock v1.3.5 // indirect
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/bits-and-blooms/bitset v1.24.4 // indirect
	github.com/blang/semver/v4 v4.0.0 // indirect
	github.com/cenkalti/backoff/v5 v5.0.3 // indirect
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
	github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
	github.com/containerd/console v1.0.5 // indirect
	github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
	github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
	github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
	github.com/deckarep/golang-set/v2 v2.9.0 // indirect
	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
	github.com/dgraph-io/ristretto/v2 v2.4.0 // indirect
	github.com/dunglas/httpsfv v1.1.0 // indirect
	github.com/dustin/go-humanize v1.0.1 // indirect
	github.com/emicklei/dot v1.11.0 // indirect
	github.com/ethereum/c-kzg-4844/v2 v2.1.7 // indirect
	github.com/filecoin-project/go-clock v0.1.0 // indirect
	github.com/flynn/noise v1.1.0 // indirect
	github.com/fsnotify/fsnotify v1.10.1 // indirect
	github.com/fxamacker/cbor/v2 v2.9.2 // indirect
	github.com/gabriel-vasile/mimetype v1.4.13 // indirect
	github.com/go-logr/logr v1.4.3 // indirect
	github.com/go-logr/stdr v1.2.2 // indirect
	github.com/go-ole/go-ole v1.3.0 // indirect
	github.com/go-playground/locales v0.14.1 // indirect
	github.com/go-playground/universal-translator v0.18.1 // indirect
	github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/google/flatbuffers v25.12.19+incompatible // indirect
	github.com/google/gopacket v1.1.19 // indirect
	github.com/google/pprof v0.0.0-20260507013755-92041b743c96 // indirect
	github.com/gookit/color v1.6.1 // indirect
	github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
	github.com/hashicorp/golang-lru v1.0.2 // indirect
	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
	github.com/holiman/uint256 v1.3.2 // indirect
	github.com/huin/goupnp v1.3.0 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 // indirect
	github.com/ipfs/boxo v0.39.0 // indirect
	github.com/ipfs/go-cid v0.6.1 // indirect
	github.com/ipfs/go-datastore v0.9.1 // indirect
	github.com/ipfs/go-log/v2 v2.9.1 // indirect
	github.com/ipld/go-ipld-prime v0.23.0 // indirect
	github.com/jackpal/go-nat-pmp v1.0.2 // indirect
	github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
	github.com/klauspost/compress v1.18.6 // indirect
	github.com/klauspost/cpuid/v2 v2.3.0 // indirect
	github.com/koron/go-ssdp v0.1.0 // indirect
	github.com/leodido/go-urn v1.4.0 // indirect
	github.com/libp2p/go-buffer-pool v0.1.0 // indirect
	github.com/libp2p/go-cidranger v1.1.0 // indirect
	github.com/libp2p/go-flow-metrics v0.3.0 // indirect
	github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
	github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect
	github.com/libp2p/go-libp2p-record v0.3.1 // indirect
	github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
	github.com/libp2p/go-msgio v0.3.0 // indirect
	github.com/libp2p/go-netroute v0.4.0 // indirect
	github.com/libp2p/go-reuseport v0.4.0 // indirect
	github.com/libp2p/go-yamux/v5 v5.1.0 // indirect
	github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
	github.com/lithammer/fuzzysearch v1.1.8 // indirect
	github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
	github.com/mattn/go-colorable v0.1.14 // indirect
	github.com/mattn/go-isatty v0.0.22 // indirect
	github.com/mattn/go-runewidth v0.0.23 // indirect
	github.com/miekg/dns v1.1.72 // indirect
	github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
	github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
	github.com/minio/sha256-simd v1.0.1 // indirect
	github.com/mitchellh/mapstructure v1.5.0 // indirect
	github.com/mr-tron/base58 v1.3.0 // indirect
	github.com/mschoch/smat v0.2.0 // indirect
	github.com/multiformats/go-base32 v0.1.0 // indirect
	github.com/multiformats/go-base36 v0.2.0 // indirect
	github.com/multiformats/go-multiaddr-dns v0.5.0 // indirect
	github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
	github.com/multiformats/go-multibase v0.3.0 // indirect
	github.com/multiformats/go-multicodec v0.10.0 // indirect
	github.com/multiformats/go-multihash v0.2.3 // indirect
	github.com/multiformats/go-multistream v0.6.1 // indirect
	github.com/multiformats/go-varint v0.1.0 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
	github.com/pion/datachannel v1.6.0 // indirect
	github.com/pion/dtls/v3 v3.1.2 // indirect
	github.com/pion/ice/v4 v4.2.5 // indirect
	github.com/pion/interceptor v0.1.45 // indirect
	github.com/pion/logging v0.2.4 // indirect
	github.com/pion/mdns/v2 v2.1.0 // indirect
	github.com/pion/randutil v0.1.0 // indirect
	github.com/pion/rtcp v1.2.16 // indirect
	github.com/pion/rtp v1.10.2 // indirect
	github.com/pion/sctp v1.9.5 // indirect
	github.com/pion/sdp/v3 v3.0.18 // indirect
	github.com/pion/srtp/v3 v3.0.10 // indirect
	github.com/pion/stun/v3 v3.1.2 // indirect
	github.com/pion/transport/v4 v4.0.1 // indirect
	github.com/pion/turn/v5 v5.0.3 // indirect
	github.com/pion/webrtc/v4 v4.2.12 // indirect
	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
	github.com/polydawn/refmt v0.89.1-0.20231129105047-37766d95467a // indirect
	github.com/prometheus/client_model v0.6.2 // indirect
	github.com/prometheus/common v0.67.5 // indirect
	github.com/prometheus/procfs v0.20.1 // indirect
	github.com/quic-go/qpack v0.6.0 // indirect
	github.com/quic-go/quic-go v0.59.0 // indirect
	github.com/quic-go/webtransport-go v0.10.0 // indirect
	github.com/ronanh/intcomp v1.1.1 // indirect
	github.com/rs/zerolog v1.35.1 // indirect
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
	github.com/sagikazarmark/locafero v0.12.0 // indirect
	github.com/samber/slog-common v0.22.0 // indirect
	github.com/shirou/gopsutil v3.21.11+incompatible // indirect
	github.com/spaolacci/murmur3 v1.1.0 // indirect
	github.com/spf13/afero v1.15.0 // indirect
	github.com/spf13/cast v1.10.0 // indirect
	github.com/subosito/gotenv v1.6.0 // indirect
	github.com/supranational/blst v0.3.16 // indirect
	github.com/tklauser/go-sysconf v0.3.16 // indirect
	github.com/tklauser/numcpus v0.11.0 // indirect
	github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
	github.com/wlynxg/anet v0.0.5 // indirect
	github.com/x448/float16 v0.8.4 // indirect
	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
	github.com/yusufpapurcu/wmi v1.2.4 // indirect
	go.mongodb.org/mongo-driver v1.17.9 // indirect
	go.opentelemetry.io/auto/sdk v1.2.1 // indirect
	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
	go.opentelemetry.io/otel/metric v1.43.0 // indirect
	go.opentelemetry.io/proto/otlp v1.10.0 // indirect
	go.uber.org/dig v1.19.0 // indirect
	go.uber.org/fx v1.24.0 // indirect
	go.uber.org/multierr v1.11.0 // indirect
	go.uber.org/zap v1.28.0 // indirect
	go.yaml.in/yaml/v2 v2.4.4 // indirect
	go.yaml.in/yaml/v3 v3.0.4 // indirect
	golang.org/x/crypto v0.50.0 // indirect
	golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
	golang.org/x/mod v0.35.0 // indirect
	golang.org/x/sys v0.44.0 // indirect
	golang.org/x/telemetry v0.0.0-20260506145330-5a0966d74795 // indirect
	golang.org/x/text v0.36.0 // indirect
	golang.org/x/time v0.15.0 // indirect
	golang.org/x/tools v0.44.0 // indirect
	gonum.org/v1/gonum v0.17.0 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
	k8s.io/apimachinery v0.36.0 // indirect
	k8s.io/klog/v2 v2.140.0 // indirect
	k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect
	lukechampine.com/blake3 v1.4.1 // indirect
)

// pinned versions
replace (
	github.com/consensys/gnark => github.com/consensys/gnark v0.14.0
	github.com/consensys/gnark-crypto => github.com/consensys/gnark-crypto v0.19.2
)
```

## File: LICENSE

```
Business Source License 1.1

License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.

-----------------------------------------------------------------------------

Parameters

Licensor:             GPRP

Licensed Work:        Symbiotic Relay
                      The Licensed Work is (c) 2026 GPRP

Additional Use Grant: None

Change Date:          2030-05-06

Change License:       GNU General Public License v2.0 or later

-----------------------------------------------------------------------------

Terms

The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.

Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.

If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.

All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.

You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.

Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.

This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).

TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.

MariaDB hereby grants you permission to use this License’s text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.

-----------------------------------------------------------------------------

Covenants of Licensor

In consideration of the right to use this License’s text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:

1. To specify as the Change License the GPL Version 2.0 or any later version,
   or a license that is compatible with GPL Version 2.0 or a later version,
   where "compatible" means that software provided under the Change License can
   be included in a program with software provided under GPL Version 2.0 or a
   later version. Licensor may specify additional Change Licenses without
   limitation.

2. To either: (a) specify an additional grant of rights to use that does not
   impose any additional restriction on the right granted in this License, as
   the Additional Use Grant; or (b) insert the text "None".

3. To specify a Change Date.

4. Not to modify this License in any other way.

-----------------------------------------------------------------------------

Notice

The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.
```

## File: Makefile

```makefile
PACKAGE=github.com/symbioticfi/relay
IMAGE_REPO ?= relay_sidecar
BUILD_TIME ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)

TAG ?=

ifeq ($(strip $(TAG)),)
	CURRENT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
	PSEUDO_VERSION := $(shell go list -f {{.Version}} -m ${PACKAGE}@${CURRENT_BRANCH} 2>/dev/null || echo "unspecified-$(CURRENT_BRANCH)")
	# Trim the `v` prefix from golang pseudo version as the TAG if not set
	FINAL_TAG := $(shell echo $(PSEUDO_VERSION) | sed 's/^v//' | sed 's/-0\./-/')
else
	# If TAG was explicitly passed, strip the v prefix
	TAG_ORIGINAL := $(TAG)
	FINAL_TAG := $(shell echo '$(TAG_ORIGINAL)' | sed 's/^v//')
endif

# add v prefix for APP_VERSION
APP_VERSION := v$(FINAL_TAG)

# create image tags without v prefix
IMAGE_TAGS := -t ${IMAGE_REPO}:${FINAL_TAG}
ifeq ($(PUSH_LATEST), true)
	IMAGE_TAGS := ${IMAGE_TAGS} -t ${IMAGE_REPO}:latest
endif

.PHONY: local-setup
local-setup:
	cd e2e && \
	bash setup.sh && \
	cd temp-network && \
	docker compose up -d

.PHONY: clean-local-setup
clean-local-setup:
	if [ -d "e2e/temp-network" ]; then \
		docker compose --project-directory e2e/temp-network down; \
	fi

.PHONY: lint
lint: install-tools buf-lint go-lint

.PHONY: buf-lint
buf-lint:
	buf lint

.PHONY: go-lint
go-lint:
	go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 -v run ./...

.PHONY: go-lint-fix
go-lint-fix:
	go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 -v run ./... --fix

.PHONY: generate
generate: install-tools generate-mocks generate-api-types generate-votingpower-types generate-client-types generate-p2p-types generate-badger-types gen-abi generate-cli-docs

.PHONY: install-tools
install-tools:
	go install github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc@v1.5.1
	go install go.uber.org/mock/mockgen@v0.6.0
	go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.5.1
	go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.6
	go install github.com/bufbuild/buf/cmd/buf@v1.59.0
	go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.27.7
	go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.27.7

.PHONY: generate-mocks
generate-mocks:
	go generate ./...

.PHONY: generate-api-types
generate-api-types:
	buf generate

.PHONY: generate-votingpower-types
generate-votingpower-types:
	buf generate --template=buf.votingpower.gen.yaml

.PHONY: generate-p2p-types
generate-p2p-types:
	buf generate --template=buf.p2p.gen.yaml

.PHONY: generate-badger-types
generate-badger-types:
	buf generate --template=buf.badger.gen.yaml

.PHONY: generate-client-types
generate-client-types:
	go run hack/codegen/generate-client-types.go

.PHONY: generate-cli-docs
generate-cli-docs:
	@echo "Generating CLI documentation..."
	go run hack/docgen/generate-cli-docs.go
	@echo "CLI documentation generated in docs/cli/"

.PHONY: unit-test
unit-test:
	go test $(shell go list ./... | grep -v '/e2e/') -v -covermode atomic -race -coverprofile=cover.out.tmp -coverpkg=$(shell go list ./... | grep -v '/e2e/' | tr '\n' ',')
	cat cover.out.tmp | grep -v "gen"  | grep -v "mocks" > coverage.out # strip out generated files
	go tool cover -func coverage.out > coverage.txt
	rm cover.out.tmp

.PHONY: e2e-test
e2e-test:
	cd e2e/tests && go test -v -timeout 40m

.PHONY: gen-abi
gen-abi:
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi symbiotic/client/evm/abi/ValSetDriver.abi.json \
		--type ValSetDriver \
		--pkg gen \
		--out symbiotic/client/evm/gen/valsetDriver.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi symbiotic/client/evm/abi/Settlement.abi.json \
		--type Settlement \
		--pkg gen \
		--out symbiotic/client/evm/gen/settlement.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi symbiotic/client/evm/abi/KeyRegistry.abi.json \
		--type KeyRegistry \
		--pkg gen \
		--out symbiotic/client/evm/gen/keyRegistry.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi symbiotic/client/evm/abi/VotingPowerProvider.abi.json \
		--type VotingPowerProvider \
		--pkg gen \
		--out symbiotic/client/evm/gen/votingPowerProvider.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi symbiotic/client/evm/abi/OperatorRegistry.abi.json \
		--type OperatorRegistry \
		--pkg gen \
		--out symbiotic/client/evm/gen/operatorRegistry.go

.PHONY: gen-abi-test
gen-abi-test:
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi e2e/tests/evm/abi/MockERC20.abi.json \
		--type MockERC20 \
		--pkg gen \
		--out e2e/tests/evm/gen/mockERC20.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi e2e/tests/evm/abi/IOptInService.abi.json \
		--type OptInService \
		--pkg gen \
		--out e2e/tests/evm/gen/optInService.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi e2e/tests/evm/abi/OpNetVaultAutoDeployLogic.abi.json \
		--type OpNetVaultAutoDeployLogic \
		--pkg gen \
		--out e2e/tests/evm/gen/opNetVaultAutoDeployLogic.go
	go run github.com/ethereum/go-ethereum/cmd/abigen@latest \
		--abi e2e/tests/evm/abi/Vault.abi.json \
		--type Vault \
		--pkg gen \
		--out e2e/tests/evm/gen/vault.go

# Generic build target that takes OS and architecture as parameters
# Usage: make build-relay-utils OS=linux ARCH=amd64
# Usage: make build-relay-sidecar OS=darwin ARCH=arm64
.PHONY: build-relay-utils
build-relay-utils:
	@if [ -z "$(OS)" ] || [ -z "$(ARCH)" ]; then \
		echo "Error: OS and ARCH parameters are required"; \
		echo "Usage: make build-relay-utils OS=<os> ARCH=<arch>"; \
		exit 1; \
	fi
	GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build -ldflags "-extldflags '-static' -X 'github.com/symbioticfi/relay/cmd/utils/root.Version=$(APP_VERSION)' -X 'github.com/symbioticfi/relay/cmd/utils/root.BuildTime=$(BUILD_TIME)'" -o relay_utils_$(OS)_$(ARCH) ./cmd/utils && \
		chmod a+x relay_utils_$(OS)_$(ARCH)

.PHONY: build-relay-sidecar
build-relay-sidecar:
	@if [ -z "$(OS)" ] || [ -z "$(ARCH)" ]; then \
		echo "Error: OS and ARCH parameters are required"; \
		echo "Usage: make build-relay-sidecar OS=<os> ARCH=<arch>"; \
		exit 1; \
	fi
	GOOS=$(OS) GOARCH=$(ARCH) CGO_ENABLED=0 go build -ldflags "-extldflags '-static' -X 'github.com/symbioticfi/relay/cmd/relay/root.Version=$(APP_VERSION)' -X 'github.com/symbioticfi/relay/cmd/relay/root.BuildTime=$(BUILD_TIME)'" -o relay_sidecar_$(OS)_$(ARCH) ./cmd/relay && \
		chmod a+x relay_sidecar_$(OS)_$(ARCH)

# Legacy targets for backward compatibility
.PHONY: build-relay-utils-linux
build-relay-utils-linux:
	$(MAKE) build-relay-utils OS=linux ARCH=amd64

.PHONY: build-relay-utils-darwin
build-relay-utils-darwin:
	$(MAKE) build-relay-utils OS=darwin ARCH=arm64

.PHONY: build-relay-sidecar-linux
build-relay-sidecar-linux:
	$(MAKE) build-relay-sidecar OS=linux ARCH=amd64

.PHONY: build-relay-sidecar-darwin
build-relay-sidecar-darwin:
	$(MAKE) build-relay-sidecar OS=darwin ARCH=arm64

.PHONY: image
image:
ifeq ($(PUSH_IMAGE), true)
	@docker buildx build --push --platform=linux/amd64,linux/arm64 . ${IMAGE_TAGS} --build-arg APP_VERSION=$(APP_VERSION) --build-arg BUILD_TIME=$(BUILD_TIME)
	# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
	echo "image=${IMAGE_REPO}:${FINAL_TAG}" >> $$GITHUB_OUTPUT
else
	@DOCKER_BUILDKIT=1 docker build . ${IMAGE_TAGS} --build-arg APP_VERSION=$(APP_VERSION) --build-arg BUILD_TIME=$(BUILD_TIME)
endif

.PHONY: fix-goimports
fix-goimports:
	go run golang.org/x/tools/cmd/goimports@latest -w .
```

## File: README.md

````markdown
# Symbiotic Relay

[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/symbioticfi/relay)

> [!WARNING]  
> The code is a work in progress and not production ready yet.
> Breaking changes may occur in the code updates as well as backward compatibility is not guaranteed.
> Use with caution.

## Overview

The Symbiotic Relay operates as a distributed middleware layer that facilitates:

- **Validator Set Management**: Derives and maintains validator sets across different epochs based on on-chain state
- **Signature Aggregation**: Collects individual validator signatures and aggregates them using BLS signatures or zero-knowledge proofs
- **Cross-Chain Coordination**: Manages validator sets across multiple EVM-compatible blockchains

## Architecture

The relay consists of several key components:

- **P2P Layer**: Uses libp2p with GossipSub for decentralized communication
- **Signer Nodes**: Sign messages using BLS/ECDSA keys
- **Aggregator Nodes**: Collect and aggregate signatures with configurable policies
- **Committer Nodes**: Submit aggregated proofs to settlement chains
- **API Server**: Exposes gRPC API for external clients

For detailed architecture information, see [DEVELOPMENT.md](DEVELOPMENT.md).

## Documentation

- **[Development Guide](DEVELOPMENT.md)** - Comprehensive guide for developers including testing, API changes, and code generation
- **[Relay Docs](https://docs.symbiotic.fi/category/relay-sdk)** - Official documentation
- **[CLI Documentation](docs/cli/)** - Command-line interface reference for relay_sidecar and relay_utils
- **[Contributing](CONTRIBUTING.md)** - Contribution guidelines and workflow

## Running Examples

For a complete end-to-end example application using the relay, see:

**[Symbiotic Super Sum](https://github.com/symbioticfi/symbiotic-super-sum)** - A task-based network example demonstrating relay integration

## API

The relay exposes both gRPC and HTTP/JSON REST APIs for interacting with the network:

### gRPC API

- **API Documentation**: [docs/api/v1/doc.md](docs/api/v1/doc.md)
- **Proto Definitions**: [api/proto/v1/api.proto](api/proto/v1/api.proto)
- **Go Client**: [api/client/v1/](api/client/v1/)
- **Client Examples**: [api/client/examples/](api/client/examples/)

### Voting Power Provider API

- **Documentation**: [docs/votingpower/v1/doc.md](docs/votingpower/v1/doc.md)
- **Proto Definitions**: [votingpower/proto/v1/votingpower.proto](votingpower/proto/v1/votingpower.proto)

### HTTP/JSON REST API Gateway

The relay includes an optional HTTP/JSON REST API gateway that translates HTTP requests to gRPC:

- **Swagger File**: [docs/v1/api.swagger.json](docs/api/v1/api.swagger.json)
- **OpenAPI/Swagger Spec**: Available at `/docs/api.swagger.json` when enabled
- **Endpoints**: All gRPC methods accessible via RESTful HTTP at `/api/v1/*`

Enable via configuration:

```yaml
api:
    http-gateway: true
```

Or via command-line flag:

```bash
./relay_sidecar --api.http-gateway=true
```

### Client Libraries

- **Go**: Included in this repository at `github.com/symbioticfi/relay/api/client/v1`
- **TypeScript**: [relay-client-ts](https://github.com/symbioticfi/relay-client-ts)
- **Rust**: [relay-client-rs](https://github.com/symbioticfi/relay-client-rs)
- **HTTP/cURL**: Use the HTTP gateway for language-agnostic access

## Quick Start

### Use Pre-built Releases

Instead of building from source, you can download pre-built binaries from GitHub releases:

```bash
# Download the latest release for your platform
# Linux AMD64
wget https://github.com/symbioticfi/relay/releases/latest/download/relay_sidecar_linux_amd64
wget https://github.com/symbioticfi/relay/releases/latest/download/relay_utils_linux_amd64
chmod +x relay_sidecar_linux_amd64 relay_utils_linux_amd64

# macOS ARM64
wget https://github.com/symbioticfi/relay/releases/latest/download/relay_sidecar_darwin_arm64
wget https://github.com/symbioticfi/relay/releases/latest/download/relay_utils_darwin_arm64
chmod +x relay_sidecar_darwin_arm64 relay_utils_darwin_arm64

# Run the binaries
./relay_sidecar_linux_amd64 --config config.yaml
```

Browse all releases at: https://github.com/symbioticfi/relay/releases

### Use Docker Images

Pre-built Docker images are available from Docker Hub:

```bash
# Pull the latest image
docker pull symbioticfi/relay:latest

# Or pull a specific version
docker pull symbioticfi/relay:<tag>

# Run the relay sidecar
docker run -v $(pwd)/config.yaml:/config.yaml \
  symbioticfi/relay:latest \
  --config /config.yaml
```

Docker Hub: https://hub.docker.com/r/symbioticfi/relay

## Build Locally

### Dependencies

- **Go 1.26.1+**
- **Docker & Docker Compose** (for local setup and E2E tests)
- **Node.js & Foundry** (for contract compilation in E2E)

### Build Binaries

Build the relay sidecar and utils binaries:

```bash
# For Linux
make build-relay-sidecar OS=linux ARCH=amd64
make build-relay-utils OS=linux ARCH=amd64

# For macOS ARM
make build-relay-sidecar OS=darwin ARCH=arm64
make build-relay-utils OS=darwin ARCH=arm64
```

### Build Docker Image

```bash
make image TAG=dev
```

## Local Setup

### Automated Local Network

Set up a complete local relay network with blockchain nodes and multiple relay sidecars:

```bash
make local-setup
```

This command:

1. Builds the relay Docker image
2. Sets up local blockchain nodes (Anvil)
3. Deploys contracts
4. Generates sidecar configurations
5. Starts relay nodes in Docker

**Customize the network** using environment variables (see [DEVELOPMENT.md](DEVELOPMENT.md) for details):

```bash
OPERATORS=6 COMMITERS=2 AGGREGATORS=1 make local-setup
```

## Configuration File Structure

> **Note**: For a complete reference of all configuration options and command-line flags, see the [relay_sidecar CLI documentation](docs/cli/relay/relay_sidecar.md).

Create a `config.yaml` file with the following structure:

```yaml
# Logging
log:
    level: "debug" # Options: debug, info, warn, error
    mode: "pretty" # Options: json, text, pretty

# Storage
storage-dir: ".data" # Directory for persistent data
circuits-dir: "" # Path to ZK circuits (optional, empty disables ZK proofs)

# API Server
api:
    listen: ":8080" # API server address
    verbose-logging: false # Enable verbose API logging

# Metrics (optional)
metrics:
    listen: ":9090" # Metrics endpoint address
    pprof: false # Enable pprof debug endpoints

# Driver Contract
driver:
    chain-id: 31337 # Chain ID where driver contract is deployed
    address: "0x..." # Driver contract address

# Secret Keys
secret-keys:
    - namespace: "symb" # Namespace for the key
      key-type: 0 # 0=BLS-BN254, 1=ECDSA
      key-id: 15 # Key identifier
      secret: "0x..." # Private key hex

    - namespace: "evm"
      key-type: 1
      key-id: 31337
      secret: "0x..."

    - namespace: "p2p"
      key-type: 1
      key-id: 1
      secret: "0x..."

# Alternatively, use keystore
# keystore:
#   path: "/path/to/keystore.json"
#   password: "your-password"

# Signal Configuration, used for internal messages and event queues
signal:
    worker-count: 10 # Number of signal workers
    buffer-size: 20 # Signal buffer size

# Cache Configuration, used for in memorylookups for db queries
cache:
    network-config-size: 10 # Network config cache size
    validator-set-size: 10 # Validator set cache size

# Sync Configuration, sync signatures and proofs over p2p to recover missing information
sync:
    enabled: true # Enable P2P sync
    period: 5s # Sync period
    timeout: 1m # Sync timeout
    epochs: 5 # Number of epochs to sync

# Key Cache, used for fast public key lookups
key-cache:
    size: 100 # Key cache size
    enabled: true # Enable key caching

# P2P Configuration
p2p:
    listen: "/ip4/0.0.0.0/tcp/8880" # P2P listen address
    bootnodes: # List of bootstrap nodes (optional)
        - /dns4/node1/tcp/8880/p2p/...
    dht-mode: "server" # Options: auto, server, client, disabled, default: server (ideally should not change)
    mdns: true # Enable mDNS local discovery (useful for local networks)

# EVM Configuration
evm:
    chains: # List of settlement chain RPC endpoints
        - "http://localhost:8545"
        - "http://localhost:8546"
    max-calls: 30 # Max calls in multicall batches

# Aggregation Policy
aggregation-policy-max-unsigners: 50 # Max unsigners for low-cost policy

# Data Retention (optional)
# Controls how much historical data to keep on this node
retention:
    valset-epochs:
        0 # Number of historical epochs to retain on fresh node startup
        # 0 = unlimited (sync from genesis)
        # N > 0 = sync only last N epochs (for fresh nodes only)
```

#### Data Retention

Control historical data sync for new nodes:

```bash
--retention.valset-epochs=20  # Keep only last 20 validator set epochs on fresh node startup
```

**Important Notes**:

- Only affects fresh nodes (no existing epoch data)
- Set to match your pruner retention period (if pruning is enabled)
- Must be >= `--sync.epochs` if both are set
- Does not backfill gaps if increased on existing node

#### Automatic Data Pruning

Periodically delete old epoch data to prevent unbounded storage growth:

```bash
--pruner.enabled=true                # Enable automatic pruning (default: false)
--pruner.interval=1h                 # How often to run pruning (default: 1h)
```

**How it works**:

- Runs every `interval` and deletes epochs older than `retention.valset-epochs`
- Keeps N+1 epochs (N operational + 1 anchor for signing)
- Example: `retention.valset-epochs=100` keeps epochs [currentEpoch-100, currentEpoch]
- Metric: `symbiotic_relay_pruned_epochs_total` tracks pruned epochs

**Important Notes**:

- Pruning is disabled by default for safety
- All nodes prune independently based on their own config
- Pruning skipped when `retention.valset-epochs=0` (unlimited)

#### Configuration via Command-Line Flags

You can override config file values with command-line flags:

```bash
./relay_sidecar \
  --config config.yaml \
  --log.level debug \
  --storage-dir /var/lib/relay \
  --api.listen ":8080" \
  --p2p.listen "/ip4/0.0.0.0/tcp/8880" \
  --driver.chain-id 1 \
  --driver.address "0x..." \
  --secret-keys "symb/0/15/0x...,evm/1/31337/0x..." \
  --evm.chains "http://localhost:8545"
```

#### Configuration via Environment Variables

Environment variables use the `SYMB_` prefix with underscores instead of dashes and dots:

```bash
export SYMB_LOG_LEVEL=debug
export SYMB_LOG_MODE=pretty
export SYMB_STORAGE_DIR=/var/lib/relay
export SYMB_API_LISTEN=":8080"
export SYMB_P2P_LISTEN="/ip4/0.0.0.0/tcp/8880"
export SYMB_DRIVER_CHAIN_ID=1
export SYMB_DRIVER_ADDRESS="0x..."

./relay_sidecar --config config.yaml
```

#### Configuration Priority

Configuration is loaded in the following order (highest priority first):

1. Command-line flags
2. Environment variables (with `SYMB_` prefix)
3. Configuration file (specified by `--config`)

#### Example Configuration Generation

For reference, see how configurations are generated in the E2E setup:

```bash
# See the template in e2e/scripts/sidecar-start.sh (lines 11-27)
cat e2e/scripts/sidecar-start.sh
```

To customize the local setup configuration, modify the template in `e2e/scripts/sidecar-start.sh` and run:

```bash
make local-setup
```

### Running the Relay Sidecar

Once you have your configuration file ready:

```bash
./relay_sidecar --config config.yaml
```

Or with Docker:

```bash
docker run -v $(pwd)/config.yaml:/config.yaml symbioticfi/relay:latest --config /config.yaml
```

## Contributing

We welcome contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for:

- Branching strategy and PR process
- Code style and linting requirements
- Testing requirements

For development workflows, API changes, and testing procedures, see [DEVELOPMENT.md](DEVELOPMENT.md).
````
