# AI Pack: cli-python

- Description: Python CLI tooling.
- Remote: https://github.com/symbioticfi/cli
- Remote ref: HEAD
- Commit: 2083a7dc7dbd8ab4cde656db9cc897f7d9244280
- 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: none

---

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.

# 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
- Files are sorted by Git change count (files with more changes are at the bottom)

# Directory Structure

```
abi/
  BurnerRouterABI.json
  BurnerRouterFactoryABI.json
  CumulativeMerkleRewardsABI.json
  CuratorRegistryABI.json
  DefaultCollateralMigratorABI.json
  DefaultOperatorRewardsABI.json
  DefaultOperatorRewardsFactoryABI.json
  DefaultStakerRewardsABI.json
  DefaultStakerRewardsFactoryABI.json
  DelegatorFactoryABI.json
  ETHx_BurnerABI.json
  FeeRegistryABI.json
  FullRestakeDecreaseHookABI.json
  FullRestakeDelegatorABI.json
  mETH_BurnerABI.json
  NetworkMiddlewareServiceABI.json
  NetworkRegistryABI.json
  NetworkRestakeDecreaseHookABI.json
  NetworkRestakeDelegatorABI.json
  NetworkRestakeRedistributeHookABI.json
  OperatorNetworkOptInServiceABI.json
  OperatorNetworkSpecificDelegatorABI.json
  OperatorRegistryABI.json
  OperatorSpecificDecreaseHookABI.json
  OperatorSpecificDelegatorABI.json
  OperatorVaultOptInServiceABI.json
  ProtocolFeesABI.json
  rETH_BurnerABI.json
  RewardsABI.json
  sfrxETH_BurnerABI.json
  SlasherABI.json
  SlasherFactoryABI.json
  swETH_BurnerABI.json
  VaultABI.json
  VaultConfiguratorABI.json
  VaultFactoryABI.json
  VaultSnapshotRewardsABI.json
  VaultTokenizedABI.json
  VetoSlasherABI.json
  wstETH_BurnerABI.json
src/
  cli/
    argParsers.ts
    context.ts
    parse.ts
    program.ts
    run.ts
    signing.ts
    signingOptions.ts
  commands/
    nets.ts
    operators.ts
    rewards.ts
    stakers.ts
    vaults.ts
    writeOptions.ts
    writesCurator.ts
    writesNetwork.ts
    writesOperator.ts
    writesRewards.ts
    writesStaker.ts
  config/
    chains.ts
    env.ts
  core/
    signing/
      ledger.ts
      local.ts
      typedData.ts
    cache.ts
    client.ts
    confirm.ts
    constants.ts
    contracts.ts
    format.ts
    multicall.ts
    output.ts
    spinner.ts
    subnetwork.ts
    symbiotic.ts
    time.ts
    tx.ts
    types.ts
    units.ts
  index.ts
test/
  clientConfig.test.ts
  cliHelp.test.ts
  confirm.test.ts
  format.test.ts
  ledgerAccount.test.ts
  multicallChunked.test.ts
  output.test.ts
  parse.test.ts
  signingLedgerResolve.test.ts
  subnetwork.test.ts
  symbioticClient.test.ts
  units.test.ts
  write-commands-real-fork.sh
.prettierrc.json
eslint.config.js
install.sh
LICENSE
package.json
README.md
tsconfig.json
tsdown.config.ts
vitest.config.ts
```

# Files

## File: abi/BurnerRouterABI.json

```json
[
    { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "DuplicateNetworkReceiver", "type": "error" },
    { "inputs": [], "name": "DuplicateOperatorNetworkReceiver", "type": "error" },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "InsufficientBalance", "type": "error" },
    { "inputs": [], "name": "InvalidCollateral", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidReceiver", "type": "error" },
    { "inputs": [], "name": "InvalidReceiverSetEpochsDelay", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotReady", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    { "anonymous": false, "inputs": [], "name": "AcceptDelay", "type": "event" },
    {
        "anonymous": false,
        "inputs": [],
        "name": "AcceptGlobalReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            }
        ],
        "name": "AcceptNetworkReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            }
        ],
        "name": "AcceptOperatorNetworkReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "delay",
                "type": "uint48"
            }
        ],
        "name": "SetDelay",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "address",
                "name": "receiver",
                "type": "address"
            }
        ],
        "name": "SetGlobalReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "address",
                "name": "receiver",
                "type": "address"
            }
        ],
        "name": "SetNetworkReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "address",
                "name": "receiver",
                "type": "address"
            }
        ],
        "name": "SetOperatorNetworkReceiver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "receiver",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "TriggerTransfer",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "acceptDelay",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "acceptGlobalReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "network", "type": "address" }],
        "name": "acceptNetworkReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "acceptOperatorNetworkReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }],
        "name": "balanceOf",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "collateral",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "delay",
        "outputs": [{ "internalType": "uint48", "name": "value", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "globalReceiver",
        "outputs": [{ "internalType": "address", "name": "value", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            {
                "components": [
                    { "internalType": "address", "name": "owner", "type": "address" },
                    {
                        "internalType": "address",
                        "name": "collateral",
                        "type": "address"
                    },
                    { "internalType": "uint48", "name": "delay", "type": "uint48" },
                    {
                        "internalType": "address",
                        "name": "globalReceiver",
                        "type": "address"
                    },
                    {
                        "components": [
                            {
                                "internalType": "address",
                                "name": "network",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "receiver",
                                "type": "address"
                            }
                        ],
                        "internalType": "struct IBurnerRouter.NetworkReceiver[]",
                        "name": "networkReceivers",
                        "type": "tuple[]"
                    },
                    {
                        "components": [
                            {
                                "internalType": "address",
                                "name": "network",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "operator",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "receiver",
                                "type": "address"
                            }
                        ],
                        "internalType": "struct IBurnerRouter.OperatorNetworkReceiver[]",
                        "name": "operatorNetworkReceivers",
                        "type": "tuple[]"
                    }
                ],
                "internalType": "struct IBurnerRouter.InitParams",
                "name": "params",
                "type": "tuple"
            }
        ],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "lastBalance",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "network", "type": "address" }],
        "name": "networkReceiver",
        "outputs": [{ "internalType": "address", "name": "value", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "", "type": "uint256" },
            { "internalType": "uint48", "name": "", "type": "uint48" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "operatorNetworkReceiver",
        "outputs": [{ "internalType": "address", "name": "value", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "pendingDelay",
        "outputs": [
            { "internalType": "uint48", "name": "value", "type": "uint48" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "pendingGlobalReceiver",
        "outputs": [
            { "internalType": "address", "name": "value", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "network", "type": "address" }],
        "name": "pendingNetworkReceiver",
        "outputs": [
            { "internalType": "address", "name": "value", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "pendingOperatorNetworkReceiver",
        "outputs": [
            { "internalType": "address", "name": "value", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint48", "name": "newDelay", "type": "uint48" }],
        "name": "setDelay",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }],
        "name": "setGlobalReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "receiver", "type": "address" }
        ],
        "name": "setNetworkReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "address", "name": "receiver", "type": "address" }
        ],
        "name": "setOperatorNetworkReceiver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }],
        "name": "triggerTransfer",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/BurnerRouterFactoryABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "burnerRouterImplementation",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "ERC1167FailedCreateClone", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "inputs": [
            {
                "components": [
                    { "internalType": "address", "name": "owner", "type": "address" },
                    {
                        "internalType": "address",
                        "name": "collateral",
                        "type": "address"
                    },
                    { "internalType": "uint48", "name": "delay", "type": "uint48" },
                    {
                        "internalType": "address",
                        "name": "globalReceiver",
                        "type": "address"
                    },
                    {
                        "components": [
                            {
                                "internalType": "address",
                                "name": "network",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "receiver",
                                "type": "address"
                            }
                        ],
                        "internalType": "struct IBurnerRouter.NetworkReceiver[]",
                        "name": "networkReceivers",
                        "type": "tuple[]"
                    },
                    {
                        "components": [
                            {
                                "internalType": "address",
                                "name": "network",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "operator",
                                "type": "address"
                            },
                            {
                                "internalType": "address",
                                "name": "receiver",
                                "type": "address"
                            }
                        ],
                        "internalType": "struct IBurnerRouter.OperatorNetworkReceiver[]",
                        "name": "operatorNetworkReceivers",
                        "type": "tuple[]"
                    }
                ],
                "internalType": "struct IBurnerRouter.InitParams",
                "name": "params",
                "type": "tuple"
            }
        ],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/CumulativeMerkleRewardsABI.json

```json
[
    {
        "type": "function",
        "name": "balance",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "claimCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "leaf",
                "type": "tuple",
                "internalType": "struct ICumulativeMerkleRewards.CumulativeDistributionLeaf",
                "components": [
                    {
                        "name": "token",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "rewardeeType",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "amount",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "rewardeeDataHash",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "proof",
                "type": "bytes32[]",
                "internalType": "bytes32[]"
            },
            {
                "name": "merkleRoot",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimed",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "rewardee",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "rewardeeType",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "depositCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "distributeCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "cumulativeDistribution",
                "type": "tuple",
                "internalType": "struct ICumulativeMerkleRewards.CumulativeDistribution",
                "components": [
                    {
                        "name": "timestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "merkleRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            },
            {
                "name": "totalAmounts",
                "type": "tuple[]",
                "internalType": "struct ICumulativeMerkleRewards.TokenAmount[]",
                "components": [
                    {
                        "name": "chainId",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "token",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "amount",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            },
            {
                "name": "protocolSignature",
                "type": "bytes",
                "internalType": "bytes"
            },
            {
                "name": "rewarderSignature",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "isCumulativeDistributionRoot",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "root",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "bool",
                "internalType": "bool"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "lastCumulativeDistribution",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct ICumulativeMerkleRewards.CumulativeDistribution",
                "components": [
                    {
                        "name": "timestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "merkleRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "lastTotalAmount",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "protocol",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "rewarder",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "setProtocol",
        "inputs": [
            {
                "name": "protocol",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setRewarder",
        "inputs": [
            {
                "name": "rewarder",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "withdrawCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "ClaimCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "rewardee",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "leaf",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct ICumulativeMerkleRewards.CumulativeDistributionLeaf",
                "components": [
                    {
                        "name": "token",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "rewardeeType",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "amount",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "rewardeeDataHash",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "DepositCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "DistributeCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "cumulativeDistribution",
                "type": "tuple",
                "indexed": false,
                "internalType": "struct ICumulativeMerkleRewards.CumulativeDistribution",
                "components": [
                    {
                        "name": "timestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "merkleRoot",
                        "type": "bytes32",
                        "internalType": "bytes32"
                    }
                ]
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetProtocol",
        "inputs": [
            {
                "name": "protocol",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetRewarder",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "rewarder",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "WithdrawCumulativeMerkleRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "InsufficientDeposit",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidMerkleProof",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidMerkleRoot",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidSignature",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidToken",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NoCumulativeRewardsToClaim",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotRewarder",
        "inputs": []
    },
    {
        "type": "error",
        "name": "RootAlreadySet",
        "inputs": []
    }
]
```

## File: abi/CuratorRegistryABI.json

```json
[
    {
        "type": "function",
        "name": "getCurator",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "setCurator",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "curator",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "SetCurator",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "curator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "NotAuthorized",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotVault",
        "inputs": []
    }
]
```

## File: abi/DefaultCollateralMigratorABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "collateral", "type": "address" },
            { "internalType": "address", "name": "vault", "type": "address" },
            { "internalType": "address", "name": "onBehalfOf", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "migrate",
        "outputs": [
            { "internalType": "uint256", "name": "", "type": "uint256" },
            { "internalType": "uint256", "name": "", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/DefaultOperatorRewardsABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "networkMiddlewareService",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "InsufficientBalance", "type": "error" },
    { "inputs": [], "name": "InsufficientTotalClaimable", "type": "error" },
    { "inputs": [], "name": "InsufficientTransfer", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidProof", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetworkMiddleware", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    { "inputs": [], "name": "RootNotSet", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "token",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "ClaimRewards",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "token",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "bytes32",
                "name": "root",
                "type": "bytes32"
            }
        ],
        "name": "DistributeRewards",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "NETWORK_MIDDLEWARE_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" }
        ],
        "name": "balance",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            {
                "internalType": "uint256",
                "name": "totalClaimable",
                "type": "uint256"
            },
            { "internalType": "bytes32[]", "name": "proof", "type": "bytes32[]" }
        ],
        "name": "claimRewards",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "claimed",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            { "internalType": "bytes32", "name": "root_", "type": "bytes32" }
        ],
        "name": "distributeRewards",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" }
        ],
        "name": "root",
        "outputs": [{ "internalType": "bytes32", "name": "value", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/DefaultOperatorRewardsFactoryABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "operatorRewardsImplementation",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "ERC1167FailedCreateClone", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/DefaultStakerRewardsABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "networkMiddlewareService",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "HighAdminFee", "type": "error" },
    { "inputs": [], "name": "InsufficientAdminFee", "type": "error" },
    { "inputs": [], "name": "InsufficientReward", "type": "error" },
    { "inputs": [], "name": "InvalidAdminFee", "type": "error" },
    { "inputs": [], "name": "InvalidHintsLength", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidRecipient", "type": "error" },
    { "inputs": [], "name": "InvalidRewardTimestamp", "type": "error" },
    { "inputs": [], "name": "MathOverflowedMulDiv", "type": "error" },
    { "inputs": [], "name": "MissingRoles", "type": "error" },
    { "inputs": [], "name": "NoRewardsToClaim", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotNetworkMiddleware", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "ClaimAdminFee",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "token",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "firstRewardIndex",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "numRewards",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "ClaimRewards",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "token",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "bytes",
                "name": "data",
                "type": "bytes"
            }
        ],
        "name": "DistributeRewards",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "adminFee",
                "type": "uint256"
            }
        ],
        "name": "SetAdminFee",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "ADMIN_FEE_BASE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "ADMIN_FEE_CLAIM_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "ADMIN_FEE_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_MIDDLEWARE_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "adminFee",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" }
        ],
        "name": "claimAdminFee",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "claimRewards",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "claimable",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "claimableAdminFee",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "distributeRewards",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            {
                "components": [
                    { "internalType": "address", "name": "vault", "type": "address" },
                    { "internalType": "uint256", "name": "adminFee", "type": "uint256" },
                    {
                        "internalType": "address",
                        "name": "defaultAdminRoleHolder",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "adminFeeClaimRoleHolder",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "adminFeeSetRoleHolder",
                        "type": "address"
                    }
                ],
                "internalType": "struct IDefaultStakerRewards.InitParams",
                "name": "params",
                "type": "tuple"
            }
        ],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "address", "name": "network", "type": "address" }
        ],
        "name": "lastUnclaimedReward",
        "outputs": [{ "internalType": "uint256", "name": "rewardIndex", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes[]", "name": "data", "type": "bytes[]" }],
        "name": "multicall",
        "outputs": [{ "internalType": "bytes[]", "name": "results", "type": "bytes[]" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "address", "name": "network", "type": "address" },
            { "internalType": "uint256", "name": "", "type": "uint256" }
        ],
        "name": "rewards",
        "outputs": [
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "token", "type": "address" },
            { "internalType": "address", "name": "network", "type": "address" }
        ],
        "name": "rewardsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "adminFee_", "type": "uint256" }],
        "name": "setAdminFee",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "version",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/DefaultStakerRewardsFactoryABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "stakerRewardsImplementation",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "ERC1167FailedCreateClone", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "inputs": [
            {
                "components": [
                    { "internalType": "address", "name": "vault", "type": "address" },
                    { "internalType": "uint256", "name": "adminFee", "type": "uint256" },
                    {
                        "internalType": "address",
                        "name": "defaultAdminRoleHolder",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "adminFeeClaimRoleHolder",
                        "type": "address"
                    },
                    {
                        "internalType": "address",
                        "name": "adminFeeSetRoleHolder",
                        "type": "address"
                    }
                ],
                "internalType": "struct IDefaultStakerRewards.InitParams",
                "name": "params",
                "type": "tuple"
            }
        ],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/DelegatorFactoryABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "owner_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadyBlacklisted", "type": "error" },
    { "inputs": [], "name": "AlreadyWhitelisted", "type": "error" },
    { "inputs": [], "name": "ERC1167FailedCreateClone", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    { "inputs": [], "name": "InvalidImplementation", "type": "error" },
    { "inputs": [], "name": "InvalidType", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint64",
                "name": "type_",
                "type": "uint64"
            }
        ],
        "name": "Blacklist",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "implementation",
                "type": "address"
            }
        ],
        "name": "Whitelist",
        "type": "event"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "blacklist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "blacklisted",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "type_", "type": "uint64" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "implementation",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalTypes",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "implementation_",
                "type": "address"
            }
        ],
        "name": "whitelist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/ETHx_BurnerABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "collateral", "type": "address" },
            { "internalType": "address", "name": "staderConfig", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "InvalidETHxMaximumWithdrawal", "type": "error" },
    { "inputs": [], "name": "InvalidRequestId", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerWithdrawal",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "STADER_CONFIG",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "STAKE_POOLS_MANAGER",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "USER_WITHDRAW_MANAGER",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes[]", "name": "data", "type": "bytes[]" }],
        "name": "multicall",
        "outputs": [{ "internalType": "bytes[]", "name": "results", "type": "bytes[]" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "index", "type": "uint256" },
            { "internalType": "uint256", "name": "maxRequestIds", "type": "uint256" }
        ],
        "name": "requestIds",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "requestIdsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256",
                "name": "maxWithdrawalAmount",
                "type": "uint256"
            }
        ],
        "name": "triggerWithdrawal",
        "outputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: abi/FeeRegistryABI.json

```json
[
    {
        "type": "function",
        "name": "CURATOR_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "MAX_FEE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "MAX_PARTICIPANT_FEE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorDefaultFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorDefaultFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hints",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "isEnabled",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getCuratorNetworkFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "isEnabled",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsDefaultFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsDefaultFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hints",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "isEnabled",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getOperatorsNetworkFeeAt",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hint",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [
            {
                "name": "isEnabled",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "getProtocolFee",
        "inputs": [
            {
                "name": "id",
                "type": "bytes32",
                "internalType": "bytes32"
            }
        ],
        "outputs": [
            {
                "name": "isEnabled",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "setCuratorFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setCuratorNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "enable",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setOperatorsFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setOperatorsNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "enable",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "setProtocolFee",
        "inputs": [
            {
                "name": "id",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "enable",
                "type": "bool",
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "event",
        "name": "SetCuratorFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "fee",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetCuratorNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "enable",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetOperatorsFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "fee",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetOperatorsNetworkFee",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "enable",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "SetProtocolFee",
        "inputs": [
            {
                "name": "id",
                "type": "bytes32",
                "indexed": true,
                "internalType": "bytes32"
            },
            {
                "name": "enable",
                "type": "bool",
                "indexed": false,
                "internalType": "bool"
            },
            {
                "name": "fee",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "FeeTooHigh",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotCurator",
        "inputs": []
    }
]
```

## File: abi/FullRestakeDecreaseHookABI.json

```json
[
    { "inputs": [], "name": "NotFullRestakeDelegator", "type": "error" },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "slashedAmount", "type": "uint256" },
            { "internalType": "uint48", "name": "", "type": "uint48" },
            { "internalType": "bytes", "name": "", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/FullRestakeDelegatorABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "operatorVaultOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "operatorNetworkOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "DuplicateRoleHolder", "type": "error" },
    { "inputs": [], "name": "ExceedsMaxNetworkLimit", "type": "error" },
    { "inputs": [], "name": "InsufficientHookGas", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "MissingRoleHolders", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    { "inputs": [], "name": "ZeroAddressRoleHolder", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "hook",
                "type": "address"
            }
        ],
        "name": "SetHook",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetMaxNetworkLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetNetworkLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetOperatorNetworkLimit",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_VAULT_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VERSION",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "pure",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "hook",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "maxNetworkLimit",
        "outputs": [{ "internalType": "uint256", "name": "value", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "networkLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "networkLimitAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "operatorNetworkLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "operatorNetworkLimitAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "hook_", "type": "address" }],
        "name": "setHook",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint96", "name": "identifier", "type": "uint96" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setMaxNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setOperatorNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "stake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "stakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/mETH_BurnerABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "collateral", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "InvalidRequestId", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerWithdrawal",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "STAKING",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "index", "type": "uint256" },
            { "internalType": "uint256", "name": "maxRequestIds", "type": "uint256" }
        ],
        "name": "requestIds",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "requestIdsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "triggerWithdrawal",
        "outputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: abi/NetworkMiddlewareServiceABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "network",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "address",
                "name": "middleware",
                "type": "address"
            }
        ],
        "name": "SetMiddleware",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "network", "type": "address" }],
        "name": "middleware",
        "outputs": [{ "internalType": "address", "name": "value", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "middleware_", "type": "address" }],
        "name": "setMiddleware",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/NetworkRegistryABI.json

```json
[
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    { "inputs": [], "name": "NetworkAlreadyRegistered", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "registerNetwork",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/NetworkRestakeDecreaseHookABI.json

```json
[
    { "inputs": [], "name": "NotNetworkRestakeDelegator", "type": "error" },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "slashedAmount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/NetworkRestakeDelegatorABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "operatorVaultOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "operatorNetworkOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "DuplicateRoleHolder", "type": "error" },
    { "inputs": [], "name": "ExceedsMaxNetworkLimit", "type": "error" },
    { "inputs": [], "name": "InsufficientHookGas", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "MathOverflowedMulDiv", "type": "error" },
    { "inputs": [], "name": "MissingRoleHolders", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    { "inputs": [], "name": "ZeroAddressRoleHolder", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "hook",
                "type": "address"
            }
        ],
        "name": "SetHook",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetMaxNetworkLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetNetworkLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "shares",
                "type": "uint256"
            }
        ],
        "name": "SetOperatorNetworkShares",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_SHARES_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_VAULT_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VERSION",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "pure",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "hook",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "maxNetworkLimit",
        "outputs": [{ "internalType": "uint256", "name": "value", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "networkLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "networkLimitAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "operatorNetworkShares",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "operatorNetworkSharesAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "hook_", "type": "address" }],
        "name": "setHook",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint96", "name": "identifier", "type": "uint96" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setMaxNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "shares", "type": "uint256" }
        ],
        "name": "setOperatorNetworkShares",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "stake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "stakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "totalOperatorNetworkShares",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "totalOperatorNetworkSharesAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/NetworkRestakeRedistributeHookABI.json

```json
[
    { "inputs": [], "name": "NotNetworkRestakeDelegator", "type": "error" },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "slashedAmount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/OperatorNetworkOptInServiceABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "whoRegistry", "type": "address" },
            { "internalType": "address", "name": "whereRegistry", "type": "address" },
            { "internalType": "string", "name": "name", "type": "string" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadyOptedIn", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "ExpiredSignature", "type": "error" },
    { "inputs": [], "name": "InvalidShortString", "type": "error" },
    { "inputs": [], "name": "InvalidSignature", "type": "error" },
    { "inputs": [], "name": "NotOptedIn", "type": "error" },
    { "inputs": [], "name": "NotWhereEntity", "type": "error" },
    { "inputs": [], "name": "NotWho", "type": "error" },
    { "inputs": [], "name": "OptOutCooldown", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "string", "name": "str", "type": "string" }],
        "name": "StringTooLong",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [],
        "name": "EIP712DomainChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "IncreaseNonce",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "OptIn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "OptOut",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "WHERE_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "WHO_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "eip712Domain",
        "outputs": [
            { "internalType": "bytes1", "name": "fields", "type": "bytes1" },
            { "internalType": "string", "name": "name", "type": "string" },
            { "internalType": "string", "name": "version", "type": "string" },
            { "internalType": "uint256", "name": "chainId", "type": "uint256" },
            {
                "internalType": "address",
                "name": "verifyingContract",
                "type": "address"
            },
            { "internalType": "bytes32", "name": "salt", "type": "bytes32" },
            { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "increaseNonce",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" }
        ],
        "name": "isOptedIn",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "isOptedInAt",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" }
        ],
        "name": "nonces",
        "outputs": [{ "internalType": "uint256", "name": "nonce", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "optIn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "deadline", "type": "uint48" },
            { "internalType": "bytes", "name": "signature", "type": "bytes" }
        ],
        "name": "optIn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "deadline", "type": "uint48" },
            { "internalType": "bytes", "name": "signature", "type": "bytes" }
        ],
        "name": "optOut",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "optOut",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/OperatorNetworkSpecificDelegatorABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "operatorRegistry",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "operatorVaultOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "operatorNetworkOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "InsufficientHookGas", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidNetwork", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotOperator", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "hook",
                "type": "address"
            }
        ],
        "name": "SetHook",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetMaxNetworkLimit",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_VAULT_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VERSION",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "pure",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "hook",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "maxNetworkLimit",
        "outputs": [{ "internalType": "uint256", "name": "value", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "maxNetworkLimitAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "network",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "operator",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "hook_", "type": "address" }],
        "name": "setHook",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint96", "name": "identifier", "type": "uint96" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setMaxNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "stake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "stakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/OperatorRegistryABI.json

```json
[
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    { "inputs": [], "name": "OperatorAlreadyRegistered", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "registerOperator",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/OperatorSpecificDecreaseHookABI.json

```json
[
    { "inputs": [], "name": "NotOperatorSpecificDelegator", "type": "error" },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "", "type": "address" },
            { "internalType": "uint256", "name": "slashedAmount", "type": "uint256" },
            { "internalType": "uint48", "name": "", "type": "uint48" },
            { "internalType": "bytes", "name": "", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/OperatorSpecificDelegatorABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "operatorRegistry",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "operatorVaultOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "operatorNetworkOptInService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "DuplicateRoleHolder", "type": "error" },
    { "inputs": [], "name": "ExceedsMaxNetworkLimit", "type": "error" },
    { "inputs": [], "name": "InsufficientHookGas", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "MissingRoleHolders", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotOperator", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    { "inputs": [], "name": "ZeroAddressRoleHolder", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "hook",
                "type": "address"
            }
        ],
        "name": "SetHook",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetMaxNetworkLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "SetNetworkLimit",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "HOOK_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_NETWORK_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "OPERATOR_VAULT_OPT_IN_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VERSION",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "pure",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "hook",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "maxNetworkLimit",
        "outputs": [{ "internalType": "uint256", "name": "value", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" }],
        "name": "networkLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "networkLimitAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "onSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "operator",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "hook_", "type": "address" }],
        "name": "setHook",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint96", "name": "identifier", "type": "uint96" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setMaxNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "setNetworkLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "stake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "stakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/OperatorVaultOptInServiceABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "whoRegistry", "type": "address" },
            { "internalType": "address", "name": "whereRegistry", "type": "address" },
            { "internalType": "string", "name": "name", "type": "string" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadyOptedIn", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "ExpiredSignature", "type": "error" },
    { "inputs": [], "name": "InvalidShortString", "type": "error" },
    { "inputs": [], "name": "InvalidSignature", "type": "error" },
    { "inputs": [], "name": "NotOptedIn", "type": "error" },
    { "inputs": [], "name": "NotWhereEntity", "type": "error" },
    { "inputs": [], "name": "NotWho", "type": "error" },
    { "inputs": [], "name": "OptOutCooldown", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "string", "name": "str", "type": "string" }],
        "name": "StringTooLong",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [],
        "name": "EIP712DomainChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "IncreaseNonce",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "OptIn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "who",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "where",
                "type": "address"
            }
        ],
        "name": "OptOut",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "WHERE_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "WHO_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "eip712Domain",
        "outputs": [
            { "internalType": "bytes1", "name": "fields", "type": "bytes1" },
            { "internalType": "string", "name": "name", "type": "string" },
            { "internalType": "string", "name": "version", "type": "string" },
            { "internalType": "uint256", "name": "chainId", "type": "uint256" },
            {
                "internalType": "address",
                "name": "verifyingContract",
                "type": "address"
            },
            { "internalType": "bytes32", "name": "salt", "type": "bytes32" },
            { "internalType": "uint256[]", "name": "extensions", "type": "uint256[]" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "increaseNonce",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" }
        ],
        "name": "isOptedIn",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "isOptedInAt",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" }
        ],
        "name": "nonces",
        "outputs": [{ "internalType": "uint256", "name": "nonce", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "optIn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "deadline", "type": "uint48" },
            { "internalType": "bytes", "name": "signature", "type": "bytes" }
        ],
        "name": "optIn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "who", "type": "address" },
            { "internalType": "address", "name": "where", "type": "address" },
            { "internalType": "uint48", "name": "deadline", "type": "uint48" },
            { "internalType": "bytes", "name": "signature", "type": "bytes" }
        ],
        "name": "optOut",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "where", "type": "address" }],
        "name": "optOut",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/ProtocolFeesABI.json

```json
[
    {
        "type": "function",
        "name": "FEE_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "MAX_FEE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "claimProtocolFees",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "fees",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "distributionToTotalAmount",
        "inputs": [
            {
                "name": "rewardsType",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "distributionAmount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "protocolFee",
        "inputs": [
            {
                "name": "rewardsType",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "protocolFees",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "totalToDistributionAmount",
        "inputs": [
            {
                "name": "rewardsType",
                "type": "uint64",
                "internalType": "uint64"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "totalDistributionAmount",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "AccountProtocolFees",
        "inputs": [
            {
                "name": "rewardsType",
                "type": "uint64",
                "indexed": true,
                "internalType": "uint64"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "fees",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "ClaimProtocolFees",
        "inputs": [
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "fees",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "InsufficientClaimableFees",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidRecipient",
        "inputs": []
    }
]
```

## File: abi/rETH_BurnerABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "collateral", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "assetAmount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "ethAmount",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: abi/RewardsABI.json

```json
[
    {
        "type": "function",
        "name": "claimRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "error",
        "name": "InvalidRewardType",
        "inputs": []
    }
]
```

## File: abi/sfrxETH_BurnerABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "collateral", "type": "address" },
            {
                "internalType": "address",
                "name": "fraxEtherRedemptionQueue",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "InvalidRequestId", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerWithdrawal",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FRAX_ETHER_REDEMPTION_QUEUE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "", "type": "address" },
            { "internalType": "address", "name": "", "type": "address" },
            { "internalType": "uint256", "name": "", "type": "uint256" },
            { "internalType": "bytes", "name": "", "type": "bytes" }
        ],
        "name": "onERC721Received",
        "outputs": [{ "internalType": "bytes4", "name": "", "type": "bytes4" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "index", "type": "uint256" },
            { "internalType": "uint256", "name": "maxRequestIds", "type": "uint256" }
        ],
        "name": "requestIds",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "requestIdsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "triggerWithdrawal",
        "outputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: abi/SlasherABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "networkMiddlewareService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "slasherFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "InsufficientBurnerGas", "type": "error" },
    { "inputs": [], "name": "InsufficientSlash", "type": "error" },
    { "inputs": [], "name": "InvalidCaptureTimestamp", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "NoBurner", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetworkMiddleware", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "slashedAmount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            }
        ],
        "name": "Slash",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "BURNER_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "BURNER_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_MIDDLEWARE_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "cumulativeSlash",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "cumulativeSlashAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isBurnerHook",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "latestSlashedCaptureTimestamp",
        "outputs": [{ "internalType": "uint48", "name": "value", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "slash",
        "outputs": [{ "internalType": "uint256", "name": "slashedAmount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "slashableStake",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/SlasherFactoryABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "owner_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadyBlacklisted", "type": "error" },
    { "inputs": [], "name": "AlreadyWhitelisted", "type": "error" },
    { "inputs": [], "name": "ERC1167FailedCreateClone", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    { "inputs": [], "name": "InvalidImplementation", "type": "error" },
    { "inputs": [], "name": "InvalidType", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint64",
                "name": "type_",
                "type": "uint64"
            }
        ],
        "name": "Blacklist",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "implementation",
                "type": "address"
            }
        ],
        "name": "Whitelist",
        "type": "event"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "blacklist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "blacklisted",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "type_", "type": "uint64" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "type_", "type": "uint64" }],
        "name": "implementation",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalTypes",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "implementation_",
                "type": "address"
            }
        ],
        "name": "whitelist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/swETH_BurnerABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "collateral", "type": "address" },
            { "internalType": "address", "name": "swEXIT", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "InsufficientWithdrawal", "type": "error" },
    { "inputs": [], "name": "InvalidRequestId", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "firstRequestId",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "lastRequestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerWithdrawal",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "SWEXIT",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "", "type": "address" },
            { "internalType": "address", "name": "", "type": "address" },
            { "internalType": "uint256", "name": "", "type": "uint256" },
            { "internalType": "bytes", "name": "", "type": "bytes" }
        ],
        "name": "onERC721Received",
        "outputs": [{ "internalType": "bytes4", "name": "", "type": "bytes4" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "index", "type": "uint256" },
            { "internalType": "uint256", "name": "maxRequestIds", "type": "uint256" }
        ],
        "name": "requestIds",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "requestIdsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "maxRequests", "type": "uint256" }],
        "name": "triggerWithdrawal",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "firstRequestId",
                "type": "uint256"
            },
            { "internalType": "uint256", "name": "lastRequestId", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: abi/VaultABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "slasherFactory",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadyClaimed", "type": "error" },
    { "inputs": [], "name": "AlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "DelegatorAlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "DepositLimitReached", "type": "error" },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "InsufficientClaim", "type": "error" },
    { "inputs": [], "name": "InsufficientDeposit", "type": "error" },
    { "inputs": [], "name": "InsufficientRedemption", "type": "error" },
    { "inputs": [], "name": "InsufficientWithdrawal", "type": "error" },
    { "inputs": [], "name": "InvalidAccount", "type": "error" },
    { "inputs": [], "name": "InvalidCaptureEpoch", "type": "error" },
    { "inputs": [], "name": "InvalidClaimer", "type": "error" },
    { "inputs": [], "name": "InvalidCollateral", "type": "error" },
    { "inputs": [], "name": "InvalidDelegator", "type": "error" },
    { "inputs": [], "name": "InvalidEpoch", "type": "error" },
    { "inputs": [], "name": "InvalidEpochDuration", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidLengthEpochs", "type": "error" },
    { "inputs": [], "name": "InvalidOnBehalfOf", "type": "error" },
    { "inputs": [], "name": "InvalidRecipient", "type": "error" },
    { "inputs": [], "name": "InvalidSlasher", "type": "error" },
    { "inputs": [], "name": "InvalidTimestamp", "type": "error" },
    { "inputs": [], "name": "MathOverflowedMulDiv", "type": "error" },
    { "inputs": [], "name": "MissingRoles", "type": "error" },
    { "inputs": [], "name": "NoPreviousEpoch", "type": "error" },
    { "inputs": [], "name": "NotDelegator", "type": "error" },
    { "inputs": [], "name": "NotFactory", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotWhitelistedDepositor", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    { "inputs": [], "name": "SlasherAlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "TooMuchRedeem", "type": "error" },
    { "inputs": [], "name": "TooMuchWithdraw", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "epoch",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "Claim",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256[]",
                "name": "epochs",
                "type": "uint256[]"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "ClaimBatch",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "depositor",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "onBehalfOf",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "shares",
                "type": "uint256"
            }
        ],
        "name": "Deposit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "slashedAmount",
                "type": "uint256"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "delegator",
                "type": "address"
            }
        ],
        "name": "SetDelegator",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "limit",
                "type": "uint256"
            }
        ],
        "name": "SetDepositLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetDepositWhitelist",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetDepositorWhitelistStatus",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetIsDepositLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "slasher",
                "type": "address"
            }
        ],
        "name": "SetSlasher",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "withdrawer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "burnedShares",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "mintedShares",
                "type": "uint256"
            }
        ],
        "name": "Withdraw",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DELEGATOR_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSITOR_WHITELIST_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSIT_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSIT_WHITELIST_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "IS_DEPOSIT_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "SLASHER_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "activeBalanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "activeBalanceOfAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "activeShares",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeSharesAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "activeSharesOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeSharesOfAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "activeStake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeStakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "burner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "epoch", "type": "uint256" }
        ],
        "name": "claim",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256[]", "name": "epochs", "type": "uint256[]" }
        ],
        "name": "claimBatch",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "collateral",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "currentEpoch",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "currentEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "delegator",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "onBehalfOf", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "deposit",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "depositedAmount",
                "type": "uint256"
            },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "depositLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "depositWhitelist",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint48", "name": "timestamp", "type": "uint48" }],
        "name": "epochAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "epochDuration",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "epochDurationInit",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "initialVersion", "type": "uint64" },
            { "internalType": "address", "name": "owner_", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isDelegatorInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isDepositLimit",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "isDepositorWhitelisted",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isSlasherInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "isWithdrawalsClaimed",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "newVersion", "type": "uint64" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "migrate",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "nextEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            { "internalType": "uint48", "name": "captureTimestamp", "type": "uint48" }
        ],
        "name": "onSlash",
        "outputs": [{ "internalType": "uint256", "name": "slashedAmount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "previousEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "claimer", "type": "address" },
            { "internalType": "uint256", "name": "shares", "type": "uint256" }
        ],
        "name": "redeem",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "withdrawnAssets",
                "type": "uint256"
            },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "delegator_", "type": "address" }],
        "name": "setDelegator",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "limit", "type": "uint256" }],
        "name": "setDepositLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bool", "name": "status", "type": "bool" }],
        "name": "setDepositWhitelist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bool", "name": "status", "type": "bool" }
        ],
        "name": "setDepositorWhitelistStatus",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bool", "name": "status", "type": "bool" }],
        "name": "setIsDepositLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "slasher_", "type": "address" }],
        "name": "setSlasher",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "slashableBalanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "slasher",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalStake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "version",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "claimer", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "withdraw",
        "outputs": [
            { "internalType": "uint256", "name": "burnedShares", "type": "uint256" },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "epoch", "type": "uint256" }],
        "name": "withdrawalShares",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "withdrawalSharesOf",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "epoch", "type": "uint256" }],
        "name": "withdrawals",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "withdrawalsOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/VaultConfiguratorABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            { "internalType": "address", "name": "slasherFactory", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "inputs": [],
        "name": "DELEGATOR_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "SLASHER_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            {
                "components": [
                    { "internalType": "uint64", "name": "version", "type": "uint64" },
                    { "internalType": "address", "name": "owner", "type": "address" },
                    { "internalType": "bytes", "name": "vaultParams", "type": "bytes" },
                    {
                        "internalType": "uint64",
                        "name": "delegatorIndex",
                        "type": "uint64"
                    },
                    {
                        "internalType": "bytes",
                        "name": "delegatorParams",
                        "type": "bytes"
                    },
                    { "internalType": "bool", "name": "withSlasher", "type": "bool" },
                    {
                        "internalType": "uint64",
                        "name": "slasherIndex",
                        "type": "uint64"
                    },
                    { "internalType": "bytes", "name": "slasherParams", "type": "bytes" }
                ],
                "internalType": "struct IVaultConfigurator.InitParams",
                "name": "params",
                "type": "tuple"
            }
        ],
        "name": "create",
        "outputs": [
            { "internalType": "address", "name": "vault", "type": "address" },
            { "internalType": "address", "name": "delegator", "type": "address" },
            { "internalType": "address", "name": "slasher", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/VaultFactoryABI.json

```json
[
    {
        "inputs": [{ "internalType": "address", "name": "owner_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadyBlacklisted", "type": "error" },
    { "inputs": [], "name": "AlreadyWhitelisted", "type": "error" },
    { "inputs": [], "name": "EntityNotExist", "type": "error" },
    { "inputs": [], "name": "InvalidImplementation", "type": "error" },
    { "inputs": [], "name": "InvalidVersion", "type": "error" },
    { "inputs": [], "name": "NotOwner", "type": "error" },
    { "inputs": [], "name": "OldVersion", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            }
        ],
        "name": "AddEntity",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Blacklist",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "entity",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "newVersion",
                "type": "uint64"
            }
        ],
        "name": "Migrate",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "implementation",
                "type": "address"
            }
        ],
        "name": "Whitelist",
        "type": "event"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "version", "type": "uint64" }],
        "name": "blacklist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "version", "type": "uint64" }],
        "name": "blacklisted",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "version", "type": "uint64" },
            { "internalType": "address", "name": "owner_", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "create",
        "outputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }],
        "name": "entity",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint64", "name": "version", "type": "uint64" }],
        "name": "implementation",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "entity_", "type": "address" }],
        "name": "isEntity",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "lastVersion",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "entity_", "type": "address" },
            { "internalType": "uint64", "name": "newVersion", "type": "uint64" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "migrate",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalEntities",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "implementation_",
                "type": "address"
            }
        ],
        "name": "whitelist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/VaultSnapshotRewardsABI.json

```json
[
    {
        "type": "function",
        "name": "CURATOR_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "NETWORK_MIDDLEWARE_SERVICE",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "NETWORK_REGISTRY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "VAULT_FACTORY",
        "inputs": [],
        "outputs": [
            {
                "name": "",
                "type": "address",
                "internalType": "address"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "claimCuratorFees",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimOperatorFees",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "lastUnclaimedRewards",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "firstRewardToClaim",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "rewardsToClaim",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "extraData",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "data",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "claimVaultSnapshotRewards",
        "inputs": [
            {
                "name": "recipient",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "lastUnclaimedRewards",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "firstRewardToClaim",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "rewardsToClaim",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "activeSharesOfHints",
                "type": "bytes[]",
                "internalType": "bytes[]"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "curatorFees",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "distributeVaultSnapshotRewards",
        "inputs": [
            {
                "name": "subnetwork",
                "type": "bytes32",
                "internalType": "bytes32"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "internalType": "uint256"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "internalType": "uint48"
            },
            {
                "name": "hints",
                "type": "bytes",
                "internalType": "bytes"
            }
        ],
        "outputs": [],
        "stateMutability": "nonpayable"
    },
    {
        "type": "function",
        "name": "lastUnclaimedOperatorReward",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "lastUnclaimedReward",
        "inputs": [
            {
                "name": "account",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "rewards",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "index",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "tuple",
                "internalType": "struct IVaultSnapshotRewards.RewardDistribution",
                "components": [
                    {
                        "name": "subnetworkId",
                        "type": "uint96",
                        "internalType": "uint96"
                    },
                    {
                        "name": "delegator",
                        "type": "address",
                        "internalType": "address"
                    },
                    {
                        "name": "delegatorType",
                        "type": "uint64",
                        "internalType": "uint64"
                    },
                    {
                        "name": "timestamp",
                        "type": "uint48",
                        "internalType": "uint48"
                    },
                    {
                        "name": "amount",
                        "type": "uint256",
                        "internalType": "uint256"
                    },
                    {
                        "name": "operatorsFees",
                        "type": "uint256",
                        "internalType": "uint256"
                    }
                ]
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "function",
        "name": "rewardsLength",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "internalType": "address"
            }
        ],
        "outputs": [
            {
                "name": "",
                "type": "uint256",
                "internalType": "uint256"
            }
        ],
        "stateMutability": "view"
    },
    {
        "type": "event",
        "name": "ClaimCuratorFees",
        "inputs": [
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "ClaimOperatorFees",
        "inputs": [
            {
                "name": "operator",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "firstClaimedReward",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "rewardsClaimed",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "ClaimVaultSnapshotRewards",
        "inputs": [
            {
                "name": "staker",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "indexed": false,
                "internalType": "address"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "firstClaimedReward",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "rewardsClaimed",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "event",
        "name": "DistributeVaultSnapshotRewards",
        "inputs": [
            {
                "name": "network",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "token",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "vault",
                "type": "address",
                "indexed": true,
                "internalType": "address"
            },
            {
                "name": "subnetworkId",
                "type": "uint96",
                "indexed": false,
                "internalType": "uint96"
            },
            {
                "name": "timestamp",
                "type": "uint48",
                "indexed": false,
                "internalType": "uint48"
            },
            {
                "name": "amount",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "curatorFees",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            },
            {
                "name": "operatorsFees",
                "type": "uint256",
                "indexed": false,
                "internalType": "uint256"
            }
        ],
        "anonymous": false
    },
    {
        "type": "error",
        "name": "InsufficientReward",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidDelegatorType",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidLastUnclaimedReward",
        "inputs": []
    },
    {
        "type": "error",
        "name": "InvalidRewardTimestamp",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NoRewardsToClaim",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotCurator",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotNetworkOrMiddleware",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotOperator",
        "inputs": []
    },
    {
        "type": "error",
        "name": "NotVault",
        "inputs": []
    }
]
```

## File: abi/VaultTokenizedABI.json

```json
[
    {
        "inputs": [
            {
                "internalType": "address",
                "name": "delegatorFactory",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "slasherFactory",
                "type": "address"
            },
            { "internalType": "address", "name": "vaultFactory", "type": "address" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AccessControlBadConfirmation", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bytes32", "name": "neededRole", "type": "bytes32" }
        ],
        "name": "AccessControlUnauthorizedAccount",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "target", "type": "address" }],
        "name": "AddressEmptyCode",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "AddressInsufficientBalance",
        "type": "error"
    },
    { "inputs": [], "name": "AlreadyClaimed", "type": "error" },
    { "inputs": [], "name": "AlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "DelegatorAlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "DepositLimitReached", "type": "error" },
    {
        "inputs": [
            { "internalType": "address", "name": "spender", "type": "address" },
            { "internalType": "uint256", "name": "allowance", "type": "uint256" },
            { "internalType": "uint256", "name": "needed", "type": "uint256" }
        ],
        "name": "ERC20InsufficientAllowance",
        "type": "error"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "sender", "type": "address" },
            { "internalType": "uint256", "name": "balance", "type": "uint256" },
            { "internalType": "uint256", "name": "needed", "type": "uint256" }
        ],
        "name": "ERC20InsufficientBalance",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "approver", "type": "address" }],
        "name": "ERC20InvalidApprover",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "receiver", "type": "address" }],
        "name": "ERC20InvalidReceiver",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "sender", "type": "address" }],
        "name": "ERC20InvalidSender",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }],
        "name": "ERC20InvalidSpender",
        "type": "error"
    },
    { "inputs": [], "name": "FailedInnerCall", "type": "error" },
    { "inputs": [], "name": "InsufficientClaim", "type": "error" },
    { "inputs": [], "name": "InsufficientDeposit", "type": "error" },
    { "inputs": [], "name": "InsufficientRedemption", "type": "error" },
    { "inputs": [], "name": "InsufficientWithdrawal", "type": "error" },
    { "inputs": [], "name": "InvalidAccount", "type": "error" },
    { "inputs": [], "name": "InvalidCaptureEpoch", "type": "error" },
    { "inputs": [], "name": "InvalidClaimer", "type": "error" },
    { "inputs": [], "name": "InvalidCollateral", "type": "error" },
    { "inputs": [], "name": "InvalidDelegator", "type": "error" },
    { "inputs": [], "name": "InvalidEpoch", "type": "error" },
    { "inputs": [], "name": "InvalidEpochDuration", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidLengthEpochs", "type": "error" },
    { "inputs": [], "name": "InvalidOnBehalfOf", "type": "error" },
    { "inputs": [], "name": "InvalidRecipient", "type": "error" },
    { "inputs": [], "name": "InvalidSlasher", "type": "error" },
    { "inputs": [], "name": "InvalidTimestamp", "type": "error" },
    { "inputs": [], "name": "MathOverflowedMulDiv", "type": "error" },
    { "inputs": [], "name": "MissingRoles", "type": "error" },
    { "inputs": [], "name": "NoPreviousEpoch", "type": "error" },
    { "inputs": [], "name": "NotDelegator", "type": "error" },
    { "inputs": [], "name": "NotFactory", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotSlasher", "type": "error" },
    { "inputs": [], "name": "NotWhitelistedDepositor", "type": "error" },
    {
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }],
        "name": "OwnableInvalidOwner",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "OwnableUnauthorizedAccount",
        "type": "error"
    },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    {
        "inputs": [{ "internalType": "address", "name": "token", "type": "address" }],
        "name": "SafeERC20FailedOperation",
        "type": "error"
    },
    { "inputs": [], "name": "SlasherAlreadyInitialized", "type": "error" },
    { "inputs": [], "name": "TooMuchRedeem", "type": "error" },
    { "inputs": [], "name": "TooMuchWithdraw", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "owner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Approval",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "epoch",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "Claim",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "recipient",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256[]",
                "name": "epochs",
                "type": "uint256[]"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "ClaimBatch",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "depositor",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "onBehalfOf",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "shares",
                "type": "uint256"
            }
        ],
        "name": "Deposit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "slashedAmount",
                "type": "uint256"
            }
        ],
        "name": "OnSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "previousOwner",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "newOwner",
                "type": "address"
            }
        ],
        "name": "OwnershipTransferred",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "previousAdminRole",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "newAdminRole",
                "type": "bytes32"
            }
        ],
        "name": "RoleAdminChanged",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleGranted",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "role",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            }
        ],
        "name": "RoleRevoked",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "delegator",
                "type": "address"
            }
        ],
        "name": "SetDelegator",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "limit",
                "type": "uint256"
            }
        ],
        "name": "SetDepositLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetDepositWhitelist",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "account",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetDepositorWhitelistStatus",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "bool",
                "name": "status",
                "type": "bool"
            }
        ],
        "name": "SetIsDepositLimit",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "slasher",
                "type": "address"
            }
        ],
        "name": "SetSlasher",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "from",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "to",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Transfer",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "withdrawer",
                "type": "address"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "claimer",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "burnedShares",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "mintedShares",
                "type": "uint256"
            }
        ],
        "name": "Withdraw",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "DEFAULT_ADMIN_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DELEGATOR_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSITOR_WHITELIST_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSIT_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "DEPOSIT_WHITELIST_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "IS_DEPOSIT_LIMIT_SET_ROLE",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "SLASHER_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "activeBalanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "activeBalanceOfAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "activeShares",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeSharesAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "activeSharesOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeSharesOfAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "activeStake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "activeStakeAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "owner", "type": "address" },
            { "internalType": "address", "name": "spender", "type": "address" }
        ],
        "name": "allowance",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "spender", "type": "address" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "approve",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "balanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "burner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "epoch", "type": "uint256" }
        ],
        "name": "claim",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256[]", "name": "epochs", "type": "uint256[]" }
        ],
        "name": "claimBatch",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "collateral",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "currentEpoch",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "currentEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "decimals",
        "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "delegator",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "onBehalfOf", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "deposit",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "depositedAmount",
                "type": "uint256"
            },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "depositLimit",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "depositWhitelist",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint48", "name": "timestamp", "type": "uint48" }],
        "name": "epochAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "epochDuration",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "epochDurationInit",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }],
        "name": "getRoleAdmin",
        "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "grantRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "hasRole",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "initialVersion", "type": "uint64" },
            { "internalType": "address", "name": "owner_", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isDelegatorInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isDepositLimit",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "isDepositorWhitelisted",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isSlasherInitialized",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "isWithdrawalsClaimed",
        "outputs": [{ "internalType": "bool", "name": "value", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint64", "name": "newVersion", "type": "uint64" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "migrate",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "name",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "nextEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            { "internalType": "uint48", "name": "captureTimestamp", "type": "uint48" }
        ],
        "name": "onSlash",
        "outputs": [{ "internalType": "uint256", "name": "slashedAmount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "owner",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "previousEpochStart",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "claimer", "type": "address" },
            { "internalType": "uint256", "name": "shares", "type": "uint256" }
        ],
        "name": "redeem",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "withdrawnAssets",
                "type": "uint256"
            },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "renounceOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            {
                "internalType": "address",
                "name": "callerConfirmation",
                "type": "address"
            }
        ],
        "name": "renounceRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "role", "type": "bytes32" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "revokeRole",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "delegator_", "type": "address" }],
        "name": "setDelegator",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "limit", "type": "uint256" }],
        "name": "setDepositLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bool", "name": "status", "type": "bool" }],
        "name": "setDepositWhitelist",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "account", "type": "address" },
            { "internalType": "bool", "name": "status", "type": "bool" }
        ],
        "name": "setDepositorWhitelistStatus",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bool", "name": "status", "type": "bool" }],
        "name": "setIsDepositLimit",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "slasher_", "type": "address" }],
        "name": "setSlasher",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "slashableBalanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "slasher",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }],
        "name": "supportsInterface",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "symbol",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalStake",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "totalSupply",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "to", "type": "address" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "transfer",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "from", "type": "address" },
            { "internalType": "address", "name": "to", "type": "address" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "transferFrom",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
        "name": "transferOwnership",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "version",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "claimer", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "withdraw",
        "outputs": [
            { "internalType": "uint256", "name": "burnedShares", "type": "uint256" },
            { "internalType": "uint256", "name": "mintedShares", "type": "uint256" }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "epoch", "type": "uint256" }],
        "name": "withdrawalShares",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "withdrawalSharesOf",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "epoch", "type": "uint256" }],
        "name": "withdrawals",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "epoch", "type": "uint256" },
            { "internalType": "address", "name": "account", "type": "address" }
        ],
        "name": "withdrawalsOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    }
]
```

## File: abi/VetoSlasherABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "vaultFactory", "type": "address" },
            {
                "internalType": "address",
                "name": "networkMiddlewareService",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "networkRegistry",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "slasherFactory",
                "type": "address"
            },
            { "internalType": "uint64", "name": "entityType", "type": "uint64" }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "AlreadySet", "type": "error" },
    { "inputs": [], "name": "CheckpointUnorderedInsertion", "type": "error" },
    { "inputs": [], "name": "InsufficientBurnerGas", "type": "error" },
    { "inputs": [], "name": "InsufficientSlash", "type": "error" },
    { "inputs": [], "name": "InvalidCaptureTimestamp", "type": "error" },
    { "inputs": [], "name": "InvalidInitialization", "type": "error" },
    { "inputs": [], "name": "InvalidResolverSetEpochsDelay", "type": "error" },
    { "inputs": [], "name": "InvalidVetoDuration", "type": "error" },
    { "inputs": [], "name": "NoBurner", "type": "error" },
    { "inputs": [], "name": "NoResolver", "type": "error" },
    { "inputs": [], "name": "NotInitialized", "type": "error" },
    { "inputs": [], "name": "NotInitializing", "type": "error" },
    { "inputs": [], "name": "NotNetwork", "type": "error" },
    { "inputs": [], "name": "NotNetworkMiddleware", "type": "error" },
    { "inputs": [], "name": "NotResolver", "type": "error" },
    { "inputs": [], "name": "NotVault", "type": "error" },
    { "inputs": [], "name": "ReentrancyGuardReentrantCall", "type": "error" },
    {
        "inputs": [
            { "internalType": "uint8", "name": "bits", "type": "uint8" },
            { "internalType": "uint256", "name": "value", "type": "uint256" }
        ],
        "name": "SafeCastOverflowedUintDowncast",
        "type": "error"
    },
    { "inputs": [], "name": "SlashPeriodEnded", "type": "error" },
    { "inputs": [], "name": "SlashRequestCompleted", "type": "error" },
    { "inputs": [], "name": "SlashRequestNotExist", "type": "error" },
    { "inputs": [], "name": "VetoPeriodEnded", "type": "error" },
    { "inputs": [], "name": "VetoPeriodNotEnded", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint256",
                "name": "slashIndex",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "slashedAmount",
                "type": "uint256"
            }
        ],
        "name": "ExecuteSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": false,
                "internalType": "uint64",
                "name": "version",
                "type": "uint64"
            }
        ],
        "name": "Initialized",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint256",
                "name": "slashIndex",
                "type": "uint256"
            },
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "operator",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "slashAmount",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            {
                "indexed": false,
                "internalType": "uint48",
                "name": "vetoDeadline",
                "type": "uint48"
            }
        ],
        "name": "RequestSlash",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "bytes32",
                "name": "subnetwork",
                "type": "bytes32"
            },
            {
                "indexed": false,
                "internalType": "address",
                "name": "resolver",
                "type": "address"
            }
        ],
        "name": "SetResolver",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "uint256",
                "name": "slashIndex",
                "type": "uint256"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "resolver",
                "type": "address"
            }
        ],
        "name": "VetoSlash",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "BURNER_GAS_LIMIT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "BURNER_RESERVE",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_MIDDLEWARE_SERVICE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "NETWORK_REGISTRY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "TYPE",
        "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "VAULT_FACTORY",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "cumulativeSlash",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "cumulativeSlashAt",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "slashIndex", "type": "uint256" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "executeSlash",
        "outputs": [{ "internalType": "uint256", "name": "slashedAmount", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }],
        "name": "initialize",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "isBurnerHook",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "latestSlashedCaptureTimestamp",
        "outputs": [{ "internalType": "uint48", "name": "value", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "requestSlash",
        "outputs": [{ "internalType": "uint256", "name": "slashIndex", "type": "uint256" }],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "resolver",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "uint48", "name": "timestamp", "type": "uint48" },
            { "internalType": "bytes", "name": "hint", "type": "bytes" }
        ],
        "name": "resolverAt",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "resolverSetEpochsDelay",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint96", "name": "identifier", "type": "uint96" },
            { "internalType": "address", "name": "resolver_", "type": "address" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "setResolver",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "name": "slashRequests",
        "outputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "uint48", "name": "vetoDeadline", "type": "uint48" },
            { "internalType": "bool", "name": "completed", "type": "bool" }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "slashRequestsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "bytes32", "name": "subnetwork", "type": "bytes32" },
            { "internalType": "address", "name": "operator", "type": "address" },
            {
                "internalType": "uint48",
                "name": "captureTimestamp",
                "type": "uint48"
            },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "slashableStake",
        "outputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "address", "name": "target", "type": "address" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "staticDelegateCall",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vault",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "vetoDuration",
        "outputs": [{ "internalType": "uint48", "name": "", "type": "uint48" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "slashIndex", "type": "uint256" },
            { "internalType": "bytes", "name": "hints", "type": "bytes" }
        ],
        "name": "vetoSlash",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]
```

## File: abi/wstETH_BurnerABI.json

```json
[
    {
        "inputs": [
            { "internalType": "address", "name": "collateral", "type": "address" },
            {
                "internalType": "address",
                "name": "lidoWithdrawalQueue",
                "type": "address"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    { "inputs": [], "name": "InsufficientWithdrawal", "type": "error" },
    { "inputs": [], "name": "InvalidRequestId", "type": "error" },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "requestId",
                "type": "uint256"
            }
        ],
        "name": "TriggerBurn",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256[]",
                "name": "requestIds",
                "type": "uint256[]"
            }
        ],
        "name": "TriggerBurnBatch",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "caller",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256[]",
                "name": "requestIds",
                "type": "uint256[]"
            }
        ],
        "name": "TriggerWithdrawal",
        "type": "event"
    },
    {
        "inputs": [],
        "name": "COLLATERAL",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "LIDO_WITHDRAWAL_QUEUE",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "MAX_STETH_WITHDRAWAL_AMOUNT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "MIN_STETH_WITHDRAWAL_AMOUNT",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "STETH",
        "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            { "internalType": "uint256", "name": "index", "type": "uint256" },
            { "internalType": "uint256", "name": "maxRequestIds", "type": "uint256" }
        ],
        "name": "requestIds",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "requestIdsLength",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "requestId", "type": "uint256" }],
        "name": "triggerBurn",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            },
            { "internalType": "uint256[]", "name": "hints", "type": "uint256[]" }
        ],
        "name": "triggerBurnBatch",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{ "internalType": "uint256", "name": "maxRequests", "type": "uint256" }],
        "name": "triggerWithdrawal",
        "outputs": [
            {
                "internalType": "uint256[]",
                "name": "requestIds_",
                "type": "uint256[]"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    { "stateMutability": "payable", "type": "receive" }
]
```

## File: src/cli/argParsers.ts

```typescript
import { Argument, InvalidArgumentError } from "commander";

import {
    parseAddress,
    parseBytes32Hex,
    parseHex,
    parseUint48,
    parseUint96,
    parseUint256,
} from "./parse";

function wrapParser<T>(fn: (value: string) => T): (value: string) => T {
    return (value: string) => {
        try {
            return fn(value);
        } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            throw new InvalidArgumentError(message);
        }
    };
}

export function defaultedArg<T>(
    flags: string,
    description: string,
    parser: (value: string) => T,
    defaultValue: T,
    defaultValueDescription = String(defaultValue),
) {
    return new Argument(flags, description)
        .argParser(parser)
        .default(defaultValue, defaultValueDescription);
}

export const parseAddressArg = wrapParser(parseAddress);
export const parseUint256Arg = wrapParser(parseUint256);
export const parseUint96Arg = wrapParser(parseUint96);
export const parseUint48Arg = wrapParser(parseUint48);
export const parseBytes32HexArg = wrapParser(parseBytes32Hex);
export const parseHexArg = wrapParser(parseHex);
```

## File: src/cli/context.ts

```typescript
import type { Command } from "commander";

import { assertChainId, createSymbioticPublicClient, resolveClientConfig } from "../core/client";
import { SymbioticClient } from "../core/symbiotic";
import type { ResolvedClientConfig } from "../core/client";
import type { Chain, PublicClient, Transport } from "viem";

export type GlobalOptions = {
    chain: string;
    rpc?: string;
    json?: boolean;
    quiet?: boolean;
    batchSize?: number;
    concurrency?: number;
    timeoutMs?: number;
    retries?: number;
};

export type CliContext = {
    resolved: ResolvedClientConfig;
    publicClient: PublicClient<Transport, Chain>;
    symb: SymbioticClient;
    json: boolean;
    quiet: boolean;
};

export function createContextGetter(program: Command) {
    let ctxPromise: Promise<CliContext> | undefined;

    return async function getCtx(): Promise<CliContext> {
        if (ctxPromise) return ctxPromise;

        ctxPromise = (async () => {
            const opts = program.opts<GlobalOptions>();
            const resolved = await resolveClientConfig({
                chain: opts.chain,
                rpc: opts.rpc,
                timeoutMs: opts.timeoutMs,
                retries: opts.retries,
            });

            const publicClient = createSymbioticPublicClient(resolved);
            await assertChainId(publicClient, resolved.chainId);

            const symb = new SymbioticClient({
                chainKey: resolved.chainKey,
                chainId: resolved.chainId,
                addresses: resolved.addresses,
                publicClient,
                multicallBatchSize: opts.batchSize,
                multicallConcurrency: opts.concurrency,
            });

            return {
                resolved,
                publicClient,
                symb,
                json: Boolean(opts.json),
                quiet: Boolean(opts.quiet),
            };
        })();

        return ctxPromise;
    };
}
```

## File: src/cli/parse.ts

```typescript
import { getAddress, isHex, type Address, type Hex } from "viem";

const MAX_UINT256 = (1n << 256n) - 1n;
const MAX_UINT96 = (1n << 96n) - 1n;
const MAX_UINT48 = (1n << 48n) - 1n;

export function parseAddress(value: string): Address {
    return getAddress(value);
}

function parseBigint(value: string): bigint {
    try {
        // Only accept base-10 integers for CLI args.
        if (!/^\d+$/.test(value)) throw new Error("not a base-10 integer");
        return BigInt(value);
    } catch {
        throw new Error(`Invalid integer: ${value}`);
    }
}

export function parseUint256(value: string): bigint {
    const n = parseBigint(value);
    if (n < 0n || n > MAX_UINT256) throw new Error(`Invalid uint256: ${value}`);
    return n;
}

export function parseUint96(value: string): bigint {
    const n = parseBigint(value);
    if (n < 0n || n > MAX_UINT96) throw new Error(`Invalid uint96: ${value}`);
    return n;
}

export function parseUint48(value: string): bigint {
    const n = parseBigint(value);
    if (n < 0n || n > MAX_UINT48) throw new Error(`Invalid uint48: ${value}`);
    return n;
}

export function parseBytes32Hex(value: string): Hex {
    const hex = value.startsWith("0x") ? value : `0x${value}`;
    if (!isHex(hex) || hex.length !== 66) throw new Error(`Invalid bytes32 hex: ${value}`);
    return hex as Hex;
}

export function parseHex(value: string): Hex {
    const hex = value.startsWith("0x") ? value : `0x${value}`;
    if (!isHex(hex)) throw new Error(`Invalid hex: ${value}`);
    return hex as Hex;
}
```

## File: src/cli/program.ts

```typescript
import { Command } from "commander";

import { createContextGetter } from "./context";
import { registerNetworkReadCommands } from "../commands/nets";
import { registerOperatorReadCommands } from "../commands/operators";
import { registerRewardsReadCommands } from "../commands/rewards";
import { registerStakerReadCommands } from "../commands/stakers";
import { registerVaultReadCommands } from "../commands/vaults";
import { registerCuratorWriteCommands } from "../commands/writesCurator";
import { registerNetworkWriteCommands } from "../commands/writesNetwork";
import { registerOperatorWriteCommands } from "../commands/writesOperator";
import { registerRewardsWriteCommands } from "../commands/writesRewards";
import { registerStakerWriteCommands } from "../commands/writesStaker";

export function createProgram() {
    const program = new Command();

    program.name("symb").description("Symbiotic CLI (TypeScript + viem)").version("0.0.0");

    program
        .option("--chain <chain>", "Chain key or chainId (mainnet, hoodi, sepolia)", "mainnet")
        .option("--rpc <url>", "Ethereum RPC URL override")
        .option("--batch-size <n>", "Multicall batch size", (v) => Number(v))
        .option("--concurrency <n>", "Multicall concurrency", (v) => Number(v))
        .option("--timeout-ms <n>", "RPC request timeout (ms)", (v) => Number(v))
        .option("--retries <n>", "RPC retry count", (v) => Number(v))
        .option("--json", "Machine-readable JSON output", false)
        .option("--quiet", "Minimal output", false);

    program.configureHelp({ helpWidth: 110, sortSubcommands: true, sortOptions: true });
    program.showHelpAfterError();

    program.addHelpText(
        "after",
        `
Learn more:
  symb <group> --help

Examples:
  symb net list --full
  symb op stakes <operator>
  symb vault list --full
`,
    );

    const getCtx = createContextGetter(program);

    // Public groups (shown in root help).
    const net = program.command("net").description("Network-related commands");
    net.action(() => net.help());

    const op = program.command("op").description("Operator-related commands");
    op.action(() => op.help());

    const vault = program.command("vault").description("Vault-related commands");
    vault.action(() => vault.help());

    const staker = program.command("staker").description("Staker commands");
    staker.action(() => staker.help());

    const rewards = program.command("rewards").description("Rewards commands");
    rewards.action(() => rewards.help());

    // Grouped commands (primary UX).
    registerNetworkReadCommands(net, getCtx);
    registerNetworkWriteCommands(net, getCtx);

    registerOperatorReadCommands(op, getCtx);
    registerOperatorWriteCommands(op, getCtx);

    registerVaultReadCommands(vault, getCtx);
    registerCuratorWriteCommands(vault, getCtx);

    registerStakerReadCommands(staker, getCtx);
    registerStakerWriteCommands(staker, getCtx);

    registerRewardsReadCommands(rewards, getCtx);
    registerRewardsWriteCommands(rewards, getCtx);

    return program;
}
```

## File: src/cli/run.ts

```typescript
export async function runCliAction(fn: () => Promise<void>) {
    try {
        await fn();
    } catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        if (process.env.SYMB_DEBUG_STACK && err instanceof Error && err.stack) {
            process.stderr.write(`${err.stack}\n`);
        } else {
            process.stderr.write(`${message}\n`);
        }
        process.exitCode = 1;
    }
}
```

## File: src/cli/signing.ts

```typescript
import type { Address, Hex } from "viem";
import type { Account } from "viem/accounts";

import { readEnv } from "../config/env";
import { accountFromPrivateKey } from "../core/signing/local";
import type { SigningFlags } from "./signingOptions";
import { parseAddress, parseBytes32Hex } from "./parse";

export async function resolveSigningAccount(
    flags: SigningFlags,
): Promise<{ account: Account | Address; address: Address; close: () => Promise<void> }> {
    if (flags.from) {
        const address = parseAddress(flags.from);
        return { account: address, address, close: async () => {} };
    }

    if (flags.ledger) {
        const { createLedgerAccount } = await import("../core/signing/ledger");
        return createLedgerAccount({
            expectedAddress: flags.ledgerAddress ? parseAddress(flags.ledgerAddress) : undefined,
        });
    }

    const env = readEnv();
    const pkInput = flags.privateKey ?? env.SYMB_PRIVATE_KEY;
    if (!pkInput)
        throw new Error(
            "Signer is required (use --from, --ledger, or --private-key, or SYMB_PRIVATE_KEY).",
        );

    const pk = parseBytes32Hex(pkInput) as Hex;
    const account = accountFromPrivateKey(pk);
    return { account, address: account.address, close: async () => {} };
}

export async function withSigningAccount<T>(
    flags: SigningFlags,
    fn: (args: { account: Account | Address; address: Address }) => Promise<T>,
): Promise<T> {
    const { account, address, close } = await resolveSigningAccount(flags);
    try {
        return await fn({ account, address });
    } finally {
        await close();
    }
}
```

## File: src/cli/signingOptions.ts

```typescript
export type SigningFlags = {
    privateKey?: string;
    from?: string;
    ledger?: boolean;
    ledgerAddress?: string;
};

export type WriteFlags = SigningFlags & {
    yes?: boolean;
    dryRun?: boolean;
};
```

## File: src/commands/nets.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { parseAddressArg } from "../cli/argParsers";
import { runCliAction } from "../cli/run";
import { SUBNETWORK_IDS } from "../core/constants";
import { groupBy } from "../core/format";
import { printIndented, printJson, printLine } from "../core/output";
import { startSpinner } from "../core/spinner";
import { encodeSubnetwork } from "../core/subnetwork";
import { formatTokenAmount } from "../core/units";

export function registerNetworkReadCommands(program: Command, getCtx: () => Promise<CliContext>) {
    program
        .command("is")
        .description("Get whether address is a network.")
        .argument("<address>", "an address to check", parseAddressArg)
        .action((address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const isNet = await ctx.symb.isNet(address);
                if (ctx.json) return printJson({ isNet });
                printLine(String(isNet));
            }),
        );

    program
        .command("middleware")
        .description("Get network middleware address.")
        .argument(
            "<network_address>",
            "an address of the network to get a middleware for",
            parseAddressArg,
        )
        .action((networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const middleware = await ctx.symb.getMiddleware(networkAddress);
                if (ctx.json) return printJson({ middleware });
                printLine(middleware);
            }),
        );

    const listCmd = program
        .command("list")
        .description("Get all networks.")
        .option("--full", "Show full data", false)
        .action((opts: { full?: boolean }) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching networks...");
                const nets = await (async () => {
                    try {
                        return await ctx.symb.getNets();
                    } finally {
                        spinner?.stop();
                    }
                })();

                if (ctx.json) {
                    if (!opts.full) return printJson({ nets });

                    const counts = await ctx.symb.getNetsFullCounts(nets);
                    return printJson({
                        nets: nets.map((net, i) => ({
                            ...net,
                            ops: counts[i]?.ops ?? 0,
                            vaults: counts[i]?.vaults ?? 0,
                        })),
                    });
                }

                printLine(`All networks [${nets.length} total]:`);

                let fullData: Array<{ ops: number; vaults: number }> | undefined;
                if (opts.full) {
                    const fullSpinner = startSpinner(
                        ctx,
                        "Fetching full network data (this can take a while)...",
                    );
                    try {
                        fullData = await ctx.symb.getNetsFullCounts(nets);
                    } finally {
                        fullSpinner?.stop();
                    }
                }

                for (let i = 0; i < nets.length; i++) {
                    const net = nets[i]!;
                    printIndented(`Network: ${net.net}`, 2);
                    printIndented(`Middleware: ${net.middleware}`, 4);
                    if (opts.full) {
                        const f = fullData?.[i];
                        printIndented(`Operators: ${f?.ops ?? 0} total`, 4);
                        printIndented(`Vaults: ${f?.vaults ?? 0} total`, 4);
                    }
                    printLine("");
                }
            }),
        );

    listCmd.alias("ls");

    program
        .command("ops")
        .description("Get all operators opted in network.")
        .argument(
            "<network_address>",
            "an address of the network to get operators for",
            parseAddressArg,
        )
        .action((networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching network operators...");
                const ops = await (async () => {
                    try {
                        return await ctx.symb.getNetOps(networkAddress);
                    } finally {
                        spinner?.stop();
                    }
                })();

                if (ctx.json) return printJson({ network: networkAddress, operators: ops });

                printLine(`Network: ${networkAddress}`);
                printLine(`Operators [${ops.length} total]:`);
                for (const op of ops) printIndented(`Operator: ${op}`, 2);
            }),
        );

    program
        .command("stakes")
        .description("Get stakes of all operators in network.")
        .argument(
            "<network_address>",
            "an address of the network to get a whole stake data for",
            parseAddressArg,
        )
        .action((networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(
                    ctx,
                    "Fetching network stakes (this can take a while)...",
                );
                const [middleware, opsVaults] = await (async () => {
                    try {
                        return await Promise.all([
                            ctx.symb.getMiddleware(networkAddress),
                            ctx.symb.getNetOpsVaults(networkAddress),
                        ]);
                    } finally {
                        spinner?.stop();
                    }
                })();

                if (ctx.json)
                    return printJson({ network: networkAddress, middleware, operators: opsVaults });

                printLine(`Network: ${networkAddress}`);
                printLine(`Middleware: ${middleware}`);
                printLine(`Operators [${opsVaults.length} total]:`);

                const totalStakes = new Map<Address, bigint>();

                for (const op of opsVaults) {
                    printIndented(`Operator: ${op.op}`, 2);

                    const byCollateral = groupBy(op.vaults, (v) => v.collateral);
                    const totalOpStakeParts: string[] = [];

                    for (const [collateral, vaults] of byCollateral.entries()) {
                        const tokenMeta = await ctx.symb.getTokenMeta(collateral);
                        printIndented(`Collateral: ${collateral} (${tokenMeta.symbol})`, 4);

                        let stakesSum = 0n;
                        for (const vault of vaults) {
                            printIndented(`Vault: ${vault.vault}`, 6);
                            printIndented(
                                `Type: ${ctx.symb.delegatorTypeName(vault.delegatorType)} / ${ctx.symb.slasherTypeName(vault.slasherType)}`,
                                8,
                            );
                            const stake = Object.values(vault.stake).reduce((a, b) => a + b, 0n);
                            printIndented(`Stake: ${formatTokenAmount(stake, tokenMeta)}`, 8);
                            stakesSum += stake;
                        }

                        totalOpStakeParts.push(
                            `${formatTokenAmount(stakesSum, tokenMeta)} ${tokenMeta.symbol}`,
                        );
                        totalStakes.set(
                            collateral,
                            (totalStakes.get(collateral) ?? 0n) + stakesSum,
                        );
                    }

                    if (totalOpStakeParts.length) {
                        printIndented(`Total stake: ${totalOpStakeParts.join(" + ")}`, 4);
                    } else {
                        printIndented("Total stake: 0", 4);
                    }
                    printLine("");
                }

                printLine("Total stakes:");
                for (const [collateral, stake] of totalStakes.entries()) {
                    const meta = await ctx.symb.getTokenMeta(collateral);
                    printIndented(
                        `Collateral ${collateral} (${meta.symbol}): ${formatTokenAmount(stake, meta)}`,
                        2,
                    );
                }
            }),
        );

    program
        .command("max-network-limit")
        .description("Get a maximum network limit at the vault's delegator.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;
                const delegator = await ctx.symb.getVaultDelegator(vaultAddress);

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const limit = await ctx.symb.getMaxNetworkLimit(delegator, subnetwork);
                    results.push({ subnetId, subnetwork, maxNetworkLimit: limit });
                }

                if (ctx.json) return printJson({ vault, network: net, delegator, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Maximum network limit for subnetwork = ${r.subnetwork} at vault ${vault} is ${r.maxNetworkLimit}`,
                    );
                    printLine("");
                }
            }),
        );

    program
        .command("resolver")
        .description("Get a current resolver for a subnetwork in a vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;

                const slasher = await ctx.symb.getVaultSlasher(vault);
                const slasherType = await ctx.symb.tryGetEntityType(slasher);
                if (slasherType !== 1n) {
                    if (ctx.json)
                        return printJson({
                            vault,
                            network: net,
                            slasher,
                            isVetoSlasher: false,
                            error: "It is not a VetoSlasher.",
                        });
                    printLine("It is not a VetoSlasher.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const resolver = await ctx.symb.getResolver(slasher, subnetwork);
                    results.push({ subnetId, subnetwork, resolver });
                }

                if (ctx.json) return printJson({ vault, network: net, slasher, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Resolver for subnetwork = ${r.subnetwork} at vault ${vault} is ${r.resolver}`,
                    );
                    printLine("");
                }
            }),
        );

    program
        .command("pending-resolver")
        .description("Get a pending resolver for a subnetwork in a vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;

                const slasher = await ctx.symb.getVaultSlasher(vault);
                const slasherType = await ctx.symb.tryGetEntityType(slasher);
                if (slasherType !== 1n) {
                    if (ctx.json)
                        return printJson({
                            vault,
                            network: net,
                            slasher,
                            isVetoSlasher: false,
                            error: "It is not a VetoSlasher.",
                        });
                    printLine("It is not a VetoSlasher.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const resolver = await ctx.symb.getResolver(slasher, subnetwork);
                    const pending = await ctx.symb.getPendingResolver(slasher, subnetwork);
                    results.push({
                        subnetId,
                        subnetwork,
                        resolver,
                        pendingResolver: pending,
                        hasPending: resolver !== pending,
                    });
                }

                if (ctx.json) return printJson({ vault, network: net, slasher, results });

                printLine("");
                for (const r of results) {
                    if (!r.hasPending) {
                        printLine(
                            `There is no pending resolver for subnetwork = ${r.subnetwork} at vault ${vault}`,
                        );
                    } else {
                        printLine(
                            `Pending resolver for subnetwork = ${r.subnetwork} at vault ${vault} is ${r.pendingResolver}`,
                        );
                    }
                    printLine("");
                }
            }),
        );
}
```

## File: src/commands/operators.ts

```typescript
import type { Command } from "commander";
import { formatUnits, type Address } from "viem";

import type { CliContext } from "../cli/context";
import { parseAddressArg } from "../cli/argParsers";
import { runCliAction } from "../cli/run";
import { SUBNETWORK_IDS } from "../core/constants";
import { formatPercent, groupBy } from "../core/format";
import { printIndented, printJson, printLine } from "../core/output";
import { startSpinner } from "../core/spinner";
import { encodeSubnetwork } from "../core/subnetwork";
import { formatTokenAmount } from "../core/units";

export function registerOperatorReadCommands(program: Command, getCtx: () => Promise<CliContext>) {
    program
        .command("is")
        .description("Get whether address is an operator.")
        .argument("<address>", "an address to check", parseAddressArg)
        .action((address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const isOp = await ctx.symb.isOp(address);
                if (ctx.json) return printJson({ isOp });
                printLine(String(isOp));
            }),
        );

    const listCmd = program
        .command("list")
        .description("Get all operators.")
        .action(() =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching operators...");
                const ops = await (async () => {
                    try {
                        return await ctx.symb.getOps();
                    } finally {
                        spinner?.stop();
                    }
                })();
                if (ctx.json) return printJson({ operators: ops });

                printLine(`All operators [${ops.length} total]:`);
                for (const op of ops) printIndented(`Operator: ${op}`, 2);
            }),
        );

    listCmd.alias("ls");

    program
        .command("stake")
        .description(
            "Get operator stake in vault for network (includes shares for NetworkRestakeDelegator).",
        )
        .argument("<operator_address>", "operator address", parseAddressArg)
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((operatorAddress: Address, vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const op = operatorAddress;
                const vault = vaultAddress;
                const net = networkAddress;

                const spinner = startSpinner(ctx, "Fetching stake...");
                const { delegator, delegatorType, collateral, tokenMeta, perSubnet } =
                    await (async () => {
                        try {
                            const delegator = await ctx.symb.getVaultDelegator(vault);
                            const delegatorType = await ctx.symb.getEntityType(delegator);
                            const collateral = await ctx.symb.getVaultCollateral(vault);
                            const tokenMeta = await ctx.symb.getTokenMeta(collateral);

                            const perSubnet = [];
                            for (const subnetId of SUBNETWORK_IDS) {
                                const subnetwork = encodeSubnetwork({ net, subnetId });
                                const stake = await ctx.symb.getStakeByDelegator(
                                    delegator,
                                    subnetwork,
                                    op,
                                );

                                let shares:
                                    | {
                                          operatorNetworkShares: bigint;
                                          totalOperatorNetworkShares: bigint;
                                          percent: string;
                                      }
                                    | undefined;
                                if (delegatorType === 0n) {
                                    const operatorNetworkShares =
                                        await ctx.symb.getOperatorNetworkShares(
                                            delegator,
                                            subnetwork,
                                            op,
                                        );
                                    const totalOperatorNetworkShares =
                                        await ctx.symb.getTotalOperatorNetworkShares(
                                            delegator,
                                            subnetwork,
                                        );
                                    shares = {
                                        operatorNetworkShares,
                                        totalOperatorNetworkShares,
                                        percent: formatPercent(
                                            operatorNetworkShares,
                                            totalOperatorNetworkShares,
                                        ),
                                    };
                                }

                                perSubnet.push({
                                    subnetId,
                                    subnetwork,
                                    stake,
                                    stakeFormatted: formatTokenAmount(stake, tokenMeta),
                                    shares,
                                });
                            }

                            return { delegator, delegatorType, collateral, tokenMeta, perSubnet };
                        } finally {
                            spinner?.stop();
                        }
                    })();

                if (ctx.json)
                    return printJson({
                        operator: op,
                        vault,
                        network: net,
                        collateral,
                        tokenMeta,
                        delegator,
                        delegatorType,
                        perSubnet,
                    });

                printLine(`Operator stake in vault = ${vault}`);
                printLine("");

                for (const row of perSubnet) {
                    if (row.shares) {
                        printLine(
                            `for subnetwork = ${row.subnetwork} is ${row.stakeFormatted} ${tokenMeta.symbol}\nwhich is ${row.shares.percent}% (${row.shares.operatorNetworkShares} / ${row.shares.totalOperatorNetworkShares} in shares) of network stake`,
                        );
                    } else {
                        printLine(
                            `for subnetwork = ${row.subnetwork} is ${row.stakeFormatted} ${tokenMeta.symbol}`,
                        );
                    }
                    printLine("");
                }
            }),
        );

    program
        .command("nets")
        .description("Get all networks where operator is opted in.")
        .argument("<operator_address>", "operator address", parseAddressArg)
        .action((operatorAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const op = operatorAddress;
                const spinner = startSpinner(ctx, "Fetching operator networks...");
                const nets = await (async () => {
                    try {
                        return await ctx.symb.getOpNets(op);
                    } finally {
                        spinner?.stop();
                    }
                })();
                if (ctx.json) return printJson({ operator: op, networks: nets.map((n) => n.net) });

                printLine(`Operator: ${op}`);
                printLine(`Networks [${nets.length} total]:`);
                for (const net of nets) printLine(`  Network: ${net.net}`);
            }),
        );

    program
        .command("stakes")
        .description("Get operator stakes in all networks.")
        .argument("<operator_address>", "operator address", parseAddressArg)
        .action((operatorAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const op = operatorAddress;
                const spinner = startSpinner(
                    ctx,
                    "Fetching operator stakes (this can take a while)...",
                );
                const netsVaults = await (async () => {
                    try {
                        return await ctx.symb.getOpNetsVaults(op);
                    } finally {
                        spinner?.stop();
                    }
                })();

                if (ctx.json) return printJson({ operator: op, networks: netsVaults });

                printLine(`Operator: ${op}`);
                printLine(`Networks [${netsVaults.length} total]:`);

                const totalStakes = new Map<Address, bigint>();

                for (const net of netsVaults) {
                    printIndented(`Network: ${net.net}`, 2);

                    const byCollateral = groupBy(net.vaults, (v) => v.collateral);
                    const totalNetStakeParts: string[] = [];

                    for (const [collateral, vaults] of byCollateral.entries()) {
                        const meta = await ctx.symb.getTokenMeta(collateral);
                        printIndented(`Collateral: ${collateral} (${meta.symbol})`, 4);

                        let stakesSum = 0n;
                        for (const vault of vaults) {
                            printIndented(`Vault: ${vault.vault}`, 6);
                            printIndented(
                                `Type: ${ctx.symb.delegatorTypeName(vault.delegatorType)} / ${ctx.symb.slasherTypeName(vault.slasherType)}`,
                                8,
                            );
                            const stake = Object.values(vault.stake).reduce((a, b) => a + b, 0n);
                            printIndented(`Stake: ${formatTokenAmount(stake, meta)}`, 8);
                            stakesSum += stake;
                        }

                        totalNetStakeParts.push(
                            `${formatTokenAmount(stakesSum, meta)} ${meta.symbol}`,
                        );
                        totalStakes.set(
                            collateral,
                            (totalStakes.get(collateral) ?? 0n) + stakesSum,
                        );
                    }

                    if (totalNetStakeParts.length) {
                        printIndented(`Total stake: ${totalNetStakeParts.join(" + ")}`, 4);
                    } else {
                        printIndented("Total stake: 0", 4);
                    }
                    printLine("");
                }

                printLine("Total stakes:");
                for (const [collateral, stake] of totalStakes.entries()) {
                    const meta = await ctx.symb.getTokenMeta(collateral);
                    printIndented(
                        `Collateral ${collateral} (${meta.symbol}): ${formatUnits(stake, meta.decimals)}`,
                        2,
                    );
                }
            }),
        );

    program
        .command("opted-in-vault")
        .description("Get whether operator is opted in to a vault.")
        .argument("<operator_address>", "operator address", parseAddressArg)
        .argument("<vault_address>", "vault address", parseAddressArg)
        .action((operatorAddress: Address, vaultAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const op = operatorAddress;
                const vault = vaultAddress;
                const opted = await ctx.symb.isOptedInVault(op, vault);
                if (ctx.json) return printJson({ operator: op, vault, optedIn: opted });

                printLine(
                    opted
                        ? `Operator = ${op} IS opted in to vault = ${vault}`
                        : `Operator = ${op} IS NOT opted in to vault = ${vault}`,
                );
            }),
        );

    program
        .command("opted-in-net")
        .description("Get whether operator is opted in to a network.")
        .argument("<operator_address>", "operator address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((operatorAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const op = operatorAddress;
                const net = networkAddress;
                const opted = await ctx.symb.isOptedInNet(op, net);
                if (ctx.json) return printJson({ operator: op, network: net, optedIn: opted });

                printLine(
                    opted
                        ? `Operator = ${op} IS opted in to network = ${net}`
                        : `Operator = ${op} IS NOT opted in to network = ${net}`,
                );
            }),
        );
}
```

## File: src/commands/rewards.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { defaultedArg, parseAddressArg, parseUint256Arg } from "../cli/argParsers";
import { parseUint256 } from "../cli/parse";
import { runCliAction } from "../cli/run";
import { printJson, printLine } from "../core/output";
import { startSpinner } from "../core/spinner";

function feeToPercentString(feePpm: bigint) {
    // 1_000_000 = 100.00%
    const bp = feePpm / 100n; // 10_000 = 1.00%
    const whole = bp / 100n;
    const frac = (bp % 100n).toString().padStart(2, "0");
    return `${whole}.${frac}%`;
}

export function registerRewardsReadCommands(program: Command, getCtx: () => Promise<CliContext>) {
    program
        .command("curator")
        .description("Get the curator address for a vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .action((vaultAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const curator = await ctx.symb.getCurator(vaultAddress);
                if (ctx.json) return printJson({ vault: vaultAddress, curator });
                printLine(curator);
            }),
        );

    program
        .command("operators-fee")
        .description("Get effective operators fee (ppm) for a vault+network.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const fee = await ctx.symb.getOperatorsFee(vaultAddress, networkAddress);
                if (ctx.json)
                    return printJson({ vault: vaultAddress, network: networkAddress, fee });
                printLine(`${fee} (${feeToPercentString(fee)})`);
            }),
        );

    program
        .command("curator-fee")
        .description("Get effective curator fee (ppm) for a vault+network.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const fee = await ctx.symb.getCuratorFee(vaultAddress, networkAddress);
                if (ctx.json)
                    return printJson({ vault: vaultAddress, network: networkAddress, fee });
                printLine(`${fee} (${feeToPercentString(fee)})`);
            }),
        );

    program
        .command("protocol-fee")
        .description("Get protocol fee (ppm) for a rewards type and network.")
        .argument("<rewards_type>", "vault-snapshot | cumulative-merkle | 0 | 1")
        .argument("<network_address>", "network address", parseAddressArg)
        .action((rewardsType, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const network = networkAddress;
                const type =
                    rewardsType === "vault-snapshot" || rewardsType === "0"
                        ? 0n
                        : rewardsType === "cumulative-merkle" || rewardsType === "1"
                          ? 1n
                          : (() => {
                                throw new Error(`Invalid rewards type: ${rewardsType}`);
                            })();

                const fee = await ctx.symb.protocolFee(type, network);
                if (ctx.json) return printJson({ rewardsType: type, network, fee });
                printLine(`${fee} (${feeToPercentString(fee)})`);
            }),
        );

    program
        .command("curator-fees")
        .description("Get claimable curator fees (amount) for a vault+token.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<token>", "ERC20 token address", parseAddressArg)
        .action((vaultAddress: Address, tokenAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const fees = await ctx.symb.curatorFees(vaultAddress, tokenAddress);
                if (ctx.json) return printJson({ vault: vaultAddress, token: tokenAddress, fees });
                printLine(fees.toString());
            }),
        );

    program
        .command("vault-snapshot-rewards")
        .description("Get claimable vault snapshot rewards (amount) for a staker.")
        .argument("<staker_address>", "staker address", parseAddressArg)
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .argument("<token>", "ERC20 token address", parseAddressArg)
        .addArgument(
            defaultedArg(
                "[first_reward_to_claim]",
                "first reward index to claim",
                parseUint256Arg,
                0n,
            ),
        )
        .addArgument(
            defaultedArg("[max_rewards]", "max rewards to claim", parseUint256Arg, 1_000_000n),
        )
        .option("--last-unclaimed <n>", "Override lastUnclaimedReward (uint256)")
        .action(
            (
                staker: Address,
                vault: Address,
                network: Address,
                token: Address,
                firstRewardToClaim: bigint,
                maxRewards: bigint,
                cmdOpts: { lastUnclaimed?: string },
            ) =>
                runCliAction(async () => {
                    const ctx = await getCtx();
                    const spinner = startSpinner(
                        ctx,
                        "Computing claimable vault snapshot rewards...",
                    );
                    const last =
                        cmdOpts.lastUnclaimed !== undefined
                            ? parseUint256(cmdOpts.lastUnclaimed)
                            : undefined;

                    const res = await (async () => {
                        try {
                            return await ctx.symb.previewVaultSnapshotRewards({
                                staker,
                                vault,
                                network,
                                token,
                                firstRewardToClaim,
                                maxRewards,
                                lastUnclaimedOverride: last,
                            });
                        } finally {
                            spinner?.stop();
                        }
                    })();

                    if (ctx.json) return printJson(res);
                    printLine(res.amount.toString());
                }),
        );

    program
        .command("operator-fees")
        .description("Get claimable operator fees (amount) for an operator.")
        .argument("<operator_address>", "operator address", parseAddressArg)
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .argument("<token>", "ERC20 token address", parseAddressArg)
        .addArgument(
            defaultedArg(
                "[first_reward_to_claim]",
                "first reward index to claim",
                parseUint256Arg,
                0n,
            ),
        )
        .addArgument(
            defaultedArg("[max_rewards]", "max rewards to claim", parseUint256Arg, 1_000_000n),
        )
        .option("--last-unclaimed <n>", "Override lastUnclaimedOperatorReward (uint256)")
        .action(
            (
                operator: Address,
                vault: Address,
                network: Address,
                token: Address,
                firstRewardToClaim: bigint,
                maxRewards: bigint,
                cmdOpts: { lastUnclaimed?: string },
            ) =>
                runCliAction(async () => {
                    const ctx = await getCtx();
                    const spinner = startSpinner(ctx, "Computing claimable operator fees...");
                    const last =
                        cmdOpts.lastUnclaimed !== undefined
                            ? parseUint256(cmdOpts.lastUnclaimed)
                            : undefined;

                    const res = await (async () => {
                        try {
                            return await ctx.symb.previewOperatorFees({
                                operator,
                                vault,
                                network,
                                token,
                                firstRewardToClaim,
                                maxRewards,
                                lastUnclaimedOverride: last,
                            });
                        } finally {
                            spinner?.stop();
                        }
                    })();

                    if (ctx.json) return printJson(res);
                    printLine(res.amount.toString());
                }),
        );
}
```

## File: src/commands/stakers.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { parseAddressArg, parseUint256Arg } from "../cli/argParsers";
import { runCliAction } from "../cli/run";
import { printJson, printLine } from "../core/output";
import { formatTokenAmount } from "../core/units";

export function registerStakerReadCommands(program: Command, getCtx: () => Promise<CliContext>) {
    program
        .command("active-balance")
        .description("Get an active balance of a given account at a particular vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<address>", "account address", parseAddressArg)
        .action((vaultAddress: Address, address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const account = address;

                const token = await ctx.symb.getVaultCollateral(vault);
                const meta = await ctx.symb.getTokenMeta(token);
                const activeBalanceWei = await ctx.symb.getActiveBalance(vault, account);

                if (ctx.json)
                    return printJson({
                        vault,
                        account,
                        activeBalanceWei,
                        activeBalance: formatTokenAmount(activeBalanceWei, meta),
                        symbol: meta.symbol,
                    });

                printLine(
                    `${activeBalanceWei} (${formatTokenAmount(activeBalanceWei, meta)} ${meta.symbol})`,
                );
            }),
        );

    program
        .command("withdrawals")
        .description("Get some epoch's withdrawals of a given account at a particular vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<epoch>", "epoch", parseUint256Arg)
        .argument("<address>", "account address", parseAddressArg)
        .action((vaultAddress: Address, epoch: bigint, address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const ep = epoch;
                const account = address;

                const token = await ctx.symb.getVaultCollateral(vault);
                const meta = await ctx.symb.getTokenMeta(token);
                const withdrawalsWei = await ctx.symb.getWithdrawals(vault, ep, account);

                if (ctx.json)
                    return printJson({
                        vault,
                        epoch: ep,
                        account,
                        withdrawalsWei,
                        withdrawals: formatTokenAmount(withdrawalsWei, meta),
                        symbol: meta.symbol,
                    });

                printLine(
                    `${withdrawalsWei} (${formatTokenAmount(withdrawalsWei, meta)} ${meta.symbol})`,
                );
            }),
        );

    program
        .command("withdrawals-claimed")
        .description(
            "Get whether some epoch's withdrawals of a given account at a particular vault are claimed.",
        )
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<epoch>", "epoch", parseUint256Arg)
        .argument("<address>", "account address", parseAddressArg)
        .action((vaultAddress: Address, epoch: bigint, address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const ep = epoch;
                const account = address;

                const claimed = await ctx.symb.getWithdrawalsClaimed(vault, ep, account);
                if (ctx.json) return printJson({ vault, epoch: ep, account, claimed });
                printLine(String(claimed));
            }),
        );
}
```

## File: src/commands/vaults.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { parseAddressArg } from "../cli/argParsers";
import { runCliAction } from "../cli/run";
import { SUBNETWORK_IDS } from "../core/constants";
import { printIndented, printJson, printLine } from "../core/output";
import { startSpinner } from "../core/spinner";
import { encodeSubnetwork } from "../core/subnetwork";
import { formatTokenAmount } from "../core/units";

export function registerVaultReadCommands(program: Command, getCtx: () => Promise<CliContext>) {
    program
        .command("is")
        .description("Get whether address is a vault.")
        .argument("<address>", "an address to check", parseAddressArg)
        .action((address: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const isVault = await ctx.symb.isVault(address);
                if (ctx.json) return printJson({ isVault });
                printLine(String(isVault));
            }),
        );

    const listCmd = program
        .command("list")
        .description("Get all vaults.")
        .option("--full", "Show full data", false)
        .action((opts: { full?: boolean }) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vaultsSpinner = startSpinner(ctx, "Fetching vault list...");
                const vaults = await ctx.symb.getVaults();
                vaultsSpinner?.stop();

                if (ctx.json) {
                    if (!opts.full) return printJson({ vaults });

                    const vaultDatas = await ctx.symb.getVaultsNetsOpsFull(vaults);
                    return printJson({
                        vaults: vaults.map((v, i) => ({ ...v, full: vaultDatas[i] ?? [] })),
                    });
                }

                printLine(`All vaults [${vaults.length} total]:`);

                const fullSpinner = opts.full
                    ? startSpinner(ctx, "Fetching full vault data (this can take a while)...")
                    : undefined;
                let vaultDatas:
                    | Awaited<ReturnType<CliContext["symb"]["getVaultsNetsOpsFull"]>>
                    | undefined;
                try {
                    vaultDatas = opts.full
                        ? await ctx.symb.getVaultsNetsOpsFull(vaults)
                        : undefined;
                } finally {
                    fullSpinner?.stop();
                }

                for (let idx = 0; idx < vaults.length; idx++) {
                    const v = vaults[idx]!;
                    const vaultData = opts.full ? (vaultDatas?.[idx] ?? []) : [];
                    printIndented(`Vault: ${v.vault}`, 2);

                    const collateralMeta = await ctx.symb.getTokenMeta(v.collateral);
                    printIndented(`Collateral: ${v.collateral} (${collateralMeta.symbol})`, 4);
                    printIndented(
                        `Delegator: ${v.delegator} (${ctx.symb.delegatorTypeName(v.delegatorType)})`,
                        4,
                    );
                    printIndented(
                        `Slasher: ${v.slasher} (${ctx.symb.slasherTypeName(v.slasherType)})`,
                        4,
                    );
                    printIndented(
                        `TVL: ${formatTokenAmount(v.tvl, collateralMeta)} ${collateralMeta.symbol}`,
                        4,
                    );
                    printLine("");

                    if (opts.full) {
                        const totalDelegated = vaultData
                            .flatMap((n) => n.ops)
                            .flatMap((o) => Object.values(o.stake))
                            .reduce((a, b) => a + b, 0n);

                        printIndented(`Networks [${vaultData.length} total]:`, 4);
                        printIndented(
                            `Total delegated: ${formatTokenAmount(totalDelegated, collateralMeta)} ${collateralMeta.symbol}`,
                            4,
                        );

                        for (const netData of vaultData) {
                            const delegatedToNet = netData.ops
                                .flatMap((o) => Object.values(o.stake))
                                .reduce((a, b) => a + b, 0n);
                            printIndented(`Network: ${netData.net}`, 6);
                            printIndented(`Operators [${netData.ops.length} total]`, 6);
                            printIndented(
                                `Delegated to network: ${formatTokenAmount(delegatedToNet, collateralMeta)} ${collateralMeta.symbol}`,
                                6,
                            );
                            printLine("");
                        }
                        printLine("");
                    }
                }
            }),
        );

    listCmd.alias("ls");

    program
        .command("ops")
        .description("Get all operators opted into the given vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .action((vaultAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching vault operators...");
                const ops = await (async () => {
                    try {
                        return await ctx.symb.getVaultOps(vaultAddress);
                    } finally {
                        spinner?.stop();
                    }
                })();
                if (ctx.json) return printJson({ vault: vaultAddress, operators: ops });

                printLine(`Vault: ${vaultAddress}`);
                printLine(`Operators [${ops.length} total]:`);
                for (const op of ops) printIndented(`Operator: ${op}`, 2);
            }),
        );

    program
        .command("nets")
        .description("Get all networks associated with the given vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .action((vaultAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching vault networks...");
                const nets = await (async () => {
                    try {
                        return await ctx.symb.getVaultNets(vaultAddress);
                    } finally {
                        spinner?.stop();
                    }
                })();
                if (ctx.json) return printJson({ vault: vaultAddress, networks: nets });

                printLine(`Vault: ${vaultAddress}`);
                printLine(`Networks [${nets.length} total]:`);
                for (const net of nets) printIndented(`Network: ${net.net}`, 2);
            }),
        );

    program
        .command("netsops")
        .description("Get all operators and their associated networks for the given vault.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .action((vaultAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const spinner = startSpinner(ctx, "Fetching vault networks + operators...");
                const netsOps = await (async () => {
                    try {
                        return await ctx.symb.getVaultNetsOps(vaultAddress);
                    } finally {
                        spinner?.stop();
                    }
                })();
                if (ctx.json) return printJson({ vault: vaultAddress, netsOps });

                const entries = Object.entries(netsOps) as Array<[Address, Address[]]>;
                printLine(`Vault: ${vaultAddress}`);
                printLine(`Networks [${entries.length} total]:`);
                printLine("");

                for (const [net, ops] of entries) {
                    printIndented(`Network: ${net}`, 2);
                    printIndented(`Operators [${ops.length} total]:`, 2);
                    for (const op of ops) printIndented(`Operator: ${op}`, 4);
                    printLine("");
                }
            }),
        );

    program
        .command("network-limit")
        .description("Get a network limit at the vault's delegator.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);

                if (![0n, 1n, 2n].includes(delegatorType)) {
                    if (ctx.json)
                        return printJson({ error: "Delegator doesn't have such functionality." });
                    printLine("Delegator doesn't have such functionality.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const limit = await ctx.symb.getNetworkLimit(delegator, subnetwork);
                    results.push({ subnetId, subnetwork, networkLimit: limit });
                }

                if (ctx.json)
                    return printJson({ vault, network: net, delegator, delegatorType, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Network limit for subnetwork = ${r.subnetwork} at vault ${vault} is ${r.networkLimit}`,
                    );
                    printLine("");
                }
            }),
        );

    program
        .command("operator-network-limit")
        .description("Get an operator-network limit at the vault's delegator.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .argument("<operator_address>", "operator address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address, operatorAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;
                const op = operatorAddress;

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);
                if (delegatorType !== 1n) {
                    if (ctx.json) return printJson({ error: "It is not a FullRestakeDelegator." });
                    printLine("It is not a FullRestakeDelegator.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const limit = await ctx.symb.getOperatorNetworkLimit(delegator, subnetwork, op);
                    results.push({ subnetId, subnetwork, operatorNetworkLimit: limit });
                }

                if (ctx.json)
                    return printJson({ vault, network: net, operator: op, delegator, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Operator-network limit for subnetwork = ${r.subnetwork} and operator = ${op} at vault ${vault} is ${r.operatorNetworkLimit}`,
                    );
                    printLine("");
                }
            }),
        );

    program
        .command("operator-network-shares")
        .description("Get operator-network shares at the vault's delegator.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .argument("<operator_address>", "operator address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address, operatorAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;
                const op = operatorAddress;

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);
                if (delegatorType !== 0n) {
                    if (ctx.json)
                        return printJson({ error: "It is not a NetworkRestakeDelegator." });
                    printLine("It is not a NetworkRestakeDelegator.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const shares = await ctx.symb.getOperatorNetworkShares(
                        delegator,
                        subnetwork,
                        op,
                    );
                    results.push({ subnetId, subnetwork, operatorNetworkShares: shares });
                }

                if (ctx.json)
                    return printJson({ vault, network: net, operator: op, delegator, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Operator-network shares for subnetwork = ${r.subnetwork} and operator = ${op} at vault ${vault} is ${r.operatorNetworkShares}`,
                    );
                    printLine("");
                }
            }),
        );

    program
        .command("total-operator-network-shares")
        .description("Get total operator-network shares at the vault's delegator.")
        .argument("<vault_address>", "vault address", parseAddressArg)
        .argument("<network_address>", "network address", parseAddressArg)
        .action((vaultAddress: Address, networkAddress: Address) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const net = networkAddress;

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);
                if (delegatorType !== 0n) {
                    if (ctx.json)
                        return printJson({ error: "It is not a NetworkRestakeDelegator." });
                    printLine("It is not a NetworkRestakeDelegator.");
                    return;
                }

                const results = [];
                for (const subnetId of SUBNETWORK_IDS) {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    const shares = await ctx.symb.getTotalOperatorNetworkShares(
                        delegator,
                        subnetwork,
                    );
                    results.push({ subnetId, subnetwork, totalOperatorNetworkShares: shares });
                }

                if (ctx.json) return printJson({ vault, network: net, delegator, results });

                printLine("");
                for (const r of results) {
                    printLine(
                        `Total operator-network shares for subnetwork = ${r.subnetwork} at vault ${vault} is ${r.totalOperatorNetworkShares}`,
                    );
                    printLine("");
                }
            }),
        );
}
```

## File: src/commands/writeOptions.ts

```typescript
import type { Command } from "commander";

import type { SigningFlags, WriteFlags } from "../cli/signingOptions";

export type SigningOptions = SigningFlags;
export type WriteOptions = WriteFlags;

export function withSigningOptions(cmd: Command) {
    return cmd
        .option(
            "--from <address>",
            "Use an unlocked RPC account as sender (mainly for fork/local simulations)",
        )
        .option(
            "--private-key <hex>",
            "Private key to sign with (discouraged; use SYMB_PRIVATE_KEY)",
        )
        .option("--ledger", "Use a Ledger device for signing instead of a private key", false)
        .option(
            "--ledger-address <address>",
            "Expected Ledger address; the CLI discovers the matching Ledger Ethereum derivation path",
        );
}

export function withWriteOptions(cmd: Command) {
    return withSigningOptions(cmd)
        .option("--yes", "Bypass confirmation prompts", false)
        .option("--dry-run", "Simulate only (do not send transaction)", false);
}
```

## File: src/commands/writesCurator.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { defaultedArg, parseAddressArg, parseUint256Arg, parseUint96Arg } from "../cli/argParsers";
import { withSigningAccount } from "../cli/signing";
import { runCliAction } from "../cli/run";
import { formatPercent } from "../core/format";
import {
    FullRestakeDelegatorAbi,
    NetworkRestakeDelegatorAbi,
    delegatorAbiByType,
} from "../core/contracts";
import { printJson, printLine } from "../core/output";
import { encodeSubnetwork } from "../core/subnetwork";
import { runWriteTx } from "../core/tx";

import { withWriteOptions, type WriteOptions } from "./writeOptions";

export function registerCuratorWriteCommands(program: Command, getCtx: () => Promise<CliContext>) {
    withWriteOptions(
        program
            .command("set-network-limit")
            .description("Set a network limit at the vault's delegator.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<limit>", "limit (wei)", parseUint256Arg)
            .addArgument(defaultedArg("[subnetwork_id]", "subnetwork id", parseUint96Arg, 0n)),
    ).action((vault: Address, net: Address, lim: bigint, subnetId: bigint, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            const delegator = await ctx.symb.getVaultDelegator(vault);
            const delegatorType = await ctx.symb.getEntityType(delegator);
            if (![0n, 1n, 2n].includes(delegatorType)) {
                if (ctx.json)
                    return printJson({ error: "Delegator doesn't have such functionality." });
                printLine("Delegator doesn't have such functionality.");
                return;
            }

            await withSigningAccount(opts, async ({ account }) => {
                const subnetwork = encodeSubnetwork({ net, subnetId });
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: delegatorAbiByType(delegatorType),
                    address: delegator,
                    functionName: "setNetworkLimit",
                    args: [subnetwork, lim],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully set limit = ${lim} for subnetwork = ${subnetwork}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("set-operator-network-limit")
            .description("Set an operator-network limit at the vault's delegator.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<operator_address>", "operator address", parseAddressArg)
            .argument("<limit>", "limit (wei)", parseUint256Arg)
            .addArgument(defaultedArg("[subnetwork_id]", "subnetwork id", parseUint96Arg, 0n)),
    ).action(
        (
            vault: Address,
            net: Address,
            op: Address,
            lim: bigint,
            subnetId: bigint,
            opts: WriteOptions,
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);
                if (delegatorType !== 1n) {
                    if (ctx.json) return printJson({ error: "It is not a FullRestakeDelegator." });
                    printLine("It is not a FullRestakeDelegator.");
                    return;
                }

                await withSigningAccount(opts, async ({ account }) => {
                    const subnetwork = encodeSubnetwork({ net, subnetId });
                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: FullRestakeDelegatorAbi,
                        address: delegator,
                        functionName: "setOperatorNetworkLimit",
                        args: [subnetwork, op, lim],
                        dryRun: opts.dryRun,
                        yes: opts.yes,
                        successMessage: `Successfully set limit = ${lim} for operator = ${op} in subnetwork = ${subnetwork}`,
                    });
                });
            }),
    );

    withWriteOptions(
        program
            .command("set-operator-network-shares")
            .description("Set an operator-network shares at the vault's delegator.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<operator_address>", "operator address", parseAddressArg)
            .argument("<shares>", "shares (uint256)", parseUint256Arg)
            .addArgument(defaultedArg("[subnetwork_id]", "subnetwork id", parseUint96Arg, 0n)),
    ).action(
        (
            vault: Address,
            net: Address,
            op: Address,
            sh: bigint,
            subnetId: bigint,
            opts: WriteOptions,
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();

                const delegator = await ctx.symb.getVaultDelegator(vault);
                const delegatorType = await ctx.symb.getEntityType(delegator);
                if (delegatorType !== 0n) {
                    if (ctx.json)
                        return printJson({ error: "It is not a NetworkRestakeDelegator." });
                    printLine("It is not a NetworkRestakeDelegator.");
                    return;
                }

                const subnetwork = encodeSubnetwork({ net, subnetId });
                const currentShares = await ctx.symb.getOperatorNetworkShares(
                    delegator,
                    subnetwork,
                    op,
                );
                const totalShares = await ctx.symb.getTotalOperatorNetworkShares(
                    delegator,
                    subnetwork,
                );
                const newTotal = totalShares - currentShares + sh;
                const percentage = formatPercent(sh, newTotal);

                const confirmMessage = `Set operator = ${op} to get ${percentage}% of the subnetwork = ${subnetwork} stake?`;

                await withSigningAccount(opts, async ({ account }) => {
                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: NetworkRestakeDelegatorAbi,
                        address: delegator,
                        functionName: "setOperatorNetworkShares",
                        args: [subnetwork, op, sh],
                        dryRun: opts.dryRun,
                        yes: opts.yes,
                        confirmMessage,
                        successMessage: `Successfully set shares = ${sh} for operator = ${op} in subnetwork = ${subnetwork}`,
                    });
                });
            }),
    );
}
```

## File: src/commands/writesNetwork.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { defaultedArg, parseAddressArg, parseUint256Arg, parseUint96Arg } from "../cli/argParsers";
import { withSigningAccount } from "../cli/signing";
import { runCliAction } from "../cli/run";
import { NetworkRegistryAbi, NetworkRestakeDelegatorAbi, VetoSlasherAbi } from "../core/contracts";
import { printJson, printLine } from "../core/output";
import { encodeSubnetwork } from "../core/subnetwork";
import { formatUnixTimestampSeconds } from "../core/time";
import { runWriteTx } from "../core/tx";

import { withWriteOptions, type WriteOptions } from "./writeOptions";

export function registerNetworkWriteCommands(program: Command, getCtx: () => Promise<CliContext>) {
    withWriteOptions(
        program.command("register").description("Register the signer as a network."),
    ).action((opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: NetworkRegistryAbi,
                    address: ctx.resolved.addresses.net_registry,
                    functionName: "registerNetwork",
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: "Successfully registered as a network",
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("set-max-limit")
            .description("Set a maximum network limit at the vault's delegator.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument(
                "<max_limit>",
                "maximum amount of stake a network is ready to get from the vault (wei)",
                parseUint256Arg,
            )
            .addArgument(defaultedArg("[subnetwork_id]", "subnetwork id", parseUint96Arg, 0n)),
    ).action((vaultAddress: Address, maxLimit: bigint, subnetId: bigint, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            const vault = vaultAddress;
            const max = maxLimit;

            const delegator = await ctx.symb.getVaultDelegator(vault);

            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: NetworkRestakeDelegatorAbi,
                    address: delegator,
                    functionName: "setMaxNetworkLimit",
                    args: [subnetId, max],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully set max limit = ${max} in vault = ${vault}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("set-resolver")
            .description("Set a resolver for a subnetwork at VetoSlasher.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<resolver>", "resolver address", parseAddressArg)
            .addArgument(defaultedArg("[subnetwork_id]", "subnetwork id", parseUint96Arg, 0n)),
    ).action(
        (vaultAddress: Address, resolverAddress: Address, subnetId: bigint, opts: WriteOptions) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const vault = vaultAddress;
                const resolver = resolverAddress;

                await withSigningAccount(opts, async ({ account, address: signer }) => {
                    const slasher = await ctx.symb.getVaultSlasher(vault);
                    const slasherType = await ctx.symb.getEntityType(slasher);
                    if (slasherType !== 1n) {
                        if (ctx.json) return printJson({ error: "It is not a VetoSlasher." });
                        printLine("It is not a VetoSlasher.");
                        return;
                    }

                    const subnetwork = encodeSubnetwork({ net: signer, subnetId });
                    const currentResolver = await ctx.symb.getResolver(slasher, subnetwork);
                    const pendingResolver = await ctx.symb.getPendingResolver(slasher, subnetwork);

                    const currentEpochStart = await ctx.symb.getVaultCurrentEpochStart(vault);
                    const resolverSetEpochsDelay = await ctx.symb.getResolverSetEpochDelay(slasher);
                    const epochDuration = await ctx.symb.getVaultEpochDuration(vault);
                    const newTimestamp = currentEpochStart + resolverSetEpochsDelay * epochDuration;

                    const confirmMessage =
                        currentResolver !== pendingResolver
                            ? `You have a pending set resolver request for ${pendingResolver}.\nThis will replace it with ${resolver}.\nNew resolver set timestamp: ${formatUnixTimestampSeconds(newTimestamp)}\nProceed?`
                            : `Set resolver = ${resolver} for subnetwork = ${subnetwork} at vault = ${vault}?`;

                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: VetoSlasherAbi,
                        address: slasher,
                        functionName: "setResolver",
                        args: [subnetId, resolver, "0x"],
                        dryRun: opts.dryRun,
                        yes: opts.yes,
                        confirmMessage,
                        successMessage: `Successfully set resolver = ${resolver} for subnetwork = ${subnetwork} at vault = ${vault}`,
                    });
                });
            }),
    );
}
```

## File: src/commands/writesOperator.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { defaultedArg, parseAddressArg, parseUint48Arg } from "../cli/argParsers";
import { withSigningAccount } from "../cli/signing";
import { runCliAction } from "../cli/run";
import {
    OperatorNetworkOptInServiceAbi,
    OperatorRegistryAbi,
    OperatorVaultOptInServiceAbi,
} from "../core/contracts";
import { printJson, printLine } from "../core/output";
import { formatUnixTimestampSeconds } from "../core/time";
import { runWriteTx } from "../core/tx";
import {
    buildOperatorNetworkOptInTypedData,
    buildOperatorNetworkOptOutTypedData,
    buildOperatorVaultOptInTypedData,
    buildOperatorVaultOptOutTypedData,
} from "../core/signing/typedData";

import {
    withSigningOptions,
    withWriteOptions,
    type SigningOptions,
    type WriteOptions,
} from "./writeOptions";

const DEFAULT_SIG_DURATION_SECONDS = 7n * 24n * 60n * 60n;

export function registerOperatorWriteCommands(program: Command, getCtx: () => Promise<CliContext>) {
    withWriteOptions(
        program.command("register").description("Register the signer as an operator."),
    ).action((opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: OperatorRegistryAbi,
                    address: ctx.resolved.addresses.op_registry,
                    functionName: "registerOperator",
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: "Successfully registered as an operator",
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("opt-in-vault")
            .description("Opt-in to a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg),
    ).action((vault: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: OperatorVaultOptInServiceAbi,
                    address: ctx.resolved.addresses.op_vault_opt_in,
                    functionName: "optIn",
                    args: [vault],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully opted in to vault = ${vault}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("opt-out-vault")
            .description("Opt-out from a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg),
    ).action((vault: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: OperatorVaultOptInServiceAbi,
                    address: ctx.resolved.addresses.op_vault_opt_in,
                    functionName: "optOut",
                    args: [vault],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully opted out from vault = ${vault}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("opt-in-net")
            .description("Opt-in to a network.")
            .argument("<network_address>", "network address", parseAddressArg),
    ).action((net: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: OperatorNetworkOptInServiceAbi,
                    address: ctx.resolved.addresses.op_net_opt_in,
                    functionName: "optIn",
                    args: [net],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully opted in to network = ${net}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("opt-out-net")
            .description("Opt-out from a network.")
            .argument("<network_address>", "network address", parseAddressArg),
    ).action((net: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: OperatorNetworkOptInServiceAbi,
                    address: ctx.resolved.addresses.op_net_opt_in,
                    functionName: "optOut",
                    args: [net],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully opted out from network = ${net}`,
                });
            });
        }),
    );

    withSigningOptions(
        program
            .command("opt-in-vault-sig")
            .description("Get a signature for opt-in to a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[duration]",
                    "seconds until expiry",
                    parseUint48Arg,
                    DEFAULT_SIG_DURATION_SECONDS,
                ),
            ),
    ).action((vault: Address, dur: bigint, opts: SigningOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: who }) => {
                if (typeof account === "string") {
                    throw new Error("The --from option cannot be used for signature commands.");
                }
                const verifyingContract = ctx.resolved.addresses.op_vault_opt_in;

                const nonce = await ctx.symb.getOperatorVaultOptInNonce(who, vault);
                const deadline = BigInt(Math.floor(Date.now() / 1000)) + dur;

                const typedData = buildOperatorVaultOptInTypedData({
                    chainId: ctx.resolved.chainId,
                    verifyingContract,
                    who,
                    where: vault,
                    nonce,
                    deadline,
                });

                const signTypedData = account.signTypedData;
                if (!signTypedData)
                    throw new Error("This signer does not support EIP-712 typed data signing.");
                const signature = await signTypedData(typedData as any);

                if (ctx.json) {
                    return printJson({ operator: who, vault, nonce, deadline, signature });
                }

                printLine("");
                printLine(`Operator: ${who}`);
                printLine(`Vault: ${vault}`);
                printLine(`Nonce: ${nonce}`);
                printLine(`Deadline: ${deadline} (${formatUnixTimestampSeconds(deadline)})`);
                printLine(`Success! Your signature is: ${signature}`);
            });
        }),
    );

    withSigningOptions(
        program
            .command("opt-out-vault-sig")
            .description("Get a signature for opt-out from a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[duration]",
                    "seconds until expiry",
                    parseUint48Arg,
                    DEFAULT_SIG_DURATION_SECONDS,
                ),
            ),
    ).action((vault: Address, dur: bigint, opts: SigningOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: who }) => {
                if (typeof account === "string") {
                    throw new Error("The --from option cannot be used for signature commands.");
                }
                const verifyingContract = ctx.resolved.addresses.op_vault_opt_in;

                const nonce = await ctx.symb.getOperatorVaultOptInNonce(who, vault);
                const deadline = BigInt(Math.floor(Date.now() / 1000)) + dur;

                const typedData = buildOperatorVaultOptOutTypedData({
                    chainId: ctx.resolved.chainId,
                    verifyingContract,
                    who,
                    where: vault,
                    nonce,
                    deadline,
                });

                const signTypedData = account.signTypedData;
                if (!signTypedData)
                    throw new Error("This signer does not support EIP-712 typed data signing.");
                const signature = await signTypedData(typedData as any);

                if (ctx.json) {
                    return printJson({ operator: who, vault, nonce, deadline, signature });
                }

                printLine("");
                printLine(`Operator: ${who}`);
                printLine(`Vault: ${vault}`);
                printLine(`Nonce: ${nonce}`);
                printLine(`Deadline: ${deadline} (${formatUnixTimestampSeconds(deadline)})`);
                printLine(`Success! Your signature is: ${signature}`);
            });
        }),
    );

    withSigningOptions(
        program
            .command("opt-in-net-sig")
            .description("Get a signature for opt-in to a network.")
            .argument("<network_address>", "network address", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[duration]",
                    "seconds until expiry",
                    parseUint48Arg,
                    DEFAULT_SIG_DURATION_SECONDS,
                ),
            ),
    ).action((net: Address, dur: bigint, opts: SigningOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: who }) => {
                if (typeof account === "string") {
                    throw new Error("The --from option cannot be used for signature commands.");
                }
                const verifyingContract = ctx.resolved.addresses.op_net_opt_in;

                const nonce = await ctx.symb.getOperatorNetworkOptInNonce(who, net);
                const deadline = BigInt(Math.floor(Date.now() / 1000)) + dur;

                const typedData = buildOperatorNetworkOptInTypedData({
                    chainId: ctx.resolved.chainId,
                    verifyingContract,
                    who,
                    where: net,
                    nonce,
                    deadline,
                });

                const signTypedData = account.signTypedData;
                if (!signTypedData)
                    throw new Error("This signer does not support EIP-712 typed data signing.");
                const signature = await signTypedData(typedData as any);

                if (ctx.json) {
                    return printJson({ operator: who, network: net, nonce, deadline, signature });
                }

                printLine("");
                printLine(`Operator: ${who}`);
                printLine(`Network: ${net}`);
                printLine(`Nonce: ${nonce}`);
                printLine(`Deadline: ${deadline} (${formatUnixTimestampSeconds(deadline)})`);
                printLine(`Success! Your signature is: ${signature}`);
            });
        }),
    );

    withSigningOptions(
        program
            .command("opt-out-net-sig")
            .description("Get a signature for opt-out from a network.")
            .argument("<network_address>", "network address", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[duration]",
                    "seconds until expiry",
                    parseUint48Arg,
                    DEFAULT_SIG_DURATION_SECONDS,
                ),
            ),
    ).action((net: Address, dur: bigint, opts: SigningOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: who }) => {
                if (typeof account === "string") {
                    throw new Error("The --from option cannot be used for signature commands.");
                }
                const verifyingContract = ctx.resolved.addresses.op_net_opt_in;

                const nonce = await ctx.symb.getOperatorNetworkOptInNonce(who, net);
                const deadline = BigInt(Math.floor(Date.now() / 1000)) + dur;

                const typedData = buildOperatorNetworkOptOutTypedData({
                    chainId: ctx.resolved.chainId,
                    verifyingContract,
                    who,
                    where: net,
                    nonce,
                    deadline,
                });

                const signTypedData = account.signTypedData;
                if (!signTypedData)
                    throw new Error("This signer does not support EIP-712 typed data signing.");
                const signature = await signTypedData(typedData as any);

                if (ctx.json) {
                    return printJson({ operator: who, network: net, nonce, deadline, signature });
                }

                printLine("");
                printLine(`Operator: ${who}`);
                printLine(`Network: ${net}`);
                printLine(`Nonce: ${nonce}`);
                printLine(`Deadline: ${deadline} (${formatUnixTimestampSeconds(deadline)})`);
                printLine(`Success! Your signature is: ${signature}`);
            });
        }),
    );
}
```

## File: src/commands/writesRewards.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { defaultedArg, parseAddressArg, parseUint256Arg } from "../cli/argParsers";
import { parseHex, parseUint256 } from "../cli/parse";
import { withSigningAccount } from "../cli/signing";
import { runCliAction } from "../cli/run";
import { CuratorRegistryAbi, FeeRegistryAbi, VaultSnapshotRewardsAbi } from "../core/contracts";
import { runWriteTx } from "../core/tx";

import { withWriteOptions, type WriteOptions } from "./writeOptions";

const DEFAULT_FIRST_REWARD_TO_CLAIM = 0n;
const DEFAULT_MAX_REWARDS = 1_000_000n;

export function registerRewardsWriteCommands(program: Command, getCtx: () => Promise<CliContext>) {
    // CuratorRegistry
    withWriteOptions(
        program
            .command("set-curator")
            .description("Set curator for a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<curator>", "curator address", parseAddressArg),
    ).action((vault: Address, curator: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            const curatorRegistry = ctx.symb.requireAddress("curator_registry");

            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: CuratorRegistryAbi,
                    address: curatorRegistry,
                    functionName: "setCurator",
                    args: [vault, curator],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully set curator = ${curator} for vault = ${vault}`,
                });
            });
        }),
    );

    // FeeRegistry
    withWriteOptions(
        program
            .command("set-operators-fee")
            .description("Set default operators fee (ppm) for a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<fee>", "fee in ppm (max 500000)", parseUint256Arg),
    ).action((vault: Address, f: bigint, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            const feeRegistry = ctx.symb.requireAddress("fee_registry");

            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: FeeRegistryAbi,
                    address: feeRegistry,
                    functionName: "setOperatorsFee",
                    args: [vault, f],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully set operators fee = ${f} for vault = ${vault}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("set-operators-network-fee")
            .description("Set network-specific operators fee (ppm) for a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<fee>", "fee in ppm (max 500000)", parseUint256Arg)
            .option("--disable", "Disable network-specific fee override", false),
    ).action(
        (
            vault: Address,
            network: Address,
            f: bigint,
            cmdOpts: WriteOptions & { disable?: boolean },
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const feeRegistry = ctx.symb.requireAddress("fee_registry");
                const enable = !cmdOpts.disable;

                await withSigningAccount(cmdOpts, async ({ account }) => {
                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: FeeRegistryAbi,
                        address: feeRegistry,
                        functionName: "setOperatorsNetworkFee",
                        args: [vault, network, enable, f],
                        dryRun: cmdOpts.dryRun,
                        yes: cmdOpts.yes,
                        successMessage: `Successfully set operators network fee = ${f} (enabled=${enable}) for vault = ${vault} network = ${network}`,
                    });
                });
            }),
    );

    withWriteOptions(
        program
            .command("set-curator-fee")
            .description("Set default curator fee (ppm) for a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<fee>", "fee in ppm (max 500000)", parseUint256Arg),
    ).action((vault: Address, f: bigint, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();
            const feeRegistry = ctx.symb.requireAddress("fee_registry");

            await withSigningAccount(opts, async ({ account }) => {
                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: FeeRegistryAbi,
                    address: feeRegistry,
                    functionName: "setCuratorFee",
                    args: [vault, f],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    successMessage: `Successfully set curator fee = ${f} for vault = ${vault}`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("set-curator-network-fee")
            .description("Set network-specific curator fee (ppm) for a vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<fee>", "fee in ppm (max 500000)", parseUint256Arg)
            .option("--disable", "Disable network-specific fee override", false),
    ).action(
        (
            vault: Address,
            network: Address,
            f: bigint,
            cmdOpts: WriteOptions & { disable?: boolean },
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const feeRegistry = ctx.symb.requireAddress("fee_registry");
                const enable = !cmdOpts.disable;

                await withSigningAccount(cmdOpts, async ({ account }) => {
                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: FeeRegistryAbi,
                        address: feeRegistry,
                        functionName: "setCuratorNetworkFee",
                        args: [vault, network, enable, f],
                        dryRun: cmdOpts.dryRun,
                        yes: cmdOpts.yes,
                        successMessage: `Successfully set curator network fee = ${f} (enabled=${enable}) for vault = ${vault} network = ${network}`,
                    });
                });
            }),
    );

    // Rewards (VaultSnapshot)
    withWriteOptions(
        program
            .command("claim-vault-snapshot-rewards")
            .description("Claim vault snapshot rewards for the signer.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<token>", "ERC20 token address", parseAddressArg)
            .argument("[recipient]", "recipient address (default: signer)", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[first_reward_to_claim]",
                    "first reward index to claim",
                    parseUint256Arg,
                    DEFAULT_FIRST_REWARD_TO_CLAIM,
                ),
            )
            .addArgument(
                defaultedArg(
                    "[max_rewards]",
                    "max rewards to claim",
                    parseUint256Arg,
                    DEFAULT_MAX_REWARDS,
                ),
            )
            .option("--last-unclaimed <n>", "Override lastUnclaimedReward (uint256)"),
    ).action(
        (
            vaultAddress: Address,
            networkAddress: Address,
            tokenAddress: Address,
            recipient: Address | undefined,
            firstRewardToClaim: bigint,
            maxRewards: bigint,
            cmdOpts: WriteOptions & { lastUnclaimed?: string },
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const rewards = ctx.symb.requireAddress("rewards");
                const vault = vaultAddress;
                const network = networkAddress;
                const token = tokenAddress;
                const first = firstRewardToClaim;
                const max = maxRewards;

                await withSigningAccount(cmdOpts, async ({ account, address: signer }) => {
                    const to = recipient ?? signer;
                    const last =
                        cmdOpts.lastUnclaimed !== undefined
                            ? parseUint256(cmdOpts.lastUnclaimed)
                            : await ctx.symb.lastUnclaimedReward(signer, vault, network, token);

                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: VaultSnapshotRewardsAbi,
                        address: rewards,
                        functionName: "claimVaultSnapshotRewards",
                        args: [to, network, token, vault, last, first, max, []],
                        dryRun: cmdOpts.dryRun,
                        yes: cmdOpts.yes,
                        successMessage: "Successfully claimed vault snapshot rewards.",
                    });
                });
            }),
    );

    withWriteOptions(
        program
            .command("claim-operator-fees")
            .description("Claim vault snapshot operator fees for the signer.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<network_address>", "network address", parseAddressArg)
            .argument("<token>", "ERC20 token address", parseAddressArg)
            .argument("[recipient]", "recipient address (default: signer)", parseAddressArg)
            .addArgument(
                defaultedArg(
                    "[first_reward_to_claim]",
                    "first reward index to claim",
                    parseUint256Arg,
                    DEFAULT_FIRST_REWARD_TO_CLAIM,
                ),
            )
            .addArgument(
                defaultedArg(
                    "[max_rewards]",
                    "max rewards to claim",
                    parseUint256Arg,
                    DEFAULT_MAX_REWARDS,
                ),
            )
            .option("--last-unclaimed <n>", "Override lastUnclaimedOperatorReward (uint256)")
            .option("--extra-data <hex>", "Extra data (abi-encoded hints) (optional)", "0x"),
    ).action(
        (
            vaultAddress: Address,
            networkAddress: Address,
            tokenAddress: Address,
            recipient: Address | undefined,
            firstRewardToClaim: bigint,
            maxRewards: bigint,
            cmdOpts: WriteOptions & { lastUnclaimed?: string; extraData?: string },
        ) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const rewards = ctx.symb.requireAddress("rewards");
                const vault = vaultAddress;
                const network = networkAddress;
                const token = tokenAddress;
                const first = firstRewardToClaim;
                const max = maxRewards;
                const extraData = parseHex(cmdOpts.extraData ?? "0x");

                await withSigningAccount(cmdOpts, async ({ account, address: signer }) => {
                    const to = recipient ?? signer;
                    const last =
                        cmdOpts.lastUnclaimed !== undefined
                            ? parseUint256(cmdOpts.lastUnclaimed)
                            : await ctx.symb.lastUnclaimedOperatorReward(
                                  signer,
                                  vault,
                                  network,
                                  token,
                              );

                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: VaultSnapshotRewardsAbi,
                        address: rewards,
                        functionName: "claimOperatorFees",
                        args: [to, network, token, vault, last, first, max, extraData],
                        dryRun: cmdOpts.dryRun,
                        yes: cmdOpts.yes,
                        successMessage: "Successfully claimed operator fees.",
                    });
                });
            }),
    );

    withWriteOptions(
        program
            .command("claim-curator-fees")
            .description("Claim vault snapshot curator fees for the signer curator.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<token>", "ERC20 token address", parseAddressArg)
            .argument("[recipient]", "recipient address (default: signer)", parseAddressArg),
    ).action(
        (vault: Address, token: Address, recipient: Address | undefined, cmdOpts: WriteOptions) =>
            runCliAction(async () => {
                const ctx = await getCtx();
                const rewards = ctx.symb.requireAddress("rewards");

                await withSigningAccount(cmdOpts, async ({ account, address: signer }) => {
                    const to = recipient ?? signer;

                    await runWriteTx({
                        mode: ctx,
                        resolved: ctx.resolved,
                        publicClient: ctx.publicClient,
                        account,
                        abi: VaultSnapshotRewardsAbi,
                        address: rewards,
                        functionName: "claimCuratorFees",
                        args: [to, vault, token],
                        dryRun: cmdOpts.dryRun,
                        yes: cmdOpts.yes,
                        successMessage: "Successfully claimed curator fees.",
                    });
                });
            }),
    );
}
```

## File: src/commands/writesStaker.ts

```typescript
import type { Command } from "commander";
import type { Address } from "viem";

import type { CliContext } from "../cli/context";
import { parseAddressArg, parseUint256Arg } from "../cli/argParsers";
import { withSigningAccount } from "../cli/signing";
import { runCliAction } from "../cli/run";
import { ZERO_ADDRESS } from "../core/constants";
import { VaultAbi } from "../core/contracts";
import { printLine } from "../core/output";
import { formatUnixTimestampSeconds } from "../core/time";
import { runWriteTx } from "../core/tx";
import { formatTokenAmount, parseTokenAmount } from "../core/units";

import { withWriteOptions, type WriteOptions } from "./writeOptions";

export function registerStakerWriteCommands(program: Command, getCtx: () => Promise<CliContext>) {
    withWriteOptions(
        program
            .command("withdraw")
            .description("Withdraw from the vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<amount>", "amount of tokens to withdraw (token units, e.g. 1.5)")
            .argument(
                "[claimer]",
                "address that needs to claim the withdrawal",
                parseAddressArg,
                ZERO_ADDRESS,
            ),
    ).action((vault: Address, amount: string, claimer: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: signer }) => {
                const claimAddr = claimer === ZERO_ADDRESS ? signer : claimer;
                const token = await ctx.symb.getVaultCollateral(vault);
                const meta = await ctx.symb.getTokenMeta(token);
                const weiAmount = parseTokenAmount(amount, meta);

                const confirmMessage = `Withdraw ${amount} ${meta.symbol} from vault = ${vault} (claimer = ${claimAddr})?`;

                const epochDuration = await ctx.symb.getVaultEpochDuration(vault);
                const currentEpoch = await ctx.symb.getVaultCurrentEpoch(vault);
                const currentEpochStart = await ctx.symb.getVaultCurrentEpochStart(vault);
                const nextEpoch = currentEpoch + 1n;
                const nextEpochEnd = currentEpochStart + 2n * epochDuration;

                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: VaultAbi,
                    address: vault,
                    functionName: "withdraw",
                    args: [claimAddr, weiAmount],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    confirmMessage,
                    successMessage: `Successfully withdrew ${amount} ${meta.symbol} from vault = ${vault} with claimer = ${claimAddr}\nIt will be claimable after epoch ${nextEpoch} ends (${formatUnixTimestampSeconds(nextEpochEnd)})`,
                });
            });
        }),
    );

    withWriteOptions(
        program
            .command("claim")
            .description("Claim a withdrawal for some epoch at the vault.")
            .argument("<vault_address>", "vault address", parseAddressArg)
            .argument("<epoch>", "epoch", parseUint256Arg)
            .argument("[recipient]", "recipient address", parseAddressArg, ZERO_ADDRESS),
    ).action((vault: Address, ep: bigint, recipient: Address, opts: WriteOptions) =>
        runCliAction(async () => {
            const ctx = await getCtx();

            await withSigningAccount(opts, async ({ account, address: signer }) => {
                const recipientAddr = recipient === ZERO_ADDRESS ? signer : recipient;

                const currentEpoch = await ctx.symb.getVaultCurrentEpoch(vault);
                if (ep >= currentEpoch) {
                    printLine(`Epoch ${ep} isn't claimable yet`);
                    return;
                }

                const withdrawalsWei = await ctx.symb.getWithdrawals(vault, ep, signer);
                if (withdrawalsWei === 0n) {
                    printLine(`No withdrawals for epoch ${ep}`);
                    return;
                }

                const withdrawalsClaimed = await ctx.symb.getWithdrawalsClaimed(vault, ep, signer);
                if (withdrawalsClaimed) {
                    printLine(`Already claimed withdrawals for epoch ${ep}`);
                    return;
                }

                const token = await ctx.symb.getVaultCollateral(vault);
                const meta = await ctx.symb.getTokenMeta(token);
                const withdrawals = formatTokenAmount(withdrawalsWei, meta);

                const confirmMessage = `Claim ${withdrawals} ${meta.symbol} from vault = ${vault} to recipient = ${recipientAddr} for epoch = ${ep}?`;

                await runWriteTx({
                    mode: ctx,
                    resolved: ctx.resolved,
                    publicClient: ctx.publicClient,
                    account,
                    abi: VaultAbi,
                    address: vault,
                    functionName: "claim",
                    args: [recipientAddr, ep],
                    dryRun: opts.dryRun,
                    yes: opts.yes,
                    confirmMessage,
                    successMessage: `Successfully claimed ${withdrawals} ${meta.symbol} from vault = ${vault} to recipient = ${recipientAddr} for epoch = ${ep}`,
                });
            });
        }),
    );
}
```

## File: src/config/chains.ts

```typescript
import { getAddress, type Address, type Chain } from "viem";
import { hoodi, mainnet, sepolia } from "viem/chains";

export type ChainKey = "mainnet" | "hoodi" | "sepolia";

export const CORE_ADDRESS_KEYS = [
    "op_registry",
    "net_registry",
    "op_vault_opt_in",
    "op_net_opt_in",
    "middleware_service",
    "vault_factory",
] as const;
export type CoreAddressKey = (typeof CORE_ADDRESS_KEYS)[number];

// Rewards (optional on some chains).
export const REWARDS_ADDRESS_KEYS = ["curator_registry", "fee_registry", "rewards"] as const;
export type RewardsAddressKey = (typeof REWARDS_ADDRESS_KEYS)[number];

export const ALL_ADDRESS_KEYS = [...CORE_ADDRESS_KEYS, ...REWARDS_ADDRESS_KEYS] as const;
export type ChainAddressKey = (typeof ALL_ADDRESS_KEYS)[number];

export type ChainAddresses = Record<CoreAddressKey, Address> &
    Partial<Record<RewardsAddressKey, Address>>;

export type ChainConfig = {
    key: ChainKey;
    chainId: number;
    defaultRpcUrls: readonly string[];
    addresses: ChainAddresses;
    viemChain: Chain;
};

export const CHAIN_KEY_BY_ID: Record<string, ChainKey> = {
    mainnet: "mainnet",
    "1": "mainnet",
    hoodi: "hoodi",
    "560048": "hoodi",
    sepolia: "sepolia",
    "11155111": "sepolia",
};

export function resolveChainKey(input: string): ChainKey {
    const key = CHAIN_KEY_BY_ID[input.toLowerCase()];
    if (!key) {
        const valid = Object.keys(CHAIN_KEY_BY_ID).join(", ");
        throw new Error(`Invalid chain: ${input}. Valid options are: ${valid}`);
    }
    return key;
}

function a(address: string): Address {
    return getAddress(address);
}

const baseTestnetAddresses: ChainAddresses = {
    op_registry: a("0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548"),
    net_registry: a("0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9"),
    op_vault_opt_in: a("0x95CC0a052ae33941877c9619835A233D21D57351"),
    op_net_opt_in: a("0x58973d16FFA900D11fC22e5e2B6840d9f7e13401"),
    middleware_service: a("0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3"),
    vault_factory: a("0x407A039D94948484D356eFB765b3c74382A050B4"),
};

export const CHAIN_CONFIGS: Record<ChainKey, ChainConfig> = {
    mainnet: {
        key: "mainnet",
        chainId: 1,
        defaultRpcUrls: [
            "https://ethereum-rpc.publicnode.com",
            "https://rpc.mevblocker.io",
            "https://rpc.ankr.com/eth",
            "https://eth.drpc.org",
            "https://eth-pokt.nodies.app",
            "https://eth.merkle.io",
        ],
        addresses: {
            op_registry: a("0xAd817a6Bc954F678451A71363f04150FDD81Af9F"),
            net_registry: a("0xC773b1011461e7314CF05f97d95aa8e92C1Fd8aA"),
            op_vault_opt_in: a("0xb361894bC06cbBA7Ea8098BF0e32EB1906A5F891"),
            op_net_opt_in: a("0x7133415b33B438843D581013f98A08704316633c"),
            middleware_service: a("0xD7dC9B366c027743D90761F71858BCa83C6899Ad"),
            vault_factory: a("0xAEb6bdd95c502390db8f52c8909F703E9Af6a346"),
            curator_registry: a("0xF75D8d8F790178F0d7F2ee7656874567d382C21e"),
            fee_registry: a("0x3E5a669F673712Bf72De956608E89D36561cbAf1"),
            rewards: a("0xa13e65cA0FeFa52cCb9615108fF400EF4806866B"),
        },
        viemChain: mainnet,
    },
    hoodi: {
        key: "hoodi",
        chainId: 560_048,
        defaultRpcUrls: [
            ...hoodi.rpcUrls.default.http,
            "https://ethereum-hoodi-rpc.publicnode.com",
        ],
        addresses: {
            ...baseTestnetAddresses,
            curator_registry: a("0x0fbd01C89F4B12475A67204FF4e18E809839B7b4"),
            fee_registry: a("0x4804a29f16E25cE1BcBd802547445012fa7e0051"),
            rewards: a("0x2A49C0B7154919eA2453aA190A014994A5C87D84"),
        },
        viemChain: hoodi,
    },
    sepolia: {
        key: "sepolia",
        chainId: 11_155_111,
        defaultRpcUrls: [
            ...sepolia.rpcUrls.default.http,
            "https://1rpc.io/sepolia",
            "https://0xrpc.io/sep",
            "https://ethereum-sepolia-rpc.publicnode.com",
        ],
        addresses: {
            ...baseTestnetAddresses,
        },
        viemChain: sepolia,
    },
};
```

## File: src/config/env.ts

```typescript
import { z } from "zod";

const envSchema = z.object({
    SYMB_RPC_URL: z.url().optional(),
    SYMB_PRIVATE_KEY: z.string().optional(),
});

export type SymbEnv = z.infer<typeof envSchema>;

export function readEnv(): SymbEnv {
    // Don’t throw on unrelated env vars.
    return envSchema.parse(process.env);
}
```

## File: src/core/signing/ledger.ts

```typescript
import * as TransportNodeHidModule from "@ledgerhq/hw-transport-node-hid";
import * as EthModule from "@ledgerhq/hw-app-eth";
import type Eth from "@ledgerhq/hw-app-eth";
import {
    getAddress,
    getTypesForEIP712Domain,
    hashDomain,
    hashStruct,
    serializeSignature,
    serializeTransaction,
    toHex,
    type Address,
    type Hex,
    type SignableMessage,
    type TransactionSerializable,
    type TypedData,
    type TypedDataDomain,
    type TypedDataDefinition,
} from "viem";
import { toAccount } from "viem/accounts";

const DEFAULT_LEDGER_PATH = "m/44'/60'/0'/0/0";
const LEDGER_DISCOVERY_INDEX_LIMIT = 50;
const LEDGER_PATH_FACTORIES = [
    (index: number) => `m/44'/60'/${index}'/0/0`,
    (index: number) => `m/44'/60'/0'/${index}`,
];

type LedgerTransport = {
    close: () => Promise<void>;
};

type LedgerTransportFactory = {
    create?: () => Promise<LedgerTransport>;
    open?: (path?: string | null) => Promise<LedgerTransport>;
};

type EthConstructor = new (transport: unknown) => Eth;

export type LedgerAccountConfig = {
    expectedAddress?: Address;
};

function unwrapModuleDefault<T>(moduleValue: unknown): T {
    const seen = new Set<unknown>();
    let current: unknown = moduleValue;

    while (
        (typeof current === "object" || typeof current === "function") &&
        current !== null &&
        !seen.has(current)
    ) {
        if (typeof current === "function") return current as T;
        seen.add(current);

        const record = current as Record<string, unknown>;
        if (record.default != null) {
            current = record.default;
            continue;
        }
        if (record["module.exports"] != null) {
            current = record["module.exports"];
            continue;
        }
        return current as T;
    }

    return current as T;
}

function getTransportNodeHid(): LedgerTransportFactory {
    const transport = unwrapModuleDefault<LedgerTransportFactory>(TransportNodeHidModule);
    if (typeof transport?.create === "function" || typeof transport?.open === "function")
        return transport;
    throw new Error("Failed to load Ledger HID transport module");
}

function getEthConstructor(): EthConstructor {
    const EthConstructor = unwrapModuleDefault<EthConstructor>(EthModule);
    if (typeof EthConstructor === "function") return EthConstructor;
    throw new Error("Failed to load Ledger Ethereum app module");
}

async function openLedgerTransport(): Promise<LedgerTransport> {
    const transport = getTransportNodeHid();
    if (typeof transport.create === "function") return transport.create();
    if (typeof transport.open === "function") return transport.open(undefined);
    throw new Error("Failed to open Ledger HID transport");
}

function signableMessageToHex(message: SignableMessage): Hex {
    if (typeof message === "string") return toHex(message);
    if (typeof message.raw === "string") return message.raw;
    return toHex(message.raw);
}

function withEip712DomainTypes(
    types: Record<string, readonly { name: string; type: string }[]>,
    domain?: TypedDataDomain,
) {
    return {
        EIP712Domain: getTypesForEIP712Domain({ domain }),
        ...types,
    } as Record<string, readonly { name: string; type: string }[]>;
}

async function readAddressAtPath(eth: Eth, path: string): Promise<Address> {
    const { address } = await eth.getAddress(path, false, false);
    return getAddress(address);
}

async function resolveLedgerPath(
    eth: Eth,
    expectedAddress?: Address,
): Promise<{ path: string; address: Address }> {
    if (!expectedAddress) {
        return {
            path: DEFAULT_LEDGER_PATH,
            address: await readAddressAtPath(eth, DEFAULT_LEDGER_PATH),
        };
    }

    const expected = getAddress(expectedAddress);
    for (let index = 0; index < LEDGER_DISCOVERY_INDEX_LIMIT; index++) {
        for (const path of new Set(
            LEDGER_PATH_FACTORIES.map((pathFactory) => pathFactory(index)),
        )) {
            const address = await readAddressAtPath(eth, path);
            if (address === expected) return { path, address };
        }
    }

    throw new Error(
        `Ledger address ${expected} was not found in Ledger Ethereum derivation paths (scanned indices 0-${LEDGER_DISCOVERY_INDEX_LIMIT - 1})`,
    );
}

export async function createLedgerAccount(config: LedgerAccountConfig): Promise<{
    account: ReturnType<typeof toAccount>;
    address: Address;
    close: () => Promise<void>;
}> {
    // Requires native deps (node-hid/usb) to be built/enabled via `pnpm approve-builds`.
    const transport = await openLedgerTransport();
    const EthConstructor = getEthConstructor();
    const eth = new EthConstructor(transport);
    let path: string;
    let address: Address;

    try {
        const resolved = await resolveLedgerPath(eth, config.expectedAddress);
        path = resolved.path;
        address = resolved.address;
    } catch (error) {
        await transport.close();
        throw error;
    }

    const account = toAccount({
        address,
        async signMessage({ message }) {
            const messageHex = signableMessageToHex(message);
            // Ledger expects raw hex without 0x prefix.
            const sig = await eth.signPersonalMessage(path, messageHex.slice(2));
            return serializeSignature({
                r: `0x${sig.r}`,
                s: `0x${sig.s}`,
                v: BigInt(sig.v),
            });
        },
        async signTransaction(transaction, options) {
            const serializer = options?.serializer ?? serializeTransaction;
            const unsignedTx = await serializer(transaction as TransactionSerializable);
            const sig = await eth.signTransaction(path, unsignedTx.slice(2), null);

            const signed = await serializer(transaction as TransactionSerializable, {
                r: `0x${sig.r}`,
                s: `0x${sig.s}`,
                v: BigInt(`0x${sig.v}`),
            });
            return signed;
        },
        async signTypedData(parameters) {
            const {
                domain = {},
                primaryType,
                message,
                types,
            } = parameters as TypedDataDefinition<TypedData, any>;
            const fullTypes = withEip712DomainTypes(types as any, domain);

            const domainHash = hashDomain({ domain, types: fullTypes });
            const messageHash =
                primaryType === "EIP712Domain"
                    ? (("0x" + "00".repeat(32)) as Hex)
                    : hashStruct({
                          data: message as any,
                          primaryType: primaryType as any,
                          types: fullTypes,
                      });

            const sig = await eth.signEIP712HashedMessage(
                path,
                domainHash.slice(2),
                messageHash.slice(2),
            );

            return serializeSignature({
                r: `0x${sig.r}`,
                s: `0x${sig.s}`,
                v: BigInt(sig.v),
            });
        },
    });

    return {
        account,
        address,
        close: async () => {
            await transport.close();
        },
    };
}
```

## File: src/core/signing/local.ts

```typescript
import type { Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";

export function accountFromPrivateKey(privateKey: Hex) {
    return privateKeyToAccount(privateKey);
}
```

## File: src/core/signing/typedData.ts

```typescript
import type { Address } from "viem";

export function buildOperatorNetworkOptInTypedData(args: {
    chainId: number;
    verifyingContract: Address;
    who: Address;
    where: Address;
    nonce: bigint;
    deadline: bigint;
}) {
    return {
        domain: {
            name: "OperatorNetworkOptInService",
            version: "1",
            chainId: args.chainId,
            verifyingContract: args.verifyingContract,
        },
        types: {
            OptIn: [
                { name: "who", type: "address" },
                { name: "where", type: "address" },
                { name: "nonce", type: "uint256" },
                { name: "deadline", type: "uint48" },
            ],
        },
        primaryType: "OptIn" as const,
        message: {
            who: args.who,
            where: args.where,
            nonce: args.nonce,
            deadline: args.deadline,
        },
    };
}

export function buildOperatorNetworkOptOutTypedData(args: {
    chainId: number;
    verifyingContract: Address;
    who: Address;
    where: Address;
    nonce: bigint;
    deadline: bigint;
}) {
    return {
        domain: {
            name: "OperatorNetworkOptInService",
            version: "1",
            chainId: args.chainId,
            verifyingContract: args.verifyingContract,
        },
        types: {
            OptOut: [
                { name: "who", type: "address" },
                { name: "where", type: "address" },
                { name: "nonce", type: "uint256" },
                { name: "deadline", type: "uint48" },
            ],
        },
        primaryType: "OptOut" as const,
        message: {
            who: args.who,
            where: args.where,
            nonce: args.nonce,
            deadline: args.deadline,
        },
    };
}

export function buildOperatorVaultOptInTypedData(args: {
    chainId: number;
    verifyingContract: Address;
    who: Address;
    where: Address;
    nonce: bigint;
    deadline: bigint;
}) {
    return {
        domain: {
            name: "OperatorVaultOptInService",
            version: "1",
            chainId: args.chainId,
            verifyingContract: args.verifyingContract,
        },
        types: {
            OptIn: [
                { name: "who", type: "address" },
                { name: "where", type: "address" },
                { name: "nonce", type: "uint256" },
                { name: "deadline", type: "uint48" },
            ],
        },
        primaryType: "OptIn" as const,
        message: {
            who: args.who,
            where: args.where,
            nonce: args.nonce,
            deadline: args.deadline,
        },
    };
}

export function buildOperatorVaultOptOutTypedData(args: {
    chainId: number;
    verifyingContract: Address;
    who: Address;
    where: Address;
    nonce: bigint;
    deadline: bigint;
}) {
    return {
        domain: {
            name: "OperatorVaultOptInService",
            version: "1",
            chainId: args.chainId,
            verifyingContract: args.verifyingContract,
        },
        types: {
            OptOut: [
                { name: "who", type: "address" },
                { name: "where", type: "address" },
                { name: "nonce", type: "uint256" },
                { name: "deadline", type: "uint48" },
            ],
        },
        primaryType: "OptOut" as const,
        message: {
            who: args.who,
            where: args.where,
            nonce: args.nonce,
            deadline: args.deadline,
        },
    };
}
```

## File: src/core/cache.ts

```typescript
export type CacheEntry<T> = {
    value: T;
    expiresAtMs: number;
};

export class TtlCache<K, V> {
    private readonly store = new Map<K, CacheEntry<V>>();

    constructor(private readonly defaultTtlMs: number) {}

    get(key: K): V | undefined {
        const entry = this.store.get(key);
        if (!entry) return undefined;
        if (Date.now() >= entry.expiresAtMs) {
            this.store.delete(key);
            return undefined;
        }
        return entry.value;
    }

    set(key: K, value: V, ttlMs?: number) {
        this.store.set(key, {
            value,
            expiresAtMs: Date.now() + (ttlMs ?? this.defaultTtlMs),
        });
    }

    clear() {
        this.store.clear();
    }
}
```

## File: src/core/client.ts

```typescript
import {
    createPublicClient,
    fallback,
    http,
    type Chain,
    type PublicClient,
    type Transport,
} from "viem";

import { readEnv } from "../config/env";
import {
    CHAIN_CONFIGS,
    resolveChainKey,
    type ChainAddresses,
    type ChainKey,
} from "../config/chains";

export type ResolvedClientConfig = {
    chainKey: ChainKey;
    chainId: number;
    viemChain: Chain;
    rpcUrl: string;
    rpcUrls: readonly string[];
    addresses: ChainAddresses;
    timeoutMs: number;
    retries: number;
};

export type ResolveClientConfigArgs = {
    chain: string;
    rpc?: string;
    timeoutMs?: number;
    retries?: number;
};

export async function resolveClientConfig(
    args: ResolveClientConfigArgs,
): Promise<ResolvedClientConfig> {
    const env = readEnv();

    const chainKey = resolveChainKey(args.chain);
    const base = CHAIN_CONFIGS[chainKey];

    const timeoutMs = args.timeoutMs ?? 60_000;
    const retries = args.retries ?? 3;

    const rpcUrl = args.rpc ?? env.SYMB_RPC_URL;
    const rpcUrls = rpcUrl ? [rpcUrl] : base.defaultRpcUrls;

    const addresses: ChainAddresses = base.addresses;

    return {
        chainKey,
        chainId: base.chainId,
        viemChain: base.viemChain,
        rpcUrl: rpcUrls[0]!,
        rpcUrls,
        addresses,
        timeoutMs,
        retries,
    };
}

export function createSymbioticPublicClient(
    config: ResolvedClientConfig,
): PublicClient<Transport, Chain> {
    return createPublicClient({
        chain: config.viemChain,
        transport: createViemTransport(config),
    });
}

export function createViemTransport(config: ResolvedClientConfig): Transport {
    const urls = [...config.rpcUrls];
    if (urls.length === 1) {
        return http(urls[0]!, {
            timeout: config.timeoutMs,
            retryCount: config.retries,
        });
    }

    return fallback(
        urls.map((url, i) =>
            http(url, {
                // Inner HTTP transport retries are disabled by `fallback` (retryCount: 0).
                timeout: config.timeoutMs,
                key: `http-${i}`,
                name: `HTTP ${i}`,
            }),
        ),
        {
            retryCount: config.retries,
        },
    );
}

export async function assertChainId(client: PublicClient, expectedChainId: number) {
    const actual = await client.getChainId();
    if (actual !== expectedChainId) {
        throw new Error(
            `Mismatch between specified chain ID (${expectedChainId}) and provider's chain ID (${actual})`,
        );
    }
}
```

## File: src/core/confirm.ts

```typescript
import prompts from "prompts";

export async function confirmOrExit(args: { message: string; yes?: boolean }) {
    if (args.yes) return true;

    const res = await prompts(
        {
            type: "confirm",
            name: "ok",
            message: args.message,
            initial: false,
        },
        {
            onCancel: () => true,
        },
    );

    const ok = Boolean(res.ok);
    if (!ok) {
        // Caller may return early, but keep a non-zero exit code to signal cancellation.
        process.exitCode = 1;
        process.stdout.write("Cancel\n");
    }
    return ok;
}
```

## File: src/core/constants.ts

```typescript
import { zeroAddress } from "viem";

export const ZERO_ADDRESS = zeroAddress;

// Current on-chain subnetwork IDs used by Symbiotic.
export const SUBNETWORK_IDS = [0, 1] as const;

export const DELEGATOR_TYPES_NAMES: Record<number, string> = {
    0: "NetworkRestake",
    1: "FullRestake",
    2: "OperatorSpecific",
    3: "OperatorNetworkSpecific",
} as const;

export const SLASHER_TYPES_NAMES: Record<number, string> = {
    [-1]: "NonSlashable",
    0: "InstantSlasher",
    1: "VetoSlasher",
} as const;
```

## File: src/core/contracts.ts

```typescript
import type { Abi } from "viem";

import FullRestakeDelegatorJson from "../../abi/FullRestakeDelegatorABI.json";
import NetworkMiddlewareServiceJson from "../../abi/NetworkMiddlewareServiceABI.json";
import NetworkRegistryJson from "../../abi/NetworkRegistryABI.json";
import NetworkRestakeDelegatorJson from "../../abi/NetworkRestakeDelegatorABI.json";
import OperatorNetworkOptInServiceJson from "../../abi/OperatorNetworkOptInServiceABI.json";
import OperatorNetworkSpecificDelegatorJson from "../../abi/OperatorNetworkSpecificDelegatorABI.json";
import OperatorRegistryJson from "../../abi/OperatorRegistryABI.json";
import OperatorSpecificDelegatorJson from "../../abi/OperatorSpecificDelegatorABI.json";
import OperatorVaultOptInServiceJson from "../../abi/OperatorVaultOptInServiceABI.json";
import CuratorRegistryJson from "../../abi/CuratorRegistryABI.json";
import FeeRegistryJson from "../../abi/FeeRegistryABI.json";
import ProtocolFeesJson from "../../abi/ProtocolFeesABI.json";
import VaultSnapshotRewardsJson from "../../abi/VaultSnapshotRewardsABI.json";
import CumulativeMerkleRewardsJson from "../../abi/CumulativeMerkleRewardsABI.json";
import VaultFactoryJson from "../../abi/VaultFactoryABI.json";
import VaultJson from "../../abi/VaultABI.json";
import VaultTokenizedJson from "../../abi/VaultTokenizedABI.json";
import VetoSlasherJson from "../../abi/VetoSlasherABI.json";

// viem needs `Abi`-compatible shapes; JSON imports don’t keep literal types.
export const OperatorRegistryAbi = OperatorRegistryJson as unknown as Abi;
export const NetworkRegistryAbi = NetworkRegistryJson as unknown as Abi;
export const OperatorVaultOptInServiceAbi = OperatorVaultOptInServiceJson as unknown as Abi;
export const OperatorNetworkOptInServiceAbi = OperatorNetworkOptInServiceJson as unknown as Abi;
export const NetworkMiddlewareServiceAbi = NetworkMiddlewareServiceJson as unknown as Abi;
export const VaultFactoryAbi = VaultFactoryJson as unknown as Abi;
export const VaultAbi = VaultJson as unknown as Abi;
export const VaultTokenizedAbi = VaultTokenizedJson as unknown as Abi;

export const NetworkRestakeDelegatorAbi = NetworkRestakeDelegatorJson as unknown as Abi;
export const FullRestakeDelegatorAbi = FullRestakeDelegatorJson as unknown as Abi;
export const OperatorSpecificDelegatorAbi = OperatorSpecificDelegatorJson as unknown as Abi;
export const OperatorNetworkSpecificDelegatorAbi =
    OperatorNetworkSpecificDelegatorJson as unknown as Abi;

export const VetoSlasherAbi = VetoSlasherJson as unknown as Abi;

// Rewards
export const CuratorRegistryAbi = CuratorRegistryJson as unknown as Abi;
export const FeeRegistryAbi = FeeRegistryJson as unknown as Abi;
export const ProtocolFeesAbi = ProtocolFeesJson as unknown as Abi;
export const VaultSnapshotRewardsAbi = VaultSnapshotRewardsJson as unknown as Abi;
export const CumulativeMerkleRewardsAbi = CumulativeMerkleRewardsJson as unknown as Abi;

export function delegatorAbiByType(type: bigint): Abi {
    if (type === 0n) return NetworkRestakeDelegatorAbi;
    if (type === 1n) return FullRestakeDelegatorAbi;
    if (type === 2n) return OperatorSpecificDelegatorAbi;
    if (type === 3n) return OperatorNetworkSpecificDelegatorAbi;
    return NetworkRestakeDelegatorAbi;
}
```

## File: src/core/format.ts

```typescript
export function formatPercent(numerator: bigint, denominator: bigint) {
    // Returns a "whole.frac" string with 2 decimals (no '%' suffix).
    if (denominator === 0n) return "0";
    const bp = (numerator * 10_000n) / denominator; // basis points
    const whole = bp / 100n;
    const frac = (bp % 100n).toString().padStart(2, "0");
    return `${whole}.${frac}`;
}

export function groupBy<T, K>(items: readonly T[], keyFn: (item: T) => K): Map<K, T[]> {
    const out = new Map<K, T[]>();
    for (const item of items) {
        const key = keyFn(item);
        const list = out.get(key) ?? [];
        list.push(item);
        out.set(key, list);
    }
    return out;
}
```

## File: src/core/multicall.ts

```typescript
import type { Abi, Chain, ContractFunctionParameters, PublicClient, Transport } from "viem";

type MulticallContract = ContractFunctionParameters<Abi, "view" | "pure">;

// 2^14 - 1 bytes: conservative calldata chunk cap that tends to work across public RPCs.
const DEFAULT_MULTICALL_CALLDATA_BATCH_SIZE_BYTES = 16_383;

export type MulticallChunkedOptions = {
    allowFailure?: boolean;
    batchSize?: number;
    concurrency?: number;
};

async function mapWithConcurrency<T, U>(
    items: readonly T[],
    concurrency: number,
    fn: (item: T, index: number) => Promise<U>,
): Promise<U[]> {
    const results: U[] = new Array(items.length);
    let nextIndex = 0;

    const workerCount = Math.max(1, Math.min(concurrency, items.length));
    await Promise.all(
        Array.from({ length: workerCount }, async () => {
            while (true) {
                const current = nextIndex++;
                if (current >= items.length) break;
                const item = items[current]!;
                results[current] = await fn(item, current);
            }
        }),
    );

    return results;
}

export async function multicallChunked(
    client: PublicClient<Transport, Chain>,
    contracts: readonly MulticallContract[],
    opts: MulticallChunkedOptions = {},
): Promise<any[]> {
    const allowFailure = opts.allowFailure ?? false;
    const batchSize = opts.batchSize ?? 1000;
    const concurrency = opts.concurrency ?? 4;

    if (contracts.length === 0) return [];

    const out: any[] = new Array(contracts.length);
    const chunkCount = Math.ceil(contracts.length / batchSize);
    const chunkIndexes = Array.from({ length: chunkCount }, (_, i) => i);

    await mapWithConcurrency(chunkIndexes, concurrency, async (chunkIndex) => {
        const start = chunkIndex * batchSize;
        const end = Math.min(start + batchSize, contracts.length);
        const chunk = contracts.slice(start, end);

        const results = await client.multicall({
            contracts: chunk,
            allowFailure,
            batchSize: DEFAULT_MULTICALL_CALLDATA_BATCH_SIZE_BYTES,
        });

        for (let i = 0; i < results.length; i++) {
            out[start + i] = results[i];
        }
    });

    return out;
}
```

## File: src/core/output.ts

```typescript
export type OutputMode = {
    json: boolean;
    quiet: boolean;
};

function jsonReplacer(_key: string, value: unknown) {
    if (typeof value === "bigint") return value.toString();
    if (value instanceof Map) return Object.fromEntries(value.entries());
    return value;
}

export function printJson(value: unknown) {
    process.stdout.write(`${JSON.stringify(value, jsonReplacer, 2)}\n`);
}

export function printLine(line = "") {
    process.stdout.write(`${line}\n`);
}

export function printIndented(line: string, indent = 2) {
    printLine(`${" ".repeat(indent)}${line}`);
}
```

## File: src/core/spinner.ts

```typescript
import ora, { type Ora } from "ora";

import type { OutputMode } from "./output";

export function canUseSpinner(mode: OutputMode) {
    return !mode.json && !mode.quiet && process.stdout.isTTY;
}

export function startSpinner(mode: OutputMode, text: string): Ora | undefined {
    if (!canUseSpinner(mode)) return undefined;
    return ora(text).start();
}

export async function withSpinner<T>(
    mode: OutputMode,
    text: string,
    fn: () => Promise<T>,
): Promise<T> {
    const spinner = startSpinner(mode, text);
    try {
        return await fn();
    } finally {
        spinner?.stop();
    }
}
```

## File: src/core/subnetwork.ts

```typescript
import { getAddress, padHex, toHex, type Address, type Hex, size } from "viem";

const MAX_UINT96 = (1n << 96n) - 1n;

export function encodeSubnetwork(args: { net: Address; subnetId: bigint | number }): Hex {
    const net = getAddress(args.net);
    const subnetId = typeof args.subnetId === "number" ? BigInt(args.subnetId) : args.subnetId;
    if (subnetId < 0n || subnetId > MAX_UINT96) {
        throw new Error(`subnetId out of range for uint96: ${subnetId}`);
    }

    const subnetHex = padHex(toHex(subnetId), { size: 12 });
    const subnetwork = `${net}${subnetHex.slice(2)}` as Hex;
    if (size(subnetwork) !== 32) throw new Error(`Invalid subnetwork encoding: ${subnetwork}`);
    return subnetwork;
}

export function decodeSubnetwork(subnetwork: Hex): { net: Address; subnetId: bigint } {
    if (size(subnetwork) !== 32) throw new Error(`Expected bytes32 subnetwork, got: ${subnetwork}`);
    const raw = subnetwork.slice(2);
    const net = getAddress(`0x${raw.slice(0, 40)}`);
    const subnetId = BigInt(`0x${raw.slice(40)}`);
    return { net, subnetId };
}
```

## File: src/core/symbiotic.ts

```typescript
import { getAddress, type Address, type Hex } from "viem";
import type { Chain, PublicClient, Transport } from "viem";

import type { ChainAddresses, ChainAddressKey, ChainKey } from "../config/chains";
import {
    DELEGATOR_TYPES_NAMES,
    SLASHER_TYPES_NAMES,
    SUBNETWORK_IDS,
    ZERO_ADDRESS,
} from "./constants";
import {
    CuratorRegistryAbi,
    delegatorAbiByType,
    FeeRegistryAbi,
    FullRestakeDelegatorAbi,
    NetworkMiddlewareServiceAbi,
    NetworkRegistryAbi,
    NetworkRestakeDelegatorAbi,
    OperatorNetworkOptInServiceAbi,
    OperatorNetworkSpecificDelegatorAbi,
    OperatorRegistryAbi,
    OperatorSpecificDelegatorAbi,
    OperatorVaultOptInServiceAbi,
    ProtocolFeesAbi,
    VaultAbi,
    VaultFactoryAbi,
    VaultSnapshotRewardsAbi,
    VaultTokenizedAbi,
    VetoSlasherAbi,
} from "./contracts";
import { TtlCache } from "./cache";
import { multicallChunked } from "./multicall";
import { encodeSubnetwork } from "./subnetwork";
import type { NetInfo, StakeBySubnetwork, TokenMeta, VaultInfo } from "./types";
import { tokenMetaFallback } from "./units";

type RewardDistribution = {
    subnetworkId: bigint;
    delegator: Address;
    delegatorType: bigint;
    timestamp: bigint;
    amount: bigint;
    operatorsFees: bigint;
};

export type SymbioticClientOptions = {
    chainKey: ChainKey;
    chainId: number;
    addresses: ChainAddresses;
    publicClient: PublicClient<Transport, Chain>;
    multicallBatchSize?: number;
    multicallConcurrency?: number;
};

export class SymbioticClient {
    private readonly chainKey: ChainKey;
    private readonly chainId: number;
    private readonly addresses: ChainAddresses;
    private readonly publicClient: PublicClient<Transport, Chain>;
    private readonly multicallBatchSize: number;
    private readonly multicallConcurrency: number;

    private readonly tokenMetaCache = new TtlCache<Address, TokenMeta>(24 * 60 * 60 * 1000);
    private readonly netsCache = new TtlCache<string, NetInfo[]>(60 * 1000);
    private readonly opsCache = new TtlCache<string, Address[]>(60 * 1000);
    private readonly vaultsCache = new TtlCache<string, VaultInfo[]>(60 * 1000);

    constructor(opts: SymbioticClientOptions) {
        this.chainKey = opts.chainKey;
        this.chainId = opts.chainId;
        this.addresses = opts.addresses;
        this.publicClient = opts.publicClient;
        this.multicallBatchSize = opts.multicallBatchSize ?? 400;
        this.multicallConcurrency = opts.multicallConcurrency ?? 4;
    }

    getChainId() {
        return this.chainId;
    }

    getAddresses() {
        return this.addresses;
    }

    requireAddress(key: ChainAddressKey): Address {
        const address = this.addresses[key] as Address | undefined;
        return this.requireAddressValue(key, address);
    }

    private requireAddressValue(name: string, address: Address | undefined): Address {
        if (!address) {
            throw new Error(`${name} address is not configured for chain ${this.chainKey}.`);
        }
        return address;
    }

    private async read<T>(args: {
        abi: any;
        address: Address;
        functionName: string;
        args?: readonly unknown[];
    }): Promise<T> {
        return this.publicClient.readContract({
            address: args.address,
            abi: args.abi,
            functionName: args.functionName as any,
            args: args.args as any,
        }) as Promise<T>;
    }

    private async mc(contracts: any[], allowFailure = false) {
        return multicallChunked(this.publicClient, contracts, {
            allowFailure,
            batchSize: this.multicallBatchSize,
            concurrency: this.multicallConcurrency,
        });
    }

    private subnetworksForNet(net: Address): Hex[] {
        const n = getAddress(net);
        return SUBNETWORK_IDS.map((subnetId) => encodeSubnetwork({ net: n, subnetId }));
    }

    private pinnedOperator(vault: Pick<VaultInfo, "delegatorType" | "delegatorOperator">) {
        if ((vault.delegatorType === 2n || vault.delegatorType === 3n) && vault.delegatorOperator)
            return vault.delegatorOperator;
        return undefined;
    }

    private pinnedNetwork(vault: Pick<VaultInfo, "delegatorType" | "delegatorNetwork">) {
        if (vault.delegatorType === 3n && vault.delegatorNetwork) return vault.delegatorNetwork;
        return undefined;
    }

    private buildLimitCallsForNet(net: Address, vaults: readonly VaultInfo[]) {
        const network = getAddress(net);
        const subnetworks = this.subnetworksForNet(network);

        const calls: any[] = [];
        const eligible: VaultInfo[] = [];

        for (const vault of vaults) {
            if (vault.delegator === ZERO_ADDRESS) continue;

            const pinnedNet = this.pinnedNetwork(vault);
            if (pinnedNet && pinnedNet !== network) continue;

            const functionName = vault.delegatorType === 3n ? "maxNetworkLimit" : "networkLimit";
            for (const subnetwork of subnetworks) {
                calls.push({
                    address: vault.delegator,
                    abi: FullRestakeDelegatorAbi,
                    functionName,
                    args: [subnetwork],
                });
            }
            eligible.push(vault);
        }

        return { calls, eligible };
    }

    private decodeStakeBySubnetwork(
        values: readonly bigint[],
        offset: number,
    ): {
        stake: StakeBySubnetwork;
        hasValue: boolean;
        nextOffset: number;
    } {
        const stake: StakeBySubnetwork = {};
        let hasValue = false;
        for (const subnetId of SUBNETWORK_IDS) {
            const value = values[offset++]!;
            if (value > 0n) {
                stake[subnetId] = value;
                hasValue = true;
            }
        }
        return { stake, hasValue, nextOffset: offset };
    }

    private decodeStakeBySubnetworkHasValue(values: readonly bigint[], offset: number): boolean {
        for (let i = 0; i < SUBNETWORK_IDS.length; i++) {
            if ((values[offset + i] ?? 0n) > 0n) return true;
        }
        return false;
    }

    async getTokenMeta(token: Address): Promise<TokenMeta> {
        const t = getAddress(token);
        const cached = this.tokenMetaCache.get(t);
        if (cached) return cached;

        const [sym, dec] = await this.mc(
            [
                {
                    address: t,
                    abi: VaultTokenizedAbi,
                    functionName: "symbol",
                },
                {
                    address: t,
                    abi: VaultTokenizedAbi,
                    functionName: "decimals",
                },
            ],
            true,
        );

        const symbol = sym?.status === "success" ? (sym.result as string) : undefined;
        const decimals =
            dec?.status === "success"
                ? typeof dec.result === "bigint"
                    ? Number(dec.result)
                    : typeof dec.result === "number"
                      ? dec.result
                      : undefined
                : undefined;

        const meta =
            symbol && Number.isFinite(decimals)
                ? { symbol, decimals: decimals! }
                : tokenMetaFallback();

        this.tokenMetaCache.set(t, meta);
        return meta;
    }

    async getMiddleware(net: Address): Promise<Address> {
        const middleware = await this.read<Address>({
            abi: NetworkMiddlewareServiceAbi,
            address: this.requireAddress("middleware_service"),
            functionName: "middleware",
            args: [net],
        });
        return getAddress(middleware);
    }

    async getNets(): Promise<NetInfo[]> {
        const cached = this.netsCache.get("nets");
        if (cached) return cached;

        const total = await this.read<bigint>({
            abi: NetworkRegistryAbi,
            address: this.requireAddress("net_registry"),
            functionName: "totalEntities",
        });

        const calls: any[] = [];
        for (let i = 0n; i < total; i++) {
            calls.push({
                address: this.requireAddress("net_registry"),
                abi: NetworkRegistryAbi,
                functionName: "entity",
                args: [i],
            });
        }

        const entities = await this.mc(calls);
        const nets = entities.map((net: any) => getAddress(net as Address));

        const middlewareCalls = nets.map((net) => ({
            address: this.requireAddress("middleware_service"),
            abi: NetworkMiddlewareServiceAbi,
            functionName: "middleware",
            args: [net],
        }));

        const middlewareResults = await this.mc(middlewareCalls);
        const middlewares = middlewareResults.map((middleware: any) =>
            getAddress(middleware as Address),
        );

        const result: NetInfo[] = nets.map((net, i) => ({ net, middleware: middlewares[i]! }));
        this.netsCache.set("nets", result);
        return result;
    }

    async getOps(): Promise<Address[]> {
        const cached = this.opsCache.get("ops");
        if (cached) return cached;

        const total = await this.read<bigint>({
            abi: OperatorRegistryAbi,
            address: this.requireAddress("op_registry"),
            functionName: "totalEntities",
        });

        const calls: any[] = [];
        for (let i = 0n; i < total; i++) {
            calls.push({
                address: this.requireAddress("op_registry"),
                abi: OperatorRegistryAbi,
                functionName: "entity",
                args: [i],
            });
        }
        const entities = await this.mc(calls);
        const ops = entities.map((op: any) => getAddress(op as Address));
        this.opsCache.set("ops", ops);
        return ops;
    }

    async getOpNets(operator: Address): Promise<NetInfo[]> {
        const nets = await this.getNets();

        const optinCalls = nets.map((net) => ({
            address: this.requireAddress("op_net_opt_in"),
            abi: OperatorNetworkOptInServiceAbi,
            functionName: "isOptedIn",
            args: [operator, net.net],
        }));
        const optins = await this.mc(optinCalls);
        return nets.filter((net, i) => Boolean(optins[i]));
    }

    async getNetOps(net: Address): Promise<Address[]> {
        const ops = await this.getOps();

        const calls = ops.map((op) => ({
            address: this.requireAddress("op_net_opt_in"),
            abi: OperatorNetworkOptInServiceAbi,
            functionName: "isOptedIn",
            args: [op, net],
        }));
        const optins = await this.mc(calls);
        return ops.filter((op, i) => Boolean(optins[i]));
    }

    async getNetsFullCounts(
        nets?: readonly NetInfo[],
    ): Promise<Array<{ ops: number; vaults: number }>> {
        const netsList = nets ?? (await this.getNets());
        const ops = await this.getOps();
        const vaults = await this.getVaults();

        // Operators per net (N * O) but done as a single chunked multicall.
        const optinCalls: any[] = [];
        for (const net of netsList) {
            for (const op of ops) {
                optinCalls.push({
                    address: this.requireAddress("op_net_opt_in"),
                    abi: OperatorNetworkOptInServiceAbi,
                    functionName: "isOptedIn",
                    args: [op, net.net],
                });
            }
        }

        const optins = optinCalls.length ? await this.mc(optinCalls) : [];
        const opsCounts: number[] = new Array(netsList.length).fill(0);

        if (ops.length) {
            for (let netIdx = 0; netIdx < netsList.length; netIdx++) {
                let count = 0;
                const base = netIdx * ops.length;
                for (let opIdx = 0; opIdx < ops.length; opIdx++) {
                    if (optins[base + opIdx]) count++;
                }
                opsCounts[netIdx] = count;
            }
        }

        // Vaults per net: count vaults with at least one non-zero network limit for any subnetwork.
        const limitCalls: any[] = [];
        const eligibleVaultsByNet: VaultInfo[][] = new Array(netsList.length);
        for (let netIdx = 0; netIdx < netsList.length; netIdx++) {
            const { calls, eligible } = this.buildLimitCallsForNet(netsList[netIdx]!.net, vaults);
            eligibleVaultsByNet[netIdx] = eligible;
            limitCalls.push(...calls);
        }

        const limits = (await this.mc(limitCalls)) as bigint[];
        const vaultCounts: number[] = new Array(netsList.length).fill(0);

        let offset = 0;
        for (let netIdx = 0; netIdx < netsList.length; netIdx++) {
            const eligible = eligibleVaultsByNet[netIdx] ?? [];
            for (let vIdx = 0; vIdx < eligible.length; vIdx++) {
                if (this.decodeStakeBySubnetworkHasValue(limits, offset)) {
                    vaultCounts[netIdx] = (vaultCounts[netIdx] ?? 0) + 1;
                }
                offset += SUBNETWORK_IDS.length;
            }
        }

        return netsList.map((_n, i) => ({ ops: opsCounts[i] ?? 0, vaults: vaultCounts[i] ?? 0 }));
    }

    async getVaults(): Promise<VaultInfo[]> {
        const cached = this.vaultsCache.get("vaults");
        if (cached) return cached;

        const total = await this.read<bigint>({
            abi: VaultFactoryAbi,
            address: this.requireAddress("vault_factory"),
            functionName: "totalEntities",
        });

        const entityCalls: any[] = [];
        for (let i = 0n; i < total; i++) {
            entityCalls.push({
                address: this.requireAddress("vault_factory"),
                abi: VaultFactoryAbi,
                functionName: "entity",
                args: [i],
            });
        }

        const vaultResults = await this.mc(entityCalls);
        const vaults = vaultResults.map((vault: any) => getAddress(vault as Address));

        const dataCalls: any[] = [];
        for (const vault of vaults) {
            dataCalls.push({ address: vault, abi: VaultAbi, functionName: "collateral" });
            dataCalls.push({ address: vault, abi: VaultAbi, functionName: "activeStake" });
            dataCalls.push({ address: vault, abi: VaultAbi, functionName: "delegator" });
            dataCalls.push({ address: vault, abi: VaultAbi, functionName: "slasher" });
        }
        const data = await this.mc(dataCalls);

        const results: VaultInfo[] = [];
        for (let i = 0; i < vaults.length; i++) {
            const offset = i * 4;
            results.push({
                vault: vaults[i]!,
                collateral: getAddress(data[offset]! as Address),
                tvl: data[offset + 1]! as bigint,
                delegator: getAddress(data[offset + 2]! as Address),
                slasher: getAddress(data[offset + 3]! as Address),
                delegatorType: -1n,
                slasherType: -1n,
            });
        }

        // TYPE() reads
        const typeCalls: any[] = [];
        const assignments: Array<{ idx: number; role: "delegatorType" | "slasherType" }> = [];
        for (let idx = 0; idx < results.length; idx++) {
            const v = results[idx]!;
            if (v.delegator !== ZERO_ADDRESS) {
                typeCalls.push({
                    address: v.delegator,
                    abi: NetworkRestakeDelegatorAbi,
                    functionName: "TYPE",
                });
                assignments.push({ idx, role: "delegatorType" });
            }
            if (v.slasher !== ZERO_ADDRESS) {
                typeCalls.push({
                    address: v.slasher,
                    abi: NetworkRestakeDelegatorAbi,
                    functionName: "TYPE",
                });
                assignments.push({ idx, role: "slasherType" });
            }
        }
        const typeResults = await this.mc(typeCalls);
        for (let i = 0; i < assignments.length; i++) {
            const { idx, role } = assignments[i]!;
            results[idx]![role] = typeResults[i]! as bigint;
        }

        // Delegator enrichment: resolve optional operator/network fields for specific delegator types.
        const enrichCalls: any[] = [];
        const enrichAssign: Array<{ idx: number; role: "delegatorOperator" | "delegatorNetwork" }> =
            [];
        for (let idx = 0; idx < results.length; idx++) {
            const v = results[idx]!;
            if (v.delegator === ZERO_ADDRESS) continue;

            if (v.delegatorType === 2n || v.delegatorType === 3n) {
                const abi = delegatorAbiByType(v.delegatorType);
                enrichCalls.push({
                    address: v.delegator,
                    abi,
                    functionName: "operator",
                });
                enrichAssign.push({ idx, role: "delegatorOperator" });
            }
            if (v.delegatorType === 3n) {
                const abi = delegatorAbiByType(v.delegatorType);
                enrichCalls.push({ address: v.delegator, abi, functionName: "network" });
                enrichAssign.push({ idx, role: "delegatorNetwork" });
            }
        }

        if (enrichCalls.length) {
            const enrichResults = await this.mc(enrichCalls);
            for (let i = 0; i < enrichAssign.length; i++) {
                const { idx, role } = enrichAssign[i]!;
                results[idx]![role] = getAddress(enrichResults[i]! as Address);
            }
        }

        this.vaultsCache.set("vaults", results);
        return results;
    }

    async getVaultDelegator(vault: Address): Promise<Address> {
        const delegator = await this.read<Address>({
            abi: VaultAbi,
            address: vault,
            functionName: "delegator",
        });
        return getAddress(delegator);
    }

    async getVaultCollateral(vault: Address): Promise<Address> {
        const collateral = await this.read<Address>({
            abi: VaultAbi,
            address: vault,
            functionName: "collateral",
        });
        return getAddress(collateral);
    }

    async getVaultSlasher(vault: Address): Promise<Address> {
        const slasher = await this.read<Address>({
            abi: VaultAbi,
            address: vault,
            functionName: "slasher",
        });
        return getAddress(slasher);
    }

    async getNetVaults(net: Address): Promise<(VaultInfo & { limit: StakeBySubnetwork })[]> {
        const vaults = await this.getVaults();
        const { calls: limitCalls, eligible } = this.buildLimitCallsForNet(net, vaults);
        const limits = (await this.mc(limitCalls)) as bigint[];
        const results: (VaultInfo & { limit: StakeBySubnetwork })[] = [];

        let i = 0;
        for (const vault of eligible) {
            const { stake: limit, hasValue, nextOffset } = this.decodeStakeBySubnetwork(limits, i);
            i = nextOffset;
            if (hasValue) results.push({ ...vault, limit });
        }

        return results;
    }

    async getNetOpsVaults(net: Address): Promise<
        Array<{
            op: Address;
            vaults: Array<VaultInfo & { limit: StakeBySubnetwork; stake: StakeBySubnetwork }>;
        }>
    > {
        const vaults = await this.getNetVaults(net);
        const ops = await this.getNetOps(net);

        const subnetworks = this.subnetworksForNet(net);
        const results = ops.map((op) => ({ op, vaults: [] as any[] }));
        const opIndex = new Map<Address, number>();
        for (let opIdx = 0; opIdx < ops.length; opIdx++) opIndex.set(ops[opIdx]!, opIdx);

        // Pass 1: Determine which operators are opted into each vault (bounded by ops opted into network).
        const candidateOpIndexesByVault: number[][] = Array.from(
            { length: vaults.length },
            () => [],
        );
        const optinCalls: any[] = [];
        const optinPairs: Array<{ vaultIdx: number; opIdx: number }> = [];

        for (let vaultIdx = 0; vaultIdx < vaults.length; vaultIdx++) {
            const vault = vaults[vaultIdx]!;
            const pinnedOp = this.pinnedOperator(vault);
            if (pinnedOp) {
                const idx = opIndex.get(pinnedOp);
                if (idx !== undefined) candidateOpIndexesByVault[vaultIdx]!.push(idx);
                continue;
            }

            for (let opIdx = 0; opIdx < ops.length; opIdx++) {
                optinCalls.push({
                    address: this.requireAddress("op_vault_opt_in"),
                    abi: OperatorVaultOptInServiceAbi,
                    functionName: "isOptedIn",
                    args: [ops[opIdx]!, vault.vault],
                });
                optinPairs.push({ vaultIdx, opIdx });
            }
        }

        if (optinCalls.length) {
            const optins = await this.mc(optinCalls);
            for (let i = 0; i < optinPairs.length; i++) {
                if (!optins[i]) continue;
                const { vaultIdx, opIdx } = optinPairs[i]!;
                candidateOpIndexesByVault[vaultIdx]!.push(opIdx);
            }
        }

        // Pass 2: Stake calls only for (vault, op) pairs that are opted into the vault.
        const stakeCalls: any[] = [];
        const stakePairs: Array<{
            opIdx: number;
            vault: VaultInfo & { limit: StakeBySubnetwork };
        }> = [];

        for (let vaultIdx = 0; vaultIdx < vaults.length; vaultIdx++) {
            const vault = vaults[vaultIdx]!;
            const opIndexes = candidateOpIndexesByVault[vaultIdx] ?? [];
            for (const opIdx of opIndexes) {
                const op = ops[opIdx]!;
                for (const subnetwork of subnetworks) {
                    stakeCalls.push({
                        address: vault.delegator,
                        abi: NetworkRestakeDelegatorAbi,
                        functionName: "stake",
                        args: [subnetwork, op],
                    });
                }
                stakePairs.push({ opIdx, vault });
            }
        }

        const stakes = (await this.mc(stakeCalls)) as bigint[];
        let stakeOffset = 0;
        for (const pair of stakePairs) {
            const { stake, hasValue, nextOffset } = this.decodeStakeBySubnetwork(
                stakes,
                stakeOffset,
            );
            stakeOffset = nextOffset;
            if (hasValue) results[pair.opIdx]!.vaults.push({ ...pair.vault, stake });
        }

        return results;
    }

    async getVaultOps(vault: Address): Promise<Address[]> {
        const ops = await this.getOps();

        const calls = ops.map((op) => ({
            address: this.requireAddress("op_vault_opt_in"),
            abi: OperatorVaultOptInServiceAbi,
            functionName: "isOptedIn",
            args: [op, vault],
        }));
        const optins = await this.mc(calls);
        return ops.filter((op, i) => Boolean(optins[i]));
    }

    async getVaultNetsByDelegator(
        delegator: Address,
    ): Promise<Array<{ net: Address; limit: StakeBySubnetwork }>> {
        const nets = await this.getNets();

        const calls: any[] = [];
        for (const net of nets) {
            const subnetworks = this.subnetworksForNet(net.net);
            for (const subnetwork of subnetworks) {
                calls.push({
                    address: delegator,
                    abi: FullRestakeDelegatorAbi,
                    functionName: "maxNetworkLimit",
                    args: [subnetwork],
                });
            }
        }
        const results = (await this.mc(calls)) as bigint[];

        const out: Array<{ net: Address; limit: StakeBySubnetwork }> = [];
        let i = 0;
        for (const net of nets) {
            const { stake: limit, hasValue, nextOffset } = this.decodeStakeBySubnetwork(results, i);
            i = nextOffset;
            if (hasValue) out.push({ net: net.net, limit });
        }

        return out;
    }

    async getVaultNets(vault: Address): Promise<Array<{ net: Address; limit: StakeBySubnetwork }>> {
        const delegator = await this.getVaultDelegator(vault);
        return this.getVaultNetsByDelegator(delegator);
    }

    async getVaultNetsOps(vault: Address): Promise<Record<Address, Address[]>> {
        const vaultOps = await this.getVaultOps(vault);
        const vaultNets = await this.getVaultNets(vault);

        const calls: any[] = [];
        const pairs: Array<{ net: Address; op: Address }> = [];
        for (const net of vaultNets) {
            for (const op of vaultOps) {
                calls.push({
                    address: this.requireAddress("op_net_opt_in"),
                    abi: OperatorNetworkOptInServiceAbi,
                    functionName: "isOptedIn",
                    args: [op, net.net],
                });
                pairs.push({ net: net.net, op });
            }
        }
        const optins = await this.mc(calls);

        const out: Record<Address, Address[]> = {} as any;
        for (const net of vaultNets) out[net.net] = [];
        for (let i = 0; i < pairs.length; i++) {
            if (optins[i]) out[pairs[i]!.net]!.push(pairs[i]!.op);
        }
        return out;
    }

    async getVaultNetsOpsFull(
        vaultInfo: VaultInfo,
    ): Promise<Array<{ net: Address; ops: Array<{ op: Address; stake: StakeBySubnetwork }> }>> {
        const res = await this.getVaultsNetsOpsFull([vaultInfo]);
        return res[0] ?? [];
    }

    async getVaultsNetsOpsFull(
        vaultInfos: readonly VaultInfo[],
    ): Promise<
        Array<Array<{ net: Address; ops: Array<{ op: Address; stake: StakeBySubnetwork }> }>>
    > {
        if (vaultInfos.length === 0) return [];

        const nets = await this.getNets();
        const ops = await this.getOps();

        // Precompute subnetworks once per net; used by both limit and stake call builders.
        const subnetworksByNet = new Map<Address, Hex[]>();
        for (const net of nets) subnetworksByNet.set(net.net, this.subnetworksForNet(net.net));
        const getSubnetworks = (net: Address) => {
            const cached = subnetworksByNet.get(net);
            if (cached) return cached;
            const subnetworks = this.subnetworksForNet(net);
            subnetworksByNet.set(net, subnetworks);
            return subnetworks;
        };

        // Pass 1: Determine which networks are relevant for each vault by reading maxNetworkLimit.
        const limitCalls: any[] = [];
        const candidateNetsByVault: Address[][] = new Array(vaultInfos.length);
        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            const v = vaultInfos[vIdx]!;
            if (v.delegator === ZERO_ADDRESS) {
                candidateNetsByVault[vIdx] = [];
                continue;
            }

            // OperatorNetworkSpecific delegators are bound to a single network.
            const pinnedNet = this.pinnedNetwork(v);
            if (pinnedNet) {
                candidateNetsByVault[vIdx] = [pinnedNet];
            } else {
                candidateNetsByVault[vIdx] = nets.map((n) => n.net);
            }
        }

        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            const v = vaultInfos[vIdx]!;
            if (v.delegator === ZERO_ADDRESS) continue;
            const candidateNets = candidateNetsByVault[vIdx] ?? [];
            for (const net of candidateNets) {
                const subnetworks = getSubnetworks(net);
                for (const subnetwork of subnetworks) {
                    limitCalls.push({
                        address: v.delegator,
                        abi: FullRestakeDelegatorAbi,
                        functionName: "maxNetworkLimit",
                        args: [subnetwork],
                    });
                }
            }
        }

        const limitResults = (await this.mc(limitCalls)) as bigint[];
        const netsByVault: Address[][] = new Array(vaultInfos.length);
        let limitOffset = 0;

        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            if (vaultInfos[vIdx]!.delegator === ZERO_ADDRESS) {
                netsByVault[vIdx] = [];
                continue;
            }

            const selected: Address[] = [];
            const candidateNets = candidateNetsByVault[vIdx] ?? [];
            for (const net of candidateNets) {
                const hasValue = this.decodeStakeBySubnetworkHasValue(limitResults, limitOffset);
                limitOffset += SUBNETWORK_IDS.length;
                if (hasValue) selected.push(net);
            }
            netsByVault[vIdx] = selected;
        }

        // Pass 2: Determine which operators are opted into each vault.
        const opsByVault: Address[][] = new Array(vaultInfos.length);
        const optinCalls: any[] = [];
        const optinVaultIndexes: number[] = [];

        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            // No nets, no stakes, no point checking operators.
            if ((netsByVault[vIdx] ?? []).length === 0) {
                opsByVault[vIdx] = [];
                continue;
            }

            const v = vaultInfos[vIdx]!;

            // Operator-specific delegators already constrain the operator set on-chain.
            const pinnedOp = this.pinnedOperator(v);
            if (pinnedOp) {
                opsByVault[vIdx] = [pinnedOp];
                continue;
            }

            optinVaultIndexes.push(vIdx);
            for (const op of ops) {
                optinCalls.push({
                    address: this.requireAddress("op_vault_opt_in"),
                    abi: OperatorVaultOptInServiceAbi,
                    functionName: "isOptedIn",
                    args: [op, v.vault],
                });
            }
        }

        const optins = await this.mc(optinCalls);
        let optinOffset = 0;
        for (const vIdx of optinVaultIndexes) {
            const selected: Address[] = [];
            for (let opIdx = 0; opIdx < ops.length; opIdx++) {
                if (optins[optinOffset++]) selected.push(ops[opIdx]!);
            }
            opsByVault[vIdx] = selected;
        }

        // Pass 3: Stake lookups (net -> op -> subnetwork) for opted-in operators only.
        const stakeCalls: any[] = [];
        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            const v = vaultInfos[vIdx]!;
            if (v.delegator === ZERO_ADDRESS) continue;

            const vaultNets = netsByVault[vIdx] ?? [];
            const vaultOps = opsByVault[vIdx] ?? [];
            for (const net of vaultNets) {
                const subnetworks = getSubnetworks(net);
                for (const op of vaultOps) {
                    for (const subnetwork of subnetworks) {
                        stakeCalls.push({
                            address: v.delegator,
                            abi: NetworkRestakeDelegatorAbi,
                            functionName: "stake",
                            args: [subnetwork, op],
                        });
                    }
                }
            }
        }

        const stakes = (await this.mc(stakeCalls)) as bigint[];

        const out: Array<
            Array<{ net: Address; ops: Array<{ op: Address; stake: StakeBySubnetwork }> }>
        > = new Array(vaultInfos.length);

        let stakeOffset = 0;
        for (let vIdx = 0; vIdx < vaultInfos.length; vIdx++) {
            const vaultNets = netsByVault[vIdx] ?? [];
            const vaultOps = opsByVault[vIdx] ?? [];

            const vaultOut = vaultNets.map((net) => ({
                net,
                ops: [] as Array<{ op: Address; stake: StakeBySubnetwork }>,
            }));

            for (let netIdx = 0; netIdx < vaultNets.length; netIdx++) {
                for (const op of vaultOps) {
                    const { stake, hasValue, nextOffset } = this.decodeStakeBySubnetwork(
                        stakes,
                        stakeOffset,
                    );
                    stakeOffset = nextOffset;
                    if (hasValue) vaultOut[netIdx]!.ops.push({ op, stake });
                }
            }

            out[vIdx] = vaultOut;
        }

        return out;
    }

    async getOpNetsVaults(op: Address): Promise<
        Array<{
            net: Address;
            vaults: Array<VaultInfo & { limit: StakeBySubnetwork; stake: StakeBySubnetwork }>;
        }>
    > {
        const nets = await this.getOpNets(op);
        const out = nets.map((n) => ({ net: n.net, vaults: [] as any[] }));
        if (nets.length === 0) return out;

        // Pre-filter the vault universe to the operator's opted-in vaults (plus any pinned-to-operator vaults)
        // before doing per-network limit scans. This avoids scanning all vaults for each network.
        const allVaults = await this.getVaults();

        const genericVaults: VaultInfo[] = [];
        for (const vault of allVaults) {
            if (vault.delegator === ZERO_ADDRESS) continue;

            const pinnedOp = this.pinnedOperator(vault);
            if (pinnedOp && pinnedOp !== op) continue;
            if (!pinnedOp) genericVaults.push(vault);
        }

        const optinCalls = genericVaults.map((vault) => ({
            address: this.requireAddress("op_vault_opt_in"),
            abi: OperatorVaultOptInServiceAbi,
            functionName: "isOptedIn",
            args: [op, vault.vault],
        }));
        const optins = optinCalls.length ? await this.mc(optinCalls) : [];

        const optedGenericVaults = new Set<Address>();
        for (let i = 0; i < genericVaults.length; i++) {
            if (optins[i]) optedGenericVaults.add(genericVaults[i]!.vault);
        }

        const vaultsForOp: VaultInfo[] = [];
        for (const vault of allVaults) {
            if (vault.delegator === ZERO_ADDRESS) continue;

            const pinnedOp = this.pinnedOperator(vault);
            if (pinnedOp && pinnedOp !== op) continue;
            if (pinnedOp === op || optedGenericVaults.has(vault.vault)) vaultsForOp.push(vault);
        }

        // Pass 1: For each net, find vaults with non-zero limit (using the op-filtered vault set).
        const limitCalls: any[] = [];
        const eligibleVaultsByNet: VaultInfo[][] = new Array(nets.length);

        for (let netIdx = 0; netIdx < nets.length; netIdx++) {
            const net = nets[netIdx]!.net;
            const { calls, eligible } = this.buildLimitCallsForNet(net, vaultsForOp);
            eligibleVaultsByNet[netIdx] = eligible;
            limitCalls.push(...calls);
        }

        const limitResults = (await this.mc(limitCalls)) as bigint[];
        const vaultsWithLimitByNet: Array<Array<VaultInfo & { limit: StakeBySubnetwork }>> =
            nets.map(() => []);

        let limitOffset = 0;
        for (let netIdx = 0; netIdx < nets.length; netIdx++) {
            const eligible = eligibleVaultsByNet[netIdx] ?? [];
            for (const vault of eligible) {
                const {
                    stake: limit,
                    hasValue,
                    nextOffset,
                } = this.decodeStakeBySubnetwork(limitResults, limitOffset);
                limitOffset = nextOffset;
                if (hasValue) vaultsWithLimitByNet[netIdx]!.push({ ...vault, limit });
            }
        }

        // Pass 2: Stake lookups (net -> vault -> subnetwork) for vaults that have limits in that net.
        const stakeCalls: any[] = [];
        const stakeVaultsByNet: Array<Array<VaultInfo & { limit: StakeBySubnetwork }>> = nets.map(
            () => [],
        );

        for (let netIdx = 0; netIdx < nets.length; netIdx++) {
            const net = nets[netIdx]!.net;
            const subnetworks = this.subnetworksForNet(net);
            for (const vault of vaultsWithLimitByNet[netIdx] ?? []) {
                for (const subnetwork of subnetworks) {
                    stakeCalls.push({
                        address: vault.delegator,
                        abi: NetworkRestakeDelegatorAbi,
                        functionName: "stake",
                        args: [subnetwork, op],
                    });
                }
                stakeVaultsByNet[netIdx]!.push(vault);
            }
        }

        const stakeResults = (await this.mc(stakeCalls)) as bigint[];
        let stakeOffset = 0;

        for (let netIdx = 0; netIdx < nets.length; netIdx++) {
            const stakeVaults = stakeVaultsByNet[netIdx] ?? [];
            for (const vault of stakeVaults) {
                const { stake, hasValue, nextOffset } = this.decodeStakeBySubnetwork(
                    stakeResults,
                    stakeOffset,
                );
                stakeOffset = nextOffset;
                if (hasValue) out[netIdx]!.vaults.push({ ...vault, stake });
            }
        }

        return out;
    }

    async isNet(address: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: NetworkRegistryAbi,
                address: this.requireAddress("net_registry"),
                functionName: "isEntity",
                args: [address],
            }),
        );
    }

    async isOp(address: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: OperatorRegistryAbi,
                address: this.requireAddress("op_registry"),
                functionName: "isEntity",
                args: [address],
            }),
        );
    }

    async isVault(address: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: VaultFactoryAbi,
                address: this.requireAddress("vault_factory"),
                functionName: "isEntity",
                args: [address],
            }),
        );
    }

    async isOptedInVault(operator: Address, vault: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: OperatorVaultOptInServiceAbi,
                address: this.requireAddress("op_vault_opt_in"),
                functionName: "isOptedIn",
                args: [operator, vault],
            }),
        );
    }

    async isOptedInNet(operator: Address, net: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: OperatorNetworkOptInServiceAbi,
                address: this.requireAddress("op_net_opt_in"),
                functionName: "isOptedIn",
                args: [operator, net],
            }),
        );
    }

    async getEntityType(entity: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: NetworkRestakeDelegatorAbi,
            address: entity,
            functionName: "TYPE",
        });
    }

    async tryGetEntityType(entity: Address): Promise<bigint | undefined> {
        try {
            return await this.getEntityType(entity);
        } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            if (message.includes('The contract function "TYPE" returned no data')) return undefined;
            throw err;
        }
    }

    async getResolverSetEpochDelay(slasher: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VetoSlasherAbi,
            address: slasher,
            functionName: "resolverSetEpochsDelay",
        });
    }

    async getResolver(slasher: Address, subnetwork: Hex): Promise<Address> {
        const resolver = await this.read<Address>({
            abi: VetoSlasherAbi,
            address: slasher,
            functionName: "resolver",
            args: [subnetwork, "0x"],
        });
        return getAddress(resolver);
    }

    async getPendingResolver(slasher: Address, subnetwork: Hex): Promise<Address> {
        const MAX_UINT48 = (1n << 48n) - 1n;
        const resolver = await this.read<Address>({
            abi: VetoSlasherAbi,
            address: slasher,
            functionName: "resolverAt",
            args: [subnetwork, MAX_UINT48, "0x"],
        });
        return getAddress(resolver);
    }

    async getVaultEpochDuration(vault: Address): Promise<bigint> {
        const v = await this.read<number | bigint>({
            abi: VaultAbi,
            address: vault,
            functionName: "epochDuration",
        });
        return typeof v === "bigint" ? v : BigInt(v);
    }

    async getVaultCurrentEpoch(vault: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultAbi,
            address: vault,
            functionName: "currentEpoch",
        });
    }

    async getVaultCurrentEpochStart(vault: Address): Promise<bigint> {
        const v = await this.read<number | bigint>({
            abi: VaultAbi,
            address: vault,
            functionName: "currentEpochStart",
        });
        return typeof v === "bigint" ? v : BigInt(v);
    }

    async getMaxNetworkLimit(delegator: Address, subnetwork: Hex): Promise<bigint> {
        return this.read<bigint>({
            abi: FullRestakeDelegatorAbi,
            address: delegator,
            functionName: "maxNetworkLimit",
            args: [subnetwork],
        });
    }

    async getNetworkLimit(delegator: Address, subnetwork: Hex): Promise<bigint> {
        return this.read<bigint>({
            abi: FullRestakeDelegatorAbi,
            address: delegator,
            functionName: "networkLimit",
            args: [subnetwork],
        });
    }

    async getOperatorNetworkLimit(
        delegator: Address,
        subnetwork: Hex,
        operator: Address,
    ): Promise<bigint> {
        return this.read<bigint>({
            abi: FullRestakeDelegatorAbi,
            address: delegator,
            functionName: "operatorNetworkLimit",
            args: [subnetwork, operator],
        });
    }

    async getOperatorNetworkShares(
        delegator: Address,
        subnetwork: Hex,
        operator: Address,
    ): Promise<bigint> {
        return this.read<bigint>({
            abi: NetworkRestakeDelegatorAbi,
            address: delegator,
            functionName: "operatorNetworkShares",
            args: [subnetwork, operator],
        });
    }

    async getTotalOperatorNetworkShares(delegator: Address, subnetwork: Hex): Promise<bigint> {
        return this.read<bigint>({
            abi: NetworkRestakeDelegatorAbi,
            address: delegator,
            functionName: "totalOperatorNetworkShares",
            args: [subnetwork],
        });
    }

    async getStakeByDelegator(
        delegator: Address,
        subnetwork: Hex,
        operator: Address,
    ): Promise<bigint> {
        return this.read<bigint>({
            abi: NetworkRestakeDelegatorAbi,
            address: delegator,
            functionName: "stake",
            args: [subnetwork, operator],
        });
    }

    async getStake(vault: Address, subnetwork: Hex, operator: Address): Promise<bigint> {
        const delegator = await this.getVaultDelegator(vault);
        return this.getStakeByDelegator(delegator, subnetwork, operator);
    }

    async getAllowance(token: Address, owner: Address, spender: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultTokenizedAbi,
            address: token,
            functionName: "allowance",
            args: [owner, spender],
        });
    }

    async getActiveBalance(vault: Address, account: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultAbi,
            address: vault,
            functionName: "activeBalanceOf",
            args: [account],
        });
    }

    async getWithdrawals(vault: Address, epoch: bigint, account: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultAbi,
            address: vault,
            functionName: "withdrawalsOf",
            args: [epoch, account],
        });
    }

    async getWithdrawalsClaimed(vault: Address, epoch: bigint, account: Address): Promise<boolean> {
        return Boolean(
            await this.read<boolean>({
                abi: VaultAbi,
                address: vault,
                functionName: "isWithdrawalsClaimed",
                args: [epoch, account],
            }),
        );
    }

    async getOperatorNetworkOptInNonce(who: Address, where: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: OperatorNetworkOptInServiceAbi,
            address: this.requireAddress("op_net_opt_in"),
            functionName: "nonces",
            args: [who, where],
        });
    }

    async getOperatorVaultOptInNonce(who: Address, where: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: OperatorVaultOptInServiceAbi,
            address: this.requireAddress("op_vault_opt_in"),
            functionName: "nonces",
            args: [who, where],
        });
    }

    // Rewards (optional)
    async getCurator(vault: Address): Promise<Address> {
        const curator = await this.read<Address>({
            abi: CuratorRegistryAbi,
            address: this.requireAddress("curator_registry"),
            functionName: "getCurator",
            args: [vault],
        });
        return getAddress(curator);
    }

    async getOperatorsFee(vault: Address, network: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: FeeRegistryAbi,
            address: this.requireAddress("fee_registry"),
            functionName: "getOperatorsFee",
            args: [vault, network],
        });
    }

    async getCuratorFee(vault: Address, network: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: FeeRegistryAbi,
            address: this.requireAddress("fee_registry"),
            functionName: "getCuratorFee",
            args: [vault, network],
        });
    }

    async protocolFee(rewardsType: bigint, network: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: ProtocolFeesAbi,
            address: this.requireAddress("rewards"),
            functionName: "protocolFee",
            args: [rewardsType, network],
        });
    }

    async curatorFees(vault: Address, token: Address): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultSnapshotRewardsAbi,
            address: this.requireAddress("rewards"),
            functionName: "curatorFees",
            args: [vault, token],
        });
    }

    async lastUnclaimedReward(
        account: Address,
        vault: Address,
        network: Address,
        token: Address,
    ): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultSnapshotRewardsAbi,
            address: this.requireAddress("rewards"),
            functionName: "lastUnclaimedReward",
            args: [account, vault, network, token],
        });
    }

    async lastUnclaimedOperatorReward(
        account: Address,
        vault: Address,
        network: Address,
        token: Address,
    ): Promise<bigint> {
        return this.read<bigint>({
            abi: VaultSnapshotRewardsAbi,
            address: this.requireAddress("rewards"),
            functionName: "lastUnclaimedOperatorReward",
            args: [account, vault, network, token],
        });
    }

    async previewVaultSnapshotRewards(args: {
        staker: Address;
        vault: Address;
        network: Address;
        token: Address;
        firstRewardToClaim?: bigint;
        maxRewards?: bigint;
        lastUnclaimedOverride?: bigint;
    }): Promise<{
        staker: Address;
        vault: Address;
        network: Address;
        token: Address;
        amount: bigint;
        lastUnclaimedRewards: bigint;
        firstClaimedReward: bigint;
        rewardsClaimed: bigint;
        rewardsLength: bigint;
    }> {
        const staker = getAddress(args.staker);
        const vault = getAddress(args.vault);
        const network = getAddress(args.network);
        const token = getAddress(args.token);

        const rewards = this.requireAddress("rewards");
        const rewardsLength = await this.read<bigint>({
            abi: VaultSnapshotRewardsAbi,
            address: rewards,
            functionName: "rewardsLength",
            args: [vault, network, token],
        });

        const lastUnclaimedRewards =
            args.lastUnclaimedOverride ??
            (await this.lastUnclaimedReward(staker, vault, network, token));

        const firstArg = args.firstRewardToClaim ?? 0n;
        const firstClaimedReward =
            firstArg > lastUnclaimedRewards ? firstArg : lastUnclaimedRewards;

        const available =
            rewardsLength > firstClaimedReward ? rewardsLength - firstClaimedReward : 0n;
        const maxRewards = args.maxRewards ?? 1_000_000n;
        const rewardsClaimed = maxRewards < available ? maxRewards : available;

        if (rewardsClaimed === 0n) {
            return {
                staker,
                vault,
                network,
                token,
                amount: 0n,
                lastUnclaimedRewards,
                firstClaimedReward,
                rewardsClaimed,
                rewardsLength,
            };
        }

        const count = Number(rewardsClaimed);
        const rewardCalls: any[] = [];
        for (let i = 0; i < count; i++) {
            rewardCalls.push({
                address: rewards,
                abi: VaultSnapshotRewardsAbi,
                functionName: "rewards",
                args: [vault, network, token, firstClaimedReward + BigInt(i)],
            });
        }

        const distributions = (await this.mc(rewardCalls)) as RewardDistribution[];

        const timestamps: bigint[] = [];
        const timestampIndex = new Map<bigint, number>();
        for (const r of distributions) {
            const ts = r.timestamp;
            if (!timestampIndex.has(ts)) {
                timestampIndex.set(ts, timestamps.length);
                timestamps.push(ts);
            }
        }

        const totalSharesCalls = timestamps.map((timestamp) => ({
            address: vault,
            abi: VaultAbi,
            functionName: "activeSharesAt",
            args: [timestamp, "0x"],
        }));
        const sharesOfCalls = timestamps.map((timestamp) => ({
            address: vault,
            abi: VaultAbi,
            functionName: "activeSharesOfAt",
            args: [staker, timestamp, "0x"],
        }));

        const [totalSharesAt, sharesOfAt] = await Promise.all([
            this.mc(totalSharesCalls),
            this.mc(sharesOfCalls),
        ]);

        let amount = 0n;
        for (const r of distributions) {
            const idx = timestampIndex.get(r.timestamp)!;
            const total = totalSharesAt[idx] as bigint;
            if (total === 0n) {
                throw new Error(`Invalid reward timestamp (activeSharesAt=0): ${r.timestamp}`);
            }
            const shares = sharesOfAt[idx] as bigint;
            amount += (shares * r.amount) / total;
        }

        return {
            staker,
            vault,
            network,
            token,
            amount,
            lastUnclaimedRewards,
            firstClaimedReward,
            rewardsClaimed,
            rewardsLength,
        };
    }

    async previewOperatorFees(args: {
        operator: Address;
        vault: Address;
        network: Address;
        token: Address;
        firstRewardToClaim?: bigint;
        maxRewards?: bigint;
        lastUnclaimedOverride?: bigint;
    }): Promise<{
        operator: Address;
        vault: Address;
        network: Address;
        token: Address;
        amount: bigint;
        lastUnclaimedRewards: bigint;
        firstClaimedReward: bigint;
        rewardsClaimed: bigint;
        rewardsLength: bigint;
    }> {
        const operator = getAddress(args.operator);
        const vault = getAddress(args.vault);
        const network = getAddress(args.network);
        const token = getAddress(args.token);

        const rewards = this.requireAddress("rewards");
        const rewardsLength = await this.read<bigint>({
            abi: VaultSnapshotRewardsAbi,
            address: rewards,
            functionName: "rewardsLength",
            args: [vault, network, token],
        });

        const lastUnclaimedRewards =
            args.lastUnclaimedOverride ??
            (await this.lastUnclaimedOperatorReward(operator, vault, network, token));

        const firstArg = args.firstRewardToClaim ?? 0n;
        const firstClaimedReward =
            firstArg > lastUnclaimedRewards ? firstArg : lastUnclaimedRewards;

        const available =
            rewardsLength > firstClaimedReward ? rewardsLength - firstClaimedReward : 0n;
        const maxRewards = args.maxRewards ?? 1_000_000n;
        const rewardsClaimed = maxRewards < available ? maxRewards : available;

        if (rewardsClaimed === 0n) {
            return {
                operator,
                vault,
                network,
                token,
                amount: 0n,
                lastUnclaimedRewards,
                firstClaimedReward,
                rewardsClaimed,
                rewardsLength,
            };
        }

        const count = Number(rewardsClaimed);
        const rewardCalls: any[] = [];
        for (let i = 0; i < count; i++) {
            rewardCalls.push({
                address: rewards,
                abi: VaultSnapshotRewardsAbi,
                functionName: "rewards",
                args: [vault, network, token, firstClaimedReward + BigInt(i)],
            });
        }

        const distributions = (await this.mc(rewardCalls)) as RewardDistribution[];

        const delegatorOperatorCalls: any[] = [];
        const delegatorOperatorAddrByKey = new Map<string, Address>();
        const restakeCalls: any[] = [];
        const restakeParts: Array<{ operatorsFees: bigint; idx: number }> = [];

        for (let i = 0; i < distributions.length; i++) {
            const r = distributions[i]!;
            if (r.delegatorType === 1n) {
                throw new Error(
                    `Invalid delegator type for operator fees (FullRestake) at reward index ${firstClaimedReward + BigInt(i)}`,
                );
            }

            if (r.delegatorType === 0n) {
                const subnetwork = encodeSubnetwork({ net: network, subnetId: r.subnetworkId });
                restakeCalls.push({
                    address: r.delegator,
                    abi: NetworkRestakeDelegatorAbi,
                    functionName: "operatorNetworkSharesAt",
                    args: [subnetwork, operator, r.timestamp, "0x"],
                });
                restakeCalls.push({
                    address: r.delegator,
                    abi: NetworkRestakeDelegatorAbi,
                    functionName: "totalOperatorNetworkSharesAt",
                    args: [subnetwork, r.timestamp, "0x"],
                });
                restakeParts.push({ operatorsFees: r.operatorsFees, idx: i });
            } else if (r.delegatorType === 2n || r.delegatorType === 3n) {
                const key = getAddress(r.delegator).toLowerCase();
                if (!delegatorOperatorAddrByKey.has(key)) {
                    const abi =
                        r.delegatorType === 2n
                            ? OperatorSpecificDelegatorAbi
                            : OperatorNetworkSpecificDelegatorAbi;
                    delegatorOperatorAddrByKey.set(key, getAddress(r.delegator));
                    delegatorOperatorCalls.push({
                        address: r.delegator,
                        abi,
                        functionName: "operator",
                    });
                }
            }
        }

        const [restakeResults, delegatorOperators] = await Promise.all([
            restakeCalls.length ? this.mc(restakeCalls) : Promise.resolve([]),
            delegatorOperatorCalls.length ? this.mc(delegatorOperatorCalls) : Promise.resolve([]),
        ]);

        const operatorByDelegator = new Map<string, Address>();
        for (let i = 0; i < delegatorOperatorCalls.length; i++) {
            const call = delegatorOperatorCalls[i]!;
            const delegator = getAddress(call.address as Address).toLowerCase();
            operatorByDelegator.set(delegator, getAddress(delegatorOperators[i] as Address));
        }

        let amount = 0n;

        // NETWORK_RESTAKE: results are paired (shares, totalShares).
        for (let i = 0; i < restakeParts.length; i++) {
            const shares = restakeResults[i * 2] as bigint;
            const totalShares = restakeResults[i * 2 + 1] as bigint;
            if (totalShares === 0n) {
                throw new Error(
                    `Invalid reward timestamp (totalOperatorNetworkSharesAt=0) at reward index ${firstClaimedReward + BigInt(restakeParts[i]!.idx)}`,
                );
            }
            const fee = restakeParts[i]!.operatorsFees;
            amount += (shares * fee) / totalShares;
        }

        // OPERATOR_SPECIFIC / OPERATOR_NETWORK_SPECIFIC: operatorsFees is fully claimable by the pinned operator.
        for (let i = 0; i < distributions.length; i++) {
            const r = distributions[i]!;
            if (r.delegatorType !== 2n && r.delegatorType !== 3n) continue;
            if (r.operatorsFees === 0n) continue;

            const delegator = getAddress(r.delegator).toLowerCase();
            const pinned = operatorByDelegator.get(delegator);
            if (!pinned) {
                throw new Error(`Failed to resolve operator for delegator: ${r.delegator}`);
            }
            if (pinned !== operator) {
                throw new Error(
                    `Not operator for delegator ${r.delegator} at reward index ${firstClaimedReward + BigInt(i)}`,
                );
            }
            amount += r.operatorsFees;
        }

        return {
            operator,
            vault,
            network,
            token,
            amount,
            lastUnclaimedRewards,
            firstClaimedReward,
            rewardsClaimed,
            rewardsLength,
        };
    }

    delegatorTypeName(type: bigint) {
        return DELEGATOR_TYPES_NAMES[Number(type)] ?? "Unknown";
    }

    slasherTypeName(type: bigint) {
        return SLASHER_TYPES_NAMES[Number(type)] ?? "Unknown";
    }
}
```

## File: src/core/time.ts

```typescript
export function formatUnixTimestampSeconds(timestamp: bigint) {
    const ms = Number(timestamp) * 1000;
    if (!Number.isFinite(ms)) return timestamp.toString();

    const d = new Date(ms);
    const pad = (n: number) => String(n).padStart(2, "0");
    const yyyy = d.getFullYear();
    const mm = pad(d.getMonth() + 1);
    const dd = pad(d.getDate());
    const hh = pad(d.getHours());
    const mi = pad(d.getMinutes());
    const ss = pad(d.getSeconds());
    return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
}
```

## File: src/core/tx.ts

```typescript
import type { Abi, Address, Chain, Hash, PublicClient, Transport, WalletClient } from "viem";
import { createWalletClient } from "viem";
import type { Account } from "viem/accounts";
import ora from "ora";

import { createViemTransport, type ResolvedClientConfig } from "./client";
import { confirmOrExit } from "./confirm";
import { printJson, printLine, type OutputMode } from "./output";
import { canUseSpinner } from "./spinner";

export function createWalletClientForAccount(
    resolved: ResolvedClientConfig,
    account: Account | Address,
): WalletClient<Transport, Chain, Account> {
    if (typeof account === "string") {
        throw new Error(
            "Sending transactions with --from is not supported. Use --dry-run, or sign via --private-key/--ledger.",
        );
    }

    return createWalletClient({
        chain: resolved.viemChain,
        transport: createViemTransport(resolved),
        account,
    });
}

export type SimulateWriteArgs = {
    publicClient: PublicClient<Transport, Chain>;
    account: Account | Address;
    abi: Abi;
    address: Address;
    functionName: string;
    args?: readonly unknown[];
};

export async function simulateWriteRequest(args: SimulateWriteArgs) {
    const { request } = await args.publicClient.simulateContract({
        address: args.address,
        abi: args.abi,
        functionName: args.functionName as any,
        args: args.args as any,
        account: args.account,
    });
    return request;
}

export async function sendWriteRequest(args: {
    walletClient: WalletClient<Transport, Chain, Account>;
    request: any;
}): Promise<Hash> {
    return args.walletClient.writeContract(args.request);
}

export async function runWriteTx(args: {
    mode: OutputMode;
    resolved: ResolvedClientConfig;
    publicClient: PublicClient<Transport, Chain>;
    account: Account | Address;
    abi: Abi;
    address: Address;
    functionName: string;
    args?: readonly unknown[];
    dryRun?: boolean;
    yes?: boolean;
    confirmMessage?: string;
    successMessage?: string;
}): Promise<Hash | undefined> {
    const canSpin = canUseSpinner(args.mode);

    const renderArg = (value: unknown) => {
        if (typeof value === "bigint") return value.toString();
        if (typeof value === "string") return value;
        if (value === null || value === undefined) return String(value);
        if (typeof value === "number" || typeof value === "boolean") return String(value);
        try {
            return JSON.stringify(value, (_k, v) => (typeof v === "bigint" ? v.toString() : v));
        } catch {
            return String(value);
        }
    };

    const defaultConfirmMessage = () => {
        const renderedArgs = (args.args ?? []).map(renderArg).join(", ");
        const call = `${args.functionName}(${renderedArgs})`;
        return `Send transaction on chainId=${args.resolved.chainId}: ${call} -> ${args.address}?`;
    };

    const simulateLabel = canSpin ? ora("Simulating...").start() : undefined;
    let request: any;
    try {
        request = await simulateWriteRequest({
            publicClient: args.publicClient,
            account: args.account,
            abi: args.abi,
            address: args.address,
            functionName: args.functionName,
            args: args.args,
        });
    } finally {
        simulateLabel?.stop();
    }

    if (args.dryRun) {
        if (args.mode.json) printJson({ dryRun: true });
        else printLine("Simulated successfully.");
        return undefined;
    }

    const walletClient = createWalletClientForAccount(args.resolved, args.account);

    if (!args.yes) {
        // Avoid breaking machine-readable output with interactive prompts.
        if (args.mode.json) {
            throw new Error("Write confirmation is required. Re-run with --yes when using --json.");
        }
        if (!process.stdin.isTTY) {
            throw new Error(
                "Write confirmation is required. Re-run with --yes in non-interactive environments.",
            );
        }

        const ok = await confirmOrExit({
            yes: args.yes,
            message: args.confirmMessage ?? defaultConfirmMessage(),
        });
        if (!ok) return undefined;
    }

    const hash = await sendWriteRequest({ walletClient, request });

    if (args.mode.json) {
        await args.publicClient.waitForTransactionReceipt({ hash });
        printJson({ hash });
        return hash;
    }

    if (canSpin) {
        printLine(`Transaction sent: ${hash}`);
        const spinner = ora("Waiting for transaction receipt...").start();
        try {
            await args.publicClient.waitForTransactionReceipt({ hash });
        } finally {
            spinner.stop();
        }
    } else {
        printLine(`Transaction sent: ${hash}, waiting...`);
        await args.publicClient.waitForTransactionReceipt({ hash });
    }

    if (args.successMessage) printLine(args.successMessage);
    return hash;
}
```

## File: src/core/types.ts

```typescript
import type { Address } from "viem";

export type TokenMeta = { symbol: string; decimals: number };

export type NetInfo = { net: Address; middleware: Address };

export type StakeBySubnetwork = Record<number, bigint>;

export type VaultInfo = {
    vault: Address;
    collateral: Address;
    tvl: bigint;
    delegator: Address;
    slasher: Address;
    delegatorType: bigint;
    slasherType: bigint;
    delegatorOperator?: Address;
    delegatorNetwork?: Address;
};
```

## File: src/core/units.ts

```typescript
import { formatUnits, parseUnits } from "viem";

import type { TokenMeta } from "./types";

export function formatTokenAmount(value: bigint, meta: TokenMeta): string {
    if (meta.decimals === 0) return value.toString();
    return formatUnits(value, meta.decimals);
}

export function parseTokenAmount(amount: string, meta: TokenMeta): bigint {
    if (meta.decimals === 0) {
        throw new Error("Token decimals are unknown; cannot parse token units");
    }
    // viem validates decimal format; this also rejects negative numbers.
    const parsed = parseUnits(amount, meta.decimals);
    if (parsed <= 0n) throw new Error("Token amount should be > 0");
    return parsed;
}

export function tokenMetaFallback(): TokenMeta {
    return { symbol: "Unknown", decimals: 0 };
}
```

## File: src/index.ts

```typescript
import { createProgram } from "./cli/program";

const program = createProgram();

// `tsx` may forward `--` into argv. Commander treats args after `--` as operands,
// which breaks `pnpm dev -- --help`.
const argv = process.argv.filter((arg) => arg !== "--");
await program.parseAsync(argv);
```

## File: test/clientConfig.test.ts

```typescript
import { afterEach, beforeEach, describe, expect, it } from "vitest";

import { CHAIN_CONFIGS } from "../src/config/chains";
import { resolveClientConfig } from "../src/core/client";

const ENV_KEYS = ["SYMB_RPC_URL"] as const;

describe("resolveClientConfig", () => {
    const oldEnv: Partial<Record<(typeof ENV_KEYS)[number], string | undefined>> = {};

    beforeEach(() => {
        for (const k of ENV_KEYS) {
            oldEnv[k] = process.env[k];
            delete process.env[k];
        }
    });

    afterEach(() => {
        for (const k of ENV_KEYS) {
            const v = oldEnv[k];
            if (v === undefined) delete process.env[k];
            else process.env[k] = v;
        }
    });

    it("uses chain default RPC URLs when no override", async () => {
        const cfg = await resolveClientConfig({ chain: "mainnet" });
        expect(cfg.rpcUrls).toEqual(CHAIN_CONFIGS.mainnet.defaultRpcUrls);
        expect(cfg.rpcUrl).toBe(CHAIN_CONFIGS.mainnet.defaultRpcUrls[0]);
    });

    it("prefers --rpc over env", async () => {
        process.env.SYMB_RPC_URL = "https://env.example";

        const a = await resolveClientConfig({ chain: "mainnet" });
        expect(a.rpcUrls).toEqual(["https://env.example"]);
        expect(a.rpcUrl).toBe("https://env.example");

        const b = await resolveClientConfig({ chain: "mainnet", rpc: "https://rpc.example" });
        expect(b.rpcUrls).toEqual(["https://rpc.example"]);
        expect(b.rpcUrl).toBe("https://rpc.example");
    });

    it("uses chain default addresses", async () => {
        const cfg = await resolveClientConfig({ chain: "mainnet" });
        expect(cfg.addresses).toEqual(CHAIN_CONFIGS.mainnet.addresses);
    });
});
```

## File: test/cliHelp.test.ts

```typescript
import { describe, expect, it } from "vitest";
import type { Command } from "commander";

import { createProgram } from "../src/cli/program";

function findCommand(root: Command, path: string[]) {
    let current: Command | undefined = root;
    for (const segment of path) {
        current = current?.commands.find((command) => command.name() === segment);
    }
    return current;
}

describe("cli help", () => {
    it("root help only shows groups", () => {
        const program = createProgram();
        const help = program.helpInformation();

        for (const name of ["net", "op", "vault", "staker", "rewards"]) {
            expect(help).toMatch(new RegExp(`\\n\\s+${name}\\b`));
        }

        // Spot-check: leaf commands should not show up in root help.
        for (const legacy of ["isnet", "nets", "ops", "vaults", "rewards-protocol-fee"]) {
            expect(help).not.toMatch(new RegExp(`\\n\\s+${legacy}\\b`));
        }

        // Legacy commands should not be registered.
        const rootNames = new Set(program.commands.map((c) => c.name()));
        for (const legacy of ["isnet", "nets", "ops", "vaults", "rewards-protocol-fee"]) {
            expect(rootNames.has(legacy)).toBe(false);
        }
    });

    it("group help is scoped", () => {
        const program = createProgram();
        const net = program.commands.find((c) => c.name() === "net");
        expect(net).toBeTruthy();

        const netHelp = net!.helpInformation();
        expect(netHelp).toMatch(/\n\s+list(\||\s)/);
        expect(netHelp).toMatch(/\n\s+middleware\b/);
        expect(netHelp).toMatch(/\n\s+max-network-limit\b/);
        expect(netHelp).toMatch(/\n\s+resolver\b/);
        expect(netHelp).toMatch(/\n\s+pending-resolver\b/);
        expect(netHelp).not.toMatch(/\n\s+nets\b/);

        const vault = program.commands.find((c) => c.name() === "vault");
        expect(vault).toBeTruthy();

        const vaultHelp = vault!.helpInformation();
        expect(vaultHelp).toMatch(/\n\s+network-limit\b/);
        expect(vaultHelp).not.toMatch(/\n\s+max-network-limit\b/);
        expect(vaultHelp).not.toMatch(/\n\s+resolver\b/);
        expect(vaultHelp).not.toMatch(/\n\s+pending-resolver\b/);

        const rewards = program.commands.find((c) => c.name() === "rewards");
        expect(rewards).toBeTruthy();

        const rewardsHelp = rewards!.helpInformation();
        expect(rewardsHelp).toMatch(/\n\s+protocol-fee\b/);
        expect(rewardsHelp).toMatch(/\n\s+vault-snapshot-rewards\b/);
        expect(rewardsHelp).toMatch(/\n\s+operator-fees\b/);
        expect(rewardsHelp).not.toMatch(/\n\s+rewards-protocol-fee\b/);
    });

    it("subcommand help works for commands with bigint defaults", () => {
        const program = createProgram();

        const commandPaths = [
            ["net", "set-resolver"],
            ["op", "opt-in-vault-sig"],
            ["vault", "set-network-limit"],
            ["rewards", "vault-snapshot-rewards"],
            ["rewards", "claim-vault-snapshot-rewards"],
        ];

        for (const path of commandPaths) {
            const command = findCommand(program, path);
            expect(command, `missing command: ${path.join(" ")}`).toBeTruthy();
            expect(() => command!.helpInformation()).not.toThrow();
        }
    });
});
```

## File: test/confirm.test.ts

```typescript
import prompts from "prompts";
import { beforeEach, describe, expect, it, vi } from "vitest";

import { confirmOrExit } from "../src/core/confirm";

vi.mock("prompts", () => ({ default: vi.fn() }));

describe("confirmOrExit", () => {
    const promptsMock = vi.mocked(prompts);

    beforeEach(() => {
        promptsMock.mockReset();
        process.exitCode = undefined;
    });

    it("bypasses prompt when yes=true", async () => {
        const ok = await confirmOrExit({ message: "x", yes: true });
        expect(ok).toBe(true);
        expect(promptsMock).not.toHaveBeenCalled();
        expect(process.exitCode).toBeUndefined();
    });

    it("returns true when confirmed", async () => {
        promptsMock.mockResolvedValueOnce({ ok: true } as any);
        const ok = await confirmOrExit({ message: "x" });
        expect(ok).toBe(true);
        expect(process.exitCode).toBeUndefined();
    });

    it("returns false, prints Cancel, and sets exitCode=1 when declined", async () => {
        promptsMock.mockResolvedValueOnce({ ok: false } as any);
        const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true as any);

        const ok = await confirmOrExit({ message: "x" });
        expect(ok).toBe(false);
        expect(process.exitCode).toBe(1);
        expect(writeSpy).toHaveBeenCalledWith("Cancel\n");

        writeSpy.mockRestore();
    });
});
```

## File: test/format.test.ts

```typescript
import { describe, expect, it } from "vitest";

import { formatPercent, groupBy } from "../src/core/format";

describe("format", () => {
    it("formatPercent handles denominator=0", () => {
        expect(formatPercent(1n, 0n)).toBe("0");
    });

    it("formatPercent renders 2 decimals", () => {
        expect(formatPercent(1n, 2n)).toBe("50.00");
        expect(formatPercent(1n, 4n)).toBe("25.00");
    });

    it("groupBy groups items by key", () => {
        const items = [
            { collateral: "a", v: 1 },
            { collateral: "a", v: 2 },
            { collateral: "b", v: 3 },
        ];

        const by = groupBy(items, (i) => i.collateral);
        expect(by.get("a")?.map((x) => x.v)).toEqual([1, 2]);
        expect(by.get("b")?.map((x) => x.v)).toEqual([3]);
    });
});
```

## File: test/ledgerAccount.test.ts

```typescript
import { beforeEach, describe, expect, it, vi } from "vitest";

const mocks = vi.hoisted(() => ({
    createTransport: vi.fn(),
    closeTransport: vi.fn(),
    getAddress: vi.fn(),
    signPersonalMessage: vi.fn(),
    signTransaction: vi.fn(),
    signEIP712HashedMessage: vi.fn(),
}));

vi.mock("@ledgerhq/hw-transport-node-hid", () => ({
    default: {
        default: {
            create: mocks.createTransport,
        },
    },
}));

vi.mock("@ledgerhq/hw-app-eth", () => ({
    default: {
        default: class EthMock {
            constructor() {}

            getAddress = mocks.getAddress;
            signPersonalMessage = mocks.signPersonalMessage;
            signTransaction = mocks.signTransaction;
            signEIP712HashedMessage = mocks.signEIP712HashedMessage;
        },
    },
}));

describe("createLedgerAccount", () => {
    const defaultPath = "m/44'/60'/0'/0/0";
    const ledgerLivePath = "m/44'/60'/7'/0/0";
    const legacyPath = "m/44'/60'/0'/7";
    const ledgerAddress = "0x8ba1f109551bd432803012645ac136ddd64dba72";
    const ledgerLiveAddress = "0x0000000000000000000000000000000000000007";
    const legacyAddress = "0x0000000000000000000000000000000000000008";

    beforeEach(() => {
        vi.resetModules();
        vi.clearAllMocks();

        mocks.createTransport.mockResolvedValue({
            close: mocks.closeTransport,
        });
        mocks.getAddress.mockImplementation(async (path: string) => {
            if (path === ledgerLivePath) return { address: ledgerLiveAddress };
            if (path === legacyPath) return { address: legacyAddress };
            return { address: ledgerAddress };
        });
        mocks.signPersonalMessage.mockResolvedValue({
            r: "1".padStart(64, "0"),
            s: "2".padStart(64, "0"),
            v: 27,
        });
        mocks.signTransaction.mockResolvedValue({
            r: "3".padStart(64, "0"),
            s: "4".padStart(64, "0"),
            v: "1b",
        });
        mocks.signEIP712HashedMessage.mockResolvedValue({
            r: "5".padStart(64, "0"),
            s: "6".padStart(64, "0"),
            v: 27,
        });
    });

    it("creates a ledger-backed account and closes transport", async () => {
        const { createLedgerAccount } = await import("../src/core/signing/ledger");
        const out = await createLedgerAccount({});

        expect(out.address).toBe("0x8ba1f109551bD432803012645Ac136ddd64DBA72");
        expect(mocks.getAddress).toHaveBeenCalledWith(defaultPath, false, false);

        await out.close();
        expect(mocks.closeTransport).toHaveBeenCalledTimes(1);
    });

    it("derives a Ledger Live account path from the expected address", async () => {
        const { createLedgerAccount } = await import("../src/core/signing/ledger");
        const { account, address } = await createLedgerAccount({
            expectedAddress: ledgerLiveAddress,
        });
        const signer = account as any;

        expect(address).toBe("0x0000000000000000000000000000000000000007");

        await signer.signMessage({ message: "hello" });
        expect(mocks.signPersonalMessage).toHaveBeenCalledWith(ledgerLivePath, "68656c6c6f");
    });

    it("derives a legacy Ledger path from the expected address", async () => {
        const { createLedgerAccount } = await import("../src/core/signing/ledger");
        const { account, address } = await createLedgerAccount({
            expectedAddress: legacyAddress,
        });
        const signer = account as any;

        expect(address).toBe("0x0000000000000000000000000000000000000008");

        await signer.signMessage({ message: "hello" });
        expect(mocks.signPersonalMessage).toHaveBeenCalledWith(legacyPath, "68656c6c6f");
    });

    it("fails when the expected Ledger address is not found and closes transport", async () => {
        const { createLedgerAccount } = await import("../src/core/signing/ledger");

        await expect(
            createLedgerAccount({ expectedAddress: "0x0000000000000000000000000000000000000001" }),
        ).rejects.toThrow("was not found in Ledger Ethereum derivation paths");

        expect(mocks.closeTransport).toHaveBeenCalledTimes(1);
    });

    it("uses Ledger methods for signMessage, signTransaction, signTypedData", async () => {
        const { createLedgerAccount } = await import("../src/core/signing/ledger");
        const { account } = await createLedgerAccount({});
        const signer = account as any;

        const signedMessage = await signer.signMessage({ message: "hello" });
        expect(signedMessage.startsWith("0x")).toBe(true);
        expect(mocks.signPersonalMessage).toHaveBeenCalledWith(defaultPath, "68656c6c6f");

        const serializer = vi.fn(async (_tx: unknown, sig?: unknown) =>
            sig ? "0xsigned-tx" : "0xunsigned-tx",
        );
        const signedTx = await signer.signTransaction({} as never, { serializer });
        expect(signedTx).toBe("0xsigned-tx");
        expect(mocks.signTransaction).toHaveBeenCalledWith(defaultPath, "unsigned-tx", null);
        expect(serializer).toHaveBeenCalledTimes(2);

        const signedTypedData = await signer.signTypedData({
            domain: {
                name: "Symbiotic CLI",
                version: "1",
                chainId: 1,
                verifyingContract: "0x0000000000000000000000000000000000000001",
            },
            types: {
                Mail: [{ name: "from", type: "address" }],
            },
            primaryType: "Mail",
            message: {
                from: "0x0000000000000000000000000000000000000002",
            },
        });

        expect(signedTypedData.startsWith("0x")).toBe(true);
        expect(mocks.signEIP712HashedMessage).toHaveBeenCalledTimes(1);
        const args = mocks.signEIP712HashedMessage.mock.calls[0]!;
        expect(args[0]).toBe(defaultPath);
        expect((args[1] as string).length).toBe(64);
        expect((args[2] as string).length).toBe(64);
    });
});
```

## File: test/multicallChunked.test.ts

```typescript
import { describe, expect, it } from "vitest";

import { multicallChunked } from "../src/core/multicall";

function sleep(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

describe("multicallChunked", () => {
    it("returns empty array for empty input", async () => {
        let calls = 0;
        const client = {
            multicall: async () => {
                calls++;
                return [];
            },
        } as any;

        const res = await multicallChunked(client, [], { batchSize: 10 });
        expect(res).toEqual([]);
        expect(calls).toBe(0);
    });

    it("preserves ordering across chunks even when requests resolve out-of-order", async () => {
        const batchSize = 500;
        const total = 1_200;
        const contracts = Array.from({ length: total }, (_, id) => ({ id })) as any[];

        let calls = 0;
        const client = {
            multicall: async (args: { contracts: any[]; batchSize?: number }) => {
                calls++;
                // Ensure we always pass the conservative calldata cap through.
                expect(args.batchSize).toBe(16_383);

                const firstId = args.contracts[0]?.id as number;
                const chunkIndex = Math.floor(firstId / batchSize);
                // Delay later chunks less to force out-of-order completion.
                await sleep((3 - chunkIndex) * 2);
                return args.contracts.map((c) => c.id);
            },
        } as any;

        const res = await multicallChunked(client, contracts, { batchSize, concurrency: 2 });
        expect(res).toHaveLength(total);
        for (let i = 0; i < total; i++) expect(res[i]).toBe(i);
        expect(calls).toBe(Math.ceil(total / batchSize));
    });
});
```

## File: test/output.test.ts

```typescript
import { describe, expect, it, vi } from "vitest";

import { printJson } from "../src/core/output";

describe("output", () => {
    it("printJson stringifies bigint and Map values", () => {
        const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true as any);

        printJson({ a: 1n, m: new Map([["k", 2n]]) });

        expect(writeSpy).toHaveBeenCalledTimes(1);
        const out = String(writeSpy.mock.calls[0]?.[0] ?? "");
        const parsed = JSON.parse(out);
        expect(parsed).toEqual({ a: "1", m: { k: "2" } });

        writeSpy.mockRestore();
    });
});
```

## File: test/parse.test.ts

```typescript
import { describe, expect, it } from "vitest";
import { getAddress } from "viem";

import {
    parseAddress,
    parseBytes32Hex,
    parseHex,
    parseUint48,
    parseUint96,
    parseUint256,
} from "../src/cli/parse";

describe("cli/parse", () => {
    it("parseAddress normalizes to checksum", () => {
        const raw = "0x9101eda106a443a0fa82375936d0d1680d5a64f5";
        expect(parseAddress(raw)).toBe(getAddress(raw));
    });

    it("parseUint256 accepts base-10 integers and rejects non-integers", () => {
        expect(parseUint256("0")).toBe(0n);
        expect(parseUint256("123")).toBe(123n);
        expect(() => parseUint256("-1")).toThrow();
        expect(() => parseUint256("1.5")).toThrow();
        expect(() => parseUint256("0x10")).toThrow();
        expect(() => parseUint256("abc")).toThrow();
    });

    it("parseUint96 and parseUint48 enforce bounds", () => {
        expect(parseUint96("0")).toBe(0n);
        expect(parseUint48("0")).toBe(0n);
        expect(() => parseUint96(String(2n ** 96n))).toThrow();
        expect(() => parseUint48(String(2n ** 48n))).toThrow();
    });

    it("parseBytes32Hex accepts with/without 0x prefix and validates length", () => {
        const noPrefix = "1".repeat(64);
        expect(parseBytes32Hex(noPrefix)).toBe(`0x${noPrefix}`);
        expect(parseBytes32Hex(`0x${noPrefix}`)).toBe(`0x${noPrefix}`);
        expect(() => parseBytes32Hex("0x1")).toThrow();
    });

    it("parseHex accepts with/without 0x prefix", () => {
        expect(parseHex("0x1234")).toBe("0x1234");
        expect(parseHex("1234")).toBe("0x1234");
        expect(() => parseHex("0xZZ")).toThrow();
    });
});
```

## File: test/signingLedgerResolve.test.ts

```typescript
import { beforeEach, describe, expect, it, vi } from "vitest";

const mocks = vi.hoisted(() => ({
    createLedgerAccount: vi.fn(),
    close: vi.fn(async () => {}),
}));

vi.mock("../src/core/signing/ledger", () => ({
    createLedgerAccount: mocks.createLedgerAccount,
}));

describe("ledger resolution in cli/signing", () => {
    beforeEach(() => {
        vi.resetModules();
        vi.clearAllMocks();

        mocks.createLedgerAccount.mockResolvedValue({
            account: { address: "0x0000000000000000000000000000000000000002" },
            address: "0x0000000000000000000000000000000000000002",
            close: mocks.close,
        });
    });

    it("delegates --ledger args to createLedgerAccount", async () => {
        const { resolveSigningAccount } = await import("../src/cli/signing");
        await resolveSigningAccount({
            ledger: true,
            ledgerAddress: "0x0000000000000000000000000000000000000002",
        });

        expect(mocks.createLedgerAccount).toHaveBeenCalledWith({
            expectedAddress: "0x0000000000000000000000000000000000000002",
        });
    });

    it("withSigningAccount closes ledger transport after callback", async () => {
        const { withSigningAccount } = await import("../src/cli/signing");

        await withSigningAccount({ ledger: true }, async ({ address }) => {
            expect(address).toBe("0x0000000000000000000000000000000000000002");
        });

        expect(mocks.close).toHaveBeenCalledTimes(1);
    });
});
```

## File: test/subnetwork.test.ts

```typescript
import { describe, expect, it } from "vitest";
import { getAddress } from "viem";

import { decodeSubnetwork, encodeSubnetwork } from "../src/core/subnetwork";

describe("subnetwork", () => {
    it("roundtrips address + subnetId", () => {
        const net = getAddress("0x9101eda106A443A0fA82375936D0D1680D5a64F5");
        const subnetwork0 = encodeSubnetwork({ net, subnetId: 0 });
        expect(subnetwork0).toHaveLength(66);
        expect(decodeSubnetwork(subnetwork0)).toEqual({ net, subnetId: 0n });

        const subnetwork1 = encodeSubnetwork({ net, subnetId: 1 });
        expect(decodeSubnetwork(subnetwork1)).toEqual({ net, subnetId: 1n });
    });

    it("rejects out-of-range subnetId", () => {
        const net = getAddress("0x9101eda106A443A0fA82375936D0D1680D5a64F5");
        expect(() => encodeSubnetwork({ net, subnetId: -1 })).toThrow();
        expect(() => encodeSubnetwork({ net, subnetId: 2n ** 96n })).toThrow();
    });
});
```

## File: test/symbioticClient.test.ts

```typescript
import { describe, expect, it, vi } from "vitest";
import { getAddress, type Address } from "viem";

import { CHAIN_CONFIGS } from "../src/config/chains";
import { ZERO_ADDRESS } from "../src/core/constants";
import { decodeSubnetwork } from "../src/core/subnetwork";
import { SymbioticClient } from "../src/core/symbiotic";
import type { NetInfo, StakeBySubnetwork, VaultInfo } from "../src/core/types";
import * as subnetwork from "../src/core/subnetwork";

function a(value: string): Address {
    return getAddress(value);
}

function makeVault(args: {
    vault: Address;
    delegator: Address;
    delegatorType: bigint;
    delegatorNetwork?: Address;
    delegatorOperator?: Address;
}): VaultInfo {
    return {
        vault: args.vault,
        collateral: a("0xcccccccccccccccccccccccccccccccccccccccc"),
        tvl: 0n,
        delegator: args.delegator,
        slasher: a("0xdddddddddddddddddddddddddddddddddddddddd"),
        delegatorType: args.delegatorType,
        slasherType: 0n,
        delegatorOperator: args.delegatorOperator,
        delegatorNetwork: args.delegatorNetwork,
    };
}

function makeClient(publicClient: { multicall: (args: any) => Promise<any[]> }) {
    return new SymbioticClient({
        chainKey: "mainnet",
        chainId: 1,
        addresses: CHAIN_CONFIGS.mainnet.addresses,
        publicClient: publicClient as any,
        multicallBatchSize: 1_000,
        multicallConcurrency: 4,
    });
}

describe("SymbioticClient (call building + StakeBySubnetwork decoding)", () => {
    it("getVaultNetsByDelegator builds calls in net->subnet order and filters empty limits", async () => {
        const delegator = a("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        const netA = a("0x1000000000000000000000000000000000000000");
        const netB = a("0x2000000000000000000000000000000000000000");

        const publicClient = {
            multicall: vi.fn().mockResolvedValueOnce([0n, 5n, 0n, 0n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getNets").mockResolvedValueOnce([
            { net: netA, middleware: ZERO_ADDRESS } satisfies NetInfo,
            { net: netB, middleware: ZERO_ADDRESS } satisfies NetInfo,
        ]);

        const res = await symb.getVaultNetsByDelegator(delegator);
        expect(res).toEqual([{ net: netA, limit: { 1: 5n } as StakeBySubnetwork }]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(1);
        const calls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(calls).toHaveLength(4);
        for (const c of calls) {
            expect(c.address).toBe(delegator);
            expect(c.functionName).toBe("maxNetworkLimit");
            expect(Array.isArray(c.args)).toBe(true);
            expect(c.args).toHaveLength(1);
        }

        const decoded = calls.map((c) => decodeSubnetwork(c.args[0]));
        expect(decoded.map((d) => d.net)).toEqual([netA, netA, netB, netB]);
        expect(decoded.map((d) => d.subnetId)).toEqual([0n, 1n, 0n, 1n]);
    });

    it("getNetVaults chooses limit function by delegatorType and decodes StakeBySubnetwork", async () => {
        const network = a("0x1000000000000000000000000000000000000000");
        const v1 = makeVault({
            vault: a("0x0100000000000000000000000000000000000000"),
            delegator: a("0x1111111111111111111111111111111111111111"),
            delegatorType: 3n,
            delegatorNetwork: network,
        });
        const v2 = makeVault({
            vault: a("0x0200000000000000000000000000000000000000"),
            delegator: a("0x2222222222222222222222222222222222222222"),
            delegatorType: 1n,
        });

        const publicClient = {
            multicall: vi.fn().mockResolvedValueOnce([0n, 10n, 0n, 0n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getVaults").mockResolvedValueOnce([v1, v2]);

        const res = await symb.getNetVaults(network);
        expect(res).toEqual([{ ...v1, limit: { 1: 10n } as StakeBySubnetwork }]);

        const calls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(calls).toHaveLength(4);
        expect(calls.slice(0, 2).map((c) => c.functionName)).toEqual([
            "maxNetworkLimit",
            "maxNetworkLimit",
        ]);
        expect(calls.slice(2).map((c) => c.functionName)).toEqual(["networkLimit", "networkLimit"]);

        const decoded = calls.map((c) => decodeSubnetwork(c.args[0]));
        expect(decoded.map((d) => d.net)).toEqual([network, network, network, network]);
        expect(decoded.map((d) => d.subnetId)).toEqual([0n, 1n, 0n, 1n]);
    });

    it("getNetOpsVaults decodes stakes per op/vault and precomputes subnetworks once", async () => {
        const network = a("0x1000000000000000000000000000000000000000");
        const op1 = a("0x9000000000000000000000000000000000000001");
        const op2 = a("0x9000000000000000000000000000000000000002");

        const vault1 = {
            ...makeVault({
                vault: a("0x0100000000000000000000000000000000000000"),
                delegator: a("0x1111111111111111111111111111111111111111"),
                delegatorType: 0n,
            }),
            limit: { 0: 1n } as StakeBySubnetwork,
        };
        const vault2 = {
            ...makeVault({
                vault: a("0x0200000000000000000000000000000000000000"),
                delegator: a("0x2222222222222222222222222222222222222222"),
                delegatorType: 0n,
            }),
            limit: { 1: 2n } as StakeBySubnetwork,
        };

        const publicClient = {
            multicall: vi
                .fn()
                // optins: vault1 op1 true, vault1 op2 false, vault2 op1 false, vault2 op2 true
                .mockResolvedValueOnce([true, false, false, true])
                // stakes: vault1 op1 [5,0], vault2 op2 [0,7]
                .mockResolvedValueOnce([5n, 0n, 0n, 7n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getNetVaults").mockResolvedValueOnce([vault1, vault2] as any);
        vi.spyOn(symb, "getNetOps").mockResolvedValueOnce([op1, op2]);

        const encodeSpy = vi.spyOn(subnetwork, "encodeSubnetwork");
        const res = await symb.getNetOpsVaults(network);

        expect(encodeSpy).toHaveBeenCalledTimes(2);
        encodeSpy.mockRestore();

        expect(res).toEqual([
            { op: op1, vaults: [{ ...vault1, stake: { 0: 5n } as StakeBySubnetwork }] },
            { op: op2, vaults: [{ ...vault2, stake: { 1: 7n } as StakeBySubnetwork }] },
        ]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(2);

        const optinCalls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(optinCalls).toHaveLength(4);
        for (const c of optinCalls) expect(c.functionName).toBe("isOptedIn");

        const stakeCalls = publicClient.multicall.mock.calls[1]?.[0]?.contracts as any[];
        expect(stakeCalls).toHaveLength(4);
        for (const c of stakeCalls) expect(c.functionName).toBe("stake");

        const decoded = stakeCalls.map((c) => decodeSubnetwork(c.args[0]));
        expect(decoded.every((d) => d.net === network)).toBe(true);
    });

    it("getNetOpsVaults prunes operator-specific vaults to their pinned operator", async () => {
        const network = a("0x1000000000000000000000000000000000000000");
        const op1 = a("0x9000000000000000000000000000000000000001");
        const op2 = a("0x9000000000000000000000000000000000000002");

        const vaultGeneric = {
            ...makeVault({
                vault: a("0x0100000000000000000000000000000000000000"),
                delegator: a("0x1111111111111111111111111111111111111111"),
                delegatorType: 0n,
            }),
            limit: { 0: 1n } as StakeBySubnetwork,
        };
        const vaultOpSpecific = {
            ...makeVault({
                vault: a("0x0200000000000000000000000000000000000000"),
                delegator: a("0x2222222222222222222222222222222222222222"),
                delegatorType: 2n,
                delegatorOperator: op1,
            }),
            limit: { 0: 1n } as StakeBySubnetwork,
        };

        const publicClient = {
            multicall: vi
                .fn()
                // optins: vaultGeneric op1 true, vaultGeneric op2 false
                .mockResolvedValueOnce([true, false])
                // stakes: vaultGeneric op1 [5,0], vaultOpSpecific op1 [0,7]
                .mockResolvedValueOnce([5n, 0n, 0n, 7n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getNetVaults").mockResolvedValueOnce([
            vaultGeneric,
            vaultOpSpecific,
        ] as any);
        vi.spyOn(symb, "getNetOps").mockResolvedValueOnce([op1, op2]);

        const res = await symb.getNetOpsVaults(network);
        expect(res).toEqual([
            {
                op: op1,
                vaults: [
                    { ...vaultGeneric, stake: { 0: 5n } as StakeBySubnetwork },
                    { ...vaultOpSpecific, stake: { 1: 7n } as StakeBySubnetwork },
                ],
            },
            { op: op2, vaults: [] },
        ]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(2);

        const optinCalls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(optinCalls).toHaveLength(2);
        expect(optinCalls.every((c) => c.functionName === "isOptedIn")).toBe(true);

        const stakeCalls = publicClient.multicall.mock.calls[1]?.[0]?.contracts as any[];
        // 1 generic vault * 1 opted-in op * 2 subnetworks + 1 pinned vault * 1 op * 2 subnetworks = 4 calls
        expect(stakeCalls).toHaveLength(4);
        expect(stakeCalls.every((c) => c.functionName === "stake")).toBe(true);
        expect(
            stakeCalls.some(
                (c) =>
                    c.address === vaultOpSpecific.delegator &&
                    Array.isArray(c.args) &&
                    c.args[1] === op2,
            ),
        ).toBe(false);
    });

    it("getNetsFullCounts batches ops opt-ins + vault limits for all nets", async () => {
        const netA = a("0x1000000000000000000000000000000000000000");
        const netB = a("0x2000000000000000000000000000000000000000");

        const op1 = a("0x9000000000000000000000000000000000000001");
        const op2 = a("0x9000000000000000000000000000000000000002");

        const vault1 = makeVault({
            vault: a("0x0100000000000000000000000000000000000000"),
            delegator: a("0x1111111111111111111111111111111111111111"),
            delegatorType: 0n,
        });
        const vault2 = makeVault({
            vault: a("0x0200000000000000000000000000000000000000"),
            delegator: a("0x2222222222222222222222222222222222222222"),
            delegatorType: 3n,
            delegatorNetwork: netB,
        });

        const nets = [
            { net: netA, middleware: ZERO_ADDRESS } satisfies NetInfo,
            { net: netB, middleware: ZERO_ADDRESS } satisfies NetInfo,
        ];

        const publicClient = {
            multicall: vi
                .fn()
                // ops opt-ins:
                // netA: op1 true, op2 true
                // netB: op1 false, op2 true
                .mockResolvedValueOnce([true, true, false, true])
                // limits:
                // netA: vault1 [0,10] (selected)
                // netB: vault1 [0,0] (skipped), vault2 [5,0] (selected)
                .mockResolvedValueOnce([0n, 10n, 0n, 0n, 5n, 0n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getOps").mockResolvedValueOnce([op1, op2]);
        vi.spyOn(symb, "getVaults").mockResolvedValueOnce([vault1, vault2]);

        const res = await symb.getNetsFullCounts(nets);
        expect(res).toEqual([
            { ops: 2, vaults: 1 },
            { ops: 1, vaults: 1 },
        ]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(2);

        const optinCalls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(optinCalls).toHaveLength(4);
        expect(optinCalls.every((c) => c.functionName === "isOptedIn")).toBe(true);

        const limitCalls = publicClient.multicall.mock.calls[1]?.[0]?.contracts as any[];
        expect(limitCalls).toHaveLength(6);
        expect(limitCalls.slice(0, 4).every((c) => c.functionName === "networkLimit")).toBe(true);
        expect(limitCalls.slice(4).every((c) => c.functionName === "maxNetworkLimit")).toBe(true);
        // Pinned-to-netB vault should not be queried against netA.
        expect(
            limitCalls.some(
                (c) => c.address === vault2.delegator && c.functionName === "networkLimit",
            ),
        ).toBe(false);
    });

    it("getVaultNetsOpsFull decodes stakes per net/op and filters empty", async () => {
        const vault1 = makeVault({
            vault: a("0x0100000000000000000000000000000000000000"),
            delegator: a("0x1111111111111111111111111111111111111111"),
            delegatorType: 0n,
        });
        const vault2 = makeVault({
            vault: a("0x0200000000000000000000000000000000000000"),
            delegator: a("0x2222222222222222222222222222222222222222"),
            delegatorType: 0n,
        });

        const netA = a("0x1000000000000000000000000000000000000000");
        const netB = a("0x2000000000000000000000000000000000000000");
        const op1 = a("0x9000000000000000000000000000000000000001");
        const op2 = a("0x9000000000000000000000000000000000000002");

        const publicClient = {
            multicall: vi
                .fn()
                // limits:
                // v1 netA [0,5] (selected), v1 netB [0,0] (skipped),
                // v2 netA [0,0] (skipped), v2 netB [1,0] (selected)
                .mockResolvedValueOnce([0n, 5n, 0n, 0n, 0n, 0n, 1n, 0n])
                // optins: v1 op1 true, v1 op2 false, v2 op1 true, v2 op2 true
                .mockResolvedValueOnce([true, false, true, true])
                // stakes:
                // v1 netA op1 [0,10],
                // v2 netB op1 [0,0] (filtered), v2 netB op2 [5,0]
                .mockResolvedValueOnce([0n, 10n, 0n, 0n, 5n, 0n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getNets").mockResolvedValueOnce([
            { net: netA, middleware: ZERO_ADDRESS } satisfies NetInfo,
            { net: netB, middleware: ZERO_ADDRESS } satisfies NetInfo,
        ]);
        vi.spyOn(symb, "getOps").mockResolvedValueOnce([op1, op2]);

        const encodeSpy = vi.spyOn(subnetwork, "encodeSubnetwork");
        const res = await symb.getVaultsNetsOpsFull([vault1, vault2]);
        expect(encodeSpy).toHaveBeenCalledTimes(4);
        encodeSpy.mockRestore();

        expect(publicClient.multicall).toHaveBeenCalledTimes(3);
        expect(res).toEqual([
            [{ net: netA, ops: [{ op: op1, stake: { 1: 10n } as StakeBySubnetwork }] }],
            [{ net: netB, ops: [{ op: op2, stake: { 0: 5n } as StakeBySubnetwork }] }],
        ]);
    });

    it("getVaultNetsOpsFull delegates to getVaultsNetsOpsFull", async () => {
        const vaultInfo = makeVault({
            vault: a("0x0100000000000000000000000000000000000000"),
            delegator: a("0x1111111111111111111111111111111111111111"),
            delegatorType: 0n,
        });

        const publicClient = {
            multicall: vi.fn(),
        };
        const symb = makeClient(publicClient);
        const spy = vi
            .spyOn(symb, "getVaultsNetsOpsFull")
            .mockResolvedValueOnce([[{ net: ZERO_ADDRESS, ops: [] }]]);

        const res = await symb.getVaultNetsOpsFull(vaultInfo);
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith([vaultInfo]);
        expect(res).toEqual([{ net: ZERO_ADDRESS, ops: [] }]);
    });

    it("getOpNetsVaults builds calls net->vault->subnet and filters via vault opt-in + limits", async () => {
        const operator = a("0x9000000000000000000000000000000000000001");
        const netA = a("0x1000000000000000000000000000000000000000");
        const netB = a("0x2000000000000000000000000000000000000000");

        const vault1 = makeVault({
            vault: a("0x0100000000000000000000000000000000000000"),
            delegator: a("0x1111111111111111111111111111111111111111"),
            delegatorType: 0n,
        });
        const vault2 = makeVault({
            vault: a("0x0200000000000000000000000000000000000000"),
            delegator: a("0x2222222222222222222222222222222222222222"),
            delegatorType: 0n,
        });
        const vault3 = makeVault({
            vault: a("0x0300000000000000000000000000000000000000"),
            delegator: a("0x3333333333333333333333333333333333333333"),
            delegatorType: 0n,
        });

        const publicClient = {
            multicall: vi
                .fn()
                // optins: v1 false, v2 true, v3 true
                .mockResolvedValueOnce([false, true, true])
                // limits:
                // netA v2 [0,0], netA v3 [0,0], netB v2 [1,0] (selected), netB v3 [0,0]
                .mockResolvedValueOnce([0n, 0n, 0n, 0n, 1n, 0n, 0n, 0n])
                // stakes: netB v2 [1,0]
                .mockResolvedValueOnce([1n, 0n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getOpNets").mockResolvedValueOnce([
            { net: netA, middleware: ZERO_ADDRESS } satisfies NetInfo,
            { net: netB, middleware: ZERO_ADDRESS } satisfies NetInfo,
        ]);
        vi.spyOn(symb, "getVaults").mockResolvedValueOnce([vault1, vault2, vault3]);

        const encodeSpy = vi.spyOn(subnetwork, "encodeSubnetwork");
        const res = await symb.getOpNetsVaults(operator);
        // subnetworks are computed twice per net (limits pass + stakes pass)
        expect(encodeSpy).toHaveBeenCalledTimes(8);
        encodeSpy.mockRestore();

        expect(res).toEqual([
            { net: netA, vaults: [] },
            {
                net: netB,
                vaults: [
                    {
                        ...vault2,
                        limit: { 0: 1n } as StakeBySubnetwork,
                        stake: { 0: 1n } as StakeBySubnetwork,
                    },
                ],
            },
        ]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(3);
        const optinCalls = publicClient.multicall.mock.calls[0]?.[0]?.contracts as any[];
        expect(optinCalls).toHaveLength(3);
        for (const c of optinCalls) expect(c.functionName).toBe("isOptedIn");

        const limitCalls = publicClient.multicall.mock.calls[1]?.[0]?.contracts as any[];
        expect(limitCalls).toHaveLength(8);
        for (const c of limitCalls) expect(c.functionName).toBe("networkLimit");
        expect(limitCalls.some((c) => c.address === vault1.delegator)).toBe(false);

        const stakeCalls = publicClient.multicall.mock.calls[2]?.[0]?.contracts as any[];
        expect(stakeCalls).toHaveLength(2);
        for (const c of stakeCalls) expect(c.functionName).toBe("stake");
    });

    it("getOpNetsVaults prunes operator-specific vaults pinned to other operators", async () => {
        const operator = a("0x9000000000000000000000000000000000000001");
        const other = a("0x9000000000000000000000000000000000000002");
        const netA = a("0x1000000000000000000000000000000000000000");

        const vaultGeneric = {
            ...makeVault({
                vault: a("0x0100000000000000000000000000000000000000"),
                delegator: a("0x1111111111111111111111111111111111111111"),
                delegatorType: 0n,
            }),
            limit: { 0: 1n } as StakeBySubnetwork,
        };
        const vaultPinnedOther = {
            ...makeVault({
                vault: a("0x0200000000000000000000000000000000000000"),
                delegator: a("0x2222222222222222222222222222222222222222"),
                delegatorType: 2n,
                delegatorOperator: other,
            }),
            limit: { 0: 1n } as StakeBySubnetwork,
        };

        const publicClient = {
            multicall: vi
                .fn()
                // optins: vaultGeneric opted in
                .mockResolvedValueOnce([true])
                // limits: vaultGeneric [1,0] (selected)
                .mockResolvedValueOnce([1n, 0n])
                // stakes: vaultGeneric [0,9]
                .mockResolvedValueOnce([0n, 9n]),
        };
        const symb = makeClient(publicClient);
        vi.spyOn(symb, "getOpNets").mockResolvedValueOnce([
            { net: netA, middleware: ZERO_ADDRESS } satisfies NetInfo,
        ]);
        vi.spyOn(symb, "getVaults").mockResolvedValueOnce([vaultGeneric, vaultPinnedOther] as any);

        const res = await symb.getOpNetsVaults(operator);
        expect(res).toEqual([
            {
                net: netA,
                vaults: [
                    {
                        ...vaultGeneric,
                        limit: { 0: 1n } as StakeBySubnetwork,
                        stake: { 1: 9n } as StakeBySubnetwork,
                    },
                ],
            },
        ]);

        expect(publicClient.multicall).toHaveBeenCalledTimes(3);
        const calls = publicClient.multicall.mock.calls[2]?.[0]?.contracts as any[];
        expect(calls).toHaveLength(2);
        expect(calls.every((c) => c.address === vaultGeneric.delegator)).toBe(true);
    });
});
```

## File: test/units.test.ts

```typescript
import { describe, expect, it } from "vitest";

import { formatTokenAmount, parseTokenAmount } from "../src/core/units";

describe("units", () => {
    it("parses and formats token amounts", () => {
        const meta = { symbol: "T", decimals: 18 };
        const wei = parseTokenAmount("1.5", meta);
        expect(wei).toBe(1_500_000_000_000_000_000n);
        expect(formatTokenAmount(wei, meta)).toBe("1.5");
    });

    it("rejects non-positive amounts", () => {
        const meta = { symbol: "T", decimals: 18 };
        expect(() => parseTokenAmount("0", meta)).toThrow();
        expect(() => parseTokenAmount("-1", meta)).toThrow();
    });

    it("rejects token amount when decimals unknown", () => {
        const meta = { symbol: "Unknown", decimals: 0 };
        expect(() => parseTokenAmount("1", meta)).toThrow();
    });
});
```

## File: test/write-commands-real-fork.sh

```bash
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "Missing required command: $1" >&2
    exit 1
  fi
}

require_cmd anvil
require_cmd cast
require_cmd solc
require_cmd node

if [[ ! -x ./dist/index.js ]]; then
  require_cmd pnpm
  pnpm -s build >/dev/null
fi

FORK_URL="${FORK_URL:-https://ethereum-rpc.gprptest.net/mainnet}"
ANVIL_PORT="${ANVIL_PORT:-9546}"
ANVIL_HOST="${ANVIL_HOST:-127.0.0.1}"
RPC_URL="http://${ANVIL_HOST}:${ANVIL_PORT}"
START_ANVIL="${START_ANVIL:-1}"

TMP_DIR="$(mktemp -d)"
ANVIL_LOG="$TMP_DIR/anvil.log"
ANVIL_PID=""

cleanup() {
  if [[ -n "$ANVIL_PID" ]]; then
    kill "$ANVIL_PID" >/dev/null 2>&1 || true
  fi
  rm -rf "$TMP_DIR"
}
trap cleanup EXIT

if [[ "$START_ANVIL" == "1" ]]; then
  anvil --fork-url "$FORK_URL" --host "$ANVIL_HOST" --port "$ANVIL_PORT" >"$ANVIL_LOG" 2>&1 &
  ANVIL_PID="$!"
fi

for _ in $(seq 1 60); do
  if cast block latest --rpc-url "$RPC_URL" >/dev/null 2>&1; then
    break
  fi
  sleep 1
done

if ! cast block latest --rpc-url "$RPC_URL" >/dev/null 2>&1; then
  echo "RPC is not reachable at $RPC_URL" >&2
  [[ -f "$ANVIL_LOG" ]] && tail -n 40 "$ANVIL_LOG" >&2
  exit 1
fi

# Core addresses.
NET_REGISTRY="0xC773b1011461e7314CF05f97d95aa8e92C1Fd8aA"
CURATOR_REGISTRY="0xF75D8d8F790178F0d7F2ee7656874567d382C21e"
FEE_REGISTRY="0x3E5a669F673712Bf72De956608E89D36561cbAf1"
REWARDS="0xa13e65cA0FeFa52cCb9615108fF400EF4806866B"

# Anvil account #0.
PK0="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
NETWORK_SENDER="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"

# Rewards tuple created during setup.
REWARD_VAULT="0x93b96D7cDe40DC340CA55001F46B3B8E41bC89B4"
REWARD_OPERATOR="0x4B9F8FEbAfDeD90E66C9896B729196a061d69B2F"

# 1) Ensure NETWORK_SENDER is a registered network.
if [[ "$(cast call "$NET_REGISTRY" "isEntity(address)(bool)" "$NETWORK_SENDER" --rpc-url "$RPC_URL")" != "true" ]]; then
  ./dist/index.js --rpc "$RPC_URL" net register --private-key "$PK0" --yes >/dev/null
fi

# 2) Ensure NETWORK_SENDER is curator for REWARD_VAULT.
ZERO_ADDR="0x0000000000000000000000000000000000000000"
CURRENT_CURATOR="$(cast call "$CURATOR_REGISTRY" "getCurator(address)(address)" "$REWARD_VAULT" --rpc-url "$RPC_URL")"
to_lower() {
  printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
}

if [[ "$(to_lower "$CURRENT_CURATOR")" == "$(to_lower "$ZERO_ADDR")" ]]; then
  VAULT_OWNER="$(cast call "$REWARD_VAULT" "owner()(address)" --rpc-url "$RPC_URL")"
  cast rpc --rpc-url "$RPC_URL" anvil_setBalance "$VAULT_OWNER" 0x3635C9ADC5DEA00000 >/dev/null
  cast rpc --rpc-url "$RPC_URL" anvil_impersonateAccount "$VAULT_OWNER" >/dev/null
  cast send "$CURATOR_REGISTRY" "setCurator(address,address)" "$REWARD_VAULT" "$NETWORK_SENDER" --rpc-url "$RPC_URL" --from "$VAULT_OWNER" --unlocked >/dev/null
elif [[ "$(to_lower "$CURRENT_CURATOR")" != "$(to_lower "$NETWORK_SENDER")" ]]; then
  cast rpc --rpc-url "$RPC_URL" anvil_setBalance "$CURRENT_CURATOR" 0x3635C9ADC5DEA00000 >/dev/null
  cast rpc --rpc-url "$RPC_URL" anvil_impersonateAccount "$CURRENT_CURATOR" >/dev/null
  cast send "$CURATOR_REGISTRY" "setCurator(address,address)" "$REWARD_VAULT" "$NETWORK_SENDER" --rpc-url "$RPC_URL" --from "$CURRENT_CURATOR" --unlocked >/dev/null
fi

# 3) Set non-zero fees for reward distribution.
cast send "$FEE_REGISTRY" "setOperatorsFee(address,uint256)" "$REWARD_VAULT" 50000 --rpc-url "$RPC_URL" --private-key "$PK0" >/dev/null
cast send "$FEE_REGISTRY" "setCuratorFee(address,uint256)" "$REWARD_VAULT" 50000 --rpc-url "$RPC_URL" --private-key "$PK0" >/dev/null

# 4) Deploy ERC20 for realistic rewards distribution on fork.
cat >"$TMP_DIR/RealForkToken.sol" <<'SOL'
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract RealForkToken {
  string public name = "Fork Real Test Token";
  string public symbol = "FRT";
  uint8 public decimals = 18;
  uint256 public totalSupply;
  mapping(address => uint256) public balanceOf;
  mapping(address => mapping(address => uint256)) public allowance;
  event Transfer(address indexed from, address indexed to, uint256 amount);
  event Approval(address indexed owner, address indexed spender, uint256 amount);
  constructor() {
    uint256 s = 1_000_000_000 ether;
    totalSupply = s;
    balanceOf[msg.sender] = s;
    emit Transfer(address(0), msg.sender, s);
  }
  function transfer(address to, uint256 amount) external returns (bool) {
    require(balanceOf[msg.sender] >= amount, "bal");
    unchecked { balanceOf[msg.sender] -= amount; balanceOf[to] += amount; }
    emit Transfer(msg.sender, to, amount);
    return true;
  }
  function approve(address spender, uint256 amount) external returns (bool) {
    allowance[msg.sender][spender] = amount;
    emit Approval(msg.sender, spender, amount);
    return true;
  }
  function transferFrom(address from, address to, uint256 amount) external returns (bool) {
    uint256 allowed = allowance[from][msg.sender];
    require(allowed >= amount, "allow");
    require(balanceOf[from] >= amount, "bal");
    unchecked {
      allowance[from][msg.sender] = allowed - amount;
      balanceOf[from] -= amount;
      balanceOf[to] += amount;
    }
    emit Transfer(from, to, amount);
    return true;
  }
}
SOL

solc --bin "$TMP_DIR/RealForkToken.sol" -o "$TMP_DIR" --overwrite >/dev/null
TOKEN_BYTECODE="$(tr -d '\n' <"$TMP_DIR/RealForkToken.bin")"
REWARD_TOKEN="$(cast send --rpc-url "$RPC_URL" --private-key "$PK0" --create "0x${TOKEN_BYTECODE}" | awk '/contractAddress/ {print $2}')"
if [[ -z "$REWARD_TOKEN" ]]; then
  echo "Failed to deploy test ERC20 token." >&2
  exit 1
fi
cast send "$REWARD_TOKEN" "approve(address,uint256)" "$REWARDS" 1000000000000000000000000 --rpc-url "$RPC_URL" --private-key "$PK0" >/dev/null

# 5) Pick a valid past timestamp with non-zero active shares and distribute rewards.
NOW_TS="$(cast block latest --rpc-url "$RPC_URL" | awk '/^timestamp/ {print $2; exit}')"
REWARD_TS=""
for offset in 60 600 3600 86400 604800 2592000; do
  candidate="$((NOW_TS - offset))"
  shares="$(cast call "$REWARD_VAULT" "activeSharesAt(uint48,bytes)(uint256)" "$candidate" 0x --rpc-url "$RPC_URL" 2>/dev/null || true)"
  shares="${shares%% *}"
  if [[ -n "$shares" && "$shares" != "0" ]]; then
    REWARD_TS="$candidate"
    break
  fi
done
if [[ -z "$REWARD_TS" ]]; then
  echo "Could not find a valid reward timestamp with active shares." >&2
  exit 1
fi

SUBNETWORK="$(node -e "const net='${NETWORK_SENDER}'.toLowerCase().slice(2); console.log('0x'+net+'0'.repeat(24));")"
cast send "$REWARDS" "distributeVaultSnapshotRewards(bytes32,address,address,uint256,uint48,bytes)" "$SUBNETWORK" "$REWARD_TOKEN" "$REWARD_VAULT" 100000000000000000000000 "$REWARD_TS" 0x --rpc-url "$RPC_URL" --private-key "$PK0" >/dev/null

# 6) Sanity checks for generated real rewards state.
rewards_len="$(cast call "$REWARDS" "rewardsLength(address,address,address)(uint256)" "$REWARD_VAULT" "$NETWORK_SENDER" "$REWARD_TOKEN" --rpc-url "$RPC_URL")"
curator_fees="$(cast call "$REWARDS" "curatorFees(address,address)(uint256)" "$REWARD_VAULT" "$REWARD_TOKEN" --rpc-url "$RPC_URL")"
if [[ "$rewards_len" == "0" ]]; then
  echo "Rewards setup failed: rewardsLength=0." >&2
  exit 1
fi
if [[ "$curator_fees" == "0" ]]; then
  echo "Rewards setup failed: curatorFees=0." >&2
  exit 1
fi

pass=0
fail=0

run_cmd() {
  local name="$1"
  shift
  if "$@" >"$TMP_DIR/out.log" 2>"$TMP_DIR/err.log"; then
    echo "PASS | $name"
    pass=$((pass + 1))
  else
    echo "FAIL | $name"
    sed -n '1,6p' "$TMP_DIR/err.log"
    fail=$((fail + 1))
  fi
}

# 25 write commands.
run_cmd "net register" ./dist/index.js --rpc "$RPC_URL" net register --dry-run --from 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC --json
run_cmd "net set-max-limit" ./dist/index.js --rpc "$RPC_URL" net set-max-limit 0x65B560d887c010c4993C8F8B36E595C171d69D63 123 1 --dry-run --from 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --json
run_cmd "net set-resolver" ./dist/index.js --rpc "$RPC_URL" net set-resolver 0x65B560d887c010c4993C8F8B36E595C171d69D63 0x8560C667Ae72F28D09465B342A480daB28821f6b 1 --dry-run --from 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --json

run_cmd "op register" ./dist/index.js --rpc "$RPC_URL" op register --dry-run --from 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC --json
run_cmd "op opt-in-net" ./dist/index.js --rpc "$RPC_URL" op opt-in-net 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --dry-run --from 0x4Ea457e3F11B1ba9a8D58d3Fd2A501FB9d989E6B --json
run_cmd "op opt-out-net" ./dist/index.js --rpc "$RPC_URL" op opt-out-net 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --dry-run --from 0xAC128Aa884c64cbE6Afecf5c006D51C2bb1Bf819 --json
run_cmd "op opt-in-vault" ./dist/index.js --rpc "$RPC_URL" op opt-in-vault 0x3F326DD5f9368C9A9988353129bFA7Ad68820fE2 --dry-run --from 0x4Ea457e3F11B1ba9a8D58d3Fd2A501FB9d989E6B --json
run_cmd "op opt-out-vault" ./dist/index.js --rpc "$RPC_URL" op opt-out-vault 0x65B560d887c010c4993C8F8B36E595C171d69D63 --dry-run --from 0xAC128Aa884c64cbE6Afecf5c006D51C2bb1Bf819 --json
run_cmd "op opt-in-vault-sig" ./dist/index.js --rpc "$RPC_URL" op opt-in-vault-sig 0xfE53Bca0DF7ebe8e43Cd1b976275cCCE7C4A5edA --private-key "$PK0" --json
run_cmd "op opt-out-vault-sig" ./dist/index.js --rpc "$RPC_URL" op opt-out-vault-sig 0x65B560d887c010c4993C8F8B36E595C171d69D63 --private-key "$PK0" --json
run_cmd "op opt-in-net-sig" ./dist/index.js --rpc "$RPC_URL" op opt-in-net-sig 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --private-key "$PK0" --json
run_cmd "op opt-out-net-sig" ./dist/index.js --rpc "$RPC_URL" op opt-out-net-sig 0x9101eda106A443A0fA82375936D0D1680D5a64F5 --private-key "$PK0" --json

run_cmd "vault set-network-limit" ./dist/index.js --rpc "$RPC_URL" vault set-network-limit 0x65B560d887c010c4993C8F8B36E595C171d69D63 0x9101eda106A443A0fA82375936D0D1680D5a64F5 1 1 --dry-run --from 0xe46d876BA2F3C991F3AC3321B8C0A1c323ef8bCf --json
run_cmd "vault set-operator-network-limit" ./dist/index.js --rpc "$RPC_URL" vault set-operator-network-limit 0x9D9C57AE5DC7a8fCf71062a5d155216A170a7a4A 0x9101eda106A443A0fA82375936D0D1680D5a64F5 0xAC128Aa884c64cbE6Afecf5c006D51C2bb1Bf819 1 --dry-run --from 0xfcAF34f30fa2EbCD22DB4F4ABBaD8615D3EAA8bD --json
run_cmd "vault set-operator-network-shares" ./dist/index.js --rpc "$RPC_URL" vault set-operator-network-shares 0x65B560d887c010c4993C8F8B36E595C171d69D63 0x9101eda106A443A0fA82375936D0D1680D5a64F5 0xAC128Aa884c64cbE6Afecf5c006D51C2bb1Bf819 1 --dry-run --from 0xe46d876BA2F3C991F3AC3321B8C0A1c323ef8bCf --json

run_cmd "staker withdraw" ./dist/index.js --rpc "$RPC_URL" staker withdraw 0xc6132FAF04627c8d05d6E759FAbB331Ef2D8F8fD 1 --dry-run --from 0xdF4C5f20BE2514E3B65Eb1746B27aF6721Cc0F8B --json
run_cmd "staker claim" ./dist/index.js --rpc "$RPC_URL" staker claim 0xE1F23869776c82f691d9Cb34597Ab1830Fb0De58 4 --dry-run --from 0x729e72292917844F7C4E5c37Effa43C222aBa5E4 --json

run_cmd "rewards set-curator" ./dist/index.js --rpc "$RPC_URL" rewards set-curator "$REWARD_VAULT" "$REWARD_OPERATOR" --dry-run --from "$NETWORK_SENDER" --json
run_cmd "rewards set-operators-fee" ./dist/index.js --rpc "$RPC_URL" rewards set-operators-fee "$REWARD_VAULT" 50000 --dry-run --from "$NETWORK_SENDER" --json
run_cmd "rewards set-operators-network-fee" ./dist/index.js --rpc "$RPC_URL" rewards set-operators-network-fee "$REWARD_VAULT" "$NETWORK_SENDER" 50000 --dry-run --from "$NETWORK_SENDER" --json
run_cmd "rewards set-curator-fee" ./dist/index.js --rpc "$RPC_URL" rewards set-curator-fee "$REWARD_VAULT" 50000 --dry-run --from "$NETWORK_SENDER" --json
run_cmd "rewards set-curator-network-fee" ./dist/index.js --rpc "$RPC_URL" rewards set-curator-network-fee "$REWARD_VAULT" "$NETWORK_SENDER" 50000 --dry-run --from "$NETWORK_SENDER" --json
run_cmd "rewards claim-vault-snapshot-rewards" ./dist/index.js --rpc "$RPC_URL" rewards claim-vault-snapshot-rewards "$REWARD_VAULT" "$NETWORK_SENDER" "$REWARD_TOKEN" --dry-run --from "$REWARD_OPERATOR" --json
run_cmd "rewards claim-operator-fees" ./dist/index.js --rpc "$RPC_URL" rewards claim-operator-fees "$REWARD_VAULT" "$NETWORK_SENDER" "$REWARD_TOKEN" --dry-run --from "$REWARD_OPERATOR" --json
run_cmd "rewards claim-curator-fees" ./dist/index.js --rpc "$RPC_URL" rewards claim-curator-fees "$REWARD_VAULT" "$REWARD_TOKEN" --dry-run --from "$NETWORK_SENDER" --json

echo
echo "Summary: pass=$pass fail=$fail"
echo "Reward token: $REWARD_TOKEN"
echo "Reward timestamp: $REWARD_TS"

if [[ "$fail" -ne 0 ]]; then
  exit 1
fi
```

## File: .prettierrc.json

```json
{
    "singleQuote": true,
    "semi": false,
    "trailingComma": "all",
    "printWidth": 100
}
```

## File: eslint.config.js

```javascript
import tseslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
    {
        files: ["**/*.ts"],
        languageOptions: {
            parser: tsParser,
            parserOptions: {
                ecmaVersion: 2022,
                sourceType: "module",
            },
        },
        plugins: {
            "@typescript-eslint": tseslint,
        },
        rules: {
            ...tseslint.configs.recommended.rules,
            "@typescript-eslint/no-explicit-any": "off",
        },
    },
    eslintConfigPrettier,
];
```

## File: install.sh

```bash
#!/usr/bin/env bash
set -eo pipefail

echo "Installing symb..."

BASE_DIR="${XDG_CONFIG_HOME:-$HOME}"
SYMB_DIR="${SYMB_DIR:-"$BASE_DIR/.symb"}"
SYMB_BIN_DIR="$SYMB_DIR/bin"
SYMB_CLI_DIR="$SYMB_DIR/cli"

SYMB_REPO="${SYMB_REPO:-"symbioticfi/cli"}"
SYMB_REF="${SYMB_REF:-"main"}"
ARCHIVE_URL="${SYMB_ARCHIVE_URL:-"https://codeload.github.com/$SYMB_REPO/tar.gz/refs/heads/$SYMB_REF"}"

for cmd in curl tar node; do
  command -v "$cmd" >/dev/null 2>&1 || { echo "Missing required command: $cmd" >&2; exit 1; }
done

NODE_MAJOR="$(node -p "process.versions.node.split('.')[0]")"
if [[ ! "$NODE_MAJOR" =~ ^[0-9]+$ ]]; then
  echo "Failed to detect Node.js version. Node.js >= 20 is required." >&2
  exit 1
fi
if [ "$NODE_MAJOR" -lt 20 ]; then
  echo "Node.js >= 20 is required. Detected: $(node -v)" >&2
  exit 1
fi

# Create the symb bin directory and ensure pnpm is available (via corepack if needed).
mkdir -p "$SYMB_BIN_DIR"

PNPM="pnpm"
if ! command -v pnpm >/dev/null 2>&1; then
  echo "pnpm not found; enabling via corepack..."
  command -v corepack >/dev/null 2>&1 || { echo "corepack not found. Install pnpm and retry." >&2; exit 1; }
  corepack enable --install-directory "$SYMB_BIN_DIR"
  PNPM="$SYMB_BIN_DIR/pnpm"
fi

echo "Downloading ${SYMB_REPO}@${SYMB_REF}..."
rm -rf "$SYMB_CLI_DIR"
mkdir -p "$SYMB_CLI_DIR"
curl -sSf -L "$ARCHIVE_URL" | tar -xz -C "$SYMB_CLI_DIR" --strip-components=1

if [ ! -f "$SYMB_CLI_DIR/package.json" ]; then
  echo "package.json not found after download. Are you installing the TypeScript CLI?" >&2
  echo "Tip: set SYMB_REF=main (or SYMB_ARCHIVE_URL to a tarball URL) and retry." >&2
  exit 1
fi

echo "Installing dependencies..."
(cd "$SYMB_CLI_DIR" && "$PNPM" install --frozen-lockfile)

echo "Building..."
(cd "$SYMB_CLI_DIR" && "$PNPM" build)

# Link executable into the bin directory.
chmod +x "$SYMB_CLI_DIR/dist/index.js"
ln -sf "$SYMB_CLI_DIR/dist/index.js" "$SYMB_BIN_DIR/symb"

case $SHELL in
*/zsh)
  PROFILE="${ZDOTDIR-"$HOME"}/.zshenv"
  PREF_SHELL=zsh
  ;;
*/bash)
  PROFILE="$HOME/.bashrc"
  PREF_SHELL=bash
  ;;
*/fish)
  PROFILE="$HOME/.config/fish/config.fish"
  PREF_SHELL=fish
  ;;
*/ash)
  PROFILE="$HOME/.profile"
  PREF_SHELL=ash
  ;;
*)
  echo "symb: could not detect shell, manually add ${SYMB_BIN_DIR} to your PATH."
  exit 1
esac

if [[ ":$PATH:" != *":${SYMB_BIN_DIR}:"* ]]; then
  if [[ "$PREF_SHELL" == "fish" ]]; then
    echo >>"$PROFILE" && echo "fish_add_path -a \"$SYMB_BIN_DIR\"" >>"$PROFILE"
  else
    echo >>"$PROFILE" && echo "export PATH=\"\\$PATH:$SYMB_BIN_DIR\"" >>"$PROFILE"
  fi
fi

if [[ "$OSTYPE" =~ ^darwin ]] && [[ ! -f /usr/local/opt/libusb/lib/libusb-1.0.0.dylib ]] && [[ ! -f /opt/homebrew/opt/libusb/lib/libusb-1.0.0.dylib ]]; then
  echo && echo "warning: libusb not found. You may need to install it manually on MacOS via Homebrew (brew install libusb)."
fi

echo
echo "Detected your preferred shell is $PREF_SHELL and added symb to PATH."
echo "Run 'source $PROFILE' or start a new terminal session to use symb."
echo "Then, simply run 'symb --help'."
```

## File: LICENSE

```
MIT License

Copyright (c) 2024 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: package.json

```json
{
    "name": "symb",
    "version": "0.0.0",
    "private": true,
    "packageManager": "pnpm@10.29.3",
    "type": "module",
    "bin": {
        "symb": "dist/index.js"
    },
    "scripts": {
        "dev": "tsx src/index.ts",
        "build": "tsdown",
        "typecheck": "tsc --noEmit",
        "lint": "eslint .",
        "format": "prettier -w .",
        "test": "vitest run"
    },
    "dependencies": {
        "@ledgerhq/hw-app-eth": "^7.4.0",
        "@ledgerhq/hw-transport-node-hid": "^6.30.0",
        "commander": "^14.0.3",
        "ora": "^9.3.0",
        "prompts": "^2.4.2",
        "viem": "^2.37.5",
        "zod": "^4.3.6"
    },
    "devDependencies": {
        "@types/node": "^24.3.0",
        "@types/prompts": "^2.4.9",
        "@typescript-eslint/eslint-plugin": "^8.43.0",
        "@typescript-eslint/parser": "^8.43.0",
        "eslint": "^9.35.0",
        "eslint-config-prettier": "^10.1.8",
        "prettier": "^3.8.1",
        "tsdown": "^0.20.3",
        "tsx": "^4.21.0",
        "typescript": "^5.9.3",
        "vitest": "^3.2.4"
    },
    "pnpm": {
        "onlyBuiltDependencies": ["node-hid", "usb"]
    }
}
```

## File: README.md

````markdown
# Symbiotic CLI (symb)

Simple CLI tool for fetching data and interacting with Symbiotic core smart contracts.

[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/symbioticfi/cli)

## Documentation

Can be found [here](https://docs.symbiotic.fi/guides/cli).

## Prerequisites

- Node >= 20
- pnpm (optional; the installer will enable it via `corepack` if missing)

## Install

### Quick Install (macOS/Linux)

```bash
curl -fsSL https://raw.githubusercontent.com/symbioticfi/cli/main/install.sh | bash
symb --help
symb op list
```

By default, this installs into `~/.symb/cli` and adds `~/.symb/bin` to your `PATH` (shell profile).

### Local Install (repo)

```bash
pnpm install
```

## Usage

### CLI

```bash
# Help
symb --help

# Example
symb op list
```

Write/signature commands require a signer:

- `--private-key <hex>` (discouraged) or `SYMB_PRIVATE_KEY`.
- Ledger: `--ledger` (optionally `--ledger-address` to derive the matching Ledger Ethereum path).

Common env vars:

- `SYMB_RPC_URL`
- `SYMB_PRIVATE_KEY`

If `SYMB_RPC_URL`/`--rpc` is not provided, the CLI uses a built-in fallback list of public RPC endpoints for the selected chain.

### Development (repo)

```bash
pnpm dev -- --help
pnpm build
./dist/index.js --help
```

## Commands

### net

- `symb net is <address>` - Check if address is network.
- `symb net middleware <network_address>` - Get network middleware address.
- `symb net list [--full]` - List all networks.
- `symb net ops <network_address>` - List all operators opted in network.
- `symb net stakes <network_address>` - Show stakes of all operators in network.
- `symb net max-network-limit <vault_address> <network_address>` - Get a maximum network limit at the vault's delegator.
- `symb net resolver <vault_address> <network_address>` - Get a current resolver for a subnetwork in a vault.
- `symb net pending-resolver <vault_address> <network_address>` - Get a pending resolver for a subnetwork in a vault.
- `symb net register [write options]` - Register the signer as a network.
- `symb net set-max-limit [write options] <vault_address> <max_limit> [subnetwork_id]` - Set a maximum network limit at the vault's delegator.
- `symb net set-resolver [write options] <vault_address> <resolver> [subnetwork_id]` - Set a resolver for a subnetwork at VetoSlasher.

### op

- `symb op is <address>` - Check if address is operator.
- `symb op list` - List all operators.
- `symb op nets <operator_address>` - List all networks where operator is opted in.
- `symb op stakes <operator_address>` - Show operator stakes in all networks.
- `symb op stake <operator_address> <vault_address> <network_address>` - Get operator stake in vault for network (includes shares for NetworkRestakeDelegator).
- `symb op opted-in-vault <operator_address> <vault_address>` - Check if operator is opted in to a vault.
- `symb op opted-in-net <operator_address> <network_address>` - Check if operator is opted in to a network.
- `symb op register [write options]` - Register the signer as an operator.
- `symb op opt-in-vault [write options] <vault_address>` - Opt-in to a vault.
- `symb op opt-out-vault [write options] <vault_address>` - Opt-out from a vault.
- `symb op opt-in-net [write options] <network_address>` - Opt-in to a network.
- `symb op opt-out-net [write options] <network_address>` - Opt-out from a network.
- `symb op opt-in-vault-sig [sign options] <vault_address> [duration]` - Get a signature for opt-in to a vault.
- `symb op opt-out-vault-sig [sign options] <vault_address> [duration]` - Get a signature for opt-out from a vault.
- `symb op opt-in-net-sig [sign options] <network_address> [duration]` - Get a signature for opt-in to a network.
- `symb op opt-out-net-sig [sign options] <network_address> [duration]` - Get a signature for opt-out from a network.

### vault

- `symb vault is <address>` - Check if address is vault.
- `symb vault list [--full]` - List all vaults.
- `symb vault ops <vault_address>` - List all operators opted into the given vault.
- `symb vault nets <vault_address>` - List all networks associated with the given vault.
- `symb vault netsops <vault_address>` - List all operators and their associated networks for the given vault.
- `symb vault network-limit <vault_address> <network_address>` - Get a network limit at the vault's delegator.
- `symb vault operator-network-limit <vault_address> <network_address> <operator_address>` - Get an operator-network limit at the vault's delegator.
- `symb vault operator-network-shares <vault_address> <network_address> <operator_address>` - Get operator-network shares at the vault's delegator.
- `symb vault total-operator-network-shares <vault_address> <network_address>` - Get total operator-network shares at the vault's delegator.
- `symb vault set-network-limit [write options] <vault_address> <network_address> <limit> [subnetwork_id]` - Set a network limit at the vault's delegator.
- `symb vault set-operator-network-limit [write options] <vault_address> <network_address> <operator_address> <limit> [subnetwork_id]` - Set an operator-network limit at the vault's delegator.
- `symb vault set-operator-network-shares [write options] <vault_address> <network_address> <operator_address> <shares> [subnetwork_id]` - Set an operator-network shares at the vault's delegator.

### staker

- `symb staker active-balance <vault_address> <address>` - Get an active balance of a given account at a particular vault.
- `symb staker withdrawals <vault_address> <epoch> <address>` - Get some epoch's withdrawals of a given account at a particular vault.
- `symb staker withdrawals-claimed <vault_address> <epoch> <address>` - Check if some epoch's withdrawals of a given account at a particular vault are claimed.
- `symb staker withdraw [write options] <vault_address> <amount> [claimer]` - Withdraw from the vault.
- `symb staker claim [write options] <vault_address> <epoch> [recipient]` - Claim a withdrawal for some epoch at the vault.

### rewards

- `symb rewards curator <vault_address>` - Get the curator address for a vault.
- `symb rewards operators-fee <vault_address> <network_address>` - Get effective operators fee (ppm) for a vault+network.
- `symb rewards curator-fee <vault_address> <network_address>` - Get effective curator fee (ppm) for a vault+network.
- `symb rewards protocol-fee <rewards_type> <network_address>` - Get protocol fee (ppm) for a rewards type and network.
- `symb rewards curator-fees <vault_address> <token>` - Get claimable curator fees (amount) for a vault+token.
- `symb rewards vault-snapshot-rewards <staker_address> <vault_address> <network_address> <token> [first_reward_to_claim] [max_rewards]` - Get claimable vault snapshot rewards (amount) for a staker.
- `symb rewards operator-fees <operator_address> <vault_address> <network_address> <token> [first_reward_to_claim] [max_rewards]` - Get claimable operator fees (amount) for an operator.
- `symb rewards set-curator [write options] <vault_address> <curator>` - Set curator for a vault.
- `symb rewards set-operators-fee [write options] <vault_address> <fee>` - Set default operators fee (ppm) for a vault.
- `symb rewards set-operators-network-fee [write options] <vault_address> <network_address> <fee>` - Set network-specific operators fee (ppm) for a vault.
- `symb rewards set-curator-fee [write options] <vault_address> <fee>` - Set default curator fee (ppm) for a vault.
- `symb rewards set-curator-network-fee [write options] <vault_address> <network_address> <fee>` - Set network-specific curator fee (ppm) for a vault.
- `symb rewards claim-vault-snapshot-rewards [write options] <vault_address> <network_address> <token> [recipient] [first_reward_to_claim] [max_rewards]` - Claim vault snapshot rewards for the signer.
- `symb rewards claim-operator-fees [write options] <vault_address> <network_address> <token> [recipient] [first_reward_to_claim] [max_rewards]` - Claim vault snapshot operator fees for the signer.
- `symb rewards claim-curator-fees [write options] <vault_address> <token> [recipient]` - Claim vault snapshot curator fees for the signer curator.

## Options / Flags

Global (all commands):

- `--chain <chain>`: Chain key or chainId (default: `mainnet`; supported: `mainnet`, `hoodi`, `sepolia`)
- `--rpc <url>`: RPC URL override
- `--timeout-ms <n>`: RPC request timeout (ms)
- `--retries <n>`: RPC retry count
- `--batch-size <n>`: Multicall batch size
- `--concurrency <n>`: Multicall concurrency
- `--json`: Machine-readable JSON output
- `--quiet`: Minimal output

Signing (write + signature commands):

- `--private-key <hex>` (discouraged; use `SYMB_PRIVATE_KEY`)
- `--ledger`
- `--ledger-address <address>`: derive the matching Ledger Ethereum derivation path for this address

Write-only:

- `--yes`: Bypass confirmation prompts
- `--dry-run`: Simulate only (do not send transaction)
````

## File: tsconfig.json

```json
{
    "compilerOptions": {
        "target": "ES2022",
        "module": "ESNext",
        "moduleResolution": "Bundler",
        "strict": true,
        "noUncheckedIndexedAccess": true,
        "resolveJsonModule": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "types": ["node"],
        "outDir": "dist"
    },
    "include": ["src/**/*.ts", "test/**/*.ts"]
}
```

## File: tsdown.config.ts

```typescript
import { defineConfig } from "tsdown";

export default defineConfig({
    entry: ["src/index.ts"],
    format: ["esm"],
    platform: "node",
    target: "node20",
    outDir: "dist",
    sourcemap: true,
    clean: true,
    dts: false,
    shims: false,
    fixedExtension: false,
    // Ledger transport uses native deps that should stay external.
    external: [
        "@ledgerhq/hw-app-eth",
        "@ledgerhq/hw-transport-node-hid",
        "node-hid",
        "usb",
        "keccak",
    ],
    banner: {
        js: "#!/usr/bin/env node",
    },
});
```

## File: vitest.config.ts

```typescript
import { defineConfig } from "vitest/config";

export default defineConfig({
    test: {
        environment: "node",
        include: ["test/**/*.test.ts"],
    },
});
```
