# AI Pack: network-contracts

- Description: Network contracts for operator and network integration.
- Remote: https://github.com/symbioticfi/network
- Remote ref: HEAD
- Commit: a3cd3823b4b7065142dde5415f014f9d3d044a7c
- Generated (UTC): 2026-06-02T10:22:21.999Z
- Repomix: 1.14.1
- Preset: contract
- 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/, docs/, abis/, bindings/, test/**, !test/integration/**, script/utils/**, package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lockb, .pre-commit-config.yaml
- Flags: compress

---

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

# File Summary

## Purpose

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

## File Format

The content is organized as follows:

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

## Usage Guidelines

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

## Notes

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

# Directory Structure

```
script/
  actions/
    base/
      ActionBase.sol
      ArbitraryCallBase.sol
      SetMaxNetworkLimitBase.sol
      SetMiddlewareBase.sol
      SetResolverBase.sol
      UpgradeProxyBase.sol
    interfaces/
      ITimelockAction.sol
    ArbitraryCall.s.sol
    SetMaxNetworkLimit.s.sol
    SetMiddleware.s.sol
    SetResolver.s.sol
    UpdateBatch.s.sol
    UpgradeProxy.s.sol
  base/
    DeployNetworkBase.sol
    DeployNetworkForVaultsBase.sol
    Logs.sol
  update-delay/
    base/
      ArbitraryCallUpdateDelayBase.sol
      DefaultUpdateDelayBase.sol
      SetMaxNetworkLimitUpdateDelayBase.sol
      SetMiddlewareUpdateDelayBase.sol
      SetResolverUpdateDelayBase.sol
      UpgradeProxyUpdateDelayBase.sol
    ArbitraryCallUpdateDelay.s.sol
    ColdActionsUpdateDelay.s.sol
    DefaultUpdateDelay.s.sol
    HotActionsUpdateDelay.s.sol
    SetMaxNetworkLimitUpdateDelay.s.sol
    SetMiddlewareUpdateDelay.s.sol
    SetResolverUpdateDelay.s.sol
    UpgradeProxyUpdateDelay.s.sol
  DeployNetwork.s.sol
  DeployNetworkForVaults.s.sol
snapshots/
  gas.txt
  sizes.txt
src/
  interfaces/
    INetwork.sol
    ISetMaxNetworkLimitHook.sol
  Network.sol
ui/
  src/
    abi.ts
    index.css
    main.tsx
    TimelockDashboard.tsx
    vite-env.d.ts
    wagmiConfig.tsx
  eslint.config.js
  index.html
  postcss.config.cjs
  tailwind.config.cjs
  tsconfig.app.json
  tsconfig.json
  tsconfig.node.json
  vite.config.mts
.gitmodules
.prettierrc
codecov.yml
CONTRIBUTING.md
foundry.lock
foundry.toml
LICENSE
package.json
README.md
remappings.txt
```

# Files

## File: script/actions/base/ActionBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {Script} from "forge-std/Script.sol";
⋮----
import "../../base/Logs.sol";
import {ITimelockAction} from "../interfaces/ITimelockAction.sol";
⋮----
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
⋮----
contract ActionBase is Script, Logs {
⋮----
function callTimelock(TimelockParams memory params) internal {
⋮----
function callTimelockBatch(TimelockBatchParams memory params) internal {
⋮----
// Create values array filled with zeros
```

## File: script/actions/base/ArbitraryCallBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./ActionBase.sol";
⋮----
contract ArbitraryCallBase is ActionBase {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
```

## File: script/actions/base/SetMaxNetworkLimitBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./ActionBase.sol";
import {Network} from "../../../src/Network.sol";
⋮----
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
import {ITimelockAction} from "../interfaces/ITimelockAction.sol";
⋮----
contract SetMaxNetworkLimitBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/actions/base/SetMiddlewareBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./ActionBase.sol";
import {Network} from "../../../src/Network.sol";
⋮----
import {INetworkMiddlewareService} from "@symbioticfi/core/src/interfaces/service/INetworkMiddlewareService.sol";
import {SymbioticCoreConstants} from "@symbioticfi/core/test/integration/SymbioticCoreConstants.sol";
import {ITimelockAction} from "../interfaces/ITimelockAction.sol";
⋮----
contract SetMiddlewareBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/actions/base/SetResolverBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./ActionBase.sol";
⋮----
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
import {ITimelockAction} from "../interfaces/ITimelockAction.sol";
⋮----
contract SetResolverBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/actions/base/UpgradeProxyBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./ActionBase.sol";
import {Network} from "../../../src/Network.sol";
⋮----
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {ITimelockAction} from "../interfaces/ITimelockAction.sol";
⋮----
contract UpgradeProxyBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function _getProxyAdmin(address proxy) internal view returns (address admin) {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/actions/interfaces/ITimelockAction.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
interface ITimelockAction {
/**
     * @notice Schedule the action through the timelock
     */
function runSchedule() external;
⋮----
/**
     * @notice Execute the action immediately through the timelock
     */
function runExecute() external;
⋮----
/**
     * @notice Schedule and execute the action through the timelock
     */
function runScheduleAndExecute() external;
⋮----
/**
     * @notice Get the target and payload of the action
     */
function getTargetAndPayload() external view returns (address, bytes memory);
```

## File: script/actions/ArbitraryCall.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/ArbitraryCallBase.sol";
⋮----
contract ArbitraryCall is ArbitraryCallBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the Target
⋮----
// Data to pass to the Target
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an arbitrary function call through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an arbitrary function call immediately through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an arbitrary function call through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/actions/SetMaxNetworkLimit.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetMaxNetworkLimitBase.sol";
⋮----
contract SetMaxNetworkLimit is SetMaxNetworkLimitBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the Vault
⋮----
// Maximum amount of delegation that network is ready to receive
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different max network limits for the same network)
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule a setMaxNetworkLimit through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute a setMaxNetworkLimit immediately through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute a setMaxNetworkLimit through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/actions/SetMiddleware.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetMiddlewareBase.sol";
⋮----
contract SetMiddleware is SetMiddlewareBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the Middleware
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule a setMiddleware through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute a setMiddleware immediately through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute a setMiddleware through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/actions/SetResolver.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetResolverBase.sol";
⋮----
contract SetResolver is SetResolverBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the Vault
⋮----
// Address of the Resolver
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different resolvers for the same network)
⋮----
// Hints for the Resolver
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule a setResolver through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute a setResolver immediately through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute a setResolver through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/actions/UpdateBatch.s.sol

```solidity
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.25;
⋮----
// import {ITimelockAction} from "./interfaces/ITimelockAction.sol";
// import {ActionBase} from "./base/ActionBase.sol";
// import {SetMaxNetworkLimitBase} from "./base/SetMaxNetworkLimitBase.sol";
// import {SetMiddlewareBase} from "./base/SetMiddlewareBase.sol";
// import {SetResolverBase} from "./base/SetResolverBase.sol";
// import {UpgradeProxyBase} from "./base/UpgradeProxyBase.sol";
⋮----
// contract UpdateBatch is ActionBase {
//     // Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
//     // Address of the Network
//     address constant NETWORK = 0x0000000000000000000000000000000000000000;
//     // Delay for the action to be executed
//     uint256 constant DELAY = 14 days;
//     // Salt for TimelockController operations
//     bytes32 constant SALT = "UpdateBatch";
⋮----
//     // Address of the Vault
//     address constant VAULT1 = 0x0000000000000000000000000000000000000000;
//     // Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different resolvers for the same network)
//     uint96 constant SUBNETWORK_IDENTIFIER1 = 0;
//     // Maximum amount of delegation that network is ready to receive
//     uint256 constant MAX_NETWORK_LIMIT1 = 0;
⋮----
//     address constant VAULT2 = 0x0000000000000000000000000000000000000000;
⋮----
//     uint96 constant SUBNETWORK_IDENTIFIER2 = 0;
⋮----
//     uint256 constant MAX_NETWORK_LIMIT2 = 0;
⋮----
//     // Address of the Middleware
//     address constant MIDDLEWARE = 0x0000000000000000000000000000000000000000;
//     // Address of the Resolver
//     address constant RESOLVER = 0x0000000000000000000000000000000000000000;
//     // Address of the New Implementation
//     address constant NEW_IMPLEMENTATION = 0x0000000000000000000000000000000000000000;
//     // Data to pass to the new implementation after upgrade
//     bytes constant UPGRADE_DATA = hex"";
⋮----
//     // Hints for the Resolver
//     bytes constant HINTS = hex"";
⋮----
//     ITimelockAction[] public actions;
⋮----
//     constructor() {
//         // Add all actions needed for the update batch to the array
//         actions.push(
//             new SetMaxNetworkLimitBase(
//                 SetMaxNetworkLimitBase.SetMaxNetworkLimitParams({
//                     network: NETWORK,
//                     vault: VAULT1,
//                     subnetworkId: SUBNETWORK_IDENTIFIER1,
//                     maxNetworkLimit: MAX_NETWORK_LIMIT1,
//                     delay: DELAY,
//                     salt: SALT
//                 })
//             )
//         );
⋮----
//                     vault: VAULT2,
//                     subnetworkId: SUBNETWORK_IDENTIFIER2,
//                     maxNetworkLimit: MAX_NETWORK_LIMIT2,
⋮----
//             new SetMiddlewareBase(
//                 SetMiddlewareBase.SetMiddlewareParams({
⋮----
//                     middleware: MIDDLEWARE,
⋮----
//             new SetResolverBase(
//                 SetResolverBase.SetResolverParams({
⋮----
//                     identifier: SUBNETWORK_IDENTIFIER1,
//                     resolver: RESOLVER,
//                     hints: HINTS,
⋮----
//             new UpgradeProxyBase(
//                 UpgradeProxyBase.UpgradeProxyParams({
⋮----
//                     newImplementation: NEW_IMPLEMENTATION,
//                     upgradeData: UPGRADE_DATA,
⋮----
//     }
⋮----
//     function runS() public {
//         callTimelockBatch(
//             TimelockBatchParams({network: NETWORK, isExecutionMode: false, actions: actions, delay: DELAY, salt: SALT})
⋮----
//     function runE() public {
⋮----
//             TimelockBatchParams({network: NETWORK, isExecutionMode: true, actions: actions, delay: 0, salt: SALT})
⋮----
//     function runSE() public {
//         runS();
//         runE();
⋮----
// }
```

## File: script/actions/UpgradeProxy.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/UpgradeProxyBase.sol";
⋮----
contract UpgradeProxy is UpgradeProxyBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the new implementation
⋮----
// Data to pass to the new implementation after upgrade
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule a network upgrade through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute a network upgrade immediately through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute a network upgrade through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/base/DeployNetworkBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {Script} from "forge-std/Script.sol";
⋮----
import "./Logs.sol";
import {Network} from "../../src/Network.sol";
import {INetwork} from "../../src/interfaces/INetwork.sol";
⋮----
import {SymbioticCoreConstants} from "@symbioticfi/core/test/integration/SymbioticCoreConstants.sol";
import {INetworkMiddlewareService} from "@symbioticfi/core/src/interfaces/service/INetworkMiddlewareService.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
import {CreateXWrapper} from "@symbioticfi/core/script/utils/CreateXWrapper.sol";
⋮----
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
⋮----
contract DeployNetworkBase is Script, Logs, CreateXWrapper {
⋮----
bytes11 salt; // Salt for CREATE3 deterministic deployment
⋮----
function runBase(DeployNetworkParams memory params) public returns (address) {
⋮----
// Needed for permissioned deploy protection
⋮----
// CreateX-specific salt generation
⋮----
// Create initialization code for TransparentUpgradeableProxy
⋮----
// Deploy proxy using CREATE3
⋮----
// if target is address(0), it means that the delay is for the any address
⋮----
function _getProxyAdmin(address proxy) internal view returns (address admin) {
```

## File: script/base/DeployNetworkForVaultsBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {DeployNetworkBase} from "./DeployNetworkBase.sol";
import {Network} from "../../src/Network.sol";
import {INetwork} from "../../src/interfaces/INetwork.sol";
⋮----
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
⋮----
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
⋮----
contract DeployNetworkForVaultsBase is DeployNetworkBase {
⋮----
function runBase(DeployNetworkForVaultsParams memory params) public returns (address) {
⋮----
// update deploy network params to include deployer as proposer and executor
⋮----
// deploy network
⋮----
// update network for vaults
⋮----
function updateDeployParamsForDeployer(DeployNetworkParams memory deployNetworkParams)
⋮----
// clone the struct
⋮----
function updateNetworkForVaults(
```

## File: script/base/Logs.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {Script, console2} from "forge-std/Script.sol";
import {Vm, VmSafe} from "forge-std/Vm.sol";
⋮----
contract Logs is Script {
⋮----
function log(string memory data) internal {
```

## File: script/update-delay/base/ArbitraryCallUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
import {INetwork} from "../../../src/interfaces/INetwork.sol";
⋮----
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
contract ArbitraryCallUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target_, bytes memory payload) {
```

## File: script/update-delay/base/DefaultUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
⋮----
import {
    TimelockControllerUpgradeable
} from "@openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol";
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
contract DefaultUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/update-delay/base/SetMaxNetworkLimitUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
import {INetwork} from "../../../src/interfaces/INetwork.sol";
⋮----
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
contract SetMaxNetworkLimitUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/update-delay/base/SetMiddlewareUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
import {INetwork} from "../../../src/interfaces/INetwork.sol";
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
import {SymbioticCoreConstants} from "@symbioticfi/core/test/integration/SymbioticCoreConstants.sol";
import {INetworkMiddlewareService} from "@symbioticfi/core/src/interfaces/service/INetworkMiddlewareService.sol";
⋮----
contract SetMiddlewareUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/update-delay/base/SetResolverUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
import {INetwork} from "../../../src/interfaces/INetwork.sol";
⋮----
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
contract SetResolverUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
```

## File: script/update-delay/base/UpgradeProxyUpdateDelayBase.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {ActionBase} from "../../actions/base/ActionBase.sol";
import {Network} from "../../../src/Network.sol";
import {INetwork} from "../../../src/interfaces/INetwork.sol";
import {ITimelockAction} from "../../actions/interfaces/ITimelockAction.sol";
⋮----
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
⋮----
contract UpgradeProxyUpdateDelayBase is ActionBase, ITimelockAction {
⋮----
function runSchedule() public {
⋮----
function runExecute() public {
⋮----
function runScheduleAndExecute() public {
⋮----
function getTargetAndPayload() public view returns (address target, bytes memory payload) {
⋮----
function _getProxyAdmin(address proxy) internal view returns (address admin) {
```

## File: script/update-delay/ArbitraryCallUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/ArbitraryCallUpdateDelayBase.sol";
⋮----
contract ArbitraryCallUpdateDelay is ArbitraryCallUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// Address of the Target to set a delay for (0x0000000000000000000000000000000000000000 means "for any target")
⋮----
// Selector of the Target to set a delay for (0xEEEEEEEE means "for native asset transfers")
⋮----
// New delay for arbitrary operations
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the arbitrary call delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the arbitrary call delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the arbitrary call delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/ColdActionsUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {ITimelockAction} from "../actions/interfaces/ITimelockAction.sol";
import {ActionBase} from "../actions/base/ActionBase.sol";
import {SetMiddlewareUpdateDelayBase} from "./base/SetMiddlewareUpdateDelayBase.sol";
import {UpgradeProxyUpdateDelayBase} from "./base/UpgradeProxyUpdateDelayBase.sol";
⋮----
contract ColdActionsUpdateDelay is ActionBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for cold actions
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the cold actions delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the cold actions delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the cold actions delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/DefaultUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/DefaultUpdateDelayBase.sol";
⋮----
contract DefaultUpdateDelay is DefaultUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New default delay
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the default delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the default delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the default delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/HotActionsUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {ITimelockAction} from "../actions/interfaces/ITimelockAction.sol";
import {ActionBase} from "../actions/base/ActionBase.sol";
import {SetMaxNetworkLimitUpdateDelayBase} from "./base/SetMaxNetworkLimitUpdateDelayBase.sol";
import {SetResolverUpdateDelayBase} from "./base/SetResolverUpdateDelayBase.sol";
⋮----
contract HotActionsUpdateDelay is ActionBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for hot actions
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the hot actions delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the hot actions delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the hot actions delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/SetMaxNetworkLimitUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetMaxNetworkLimitUpdateDelayBase.sol";
⋮----
contract SetMaxNetworkLimitUpdateDelay is SetMaxNetworkLimitUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for setMaxNetworkLimit operations
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the setMaxNetworkLimit delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the setMaxNetworkLimit delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the setMaxNetworkLimit delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/SetMiddlewareUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetMiddlewareUpdateDelayBase.sol";
⋮----
contract SetMiddlewareUpdateDelay is SetMiddlewareUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for setMiddleware operations
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the setMiddleware delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the setMiddleware delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the setMiddleware delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/SetResolverUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/SetResolverUpdateDelayBase.sol";
⋮----
contract SetResolverUpdateDelay is SetResolverUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for setResolver operations
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the setResolver delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the setResolver delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the setResolver delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/update-delay/UpgradeProxyUpdateDelay.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import "./base/UpgradeProxyUpdateDelayBase.sol";
⋮----
contract UpgradeProxyUpdateDelay is UpgradeProxyUpdateDelayBase {
// Configuration constants - UPDATE THESE BEFORE EXECUTING
⋮----
// Address of the Network
⋮----
// New delay for upgradeProxy operations
⋮----
// Delay for the action to be executed
⋮----
// Optional
⋮----
// Salt for TimelockController operations
⋮----
/**
     * @notice Schedule an update of the upgradeProxy delay through the timelock
     */
function runS() public {
⋮----
/**
     * @notice Execute an update of the upgradeProxy delay through the timelock
     */
function runE() public {
⋮----
/**
     * @notice Schedule and execute an update of the upgradeProxy delay through the timelock
     * @dev It will succeed only if the delay is 0
     */
function runSE() public {
```

## File: script/DeployNetwork.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {DeployNetworkBase} from "./base/DeployNetworkBase.sol";
⋮----
/**
 * Deploys Network implementation and a TransparentUpgradeableProxy managed by ProxyAdmin.
 * Uses CREATE3 for deterministic proxy deployment.
 *
 * Configuration is handled entirely by inherited contract.
 */
contract DeployNetwork is DeployNetworkBase {
// Configuration constants - UPDATE THESE BEFORE DEPLOYMENT
⋮----
// Name of the Network
⋮----
// Default minimum delay (will be applied for any action that doesn't have a specific delay yet)
⋮----
// Cold actions delay (a delay that will be applied for major actions like upgradeProxy and setMiddleware)
⋮----
// Hot actions delay (a delay that will be applied for minor actions like setMaxNetworkLimit and setResolver)
⋮----
// Admin address (will become executor, proposer, and default admin by default)
⋮----
// Optional
⋮----
// Metadata URI of the Network
⋮----
// Salt for deterministic deployment
⋮----
function run() public {
```

## File: script/DeployNetworkForVaults.s.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {DeployNetworkForVaultsBase} from "./base/DeployNetworkForVaultsBase.sol";
⋮----
/**
 * Deploys Network implementation and a TransparentUpgradeableProxy managed by ProxyAdmin.
 * Uses CREATE3 for deterministic proxy deployment.
 * Also, opt-ins the Network to the given Vault.
 *
 * Configuration is handled entirely by inherited contract.
 */
contract DeployNetworkForVaults is DeployNetworkForVaultsBase {
// Configuration constants - UPDATE THESE BEFORE DEPLOYMENT
⋮----
// Name of the Network
⋮----
// Default minimum delay (will be applied for any action that doesn't have a specific delay yet)
⋮----
// Cold actions delay (a delay that will be applied for major actions like upgradeProxy and setMiddleware)
⋮----
// Hot actions delay (a delay that will be applied for minor actions like setMaxNetworkLimit and setResolver)
⋮----
// Admin address (will become executor, proposer, and default admin by default)
⋮----
// Vault address to opt-in to (multiple vaults can be set)
⋮----
// Maximum amount of delegation that network is ready to receive (multiple vaults can be set)
⋮----
// Resolver address (optional, is applied only if VetoSlasher is used) (multiple vaults can be set)
⋮----
// Optional
⋮----
// Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different resolvers for the same network)
⋮----
// Metadata URI of the Network
⋮----
// Salt for deterministic deployment
⋮----
function run() public {
```

## File: snapshots/gas.txt

```
No files changed, compilation skipped

Ran 20 tests for test/Network.t.sol:NetworkTest
[PASS] testInitializeCantBeCalledTwice() (gas: 38563)
[PASS] test_DirectUpdateDelayReverts() (gas: 31548)
[PASS] test_EthTransfer() (gas: 205524)
[PASS] test_GetMinDelayInvalidSelectorReverts() (gas: 9433)
[PASS] test_Init() (gas: 134556)
[PASS] test_PerSelectorDelayOverridesGlobal() (gas: 16091)
[PASS] test_ScheduleBatchAndExecute() (gas: 220484)
[PASS] test_ScheduleBatchLengthMismatchReverts() (gas: 39546)
[PASS] test_ScheduleBatchRevertsIfDelayTooShort() (gas: 59378)
[PASS] test_ScheduleRevertsIfDelayTooShort() (gas: 46561)
[PASS] test_SetMaxNetworkLimitOnlyMiddleware() (gas: 1327179)
[PASS] test_SetMaxNetworkLimitWrongCallerReverts() (gas: 38043)
[PASS] test_TryBreakInvariant() (gas: 189761)
[PASS] test_UpdateDelayThroughTimelock() (gas: 242398)
[PASS] test_UpdateDelayThroughTimelock_RevertInvalidNewDelay() (gas: 115278)
[PASS] test_UpdateDelayThroughTimelock_ZeroAddress() (gas: 204124)
[PASS] test_UpdateDelayThroughTimelock_ZeroSelector() (gas: 246360)
[PASS] test_UpdateMetadataURI() (gas: 49653)
[PASS] test_UpdateNameByRoleHolder() (gas: 49702)
[PASS] test_UpdateNameWithoutRoleReverts() (gas: 32895)
Suite result: ok. 20 passed; 0 failed; 0 skipped; finished in 4.23ms (5.08ms CPU time)

╭----------------------------------+-----------------+--------+--------+--------+---------╮
| src/Network.sol:Network Contract |                 |        |        |        |         |
+=========================================================================================+
| Deployment Cost                  | Deployment Size |        |        |        |         |
|----------------------------------+-----------------+--------+--------+--------+---------|
| 0                                | 12614           |        |        |        |         |
|----------------------------------+-----------------+--------+--------+--------+---------|
|                                  |                 |        |        |        |         |
|----------------------------------+-----------------+--------+--------+--------+---------|
| Function Name                    | Min             | Avg    | Median | Max    | # Calls |
|----------------------------------+-----------------+--------+--------+--------+---------|
| DEFAULT_ADMIN_ROLE               | 304             | 304    | 304    | 304    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| METADATA_URI_UPDATE_ROLE         | 328             | 328    | 328    | 328    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| NAME_UPDATE_ROLE                 | 284             | 284    | 284    | 284    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| NETWORK_MIDDLEWARE_SERVICE       | 261             | 261    | 261    | 261    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| NETWORK_REGISTRY                 | 304             | 304    | 304    | 304    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| PROPOSER_ROLE                    | 290             | 290    | 290    | 290    | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| execute                          | 32943           | 68180  | 70058  | 88034  | 26      |
|----------------------------------+-----------------+--------+--------+--------+---------|
| executeBatch                     | 111588          | 111588 | 111588 | 111588 | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| getMinDelay                      | 977             | 6865   | 5849   | 12568  | 20      |
|----------------------------------+-----------------+--------+--------+--------+---------|
| hasRole                          | 2767            | 2767   | 2767   | 2767   | 4       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| initialize                       | 28806           | 474797 | 497097 | 497097 | 21      |
|----------------------------------+-----------------+--------+--------+--------+---------|
| metadataURI                      | 3211            | 3211   | 3211   | 3211   | 2       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| name                             | 3233            | 3233   | 3233   | 3233   | 2       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| schedule                         | 27981           | 55314  | 58120  | 68831  | 32      |
|----------------------------------+-----------------+--------+--------+--------+---------|
| scheduleBatch                    | 27163           | 51080  | 44272  | 81805  | 3       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| setMaxNetworkLimit               | 27393           | 47484  | 47484  | 67576  | 2       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| updateDelay                      | 23280           | 23280  | 23280  | 23280  | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| updateMetadataURI                | 31848           | 31848  | 31848  | 31848  | 1       |
|----------------------------------+-----------------+--------+--------+--------+---------|
| updateName                       | 24770           | 28378  | 28378  | 31987  | 2       |
╰----------------------------------+-----------------+--------+--------+--------+---------╯


Ran 1 test suite in 13.32ms (4.23ms CPU time): 20 tests passed, 0 failed, 0 skipped (20 total tests)
```

## File: snapshots/sizes.txt

```
No files changed, compilation skipped

╭----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract                                                                         | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+====================================================================================================================================================================+
| Address                                                                          | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Bytes                                                                            | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Checkpoints (lib/core/src/contracts/libraries/Checkpoints.sol)                   | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Checkpoints (lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol) | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Create2                                                                          | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| CreateXWrapper                                                                   | 2,764            | 2,792             | 21,812             | 46,360              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC1967Proxy                                                                     | 122              | 934               | 24,454             | 48,218              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC1967Utils                                                                     | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC4626Math                                                                      | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Errors                                                                           | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| FeeOnTransferToken                                                               | 1,785            | 3,197             | 22,791             | 45,955              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Math                                                                             | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Network                                                                          | 12,358           | 12,550            | 12,218             | 36,602              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Panic                                                                            | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ProxyAdmin                                                                       | 977              | 1,213             | 23,599             | 47,939              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SafeCast                                                                         | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SafeERC20                                                                        | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SignedMath                                                                       | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| StorageSlot                                                                      | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Strings                                                                          | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Subnetwork                                                                       | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticCoreBytecode                                                            | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticCoreConstants                                                           | 44               | 94                | 24,532             | 49,058              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticUtils                                                                   | 80               | 109               | 24,496             | 49,043              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TimelockController                                                               | 6,508            | 7,426             | 18,068             | 41,726              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TimelockControllerUpgradeable                                                    | 7,690            | 7,718             | 16,886             | 41,434              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Token                                                                            | 1,723            | 3,065             | 22,853             | 46,087              |
|----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TransparentUpgradeableProxy                                                      | 1,073            | 3,445             | 23,503             | 45,707              |
╰----------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╯
```

## File: src/interfaces/INetwork.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {ISetMaxNetworkLimitHook} from "./ISetMaxNetworkLimitHook.sol";
⋮----
/**
 * @title INetwork
 * @notice Interface for the Network contract.
 */
interface INetwork is ISetMaxNetworkLimitHook {
/**
     * @notice Reverts when the calldata length is invalid.
     */
⋮----
/**
     * @notice Reverts when the new delay is non-zero but disabled.
     */
⋮----
/**
     * @notice Reverts when the "recursive" delay update is attempted.
     */
⋮----
/**
     * @notice Reverts when the caller is not the network's middleware.
     */
⋮----
/**
     * @notice The storage of the Network contract.
     * @param _minDelays The mapping from the id (derived from the target and the selector) to the minimum delay.
     * @param _isMinDelayEnabled The mapping from the id (derived from the target and the selector) to the minimum delay enabled status.
     * @param _name The name of the network.
     * @param _metadataURI The metadata URI of the network.
     * @custom:storage-location erc7201:symbiotic.storage.Network
     */
⋮----
/**
     * @notice The parameters for the initialization of the Network contract.
     * @param globalMinDelay The global minimum delay.
     * @param delayParams The delays.
     * @param proposers The proposers.
     * @param executors The executors.
     * @param name The name of the network.
     * @param metadataURI The metadata URI of the network.
     * @param defaultAdminRoleHolder The address of the default admin role holder.
     * @param nameUpdateRoleHolder The address of the name update role holder.
     * @param metadataURIUpdateRoleHolder The address of the metadata URI update role holder.
     */
⋮----
/**
     * @notice The delay parameters.
     * @param target The target address the delay is for.
     * @param selector The function selector the delay is for.
     * @param delay The delay value.
     */
⋮----
/**
     * @notice Emitted when the minimum delay is changed.
     * @param target The target address the delay is for.
     * @param selector The function selector the delay is for.
     * @param oldEnabledStatus The old enabled status.
     * @param oldDelay The old delay value.
     * @param newEnabledStatus The new enabled status.
     * @param newDelay The new delay value.
     */
event MinDelayChange(
⋮----
/**
     * @notice Emitted when the name is set.
     * @param name The name of the network.
     */
event NameSet(string name);
⋮----
/**
     * @notice Emitted when the metadata URI is set.
     * @param metadataURI The metadata URI of the network.
     */
event MetadataURISet(string metadataURI);
⋮----
/**
     * @notice Returns the role for updating the name.
     * @return The role for updating the name.
     */
function NAME_UPDATE_ROLE() external view returns (bytes32);
⋮----
/**
     * @notice Returns the role for updating the metadata URI.
     * @return The role for updating the metadata URI.
     */
function METADATA_URI_UPDATE_ROLE() external view returns (bytes32);
⋮----
/**
     * @notice Returns the address of the network registry.
     * @return The address of the network registry.
     */
function NETWORK_REGISTRY() external view returns (address);
⋮----
/**
     * @notice Returns the address of the network middleware service.
     * @return The address of the network middleware service.
     */
function NETWORK_MIDDLEWARE_SERVICE() external view returns (address);
⋮----
/**
     * @notice Returns the minimum delay for a given target and calldata.
     * @param target The target address the delay is for.
     * @param data The calldata of the function call.
     * @return The minimum delay for a given target and calldata.
     */
function getMinDelay(address target, bytes memory data) external view returns (uint256);
⋮----
/**
     * @notice Returns the name of the network.
     * @return The name of the network.
     */
function name() external view returns (string memory);
⋮----
/**
     * @notice Returns the metadata URI of the network.
     * @return The metadata URI of the network.
     */
function metadataURI() external view returns (string memory);
⋮----
/**
     * @notice Initializes the network.
     * @param networkInitParams The parameters for the initialization of the network.
     */
function initialize(NetworkInitParams memory networkInitParams) external;
⋮----
/**
     * @notice Updates the delay for a given target and selector.
     * @param target The target address the delay is for.
     * @param selector The function selector the delay is for.
     * @param enabled If to enable the delay.
     * @param newDelay The new delay value.
     * @dev Can be reached only via scheduled calls.
     */
function updateDelay(address target, bytes4 selector, bool enabled, uint256 newDelay) external;
⋮----
/**
     * @notice Updates the name of the network.
     * @param name The new name.
     * @dev The caller must have the name update role.
     */
function updateName(string memory name) external;
⋮----
/**
     * @notice Updates the metadata URI of the network.
     * @param metadataURI The new metadata URI.
     * @dev The caller must have the metadata URI update role.
     */
function updateMetadataURI(string memory metadataURI) external;
```

## File: src/interfaces/ISetMaxNetworkLimitHook.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
/**
 * @title ISetMaxNetworkLimitHook
 * @notice Interface for the setMaxNetworkLimit hook.
 */
interface ISetMaxNetworkLimitHook {
/**
     * @notice Sets the maximum network limit for a delegator.
     * @param delegator The address of the delegator.
     * @param subnetworkId The identifier of the subnetwork.
     * @param maxNetworkLimit The maximum network limit.
     * @dev The caller must be the network's middleware.
     */
function setMaxNetworkLimit(address delegator, uint96 subnetworkId, uint256 maxNetworkLimit) external;
```

## File: src/Network.sol

```solidity
// SPDX-License-Identifier: MIT
⋮----
import {INetwork} from "./interfaces/INetwork.sol";
import {ISetMaxNetworkLimitHook} from "./interfaces/ISetMaxNetworkLimitHook.sol";
⋮----
import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol";
import {
    TimelockControllerUpgradeable
} from "@openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol";
⋮----
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkMiddlewareService} from "@symbioticfi/core/src/interfaces/service/INetworkMiddlewareService.sol";
import {INetworkRegistry} from "@symbioticfi/core/src/interfaces/INetworkRegistry.sol";
⋮----
/**
 * @title Network
 * @notice Contract for network management.
 * @dev It allows any external watcher to verify if the set delay is sufficient for a given operation (call to some contract's function).
 *      It supports delays for native asset transfers (native transfer is determined as a call with 0xEEEEEEEE selector).
 *      It supports setting delay for (exact target | exact selector) pairs and for (any target | exact selector) pairs.
 */
contract Network is TimelockControllerUpgradeable, INetwork {
⋮----
/**
     * @inheritdoc INetwork
     */
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.Network")) - 1)) & ~bytes32(uint256(0xff))
⋮----
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.TimelockController")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getNetworkStorage() internal pure returns (NetworkStorage storage $) {
⋮----
function _getTimelockControllerStorageOverridden() internal pure returns (TimelockControllerStorage storage $) {
⋮----
function initialize(NetworkInitParams memory initParams) public virtual initializer {
⋮----
function __Network_init(NetworkInitParams memory initParams) internal virtual onlyInitializing {
⋮----
function getMinDelay(address target, bytes memory data) public view virtual returns (uint256) {
⋮----
function name() public view virtual returns (string memory) {
⋮----
function metadataURI() public view virtual returns (string memory) {
⋮----
function updateDelay(address target, bytes4 selector, bool enabled, uint256 newDelay) public virtual {
⋮----
/**
     * @inheritdoc TimelockControllerUpgradeable
     */
function schedule(
⋮----
function scheduleBatch(
⋮----
function updateName(string memory name_) public virtual onlyRole(NAME_UPDATE_ROLE) {
⋮----
function updateMetadataURI(string memory metadataURI_) public virtual onlyRole(METADATA_URI_UPDATE_ROLE) {
⋮----
/**
     * @inheritdoc ISetMaxNetworkLimitHook
     */
function setMaxNetworkLimit(address delegator, uint96 subnetworkId, uint256 maxNetworkLimit) public virtual {
⋮----
function _updateDelay(address target, bytes4 selector, bool enabled, uint256 newDelay) internal virtual {
⋮----
function _scheduleOverridden(bytes32 id, uint256 delay) internal virtual {
⋮----
function _updateName(string memory name_) internal virtual {
⋮----
function _updateMetadataURI(string memory metadataURI_) internal virtual {
⋮----
function _setMaxNetworkLimit(address delegator, uint96 subnetworkId, uint256 maxNetworkLimit) internal virtual {
⋮----
function _getId(address target, bytes4 selector) internal pure virtual returns (bytes32 id) {
⋮----
function _getMinDelay(address target, bytes4 selector) internal view virtual returns (uint256) {
⋮----
function _getMinDelay(bytes32 id) internal view virtual returns (bool, uint256) {
⋮----
function _getSelector(bytes memory data) internal pure returns (bytes4 selector) {
⋮----
function _getPayload(bytes memory data) internal pure returns (bytes memory payload) {
⋮----
function initialize(
uint256, /* minDelay */
address[] memory, /* proposers */
address[] memory, /* executors */
address /* admin */
```

## File: ui/src/abi.ts

```typescript
// Minimal ABI for the Network Timelock-compatible contract
// Includes OpenZeppelin TimelockController functions/events and custom INetwork bits
⋮----
// Metadata
⋮----
// Custom getMinDelay overrides
⋮----
// Timelock read helpers
⋮----
// Timelock actions
⋮----
// Events
// AccessControl events
⋮----
// Global min delay change (OpenZeppelin)
⋮----
// Custom per target/selector delay change (INetwork)
⋮----
// AccessControl functions
⋮----
// Role constant getters (Timelock & custom)
⋮----
export enum OperationState {
  Unset = 0,
  Waiting = 1,
  Ready = 2,
  Done = 3,
}
```

## File: ui/src/index.css

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
⋮----
/* Optional: smooth fonts & background for nicer look */
:root {
html,
body {
```

## File: ui/src/main.tsx

```typescript
import React from "react";
⋮----
import { createRoot } from "react-dom/client";
import TimelockDashboard from "./TimelockDashboard";
import { WagmiProviders } from "./wagmiConfig";
```

## File: ui/src/TimelockDashboard.tsx

```typescript
import { useEffect, useMemo, useRef, useState } from "react";
import {
  createPublicClient,
  decodeEventLog,
  encodeFunctionData,
  formatEther,
  getAddress,
  Hex,
  http,
  parseEther,
  parseAbiItem,
} from "viem";
import type { Abi, AbiFunction, PublicClient } from "viem";
import { useAccount, useChainId, usePublicClient as useWagmiPublicClient, useWalletClient } from "wagmi";
import { wagmiAdapter } from "./wagmiConfig";
import { networkAbi, OperationState } from "./abi";
import { useAppKit } from "@reown/appkit/library/react";
⋮----
// Constants
⋮----
// Types
type ScheduledTx = {
  target: `0x${string}`;
  value: bigint;
  data: Hex;
  index: bigint;
};
⋮----
type OperationEntry = {
  id: Hex;
  predecessor: Hex;
  salt: Hex;
  delay: bigint;
  txs: ScheduledTx[];
  timestamp: bigint;
  state: OperationState;
};
⋮----
type RoleEntry = {
  role: Hex;
  name?: string;
  admin?: Hex | null;
  members: `0x${string}`[];
};
⋮----
type DelayEntry = {
  key: string;
  target: `0x${string}`;
  selector: string;
  enabled: boolean;
  delay: bigint;
};
⋮----
type BatchRow = {
  target: string;
  valueEth: string;
  data: string;
};
⋮----
type BatchBuilderMode = "raw" | "abi" | "sig";
⋮----
type ActiveTab = "main" | "acl";
⋮----
// Utility functions
const selectorFromData = (data: string): string =>
⋮----
const getLogsChunked = async (
  client: PublicClient,
  params: any,
  start: bigint,
  end: bigint,
  maxSpan: bigint,
  tokenRef: React.MutableRefObject<number>,
  myToken: number,
) =>
⋮----
const isArchiveRpcError = (error: any): boolean =>
⋮----
const handleError = (error: any, context: string) =>
⋮----
// Could add user-facing error notifications here
⋮----
// Custom hooks
const useRpcChainId = (rpcUrl: string, effectivePublicClient: PublicClient | null) =>
⋮----
async function fetchChainId()
⋮----
// Loading states
⋮----
const [executing, setExecuting] = useState<string>(""); // id being executed
⋮----
// Batch builder state
⋮----
// Batch schedule state
⋮----
// Configuration state
⋮----
// Token refs for cancellation
⋮----
// Access Control state
⋮----
// Unified loading state across sections
⋮----
// Extracted Access Control loader for unified Load
const loadAccessControl = async () =>
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
const tryRead = async (fn: string, name: string) =>
⋮----
// Unified load and cancel controls
⋮----
const detectDeploymentBlock = async () =>
⋮----
// Derive chainId from custom RPC when wallet is not connected
⋮----
// Explorer link for manual deployment block lookup (uses configured chains)
⋮----
const readHeader = async () =>
⋮----
const loadDelays = async () =>
⋮----
// Decode only the custom MinDelayChange by trying both event defs and accepting the address+bytes4 one
⋮----
// Two possible overloads; we need the one with address + bytes4 indexed
⋮----
// Sort: enabled first, then by target, then selector
⋮----
const loadOperations = async () =>
⋮----
// Fetch CallScheduled logs
⋮----
// Fetch CallSalt logs
⋮----
// @ts-ignore viem narrows via event
⋮----
// Group scheduled by id
⋮----
// @ts-ignore event typing from viem
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// @ts-ignore
⋮----
// Sort txs by index and fill status/timestamp from contract
⋮----
// ignore
⋮----
// Sort entries: Ready first, then Waiting by timestamp, then Done
⋮----
const prio = (x: OperationEntry)
⋮----
// Single schedule removed
⋮----
const onScheduleBatch = async () =>
⋮----
// Prompt user to connect if not connected
⋮----
const onExecute = async (entry: OperationEntry) =>
⋮----
// Single builder removed
⋮----
// Batch builder helpers
const buildBatchCalldataFromAbi = () =>
⋮----
const buildBatchCalldataFromSignature = () =>
⋮----
const computeBatchMinDelay = async () =>
⋮----
// Keep required min delay up to date when inputs change
⋮----
onChange=
⋮----
setDetectingFromBlock(false);
⋮----
onClick=
⋮----
```

## File: ui/src/vite-env.d.ts

```typescript
/// <reference types="vite/client" />
```

## File: ui/src/wagmiConfig.tsx

```typescript
import type { ReactNode } from "react";
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { mainnet, sepolia, holesky, hoodi } from "@reown/appkit/networks";
import { createAppKit } from "@reown/appkit/react";
import { WagmiAdapter } from "@reown/appkit-adapter-wagmi";
⋮----
// 0. Setup queryClient
⋮----
// 1. Get projectId from https://dashboard.reown.com
⋮----
// 2. Create a metadata object
⋮----
// 4. Create Wagmi Adapter
⋮----
// 5. Create modal
⋮----
export function AppKitProvider(
```

## File: ui/eslint.config.js

```javascript

```

## File: ui/index.html

```html
<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Network Dashboard</title>
    </head>
    <body>
        <div id="root"></div>
        <script type="module" src="/src/main.tsx"></script>
    </body>
</html>
```

## File: ui/postcss.config.cjs

```javascript
// Resolve config path regardless of CWD
```

## File: ui/tailwind.config.cjs

```javascript
/** @type {import('tailwindcss').Config} */
⋮----
// Absolute paths so Tailwind finds files regardless of CWD
```

## File: ui/tsconfig.app.json

```json
{
    "compilerOptions": {
        "target": "ES2020",
        "useDefineForClassFields": true,
        "lib": ["ES2020", "DOM", "DOM.Iterable"],
        "module": "ESNext",
        "skipLibCheck": true,

        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "isolatedModules": true,
        "moduleDetection": "force",
        "noEmit": true,
        "jsx": "react-jsx",

        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true
    },
    "include": ["src"]
}
```

## File: ui/tsconfig.json

```json
{
    "files": [],
    "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
}
```

## File: ui/tsconfig.node.json

```json
{
    "compilerOptions": {
        "target": "ES2022",
        "lib": ["ES2023"],
        "module": "ESNext",
        "skipLibCheck": true,

        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "isolatedModules": true,
        "moduleDetection": "force",
        "noEmit": true,

        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true
    },
    "include": ["vite.config.mts"]
}
```

## File: ui/vite.config.mts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
```

## File: .gitmodules

```
[submodule "lib/forge-std"]
	path = lib/forge-std
	url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
	path = lib/openzeppelin-contracts
	url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
	path = lib/openzeppelin-contracts-upgradeable
	url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/core"]
	path = lib/core
	url = https://github.com/symbioticfi/core
```

## File: .prettierrc

```
{
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "singleQuote": false,
  "bracketSpacing": true,
  "trailingComma": "all",
  "overrides": [
    {
      "files": "*.sol",
      "options": {
        "printWidth": 120,
        "tabWidth": 4,
        "useTabs": false,
        "singleQuote": false,
        "bracketSpacing": false
      }
    },
    {
      "files": "*.json",
      "options": {
        "tabWidth": 4
      }
    }
  ]
}
```

## File: codecov.yml

```yaml
codecov:
    require_ci_to_pass: true

coverage:
    precision: 2
    round: down
    range: "70...100"
    status:
        project:
            default:
                # basic
                target: auto
                threshold: 0%
                base: auto
                # advanced
                if_no_uploads: error
                if_not_found: success
                if_ci_failed: error
                only_pulls: false
        patch:
            default:
                # basic
                target: auto
                threshold: 0%
                base: auto
                # advanced
                if_no_uploads: error
                if_not_found: success
                if_ci_failed: error
                only_pulls: false

parsers:
    gcov:
        branch_detection:
            conditional: true
            loop: true
            method: false
            macro: false

comment:
    layout: "reach,diff,flags,files,footer"
    behavior: default
    require_changes: false
    require_base: false
    require_head: true

ignore:
    - "script"
    - "test"
    - "src/test"
```

## File: CONTRIBUTING.md

````markdown
# Contributing

- [Install](#install)
- [Pre-commit Hooks](#pre-commit-hooks)
- [Requirements for merge](#requirements-for-merge)
- [Branching](#branching)
    - [Main](#main)
    - [Audit](#audit)
- [Code Practices](#code-practices)
    - [Code Style](#code-style)
    - [Solidity Versioning](#solidity-versioning)
    - [Interfaces](#interfaces)
    - [NatSpec \& Comments](#natspec--comments)
- [Testing](#testing)
    - [Best Practices](#best-practices)
    - [IR Compilation](#ir-compilation)
    - [Gas Metering](#gas-metering)
- [Deployment](#deployment)
    - [Bytecode Hash](#bytecode-hash)
- [Dependency Management](#dependency-management)
- [Releases](#releases)

## Install

Follow these steps to set up your local environment for development:

- [Install foundry](https://book.getfoundry.sh/getting-started/installation)
- Install dependencies: `forge install`
- [Install pre-commit](https://pre-commit.com/#installation)
- Install pre commit hooks: `pre-commit install`

## Pre-commit Hooks

Follow the [installation steps](#install) to enable pre-commit hooks. To ensure consistency in our formatting `pre-commit` is used to check whether code was formatted properly and the documentation is up to date. Whenever a commit does not meet the checks implemented by pre-commit, the commit will fail and the pre-commit checks will modify the files to make the commits pass. Include these changes in your commit for the next commit attempt to succeed. On pull requests the CI checks whether all pre-commit hooks were run correctly.
This repo includes the following pre-commit hooks that are defined in the `.pre-commit-config.yaml`:

- `mixed-line-ending`: This hook ensures that all files have the same line endings (LF).
- `trailing-whitespace`: Strips trailing spaces from lines so that diffs remain clean and editors don't introduce noise.
- `end-of-file-fixer`: Ensures every file ends with a single newline and removes extra blank lines at the end of files.
- `check-merge-conflict`: Fails when Git merge conflict markers are present to avoid committing unresolved conflicts.
- `check-json`: Validates JSON files and fails fast on malformed syntax.
- `check-yaml`: Parses YAML files to verify they are syntactically valid.
- `sort-imports`: Normalises and sorts imports according to the rules mentioned in the [Code Style](#code-style) below.
- `sort-errors`: Sorts errors according to the rules mentioned in the [Code Style](#code-style) below.
- `format`: This hook uses `forge fmt` to format all Solidity files.
- `doc`: This hook uses `forge doc` to generate the Solidity documentation. Commit the generated files whenever the documentation changes.
- `prettier`: All remaining files are formatted using prettier.

## Requirements for merge

In order for a PR to be merged, it must pass the following requirements:

- All commits within the PR must be signed
- CI must pass (tests, linting, etc.)
- New features must be merged with associated tests
- Bug fixes must have a corresponding test that fails without the fix
- The PR must be approved by at least one maintainer

## Branching

This section outlines the branching strategy of this repo.

### Main

The main branch is supposed to reflect the deployed state on all networks, if not indicated otherwise inside the README. Only audited code should be merged into main. Сommits from dev branches should be merged into the main branch using a regular merge strategy. The commit messages should follow [the Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/).

### Audit

Before an audit, the code should be frozen on a branch dedicated to the audit with the naming convention `audit/<provider>`. Each fix in response to an audit finding should be developed as a separate commit. The commit message should look similar to `fix: <provider> - <issue title>`.

## Code Practices

### Code Style

The repo follows the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). In addition to that, this repo also borrows the following rules from [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/GUIDELINES.md#solidity-conventions):

- Internal or private state variables or functions should have an underscore prefix.

    ```solidity
    contract TestContract {
        uint256 private _privateVar;
        uint256 internal _internalVar;
        function _testInternal() internal { ... }
        function _testPrivate() private { ... }
    }
    ```

- Naming collisions should be avoided using a single trailing underscore.

    ```solidity
    contract TestContract {
        uint256 public foo;

        constructor(uint256 foo_) {
          foo = foo_;
        }
    }
    ```

- Interface names should have a capital I prefix.

    ```solidity
    interface IERC777 {
    ```

- Contracts not intended to be used standalone should be marked abstract, so they are required to be inherited by other contracts.

    ```solidity
    abstract contract AccessControl is ..., {
    ```

- Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen or is permissible. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.

Also, such exceptions/additions exist:

- Functions should be grouped according to their visibility and ordered:
    1. constructor

    2. external

    3. public

    4. internal

    5. private

    6. receive function (if exists)

    7. fallback function (if exists)

- Each contract should be virtually divided into sections by using such separators:
    1. /\* CONSTANTS \*/
    2. /\* IMMUTABLES \*/
    3. /\* STATE VARIABLES \*/
    4. /\* MODIFIERS \*/
    5. /\* CONSTRUCTOR \*/
    6. /\* EXTERNAL FUNCTIONS \*/
    7. /\* PUBLIC FUNCTIONS \*/
    8. /\* INTERNAL FUNCTIONS \*/
    9. /\* PRIVATE FUNCTIONS \*/
    10. /\* RECEIVE FUNCTION \*/
    11. /\* FALLBACK FUNCTION \*/

- Each interface should be virtually divided into sections by using such separators:
    1. /\* ERRORS \*/
    2. /\* STRUCTS \*/
    3. /\* EVENTS \*/
    4. /\* FUNCTIONS \*/

- Do not use external and private visibilities in most cases.

- Events should generally be emitted immediately after the state change that they
  represent, and should be named the same as the function's name. Some exceptions may be made for gas
  efficiency if the result doesn't affect the observable ordering of events.

    ```solidity
    function _burn(address who, uint256 value) internal {
        super._burn(who, value);
        emit Burn(who, value);
    }
    ```

- Custom errors should be used whenever possible. The naming should be concise and easy to read.

- Imports should be divided into separate groups and ordered alphabetically ascending inside each group:
    1. contracts

    2. libraries

    3. interfaces

    4. external files separately

    ```solidity
    import {NetworkManager} from "../base/NetworkManager.sol";
    import {OzEIP712} from "../base/OzEIP712.sol";
    import {PermissionManager} from "../base/PermissionManager.sol";

    import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
    import {KeyTags} from "../../libraries/utils/KeyTags.sol";

    import {ISettlement} from "../interfaces/modules/settlement/ISettlement.sol";
    import {ISigVerifier} from "../interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";

    import {StaticDelegateCallable} from "@symbioticfi/core/src/contracts/common/StaticDelegateCallable.sol";
    import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";

    import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
    ```

- In case of comparison with `msg.sender` or `tx.origin`, these keywords should be on the right side of the inequality.

    ```solidity
    modifier onlyOwner() internal {
        if (owner != msg.sender) {
          revert NotOwner();
        }
    }
    ```

- Errors should be ordered alphabetically ascending.

    ```solidity
    error InsufficientFunds();
    error NoAccess();
    error NotOwner();
    ```

### Solidity Versioning

Contracts that are meant to be deployed should have an explicit version set in the `pragma` statement.

```solidity
pragma solidity 0.8.X;
```

Abstract contracts, libraries and interfaces should use the caret (`^`) range operator to specify the version range to ensure better compatibility.

```solidity
pragma solidity ^0.X.0;
```

Libraries and abstract contracts using functionality introduced in newer versions of Solidity can use caret range operators with higher path versions (e.g., `^0.8.24` when using transient storage opcodes). For interfaces, it should be considered to use the greater than or equal to (`>=`) range operator to ensure better compatibility with future versions of Solidity.

### Interfaces

Every contract MUST implement its corresponding interface that includes all externally callable functions, errors and events.

### NatSpec & Comments

Interfaces should be the entry point for all contracts. When exploring a contract within the repository, the interface MUST contain all relevant information to understand the functionality of the contract in the form of NatSpec comments. This includes all externally callable functions, structs, errors and events. The NatSpec documentation MUST be added to the functions, structs, errors and events within the interface. This allows a reader to understand the functionality of a function before moving on to the implementation. The implementing functions MUST point to the NatSpec documentation in the interface using `@inheritdoc`. Internal and private functions shouldn't have NatSpec documentation except for `@dev` comments, whenever more context is needed. Additional comments within a function should only be used to give more context to more complex operations; otherwise, the code should be kept readable and self-explanatory. NatSpec comments in contracts should use a triple slash (`///`) to bring less noise to the implementation, while libraries and interfaces should use `/* */` wrappers.

The comments should respect the following rules:

- For read functions: `@notice Returns <...>`
- For write functions: `@notice <What it does, starts with verb>`
- For structs: `@notice <What it is>`
- For errors: `@notice Raised when <...>`
- For events: `@notice Emitted when <...>`

Each contract/library/interface should have a title comment that should follow such a structure:

1. `@title <Name>` (e.g., `Vault`)
2. `@notice Contract/Library/Interface for <...>.` - also, other variations are possible, e.g.:
    - `@notice Interface for the Vault contract.`
    - `@notice Base contract for <...>.`
    - `@notice Library-logic for <...>.`
3. `@dev <...>` (optional)

## Testing

The following testing practices should be followed when writing unit tests for new code. All functions, lines and branches should be tested to result in 100% testing coverage. Fuzz parameters and conditions whenever possible. Extremes should be tested in dedicated edge case and corner case tests. Invariants should be tested in dedicated invariant tests.

Differential testing should be used to compare assembly implementations with implementations in Solidity or testing alternative implementations against existing Solidity or non-Solidity code using ffi.

New features must be merged with associated tests. Bug fixes should have a corresponding test that fails without the bug fix.

### Best Practices

Best practices and naming conventions should be followed as outlined in the [Foundry Book](https://getfoundry.sh/forge/tests/overview).

### IR Compilation

All contracts and tests should be compilable without IR whenever possible.

### Gas Metering

Gas for function calls should be metered using the built-in `vm.snapshotGasLastCall` function in forge. To meter across multiple calls `vm.startSnapshotGas` and `vm.stopSnapshotGas` can be used. Tests that measure gas should be annotated with `/// forge-config: default.isolate = true` and not be fuzzed to ensure that the gas snapshot is accurate and consistent for CI verification. All external functions should have a gas snapshot test, and diverging paths within a function should have appropriate gas snapshot tests.
For more information on gas metering, see the [Forge cheatcodes reference](https://getfoundry.sh/reference/cheatcodes/gas-snapshots/#snapshotgas-cheatcodes).

### Bytecode Hash

Bytecode hash should be set to `none` in the `foundry.toml` file to ensure that the bytecode is consistent.

## Dependency Management

The preferred way to manage dependencies is using [`forge install`](https://book.getfoundry.sh/forge/dependencies). This ensures that your project uses the correct versions and structure for all external libraries. Also, `npm` and `soldeer` packages should be published to increase coverage of different use-cases.

## Releases

Every deployment and change made to contracts after deployment should be accompanied by a tag and release on GitHub.
````

## File: foundry.lock

```
{
  "lib/core": {
    "tag": {
      "name": "v1.0.3",
      "rev": "74c0c6fbd5531a6065cdafdab07840b04a0d2039"
    }
  },
  "lib/forge-std": {
    "tag": {
      "name": "v1.10.0",
      "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824"
    }
  },
  "lib/openzeppelin-contracts": {
    "tag": {
      "name": "v5.4.0",
      "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0"
    }
  },
  "lib/openzeppelin-contracts-upgradeable": {
    "tag": {
      "name": "v5.4.0",
      "rev": "e725abddf1e01cf05ace496e950fc8e243cc7cab"
    }
  }
}
```

## File: foundry.toml

```toml
[profile.default]
evm_version = "prague"
solc = "0.8.28"
optimizer = true
optimizer_runs = 200
via_ir = false
bytecode_hash = "none"
src = "src"
out = "out"
libs = ["lib"]
fs_permissions = [{ access = "read-write", path = "./"}]
gas_reports = ["*"]
gas_limit = "18446744073709551615"
dynamic_test_linking = true
ignored_warnings_from = ["test/","script/"]
ffi = true

[rpc_endpoints]
mainnet = "${ETH_RPC_URL}"
hoodi = "${ETH_RPC_URL_HOODI}"
holesky = "${ETH_RPC_URL_HOLESKY}"
sepolia = "${ETH_RPC_URL_SEPOLIA}"

[fmt]
bracket_spacing = false
int_types = "long"
line_length = 120
multiline_func_header = "attributes_first"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
single_line_statement_blocks = "preserve"
sort_imports = false
contract_new_lines = false
override_spacing = false
hex_underscore = "preserve"
wrap_comments = false

[lint]
lint_on_build = false
exclude_lints = ["asm-keccak256","mixed-case-function","mixed-case-variable","pascal-case-struct","screaming-snake-case-const"]
ignore = ["test/**/*.sol","script/**/*.sol","src/interfaces/**/*.sol"]

additional_compiler_profiles = [
  { name = "test", via_ir = false, optimizer = false }
]

compilation_restrictions = [
  { paths = "test/**", via_ir = false, optimizer = false }
]

[profile.default.fuzz]
runs = 1000
max_test_rejects = 262144

[profile.pr.fuzz]
runs = 10000
max_test_rejects = 262144

[profile.ci.fuzz]
runs = 100000
max_test_rejects = 262144

[profile.debug]
via_ir = false
optimizer_runs = 200
fuzz.runs = 100

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
```

## 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": "@symbioticfi/network",
    "version": "1.0.0-rc.2",
    "description": "Symbiotic Network contract provides a flexible and secure mechanism to manage network operations with customizable delays.",
    "homepage": "https://symbiotic.fi/network",
    "bugs": "https://github.com/symbioticfi/network/issues",
    "license": "MIT",
    "author": "Symbiotic Team",
    "files": [
        "examples/**/*",
        "src/**/*",
        "script/**/*",
        "test/mocks/**/*",
        "abis/**/*",
        "bindings/ts-viem/**/*"
    ],
    "repository": {
        "type": "git",
        "url": "https://github.com/symbioticfi/network.git"
    },
    "keywords": ["solidity", "ethereum", "smart", "contracts", "security"],
    "scripts": {
        "dev": "vite ui",
        "build": "vite build ui",
        "preview": "vite preview ui",
        "typecheck": "tsc --noEmit"
    },
    "dependencies": {
        "@symbioticfi/core": "1.0.3",
        "@openzeppelin/contracts": "5.4.0",
        "@openzeppelin/contracts-upgradeable": "5.4.0"
    },
    "devDependencies": {
        "@reown/appkit": "^1.8.4",
        "@reown/appkit-adapter-wagmi": "^1.8.4",
        "@tanstack/react-query": "^5.87.1",
        "react": "^18.3.1",
        "react-dom": "^18.3.1",
        "viem": "^2.37.5",
        "wagmi": "^2.16.9",
        "@types/node": "^20.16.11",
        "@types/react": "^18.3.3",
        "@types/react-dom": "^18.3.0",
        "@vitejs/plugin-react": "^4.3.1",
        "autoprefixer": "^10.4.20",
        "postcss": "^8.4.41",
        "tailwindcss": "^3.4.10",
        "typescript": "^5.5.4",
        "vite": "^5.4.2"
    },
    "engines": {
        "node": ">=20"
    }
}
```

## File: README.md

````markdown
**[Symbiotic Protocol](https://symbiotic.fi) is an extremely flexible and permissionless shared security system.**

This repository contains a default Network contract and tooling to manage it. Basically, a Network contract is an [OZ's TimelockController](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/governance/TimelockController.sol) with additional functionality to define delays for either (exact target | exact selector) or (any target | exact selector) pairs.

[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/symbioticfi/network)
[![codecov](https://codecov.io/github/symbioticfi/network/graph/badge.svg?token=ZSNR9UBS59)](https://codecov.io/github/symbioticfi/network)

## Documentation

- [What is Network?](https://docs.symbiotic.fi/modules/counterparties/networks)
- [What are Resolvers?](https://docs.symbiotic.fi/modules/counterparties/resolvers)
- [Network Registration](https://docs.symbiotic.fi/modules/registries#network-registration-process)

## Usage

### Dependencies

- Git ([installation](https://git-scm.com/downloads))
- foundry ([installation](https://getfoundry.sh/introduction/installation/))
- npm ([installation](https://nodejs.org/en/download/))

### Prerequisites

**Clone the repository**

```bash
git clone --recurse-submodules https://github.com/symbioticfi/network.git
```

**Install dependencies**

```bash
npm install
```

### Deploy Your Network

- If you need a pure Network deployment

    Open [DeployNetwork.s.sol](./script/DeployNetwork.s.sol), you will see config like this:

    ```solidity
    // Name of the Network
    string NAME = "My Network";
    // Default minimum delay (will be applied for any action that doesn't have a specific delay yet)
    uint256 DEFAULT_MIN_DELAY = 3 days;
    // Cold actions delay (a delay that will be applied for major actions like upgradeProxy and setMiddleware)
    uint256 COLD_ACTIONS_DELAY = 14 days;
    // Hot actions delay (a delay that will be applied for minor actions like setMaxNetworkLimit and setResolver)
    uint256 HOT_ACTIONS_DELAY = 0;
    // Admin address (will become executor, proposer, and default admin by default)
    address ADMIN = 0x0000000000000000000000000000000000000000;

    // Optional

    // Metadata URI of the Network
    string METADATA_URI = "";
    // Salt for deterministic deployment
    bytes11 SALT = "SymNetwork";
    ```

    Edit needed fields, and execute the script via:

    ```bash
    forge script script/DeployNetwork.s.sol --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> --etherscan-api-key <ETHERSCAN_API_KEY> --broadcast --verify
    ```

- If you need a Network deployment for already-deployed Vaults

    Open [DeployNetworkForVaults.s.sol](./script/DeployNetworkForVaults.s.sol), you will see config like this:

    ```solidity
    // Name of the Network
    string NAME = "My Network";
    // Default minimum delay (will be applied for any action that doesn't have a specific delay yet)
    uint256 DEFAULT_MIN_DELAY = 3 days;
    // Cold actions delay (a delay that will be applied for major actions like upgradeProxy and setMiddleware)
    uint256 COLD_ACTIONS_DELAY = 14 days;
    // Hot actions delay (a delay that will be applied for minor actions like setMaxNetworkLimit and setResolver)
    uint256 HOT_ACTIONS_DELAY = 0;
    // Admin address (will become executor, proposer, and default admin by default)
    address ADMIN = 0x0000000000000000000000000000000000000000;
    // Vault address to opt-in to (multiple vaults can be set)
    address[] VAULTS = [0x0000000000000000000000000000000000000000];
    // Maximum amount of delegation that network is ready to receive (multiple vaults can be set)
    uint256[] MAX_NETWORK_LIMITS = [0];
    // Resolver address (optional, is applied only if VetoSlasher is used) (multiple vaults can be set)
    address[] RESOLVERS = [0x0000000000000000000000000000000000000000];

    // Optional

    // Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different resolvers for the same network)
    uint96 SUBNETWORK_ID = 0;
    // Metadata URI of the Network
    string METADATA_URI = "";
    // Salt for deterministic deployment
    bytes11 SALT = "SymNetwork";
    ```

    Edit needed fields, and execute the script via:

    ```bash
    forge script script/DeployNetworkForVaults.s.sol --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> --etherscan-api-key <ETHERSCAN_API_KEY> --broadcast --verify
    ```

In the console, you will see logs like these:

```bash
Deployed network
  network:0x90F545649eDA7a2083bA30ECC5C21335d030ae1d
  proxyAdminContract:0x79d771aeC770C936E05E51fA8e68f019a373f9b1
  newImplementation:0x3C00C0ef1B1be4dFFeF07dB148bb5fbF31277091
  salt:0x5465737433000000000000000000000000000000000000000000000000000000
Opted network into vault
  network:0x90F545649eDA7a2083bA30ECC5C21335d030ae1d
  vault:0x49fC19bAE549e0b5F99B5b42d7222Caf09E8d2a1
  subnetworkId:0
  maxNetworkLimit:1000
  resolver:0xbf616b04c463b818e3336FF3767e61AB44103243
```

### Manage Your Network

There are 5 predefined [action-scripts](./script/actions/), that you can use from the start:

- [SetMaxNetworkLimit](./script/actions/SetMaxNetworkLimit.s.sol) - set new [maximum network limit](https://docs.symbiotic.fi/modules/registries#3-network-to-vault-opt-in) for the vault
- [SetResolver](./script/actions/SetResolver.s.sol) - set a new [resolver](https://docs.symbiotic.fi/modules/counterparties/resolvers) for the vault (only if the vault uses [VetoSlasher](https://docs.symbiotic.fi/modules/vault/slashing#1-vetoslasher))
- [SetMiddleware](./script/actions/SetMiddleware.s.sol) - set a new middleware
- [UpgradeProxy](./script/actions/UpgradeProxy.s.sol) - upgrade the proxy (network itself)
- [ArbitraryCall](./script/actions/ArbitraryCall.s.sol) - make a call to any contract with any data

Interaction with different actions is similar; let's consider [SetMaxNetworkLimit](./script/actions/SetMaxNetworkLimit.s.sol) as an example:

1. Open [SetMaxNetworkLimit.s.sol](./script/actions/SetMaxNetworkLimit.s.sol), you will see config like this:

    ```solidity
    // Address of the Network
    address NETWORK = 0x0000000000000000000000000000000000000000;
    // Address of the Vault
    address VAULT = 0x0000000000000000000000000000000000000000;
    // Maximum amount of delegation that network is ready to receive
    uint256 MAX_NETWORK_LIMIT = 0;
    // Delay for the action to be executed
    uint256 DELAY = 0;

    // Optional

    // Subnetwork Identifier (multiple subnetworks can be used, e.g., to have different max network limits for the same network)
    uint96 SUBNETWORK_IDENTIFIER = 0;
    // Salt for TimelockController operations
    bytes32 SALT = "SetMaxNetworkLimit";
    ```

2. Edit needed fields, and choose an operation:
    - `runS()` - schedule an action
    - `runE` - execute an action
    - `runSE()` - schedule and execute an action (possible only if a delay for the needed action is zero)

3. Execute the operation:
    - If you use an EOA and want to execute the script:

        ```bash
        forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> --broadcast
        ```

    - If you use a Safe multisig and want to get a transaction calldata:

        ```bash
        forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url <RPC_URL> --sender <MULTISIG_ADDRESS> --unlocked
        ```

        In the logs, you will see `callData` field like this:

        ```bash
        callData:0x01d5062a00000000000000000000000025ed2ee6e295880326bdeca245ee4d8b72c8f103000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000005365744d61784e6574776f726b4c696d697400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004423f752d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6700000000000000000000000000000000000000000000000000000000
        ```

        In Safe->TransactionBuilder, you should:
        - enable "Custom data"
        - enter **Network's address** as a target address
        - use the `callData` (e.g., `0x01d5062a0000000000000000000000...`) received earlier as a `Data (Hex encoded)`

### Update Delays

Any action that can be made by the Network is protected by the corresponding delay (which can be any value from zero to infinity).

We provide "update delay" scripts for actions mentioned above, and also some additional ones:

- [SetMaxNetworkLimitUpdateDelay](./script/update-delay/SetMaxNetworkLimitUpdateDelay.s.sol)
- [SetResolverUpdateDelay](./script/update-delay/SetResolverUpdateDelay.s.sol)
- [SetMiddlewareUpdateDelay](./script/update-delay/SetMiddlewareUpdateDelay.s.sol)
- [UpgradeProxyUpdateDelay](./script/update-delay/UpgradeProxyUpdateDelay.s.sol)
- [HotActionsUpdateDelay](./script/update-delay/HotActionsUpdateDelay.s.sol) - update a delay for [SetMaxNetworkLimitUpdateDelay](./script/update-delay/SetMaxNetworkLimitUpdateDelay.s.sol) and [SetResolverUpdateDelay](./script/update-delay/SetResolverUpdateDelay.s.sol)
- [ColdActionsUpdateDelay](./script/update-delay/ColdActionsUpdateDelay.s.sol) - update a delay for [SetMiddlewareUpdateDelay](./script/update-delay/SetMiddlewareUpdateDelay.s.sol) and [UpgradeProxyUpdateDelay](./script/update-delay/UpgradeProxyUpdateDelay.s.sol)
- [DefaultUpdateDelay](./script/update-delay/DefaultUpdateDelay.s.sol) - update a delay for unconstrained actions
- [ArbitraryUpdateDelay](./script/update-delay/ArbitraryCallUpdateDelay.s.sol) - update a delay for an arbitrary call:
    - set a delay for the exact target address and the exact selector
    - set a delay for any target address and the exact selector (by setting target address to `0x0000000000000000000000000000000000000000`)

For example usage of similar scripts see ["Manage Your Network"](./README.md#manage-your-network).

### Dashboard

**Note: work-in-progress, use with caution**

`Network` contract inherits OpenZeppelin's `TimelockController`, while `TimelockController` inherits `AccessControl`. The similarity between `TimelockController` and `AccessControl` contracts' logic is that it is not possible to adequately determine their state (e.g., statuses of operations or holders of roles) using only the current chain's state via RPC calls. Hence, we provide a [Network Dashboard](./ui/) which allows you to:

- Get delays for all operations
- Get holders of any role
- Get scheduled/executed operations
- Schedule/execute arbitrary actions

Run the command:

```bash
npm run dev
```

### Build, Test, and Format

```
forge build
forge test
forge fmt
```

**Configure environment**

Create `.env` based on the template:

```
ETH_RPC_URL=
ETHERSCAN_API_KEY=
```

## Security

Security audits can be found [here](./audits).
````

## File: remappings.txt

```
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@symbioticfi/core/=lib/core/
```
