---

## /integrate/networks/helpful-core-contracts-endpoints

---
description: "This page lists useful functions for networks across Symbiotic Core contracts."
---

# Helpful Core Contracts' Endpoints

This page lists useful functions for networks across Symbiotic Core contracts.

| Function                                                                                                                                                                                                                                                            | Use-case                                                                                   |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| [`NetworkRegistry.registerNetwork()`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/INetworkRegistry.sol#L12)                                                                                                    | Register network                                                                           |
| [`Vault.isInitialized() → bool`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/vault/IVault.sol#L165)                                                                                                            | Check if the vault has set delegator and slasher before on-boarding as a valid Vault       |
| [`Vault.delegator() → address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/vault/IVaultStorage.sol#L60)                                                                                                       | Get the Vault's delegator                                                                  |
| [`Vault.slasher() → address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/vault/IVaultStorage.sol#L72)                                                                                                         | Get the Vault's slasher                                                                    |
| [`BaseDelegator.TYPE() → uint64`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/common/IEntity.sol#L17)                                                                                                          | Get the delegator's type (0 - NetworkRestake, 1 - FullRestake, etc.)                       |
| [`BaseDelegator.setMaxNetworkLimit(uint96 identifier, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IBaseDelegator.sol#L158)                                                         | Set an amount of collateral you are ready to accept from the Vault (maximum network limit) |
| [`BaseDelegator.maxNetworkLimit(bytes32 subnetwork) → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IBaseDelegator.sol#L125)                                                                 | Check the maximum network limit                                                            |
| [`BaseDelegator.stakeAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes hints) → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IBaseDelegator.sol#L137)                        | Get the operator's stake at the given timestamp                                            |
| [`BaseSlasher.TYPE() → uint64`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/common/IEntity.sol#L17)                                                                                                            | Get the slasher's type (0 - Slasher, 1 - VetoSlasher)                                      |
| [`BaseSlasher.slashableStake() → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/IBaseSlasher.sol#L113)                                                                                          | Get the operator's still slashable stake captured at the given timestamp                   |
| [`Slasher.slash() → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/ISlasher.sol#L55)                                                                                                            | Slash the operator                                                                         |
| [`VetoSlasher.requestSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp, bytes hints) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/IVetoSlasher.sol#L213) | Request slashing of the operator                                                           |
| [`VetoSlasher.executeSlash(uint256 slashIndex, bytes hints) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/IVetoSlasher.sol#L228)                                                            | Execute slashing of the operator                                                           |
| [`VetoSlasher.setResolver(uint96 identifier, address resolver, bytes hints)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/IVetoSlasher.sol#L245)                                                       | Set a resolver                                                                             |
| [`VetoSlasher.resolver(bytes32 subnetwork, bytes hint)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/slasher/IVetoSlasher.sol#L201)                                                                            | Check the resolver                                                                         |


---

## /integrate/networks

---
description: "This guide walks you through integrating your network with Symbiotic. Follow these steps to register your network, set up security, and start receiving stake..."
---

import { Card1 } from "../../../components/Card1";

# Get Started

This guide walks you through integrating your network with Symbiotic. Follow these steps to register your network, set up security, and start receiving stake allocations.

:::steps
## Network Contract

Register your network's management address in the Symbiotic system.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Quickstart: Network with Staking"
    description="Get familiar with Protocol: deploy a minimal network, middleware and vault-operator-staker setup"
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/minimal-network"
  />

  <Card1
    title="Network Contract"
    description="Deploy production-ready Network contract"
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/network-contract"
  />
</div>

## Submit Metadata

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title=""
    description="Submit a PR with your network's metadata to make it visible on the Symbiotic UI."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/submit-metadata"
  />
</div>

## Set Up Pre-deposit Vault (Optional)

If you need a self-curated vault, deploy and configure it.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Deploy Pre-deposit Vault"
    description="Configure and deploy a self-curated vault for your network."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/curators/deploy-vault"
  />

  <Card1
    title="Submit Vault's Metadata"
    description="Submit your vault's metadata after deployment."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/curators/submit-metadata"
  />
</div>

## Integrate Rewards

Rewards are essential for healthy protocol economics. Learn how to integrate Symbiotic rewards.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title=""
    description="Integrate Symbiotic rewards to distribute rewards to stakers."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/rewards"
  />
</div>

## Integrate Slashing

Slashing protects your protocol by penalizing misbehavior. Learn how slashing works in Symbiotic.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title=""
    description="Implement slashing to secure your network and penalize misbehavior."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/slashing"
  />
</div>

## Implement On-Chain Components

Build your on-chain integration using Symbiotic's Relay framework.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Use Relay Contracts"
    description="Build stake-secured applications using Symbiotic Relay. Learn how to construct Relay-compatible smart contracts."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/relay-onchain"
  />

  <Card1
    title="Set Your Middleware"
    description="Configure your middleware to perform slashings and rewards distributions using the `Network.sol` contract."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/network-contract#manage-your-network"
  />
</div>

## Implement Off-Chain Components

Build your off-chain application using Relay Sidecar.

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Use Relay Sidecar"
    description="Build your Relay App using the Sidecar architecture."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/relay-offchain"
  />
</div>
:::


---

## /integrate/networks/minimal-network

---
description: "This guide sets up a minimal Hoodi testnet environment so you can validate production flows on testnet."
---

# Quickstart: Network with Staking

This guide sets up a minimal Hoodi testnet environment so you can validate production flows on testnet.

:::info
Although this walkthrough uses externally owned accounts (EOAs) for Network and Middleware, the sequence of on-chain actions outside of the Network and Middleware is the same as if those accounts were production smart contracts.
:::

## Prerequisites

Prepare 6 EOAs for simulation:

- **Network**: network identity account
- **Middleware**: set by the network to handle reward distribution and vault opt-ins
- **Vault Curator**: sets up the vault and allocates shares
- **Operator**: receives delegated stake
- **Two Test Stakers**: deposit collateral

::::steps
### Register Network & Set Middleware

For both transactions, originator (`msg.sender`) is the network address.

1. Register your network in `NetworkRegistry` via `registerNetwork()`.  ([Sample Tx](https://hoodi.etherscan.io/tx/0x2da545af56094c2dbd7e49dfb838915b84e889ea341dae812483ee7c6840c196))
2. Set the middleware address in `NetworkMiddlewareService` via `setMiddleware(middleware)`.  ([Sample Tx](https://hoodi.etherscan.io/tx/0xf57a8e2fe75a9453620c0b2903165a34be9bc20749dc36b966f169e7f8f963ac))

### Create Vault & Register Operator

1. [Create a vault](https://app.hoodi.symbiotic.fi/create) using `wstETH` as collateral.
   - Sample Vault address: `0xb29BAD40B00587dE1145C7862F96746f043b9daD`  ([Sample Tx](https://hoodi.etherscan.io/tx/0x94ad7d76fc41e75528b1d2bbc0496c5664e59900c07f5e8bfa81505cca88d45b))
2. Register operator in `OperatorRegistry` via `registerOperator()`   ([Sample Tx](https://hoodi.etherscan.io/tx/0xc6ff4fabf604325e2357963004f4f96dceefec6e874edbec75677d827fbc507b))
3. Opt operator into Network using `OperatorNetworkOptInService` via `optIn()`  ([Sample Tx](https://hoodi.etherscan.io/tx/0xa116a2e7e7386019147b2952ad59fb169d2043f49088098dfc82c2422ecdd83d))
4. Opt operator into Vault using `OperatorVaultOptInService` via `optIn()`  ([Sample Tx](https://hoodi.etherscan.io/tx/0x81daac1756eb1ca3e5a35f10a356ff7487e0ce1b60fdbf91c05ac11dbfd42eea))
5. Allocate shares in Delegator via `setOperatorNetworkShares()`  ([Sample Tx](https://hoodi.etherscan.io/tx/0xe2ceee91cebadc1c1abf11fbad9b40d32604f00695282cc082a6796bc889376b))
6. (Optional) Submit PRs with metadata (network, vault, operator) to the [metadata-hoodi](https://github.com/symbioticfi/metadata-hoodi/) repo. Examples: [13](https://github.com/symbioticfi/metadata-hoodi/pull/13), [14](https://github.com/symbioticfi/metadata-hoodi/pull/14), [15](https://github.com/symbioticfi/metadata-hoodi/pull/15)

:::info
If you complete step 6, entities and their interactions will be reflected on [app.hoodi.symbiotic.fi](https://app.hoodi.symbiotic.fi).
:::

### Vault Opt-In (Network)

1. Opt-in to vault by calling Delegator via `setMaxNetworkLimit`  ([Sample Tx](https://hoodi.etherscan.io/tx/0x99f6a276c558184a6a5f325a25c1432f10d391d7e26207ffa8aaf1dd9a791efa))
2. From emitted event, extract `subnetwork ID`

Using the **Vault Admin** address: accept opt-in by calling Delegator via `setNetworkLimit`  ([Sample Tx](https://hoodi.etherscan.io/tx/0x3918e61998aff1dc637f15ac3fe9024d6da9f0ef299a40f0b49c12eb623ad249))
::::

When finished, 2 test stakers should be able to deposit to the wstETH vault.


---

## /integrate/networks/network-contract

---
description: "Register your network using the NetworkRegistry smart contract. The registered address serves as your management address for interacting with Symbiotic vaults..."
---

import { Card1 } from "../../../components/Card1";

# Network Contract

Register your network using the `NetworkRegistry` smart contract. The registered address serves as your management address for interacting with Symbiotic vaults to accept stake allocations.

We provide a [network repository](https://github.com/symbioticfi/network) that simplifies registration and makes management more secure. It includes the `Network.sol` contract and tooling to manage it.

The `Network.sol` contract extends [OpenZeppelin](https://www.openzeppelin.com/)'s [`TimelockController.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/governance/TimelockController.sol) with additional functionality to define delays for `(exact target | exact selector)` or `(any target | exact selector)` pairs.

## Prerequisites

:::steps
#### Clone the repository

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

#### Install dependencies

```bash [bash]
npm install
```
:::

## Deploy Network and Register

The deployment scripts support two scenarios:

1. Deploy a network only (opt into vaults later)
2. Deploy a network with vault opt-ins

:::info
The `Network.sol` contract automatically registers itself on deployment.
:::

### Pure Network Deployment

:::steps
##### Open [`DeployNetwork.s.sol`](https://github.com/symbioticfi/network/blob/main/script/DeployNetwork.s.sol) and configure these settings:

```solidity [DeployNetwork.s.sol]
// 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 the configuration fields, then run:

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

### Network Deployment With Opt-ins

:::steps
##### Open [`DeployNetworkForVaults.s.sol`](https://github.com/symbioticfi/network/blob/main/script/DeployNetworkForVaults.s.sol) and configure these settings:

```solidity [DeployNetworkForVaults.s.sol]
// 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 the configuration fields, then run:

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

## Manage Your Network

Use these five predefined action scripts:

- [SetMaxNetworkLimit](https://github.com/symbioticfi/network/blob/main/script/actions/SetMaxNetworkLimit.s.sol) - set a new maximum network limit for the vault
- [SetResolver](https://github.com/symbioticfi/network/blob/main/script/actions/SetResolver.s.sol) - set the resolver for the vault (only if the vault uses VetoSlasher)
- [SetMiddleware](https://github.com/symbioticfi/network/blob/main/script/actions/SetMiddleware.s.sol) - set the middleware
- [UpgradeProxy](https://github.com/symbioticfi/network/blob/main/script/actions/UpgradeProxy.s.sol) - upgrade the proxy (network itself)
- [ArbitraryCall](https://github.com/symbioticfi/network/blob/main/script/actions/ArbitraryCall.s.sol) - make a call to any contract with any data

All actions follow a similar pattern. Here's how to use [SetMaxNetworkLimit](https://github.com/symbioticfi/network/blob/main/script/actions/SetMaxNetworkLimit.s.sol) as an example:

:::steps
##### Open [SetMaxNetworkLimit.s.sol](https://github.com/symbioticfi/network/blob/main/script/actions/SetMaxNetworkLimit.s.sol) and configure these settings:

```solidity [SetMaxNetworkLimit.s.sol]
// 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";
```

##### Edit the configuration fields, then choose an operation:

- `runS()` - schedule an action
- `runE()` - execute an action
- `runSE()` - schedule and execute an action (only if the delay is zero)

##### Run the operation:

- To execute the script with an EOA:

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

- To get transaction calldata for a [Safe](https://app.safe.global/) multisig:

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

  The logs will show a `callData` field like this:

  ```bash [Expected output]
  callData:0x01d5062a00000000000000000000000025ed2ee6e295880326bdeca245ee4d8b72c8f103000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000005365744d61784e6574776f726b4c696d697400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004423f752d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6700000000000000000000000000000000000000000000000000000000
  ```

  In [Safe](https://app.safe.global/) Transaction Builder:

  1. Enable "Custom data"
  2. Enter the **Network's address** as the target address
  3. Use the `callData` (e.g., `0x01d5062a0000000000000000000000...`) received earlier as the `Data (Hex encoded)`
:::

## Update Delays

Every network action is protected by a delay (from zero to infinity).

Use these update delay scripts for the actions above, plus additional ones:

- [SetMaxNetworkLimitUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMaxNetworkLimitUpdateDelay.s.sol)
- [SetResolverUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetResolverUpdateDelay.s.sol)
- [SetMiddlewareUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMiddlewareUpdateDelay.s.sol)
- [UpgradeProxyUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/UpgradeProxyUpdateDelay.s.sol)
- [HotActionsUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/HotActionsUpdateDelay.s.sol) - update a delay for [SetMaxNetworkLimitUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMaxNetworkLimitUpdateDelay.s.sol) and [SetResolverUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetResolverUpdateDelay.s.sol)
- [ColdActionsUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/ColdActionsUpdateDelay.s.sol) - update a delay for [SetMiddlewareUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMiddlewareUpdateDelay.s.sol) and [UpgradeProxyUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/UpgradeProxyUpdateDelay.s.sol)
- [DefaultUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/DefaultUpdateDelay.s.sol) - update a delay for unconstrained actions
- [ArbitraryUpdateDelay](https://github.com/symbioticfi/network/blob/main/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 usage examples, see [Manage Your Network](/integrate/networks/network-contract#manage-your-network).

***

## Dashboard

:::warning
Work-in-progress, use with caution.
:::

The `Network.sol` contract inherits [OpenZeppelin](https://www.openzeppelin.com/)'s `TimelockController`, which inherits `AccessControl`. You can't determine the full state (operation statuses or role holders) using only RPC calls.

Use the Network Dashboard to:

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

:::info
Network Dashboard UI: [https://network-sage-rho.vercel.app/](https://network-sage-rho.vercel.app/)
:::

***

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Submit Metadata"
    description="Submit your network's metadata to make it visible on the Symbiotic UI."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/submit-metadata"
  />
</div>


---

## /integrate/networks/pre-deposit

---
description: "You may want to curate or deploy vaults yourself in these cases:"
---

import { Card1 } from "../../../components/Card1";

# Deploy Pre-deposit Vault

You may want to curate or deploy vaults yourself in these cases:

- A DAO-controlled vault with your network's native asset as collateral
- Your network needs a specific vault configuration for onboarding

See the [vault deployment guide](/integrate/curators/deploy-vault) for details.

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Rewards"
    description="Learn how to integrate Symbiotic Rewards into your system."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/rewards"
  />
</div>


---

## /integrate/networks/relay-offchain

---
description: ":::warning The code is a work in progress and not production ready yet. Breaking changes may occur in code updates, and backward compatibility is not..."
---

import { Card1 } from "../../../components/Card1";

# Relay Off-Chain

:::warning
The code is a work in progress and not production ready yet. Breaking changes may occur in code updates, and backward compatibility is not guaranteed. Use with caution.
:::

The Symbiotic Relay operates as a distributed middleware layer that facilitates:

- Validator Set Management: Derives and maintains validator sets across different epochs based on on-chain state
- Signature Aggregation: Collects individual validator signatures and aggregates them using BLS signatures or zero-knowledge proofs
- Cross-Chain Coordination: Manages validator sets across multiple EVM-compatible blockchains

## Architecture

The relay consists of several key components:

- **P2P Layer**: Uses libp2p with GossipSub for decentralized communication
- **Signer Nodes**: Sign messages using BLS/ECDSA keys
- **Aggregator Nodes**: Collect and aggregate signatures with configurable policies
- **Committer Nodes**: Submit aggregated proofs to settlement chains
- **API Server**: Exposes gRPC API for external clients

For detailed architecture information, see [here](https://github.com/symbioticfi/relay/blob/dev/DEVELOPMENT.md).

## Configure

:::info
For a complete reference of all configuration options and command-line flags, see the [relay\_sidecar CLI documentation](https://github.com/symbioticfi/relay/tree/dev/docs/cli/relay/relay_sidecar.md).
:::

Create a `config.yaml` file with the following structure:

```yaml [config.yaml]
# Logging
log:
    level: "debug" # Options: debug, info, warn, error
    mode: "pretty" # Options: json, text, pretty

# Storage
storage-dir: ".data" # Directory for persistent data
circuits-dir: "" # Path to ZK circuits (optional, empty disables ZK proofs)

# API Server
api:
    listen: ":8080" # API server address
    verbose-logging: false # Enable verbose API logging

# Metrics (optional)
metrics:
    listen: ":9090" # Metrics endpoint address
    pprof: false # Enable pprof debug endpoints

# Driver Contract
driver:
    chain-id: 31337 # Chain ID where driver contract is deployed
    address: "0x..." # Driver contract address

# Secret Keys
secret-keys:
    - namespace: "symb" # Namespace for the key
      key-type: 0 # 0=BLS-BN254, 1=ECDSA
      key-id: 15 # Key identifier
      secret: "0x..." # Private key hex

    - namespace: "evm"
      key-type: 1
      key-id: 31337
      secret: "0x..."

    - namespace: "p2p"
      key-type: 1
      key-id: 1
      secret: "0x..."

# Alternatively, use keystore
# keystore:
#   path: "/path/to/keystore.json"
#   password: "your-password"

# Signal Configuration, used for internal messages and event queues
signal:
    worker-count: 10 # Number of signal workers
    buffer-size: 20 # Signal buffer size

# Cache Configuration, used for in memorylookups for db queries
cache:
    network-config-size: 10 # Network config cache size
    validator-set-size: 10 # Validator set cache size

# Sync Configuration, sync signatures and proofs over p2p to recover missing information
sync:
    enabled: true # Enable P2P sync
    period: 5s # Sync period
    timeout: 1m # Sync timeout
    epochs: 5 # Number of epochs to sync

# Key Cache, used for fast public key lookups
key-cache:
    size: 100 # Key cache size
    enabled: true # Enable key caching

# P2P Configuration
p2p:
    listen: "/ip4/0.0.0.0/tcp/8880" # P2P listen address
    bootnodes: # List of bootstrap nodes (optional)
        - /dns4/node1/tcp/8880/p2p/...
    dht-mode: "server" # Options: auto, server, client, disabled, default: server (ideally should not change)
    mdns: true # Enable mDNS local discovery (useful for local networks)

# EVM Configuration
evm:
    chains: # List of settlement chain RPC endpoints
        - "http://localhost:8545"
        - "http://localhost:8546"
    max-calls: 30 # Max calls in multicall batches

# Aggregation Policy
aggregation-policy-max-unsigners: 50 # Max unsigners for low-cost policy
```

### Configure via Command-Line Flags

You can override config file values with command-line flags:

```bash
./relay_sidecar \
  --config config.yaml \
  --log.level debug \
  --storage-dir /var/lib/relay \
  --api.listen ":8080" \
  --p2p.listen "/ip4/0.0.0.0/tcp/8880" \
  --driver.chain-id 1 \
  --driver.address "0x..." \
  --secret-keys "symb/0/15/0x...,evm/1/31337/0x..." \
  --evm.chains "http://localhost:8545"
```

### Configure via Environment Variables

Environment variables use the `SYMB_` prefix with underscores instead of dashes and dots:

```bash
export SYMB_LOG_LEVEL=debug
export SYMB_LOG_MODE=pretty
export SYMB_STORAGE_DIR=/var/lib/relay
export SYMB_API_LISTEN=":8080"
export SYMB_P2P_LISTEN="/ip4/0.0.0.0/tcp/8880"
export SYMB_DRIVER_CHAIN_ID=1
export SYMB_DRIVER_ADDRESS="0x..."

./relay_sidecar --config config.yaml
```

### Configuration Priority

Configuration is loaded in the following order (highest priority first):

1. Command-line flags
2. Environment variables (with `SYMB_` prefix)
3. Configuration file (specified by `--config`)

### Example

For reference, see how configurations are generated in the E2E setup:

```bash
# See the template in e2e/scripts/sidecar-start.sh (lines 11-27)
cat e2e/scripts/sidecar-start.sh
```

## Download and Run

Pre-built Docker images are available from Docker Hub:

:::steps
#### Pull the image

The latest image:

```bash [bash]
docker pull symbioticfi/relay:latest
```

Or a specific version:

```bash [bash]
docker pull symbioticfi/relay:<tag>
```

#### Run the relay sidecar

```bash [bash]
docker run -v $(pwd)/config.yaml:/config.yaml \
  symbioticfi/relay:latest \
  --config /config.yaml
```
:::

:::info
Docker Hub: [https://hub.docker.com/r/symbioticfi/relay](https://hub.docker.com/r/symbioticfi/relay)
:::

## API

The relay exposes both gRPC and HTTP/JSON REST APIs for interacting with the network:

### gRPC API

- [**API Documentation**](https://github.com/symbioticfi/relay/tree/dev/docs/api/v1/doc.md)
- [**Proto Definitions**](https://github.com/symbioticfi/relay/blob/dev/api/proto/v1/api.proto)
- [**Go Client**](https://github.com/symbioticfi/relay/tree/dev/api/client/v1/)
- [**Client Examples**](https://github.com/symbioticfi/relay/tree/dev/api/client/examples/)

### HTTP/JSON REST API Gateway

The relay includes an optional HTTP/JSON REST API gateway that translates HTTP requests to gRPC:

- [**Swagger File**](https://github.com/symbioticfi/relay/tree/dev/docs/api/v1/api.swagger.json)
- **Endpoints**: All gRPC methods accessible via RESTful HTTP at `/api/v1/*`

Enable via configuration:

```yaml [config.yaml]
api:
    http-gateway: true
```

Or via command-line flag:

```bash [bash]
./relay_sidecar --api.http-gateway=true
```

### Client Libraries

| Language   | Repository                                                           |
| ---------- | -------------------------------------------------------------------- |
| Go         | [relay](https://github.com/symbioticfi/relay/tree/dev/api/client/v1) |
| TypeScript | [relay-client-ts](https://github.com/symbioticfi/relay-client-ts)    |
| Rust       | [relay-client-rs](https://github.com/symbioticfi/relay-client-rs)    |

:::note
Use the HTTP gateway for language-agnostic access if needed.
:::

### Snippets

Check out multiple simple snippets how to use the clients mentioned above:

:::code-group
<div data-title="Go">
  ```go [myApp.go]
  import (
      relay "github.com/symbioticfi/relay/api/client/v1"
  )

  func main() {
      relayClient = relay.NewSymbioticClient(conn)

      epochInfos, _ := relayClient.GetLastAllCommitted(ctx, &relay.GetLastAllCommittedRequest{})
      suggestedEpoch := epochInfos.SuggestedEpochInfo.GetLastCommittedEpoch()

      signMessageResponse, _ := relayClient.SignMessage(ctx, &relay.SignMessageRequest{
          KeyTag:        15, // default key tag - BN254
          Message:       encode(taskId),
          RequiredEpoch: &suggestedEpoch,
      })

      listenProofsRequest := &relay.ListenProofsRequest{
          StartEpoch: suggestedEpoch,
      }
      proofsStream, _ := relayClient.ListenProofs(ctx, listenProofsRequest)
      aggregationProof = []byte{}
      while proofResponse, _ := proofsStream.Recv() {
          if proofResponse.GetRequestId() == signMessageResponse.GetRequestId() {
              aggregationProof = proofResponse.GetAggregationProof().GetProof()
              break
          }
      }

      appContract.CompleteTask(taskId, signMessageResponse.Epoch, aggregationProof)
  }
  ```
</div>

<div data-title="TypeScript">
  ```go [myApp.ts]
  import { createClient } from "@connectrpc/connect";
  import { SymbioticAPIService } from "@symbioticfi/relay-client-ts";
  import {
    GetLastAllCommittedRequestSchema,
    SignMessageRequestSchema,
    ListenProofsRequestSchema,
  } from "@symbioticfi/relay-client-ts";
  import { create } from "@bufbuild/protobuf";

  async function main() {
      const relayClient = createClient(SymbioticAPIService, transport);

      const getLastAllCommittedResponse = await relayClient.getLastAllCommitted(create(GetLastAllCommittedRequestSchema));
      const suggestedEpoch = getLastAllCommittedResponse.suggestedEpochInfo.lastCommittedEpoch;

      const signMessageRequest = create(SignMessageRequestSchema, {
          keyTag: 15, // default key tag - BN254
          message: encode(taskId),
          requiredEpoch: suggestedEpoch,
      });
      const signMessageResponse = await relayClient.signMessage(signMessageRequest);

      const listenProofsRequest = create(ListenProofsRequestSchema, { startEpoch: suggestedEpoch });
      const proofsStream = await relayClient.listenProofs(listenProofsRequest);
      let aggregationProof;
      for await (const proofResponse of proofsStream) {
          if (proofResponse.requestId === signMessageResponse.requestId) {
              aggregationProof = proofResponse.aggregationProof?.proof;
              break;
          }
      }

      await appContract.completeTask(taskId, signMessageResponse.epoch, aggregationProof);
  }
  ```
</div>

<div data-title="Rust">
  ```go [my_app.rs]
  use symbiotic_relay_client::generated::api::proto::v1::{
      GetLastAllCommittedRequest, SignMessageRequest, ListenProofsRequest,
      symbiotic_api_service_client::SymbioticApiServiceClient,
  };

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let mut relay_client = SymbioticApiServiceClient::new(channel);

      let epoch_infos_response = relay_client.get_last_all_committed(tonic::Request::new(GetLastAllCommittedRequest {})).await?;
      let epoch_infos_data = epoch_infos_response.into_inner();
      let mut suggested_epoch = epoch_infos_data.suggested_epoch_info.last_committed_epoch;

     let sign_request = tonic::Request::new(SignMessageRequest {
          key_tag: 15, // default key tag - BN254
          message: encode(task_id).into(),
          required_epoch: suggested_epoch,
      });
      let sign_response = relay_client.sign_message(sign_request).await?;
      let sign_data = sign_response.into_inner();

      let listen_proofs_request = tonic::Request::new(ListenProofsRequest { start_epoch: suggested_epoch });
      let proofs_stream = relay_client.listen_proofs(listen_proofs_request).await?.into_inner();
      let mut aggregation_proof = None;
      while let Some(proof_response) = proofs_stream.next().await {
          match proof_response {
              Ok(proof_data) => {
                  if proof_data.request_id == sign_data.request_id {
                      if let Some(proof) = proof_data.aggregation_proof {
                          aggregation_proof = Some(proof.proof);
                          break;
                      }
                  }
              }
              Err(e) => { break; }
          }
      }

      appContract.complete_task(task_id, sign_data.epoch, aggregation_proof.unwrap()).await?;
  }
  ```
</div>
:::

## Integration Examples

For a complete end-to-end examples application using the relay, see:

| Repository                                                                | Description                                                   |
| ------------------------------------------------------------------------- | ------------------------------------------------------------- |
| [Symbiotic Super Sum](https://github.com/symbioticfi/symbiotic-super-sum) | A simple task-based network                                   |
| [Cosmos Relay SDK](https://github.com/symbioticfi/cosmos-relay-sdk)       | An application built using the Cosmos SDK and Symbiotic Relay |

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Helpful Core Contracts' Endpoints"
    description="Check out core contracts' endpoints that may help you during integration."
    icon={
          <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
              <rect
                  x="8"
                  y="8"
                  width="32"
                  height="32"
                  rx="2"
                  stroke="currentColor"
                  strokeWidth="2"
                  fill="none"
              />
              <rect
                  x="12"
                  y="12"
                  width="24"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="18"
                  width="20"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="24"
                  width="16"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="30"
                  width="18"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
          </svg>
      }
    href="/integrate/networks/helpful-core-contracts-endpoints"
  />
</div>


---

## /integrate/networks/relay-onchain

---
description: "The Symbiotic Relay system implements a complete signature aggregation workflow from validator set derivation through on-chain commitment of the ValSetHeader..."
---

import { Card1 } from "../../../components/Card1";

# Relay On-Chain

The Symbiotic Relay system implements a complete signature aggregation workflow from validator set derivation through on-chain commitment of the ValSetHeader data structure. This enables provable attestation checks on any chain for arbitrary data signed by the validator set quorum.

The system provides a modular smart contract framework that lets you manage validator sets dynamically, handle cryptographic keys, aggregate signatures, and commit cross-chain state.

## Architecture

Symbiotic provides a set of predefined smart contracts representing the following modules:

- [`VotingPowerProvider`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/) - provides basic data about operators, vaults, and their voting power, enabling various onboarding schemes
- [`KeyRegistry`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/key-registry/) - verifies and manages operators' keys; currently, these key types are supported:
  - [`BlsBn254`](https://github.com/symbioticfi/relay-contracts/blob/main/src/libraries/keys/KeyBlsBn254.sol) ([signature verification](https://github.com/symbioticfi/relay-contracts/blob/main/src/libraries/sigs/SigBlsBn254.sol))
  - [`EcdsaSecp256k1`](https://github.com/symbioticfi/relay-contracts/blob/main/src/libraries/keys/KeyEcdsaSecp256k1.sol) ([signature verification](https://github.com/symbioticfi/relay-contracts/blob/main/src/libraries/sigs/SigEcdsaSecp256k1.sol))
- [`ValSetDriver`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/valset-driver/) - used by the off-chain part of Symbiotic Relay for validator set derivation and maintenance
- [`Settlement`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/settlement/) - requires committing a compressed validator set (header) each epoch, but allows verifying signatures made by the validator set; currently supports the following verification mechanics:
  - [`SimpleVerifier`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol) - requires the whole validator set as an input during verification, but in a compressed and efficient way, making it the best choice for up to 125 validators
  - [`ZKVerifier`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol) - uses ZK verification made with [gnark](https://github.com/Consensys/gnark), allowing larger validator sets with an almost constant verification gas cost

:::info
For Symbiotic Core's `NetworkMiddlewareService` contract, set the `VotingPowerProvider` contract as the middleware.
:::

### Permissions

Relay contracts have three ready-to-use permission models:

- [`OzOwnable`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/common/permissions/OzOwnable.sol) - allows setting an owner address that can perform permissioned actions
  - Based on [OpenZeppelin's `Ownable` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol)
- [`OzAccessControl`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/common/permissions/OzAccessControl.sol) - enables role-based permissions for each action
  - Based on [OpenZeppelin's `AccessControl` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)
  - Roles can be assigned to function selectors using `_setSelectorRole(bytes4 selector, bytes32 role)`
- [`OzAccessManaged`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/common/permissions/OzAccessManaged.sol) - controls which callers can access specific functions
  - Based on [OpenZeppelin's `AccessManaged` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/manager/AccessManager.sol)

To use these permission models, inherit one of the above contracts and add the `checkPermission` modifier to functions that require access control.

:::info
Only one permission model can be used at a time.
:::

#### Examples

##### ValSetDriver with OzOwnable

```solidity [MyValSetDriver.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {ValSetDriver} from "../src/modules/valset-driver/ValSetDriver.sol";
import {OzOwnable} from "../src/modules/common/permissions/OzOwnable.sol";
import {IEpochManager} from "../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {IValSetDriver} from "../src/interfaces/modules/valset-driver/IValSetDriver.sol";

contract MyValSetDriver is ValSetDriver, OzOwnable {
    function initialize(
        ValSetDriverInitParams memory valSetDriverInitParams,
        address owner
    ) public virtual initializer {
        __ValSetDriver_init(valSetDriverInitParams);
        __OzOwnable_init(ozOwnableInitParams);
    }
}
```

##### Settlement with OzAccessControl

```solidity [MySettlement.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Settlement} from "../src/modules/settlement/Settlement.sol";
import {OzAccessControl} from "../src/modules/common/permissions/OzAccessControl.sol";
import {ISettlement} from "../src/interfaces/modules/settlement/ISettlement.sol";

contract MySettlement is Settlement, OzAccessControl {
    bytes32 public constant SET_SIG_VERIFIER_ROLE = keccak256("SET_SIG_VERIFIER_ROLE");
    bytes32 public constant SET_GENESIS_ROLE = keccak256("SET_GENESIS_ROLE");

    function initialize(
        SettlementInitParams memory settlementInitParams,
        address defaultAdmin
    ) public virtual initializer {
        __Settlement_init(settlementInitParams);

        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);

        _setSelectorRole(ISettlement.setSigVerifier.selector, SET_SIG_VERIFIER_ROLE);
        _setSelectorRole(ISettlement.setGenesis.selector, SET_GENESIS_ROLE);
    }
}
```

### VotingPowerProvider Extensions

Multiple voting power extensions can be combined to achieve different properties of the VotingPowerProvider:

- [`OperatorsWhitelist`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/OperatorsWhitelist.sol) - only whitelisted operators can register
- [`OperatorsBlacklist`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/OperatorsBlacklist.sol) - blacklisted operators are unregistered and are forbidden to return back
- [`OperatorsJail`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/OperatorsJail.sol) - operators can be jailed for some amount of time and register back after that
- [`SharedVaults`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/SharedVaults.sol) - shared (with other networks) vaults (like the ones with NetworkRestakeDelegator) can be added
- [`OperatorVaults`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/OperatorVaults.sol) - vaults that are attached to a single operator can be added
- [`MultiToken`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/MultiToken.sol) - possible to add new supported tokens on the go
- [`OpNetVaultAutoDeploy`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol) - enable auto-creation of the configured by you vault on each operator registration
- Ready bindings are also available for [slashing](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/BaseSlashing.sol) and [rewards](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/BaseRewards.sol)

#### Examples

##### Single-Operator Vaults Added by Owner

```solidity [MyVotingPowerProvider.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {VotingPowerProvider} from "../src/modules/voting-power/VotingPowerProvider.sol";
import {OzOwnable} from "../src/modules/common/permissions/OzOwnable.sol";
import {EqualStakeVPCalc} from "../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../src/modules/voting-power/extensions/OperatorVaults.sol";

contract MyVotingPowerProvider is VotingPowerProvider, OzOwnable, EqualStakeVPCalc, OperatorVaults {
    constructor(address operatorRegistry, address vaultFactory) VotingPowerProvider(operatorRegistry, vaultFactory) {}

    function initialize(
        VotingPowerProviderInitParams memory votingPowerProviderInitParams,
        OzOwnableInitParams memory ozOwnableInitParams
    ) public virtual initializer {
        __VotingPowerProvider_init(votingPowerProviderInitParams);
        __OzOwnable_init(ozOwnableInitParams);
    }
}
```

##### Shared Vaults Whitelisted under AccessControl

```solidity [MyVotingPowerProvider.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {VotingPowerProvider} from "../src/modules/voting-power/VotingPowerProvider.sol";
import {OzAccessControl} from "../src/modules/common/permissions/OzAccessControl.sol";
import {EqualStakeVPCalc} from "../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {SharedVaults} from "../src/modules/voting-power/extensions/SharedVaults.sol";
import {OperatorsWhitelist} from "../src/modules/voting-power/extensions/OperatorsWhitelist.sol";
import {ISharedVaults} from "../src/interfaces/modules/voting-power/extensions/ISharedVaults.sol";

contract MyVotingPowerProvider is VotingPowerProvider, OzAccessControl, EqualStakeVPCalc, SharedVaults, OperatorsWhitelist {
    bytes32 public constant REGISTER_SHARED_VAULT = keccak256("REGISTER_SHARED_VAULT");
    bytes32 public constant UNREGISTER_SHARED_VAULT = keccak256("UNREGISTER_SHARED_VAULT");
    bytes32 public constant SET_WHITELIST_STATUS = keccak256("SET_WHITELIST_STATUS");
    bytes32 public constant WHITELIST_OPERATOR = keccak256("WHITELIST_OPERATOR");
    bytes32 public constant UNWHITELIST_OPERATOR = keccak256("UNWHITELIST_OPERATOR");

    constructor(address operatorRegistry, address vaultFactory) VotingPowerProvider(operatorRegistry, vaultFactory) {}

    function initialize(
        VotingPowerProviderInitParams memory votingPowerProviderInitParams,
        address defaultAdmin
    ) public virtual initializer {
        __VotingPowerProvider_init(votingPowerProviderInitParams);

        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
        _setSelectorRole(ISharedVaults.registerSharedVault.selector, REGISTER_SHARED_VAULT);
        _setSelectorRole(ISharedVaults.unregisterSharedVault.selector, UNREGISTER_SHARED_VAULT);
        _setSelectorRole(ISharedVaults.setWhitelistStatus.selector, SET_WHITELIST_STATUS);
        _setSelectorRole(ISharedVaults.whitelistOperator.selector, WHITELIST_OPERATOR);
        _setSelectorRole(ISharedVaults.unwhitelistOperator.selector, UNWHITELIST_OPERATOR);
    }

    function _registerOperatorImpl(
        address operator
    ) internal virtual override(VotingPowerProvider, OperatorsWhitelist) {
        super._registerOperatorImpl(operator);
    }
}
```

### VotingPowerProvider Power Calculators

`VotingPowerProvider` always inherits a virtual [VotingPowerCalculators](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/) contracts that has to be implemented in the resulting contract.
Symbiotic provides several stake-to-votingPower conversion mechanisms you can separately or combine:

- [EqualStakeVPCalc](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol) - voting power is equal to stake
- [NormalizedTokenDecimalsVPCalc](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol) - all tokens' decimals are normalized to 18
- [PricedTokensChainlinkVPCalc](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.sol) - voting power is calculated using Chainlink price feeds
- [WeightedTokensVPCalc](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.sol) - voting power is affected by configured weights for tokens
- [WeightedVaultsVPCalc](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.sol) - voting power is affected by configured weights for vaults

#### Examples

##### Chainlink-Priced Stake with Token-/Vault-Specific Weights

```solidity [MyVotingPowerProvider.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {VotingPowerProvider} from "../src/modules/voting-power/VotingPowerProvider.sol";
import {PricedTokensChainlinkVPCalc} from
    "../src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.sol";
    import {OzOwnable} from "../src/modules/common/permissions/OzOwnable.sol";
import {WeightedTokensVPCalc} from "../src/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.sol";
import {WeightedVaultsVPCalc} from "../src/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.sol";
import {VotingPowerCalcManager} from "../src/modules/voting-power/base/VotingPowerCalcManager.sol";

contract MyVotingPowerProvider is VotingPowerProvider, OzOwnable, PricedTokensChainlinkVPCalc, WeightedTokensVPCalc, WeightedVaultsVPCalc {
    constructor(address operatorRegistry, address vaultFactory) VotingPowerProvider(operatorRegistry, vaultFactory) {}

    function initialize(
        VotingPowerProviderInitParams memory votingPowerProviderInitParams,
        OzOwnableInitParams memory ozOwnableInitParams
    ) public virtual initializer {
        __VotingPowerProvider_init(votingPowerProviderInitParams);
        __OzOwnable_init(ozOwnableInitParams);
    }

    function stakeToVotingPowerAt(
        address vault,
        uint256 stake,
        bytes memory extraData,
        uint48 timestamp
    )
        public
        view
        override(VotingPowerCalcManager, PricedTokensChainlinkVPCalc, WeightedTokensVPCalc, WeightedVaultsVPCalc)
        returns (uint256)
    {
        return super.stakeToVotingPowerAt(vault, stake, extraData, timestamp);
    }

    function stakeToVotingPower(
        address vault,
        uint256 stake,
        bytes memory extraData
    )
        public
        view
        override(VotingPowerCalcManager, PricedTokensChainlinkVPCalc, WeightedTokensVPCalc, WeightedVaultsVPCalc)
        returns (uint256)
    {
        return super.stakeToVotingPower(vault, stake, extraData);
    }
}
```

:::note
If too many extensions/additions are implemented, the contract may exceed the maximum bytecode size. In this case, try adding `via-ir` flag with low number of optimizer runs for Solidity compiler.
:::

## Deployment

The deployment tooling is in the [`script/`](https://github.com/symbioticfi/relay-contracts/tree/main/script) folder. It consists of [`RelayDeploy.sol`](https://github.com/symbioticfi/relay-contracts/tree/main/script/RelayDeploy.sol) Foundry script template and [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) bash script (Relay smart contracts use external libraries, so it's not currently possible to use solely Foundry script for multi-chain deployment).

- [`RelayDeploy.sol`](https://github.com/symbioticfi/relay-contracts/tree/main/script/RelayDeploy.sol) - abstract base that wires common Symbiotic Core helpers and exposes four deployment hooks: KeyRegistry, VotingPowerProvider, Settlement, and ValSetDriver
- [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) - orchestrates per-contract multi-chain deployments (uses Python to parse `toml` file)

The script deploys Relay modules under [OpenZeppelin's TransparentUpgradeableProxy](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) using [CreateX](https://github.com/pcaversaccio/createx), providing better control for production deployments and simpler approaches for development.

::::steps
### Configure on-chain deployment

Implement your `MyRelayDeploy.sol` ([see example](https://github.com/symbioticfi/relay-contracts/tree/main/script/examples/MyRelayDeploy.sol)):

- Include the deployment configuration of your Relay modules
- Implement all virtual functions of `RelayDeploy.sol`
- In the constructor, input the path of the `toml` file
- Use additional helpers such as `getCore()`, `getKeyRegistry()`, `getVotingPowerProvider()`, etc. (see full list in [`RelayDeploy.sol`](https://github.com/symbioticfi/relay-contracts/tree/main/script/RelayDeploy.sol))

### Choose multi-chain setup

Implement your `my-relay-deploy.toml` ([see example](https://github.com/symbioticfi/relay-contracts/tree/main/script/examples/my-relay-deploy.toml)):

- Include RPC URLs needed for deployment and specify which modules to deploy on which chains
- **Do not replace \[1234567890] placeholder with endpoint\_url = ""**
- Contracts are deployed in this order: 1. KeyRegistry 2. VotingPowerProvider 3. Settlement 4. ValSetDriver

### Run the deployment

Execute the deployment script, e.g.:

```bash [bash]
./script/relay-deploy.sh ./script/examples/MyRelayDeploy.sol ./script/examples/my-relay-deploy.toml --broadcast --ledger
```

:::note
Basic form is `./script/relay-deploy.sh <FoundryScript> <TomlConfig> <Any Foundry Flags>`
:::

At the end, your `toml` file will contain the addresses of the deployed Relay modules.
::::

## Integrate

Symbiotic Relay provides comprehensive tooling that works independently, so you can focus on your stake-backed application logic.

### Verify Message

Your application contract can verify any message using a validator set at any point in time via:

```solidity [MyApp.sol]
import {ISettlement} from "@symbioticfi/relay-contracts/src/interfaces/modules/settlement/ISettlement.sol";

function verifyMessage(bytes calldata message, uint48 epoch, bytes calldata proof) public returns (bool) {
    return ISettlement(SETTLEMENT).verifyQuorumSigAt(
            abi.encode(keccak256(message)),
            15, // default key tag - BN254
            (uint248(1e18) * 2) / 3 + 1, // default quorum threshold - 2/3 + 1
            proof,
            epoch,
            new bytes(0)
    );
}
```

:::note
You need to have a `Settlement` deployed on the verification chain first.
:::

### Use Validator Set Data

Your application contract can use the validator set at any point in time using [SSZ](https://ethereum.org/developers/docs/data-structures-and-encoding/ssz/) proof verification, for example:

```solidity [MyApp.sol]
import {ValSetVerifier} from "@symbioticfi/relay-contracts/src/libraries/utils/ValSetVerifier.sol";
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";

function verifyOperatorVotingPower(
    ValSetVerifier.SszProof calldata validatorRootProof,
    uint256 validatorRootLocalIndex,
    bytes32 validatorSetRoot,
    ValSetVerifier.SszProof calldata operatorProof,
    address operator,
    ValSetVerifier.SszProof calldata votingPowerProof,
    uint256 votingPower
) public returns (bool) {
    return operatorProof.leaf == bytes32(uint256(uint160(operator)) << 96)
        && ValSetVerifier.verifyOperator(
        validatorRootProof, validatorRootLocalIndex, validatorSetRoot, operatorProof
    ) && votingPowerProof.leaf == bytes32(votingPower << (256 - (Math.log2(votingPower) / 8 + 1) * 8))
        && ValSetVerifier.verifyVotingPower(
        validatorRootProof, validatorRootLocalIndex, validatorSetRoot, votingPowerProof
    );
}
```

:::note
You need to have a `Settlement` deployed on the verification chain first.
:::

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Relay Off-Chain"
    description="Proceed to the the development of your protocol's off-chain part using Relay."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/relay-offchain"
  />
</div>


---

## /integrate/networks/rewards

---
description: "Networks use Rewards system to compensate Stakers, Operators, and Curators for providing security and network operation."
---

import { Card1 } from "../../../components/Card1";

# Distribute Rewards

Networks use Rewards system to compensate Stakers, Operators, and Curators for providing security and network operation.

This guide highlights practical steps and contract touchpoints to distribute and claim rewards.

To reproduce this flow, follow the [Quickstart: Network with Staking](/integrate/networks/minimal-network) guide first.

***

The rewards implementation is available in the [Symbiotic Rewards Repository](https://github.com/symbioticfi/rewards-v2). There are 3 smart contracts:

- **Rewards**: Main contract for distributions and claims.
- **FeeRegistry**: Registry for operator and curator fees.
- **CuratorRegistry**: Registry mapping vaults to curators.

## Vault Snapshot Rewards

![Network rewards distribution diagram](/img/rewards-fee-split.png)

Vault Snapshot Rewards implement **fully on-chain**, snapshot-based distributions using historical vault fee split and state at specific timestamps.

:::info
The distribution and claim operations must be handled separately for each vault.
:::

Actions ([Contract](https://github.com/symbioticfi/rewards-v2/blob/main/src/contracts/VaultSnapshotRewards.sol) | [Interface](https://github.com/symbioticfi/rewards-v2/blob/main/src/interfaces/IVaultSnapshotRewards.sol)):

- **Distribution entrypoint**: `distributeVaultSnapshotRewards()` - used by network to distribute rewards.
- **Claim entrypoints** for stakers, operators and curators:
  - `claimVaultSnapshotRewards()`
  - `claimOperatorFees()`
  - `claimCuratorFees()`

:::info
Both network and its middleware can distribute Vault Snapshot rewards.
:::

### Reward Workflow

:::info
Reward distribution is a regular routine. Unlike DeFi farms that distribute rewards continuously, networks distribute rewards periodically (for example, weekly).
:::

Rewards contract addresses are listed on the [Addresses](/get-started/resources/addresses#rewards) page.

:::steps
#### Distribute Rewards

For `msg.sender`, use the Network Middleware account (see [Quickstart: Network with Staking](/integrate/networks/minimal-network)).

- Increase token allowance  ([Sample Tx](https://hoodi.etherscan.io/tx/0x51b48ffe641da09b8975a3bc670b77b7dd1b62c1d6028770cc569bcbe4404987))
- Distribute rewards by calling `Rewards` via `distributeVaultSnapshotRewards()`  ([Sample Tx](https://hoodi.etherscan.io/tx/0xca0ce507a5e93230c848cf5a4b261714847500fef5203b27dbc49dcbe78b8d1a))

#### Verify on Symbiotic dApp

Open the [Vault Page](https://app.hoodi.symbiotic.fi/vault/0xb29BAD40B00587dE1145C7862F96746f043b9daD). Find Vault Reward data and claimed rewards in the corresponding section.

#### Staker Flow

- [Acquire wstETH](https://stake-hoodi.testnet.fi/wrap)  ([Sample Tx](https://hoodi.etherscan.io/tx/0xe799b1611a19cc4ad9c8bc1d61cd328c1f54218c78a5b18f9b559c8791d5b876))
- Deposit to Vault (via UI) ([Tx 1](https://hoodi.etherscan.io/tx/0xe622a7bfd0c17e76f92da77a8ce378aebf5e32443e2fb4f78363871efab51531), [Tx 2](https://hoodi.etherscan.io/tx/0x0ebe2fedef0443d38ee7e933600b3f16139d87d31dbed627cd9fe314effddb33))
- Claim Rewards via `claimVaultSnapshotRewards` ([Sample Tx](https://hoodi.etherscan.io/tx/0x0f9d5d14772999320b88b45ad40f6764054a56993386f0d0d709ff7a2fcd7c8e))

#### Curator and Operator flows

- The `vault.owner()` registers the curator in `CuratorRegistry`
- Curator sets curator and operator fees in `FeeRegistry`.
- Curator and operator claim via `Rewards.sol`

For more details, see [Curator: Manage & Claim Fees](/integrate/curators/registry-and-fees#claim-process) and [Operator: Claim Rewards](/integrate/operators/claim-rewards).
:::

### Production considerations

This guide uses testnet and simplified EOAs for ease of replication. In production, plan the security-aware setup accordingly.

- [Implement Middleware](/integrate/networks/network-contract), do not use EOA or multisig
- Expect fees to be deducted from the amount distributed. To perform fee-related calculations, use [FeeRegistry and Rewards methods](/integrate/curators/registry-and-fees#fee-related-calculations)

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Slashing"
    description="Learn how to integrate the slashing mechanism into your system if needed."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/slashing"
  />

  <Card1
    title="Relay On-Chain"
    description="Proceed to developing your protocol's on-chain components using Relay smart contracts."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/relay-onchain"
  />
</div>


---

## /integrate/networks/slashing

---
description: "Integrate Symbiotic slashing flows, resolvers, veto slashers, burners, and operator accountability checks."
---

import { Card1 } from "../../../components/Card1";

# Slashing

[Read Learn first](/learn/core-concepts/slashing)

Slashing is a penalty mechanism that deters operators from breaking their commitments. Violations include failing to complete tasks properly or accurately. Slashing typically burns or redistributes the operator's staked funds.

## **Slasher Module**

Each Symbiotic Vault has an immutably set `Slasher` module implementation. There are three possible implementation choices:

1. **No Slasher** - no slashing can occur within the Vault

2. **Instant Slasher (`TYPE = 0`)** - allows networks to immediately slash funds in a FIFO order

3. **Veto Slasher (`TYPE = 1`)** - supports a veto process over a pre-defined veto period, where designated **Resolvers** can cancel the slashing request

Each Slasher module contains a `slashableStake(subnetwork, operator, captureTimestamp, hints)` function that returns the amount of collateral still slashable for the given `captureTimestamp` at the current moment.

:::warning
The provided slashable collateral amount may be inaccurate in practice when the vault uses **restaking** (multiple networks may slash the same amount of collateral).
:::

:::info
When executing a slashing request, funds are transferred to an immutably set `Vault.burner()`.
:::

### Slashing Guarantees

Each Symbiotic Vault has an epoch duration (obtained via `Vault.epochDuration()`), which determines the withdrawal delay and provides a period during which slashing guarantees are held.

The following inequality must hold:

<div align="center">
  <code>executeSlashTimestamp - captureTimestamp \<= epochDuration</code>
</div>

### Slasher (Type 0)

The slasher instantly executes slashing requests when received and validated.

```solidity [NetworkSlasher.sol]
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";

address slasher = IVault(vault).slasher();
bytes32 subnetwork = Subnetwork.subnetwork(NETWORK, IDENTIFIER);
ISlasher(slasher).slash(
    subnetwork,
    operator,
    amount,
    captureTimestamp,
    hints
)
```

Parameters:

- `subnetwork` - full identifier of the subnetwork (address of the network concatenated with the uint96 identifier)
- `operator` - address of the operator
- `amount` - amount of the collateral to slash
- `captureTimestamp` - time point when the stake was captured
- `hints` - hints for checkpoints' indexes

:::info
Call this function from `NetworkMiddlewareService.middleware(network)`.
:::

### VetoSlasher (Type 1)

The flow consists of three stages:

1. Request Slashing
2. Veto Slashing
3. Execute Slashing (if not vetoed)

Let’s assume the veto duration period is set to **5 days** and the epoch duration is set to **7 days**.

::::steps
#### Day 1 - Request Slashing

```solidity [NetworkSlasher.sol]
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";

address slasher = IVault(vault).slasher();
bytes32 subnetwork = Subnetwork.subnetwork(NETWORK, IDENTIFIER);
uint256 slashIndex = IVetoSlasher(slasher).requestSlash(
    subnetwork,
    operator,
    amount,
    captureTimestamp,
    hints
)
```

This call succeeds only if the following inequality holds:

<div align="center">
  <code>requestSlashTimestamp + vetoDuration - captureTimestamp \<= epochDuration</code>
</div>

:::info
`NetworkMiddlewareService.middleware(network)` should call this function.
:::

#### Days 1 to 5 - Veto Slashing

```solidity [Resolver]
IVetoSlasher(slasher).vetoSlash(slashIndex, hints)
```

:::info
Call this function from `VetoSlasher.resolver(subnetwork, hint)`.
:::

#### Days 6 to 7 - Execute Slashing

If the slashing request wasn't vetoed:

```solidity [NetworkSlasher.sol]
IVetoSlasher(slasher).executeSlash(
    slashIndex,
    hints
)
```

:::info
`NetworkMiddlewareService.middleware(network)` should call this function.
:::
::::

## Resolvers

If a vault uses a VetoSlasher, there is a veto phase (duration set during vault deployment) when the resolver can veto the request.

Networks can set the resolver via `IVetoSlasher(slasher).setResolver(identifier, resolver, hints)`.

:::note
The first time you set the resolver, it applies immediately. Otherwise, the update applies after `VetoSlasher.resolverSetEpochsDelay()` epochs.
:::

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Relay On-Chain"
    description="Proceed to developing your protocol's on-chain components using Relay smart contracts."
    icon={
          <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
              <rect
                  x="8"
                  y="8"
                  width="32"
                  height="32"
                  rx="2"
                  stroke="currentColor"
                  strokeWidth="2"
                  fill="none"
              />
              <rect
                  x="12"
                  y="12"
                  width="24"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="18"
                  width="20"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="24"
                  width="16"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
              <rect
                  x="12"
                  y="30"
                  width="18"
                  height="3"
                  rx="1.5"
                  fill="currentColor"
                  opacity="0.3"
              />
          </svg>
      }
    href="/integrate/networks/relay-onchain"
  />
</div>


---

## /integrate/networks/submit-metadata

---
description: "The Symbiotic UI displays TVL, allocations, and relationships between curators, vaults, operators, and networks. To make your entity visible on the UI, submit..."
---

import { Card1 } from "../../../components/Card1";

# Submit Metadata

The [Symbiotic UI](https://app.symbiotic.fi/deposit) displays TVL, allocations, and relationships between curators, vaults, operators, and networks. To make your entity visible on the UI, submit its metadata to the corresponding repository.

After you submit metadata, the Symbiotic team reviews and merges it. Once merged, your data appears on the UI.

## Add a New Entity Template

### Choose a Repository

| Chain   | URL                                                                                                |
| ------- | -------------------------------------------------------------------------------------------------- |
| Mainnet | [https://github.com/symbioticfi/metadata-mainnet](https://github.com/symbioticfi/metadata-mainnet) |
| Hoodi   | [https://github.com/symbioticfi/metadata-hoodi](https://github.com/symbioticfi/metadata-hoodi)     |

### Repository Structure

The repository is organized as follows:

```
repository/
├── vaults/
│   ├── 0x<address>/
│   │   ├── info.json
│   │   └── logo.png (optional)
├── networks/
├── operators/
├── tokens/
```

Each entity is identified by its Ethereum address (`0x...`), and its data is stored in a folder named after the address. Inside this folder, include a file `info.json` containing metadata, and optionally, an icon file `logo.png`.

***

### Steps to Add a New Entity

**Note: After your PR is submitted, email your PR link to [verify@symbiotic.fi](mailto\:verify@symbiotic.fi) from your official business email (domain must match that of your entity website) to allow us to confirm your identity ahead of merging your PR.**

1. **Determine the entity type**:
   - Decide whether the entity belongs to `vaults`, `networks`, `operators`, `tokens` or `points`.
   - If the entity is a `vault`, ensure its collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, add the token first.
2. **Register the entity in the registry**:
   - Before adding metadata for vaults, networks, or operators, ensure that they are registered in their respective registries. You can find the current registry contract addresses in the [Addresses page](/get-started/resources/addresses). Unregistered entities will not be accepted.
3. **Create a new folder**:
   - Navigate to the appropriate directory for the entity type.
   - Create a folder named after the Ethereum address (e.g., `0x1234567890abcdef1234567890abcdef12345678`).
4. **Add the `info.json` file**:
   - Include metadata in the specified format (see below).
5. **(Optional) Add an icon file**:
   - If available, include a `logo.png` file with the entity’s logo.

The Symbiotic team reviews your PR after automated checks pass. If approved, it will be merged into the repository.

***

### File Format: `info.json`

The `info.json` file must follow this structure:

#### Required Fields

- `name` (string): The name of the entity.
- `description` (string): A brief description of the entity.
- `tags` (array of strings): Tags categorizing the entity.
- `links` (array of objects): External links related to the entity.

#### Fields for Points

- `type` (string): The type of the point (e.g., "network").
- `decimals` (number): The number of decimal places for the point.

#### Supported `links` Types

Each link should include:

- `type`: The type of the link. Supported values are:
  - `website`: The official website of the entity.
  - `explorer`: A blockchain explorer link for the entity's Ethereum address or contract.
  - `docs`: Documentation related to the entity.
  - `example`: Example use cases or tutorials.
  - `externalLink`: A link to be shown below the entity's name.
- `name`: A user-friendly name for the link.
- `url`: The URL of the resource.

### Icon File: `logo.png` (Optional)

If you want to include an icon for the entity, follow these guidelines:

- **File Name**: `logo.png`
- **Dimensions**: 256x256 pixels
- **Format**: PNG

Place the `logo.png` file in the same folder as the `info.json` file.

***

### Validation

Before submitting your PR, ensure the following:

1. The Ethereum address is valid:
   - It must start with `0x` and be exactly 42 characters long.
2. The `info.json` file is valid:
   - Use a JSON validator, such as [https://jsonlint.com/](https://jsonlint.com/).
3. The `logo.png` file (if included) meets the size requirement of **256x256 pixels**.

***

### Submitting the Pull Request

Once your files are added to the repository, create a Pull Request with the following details:

1. **Entity Type**: Specify the type (vault, network, operator, token).
2. **Ethereum Address**: Provide the address of the entity.
3. **Description**: Summarize the entity’s purpose and data.

#### Example PR Description

```
Added new token entity: 0x1234567890abcdef1234567890abcdef12345678

- **Name**: USDT
- **Description**: USDT is a stablecoin pegged to the US Dollar, widely used for trading and liquidity in cryptocurrency markets.
- **Tags**: stablecoin, usdt
- **Links**:
  - [Website](https://tether.to/)
  - [Etherscan](https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7)
  - [Tether Documentation](https://docs.tether.to/)
- **CMC ID**: 825
- **Permit Name**: USDT Permit Token
- **Permit Version**: 1
- **Icon**: Included (256x256 px)
```

***

### Review and Approval

Your PR will be reviewed to ensure:

- The `info.json` file has all required fields and valid data.
- The `logo.png` file (if included) meets the requirements.
- The metadata is accurate and well-structured.
- The submitter of the PR is from the entity in question (verified via an email with your PR link to [verify@symbiotic.fi](mailto\:verify@symbiotic.fi) from your official business email)

After approval, your changes will be merged into the repository.

## Add a Network

:::steps
##### Create a new folder in the `/networks` directory

##### Create a new json file in the folder with the following structure:

```json [info.json]
{
    "name": "My Network",
    "description": "My Network is a network that allows you to stake your tokens and earn rewards.",
    "tags": ["network", "staking"],
    "links": [{ "type": "website", "name": "Website", "url": "https://mynetwork.com" }]
}
```

##### Save a logo of the Network to `logo.png` of 256x256 pixels size
:::

## Add Points

:::steps
##### Create a new folder in the `/points` directory

##### Create a new json file in the folder with the following structure:

```json [info.json]
{
    "name": "My Points",
    "description": "My Points is a points system that allows you to earn rewards.",
    "tags": ["points", "staking"],
    "links": [{ "type": "website", "name": "Website", "url": "https://mypoints.com" }]
}
```

##### Save a logo of the Points to `logo.png` of 256x256 pixels size
:::

## Add a Pre-deposit Vault

See the [vault metadata submission guide](/integrate/curators/submit-metadata) for details.

## Next Steps

<div
  style={{
      display: "grid",
      gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
      gap: "24px",
      marginBottom: "48px",
  }}
>
  <Card1
    title="Deploy a Pre-deposit Vault"
    description="Use this guide if you need to curate or deploy the Vault by yourself."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/pre-deposit"
  />

  <Card1
    title="Rewards"
    description="Learn how to integrate Symbiotic rewards into your system."
    icon={
      <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
          <rect
              x="8"
              y="8"
              width="32"
              height="32"
              rx="2"
              stroke="currentColor"
              strokeWidth="2"
              fill="none"
          />
          <rect x="12" y="12" width="24" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="18" width="20" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="24" width="16" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
          <rect x="12" y="30" width="18" height="3" rx="1.5" fill="currentColor" opacity="0.3" />
      </svg>
  }
    href="/integrate/networks/rewards"
  />
</div>

