# Symbiotic
> Documentation for the Symbiotic protocol
## **Universal Staking**
Universal Staking is more than just restaking. Instead of merely reusing staked assets to secure multiple networks, it introduces a flexible coordination layer for sharing collateral across a wide range of use cases beyond Proof-of-Stake (PoS) implementations.
### **Traditional Shared Security**
At its core, shared security is the alignment of incentives, either horizontally across multiple participants or vertically across layers within the same system. This foundational primitive unlocks a modular design space. Horizontally, it enables networks to tap into pooled economic security, accelerating decentralization in a capital-efficient way. Vertically, it turns existing tokens into multi-purpose assets, like using governance tokens to secure sequencing layers.
By making data around validator performance, node distribution, operator quality, and security effectiveness transparent and programmable, it reduces coordination friction and lowers the barrier to deploying decentralized infrastructure.
But shared security is just the beginning. While it allows networks to inherit trust more efficiently, it is often implemented in narrow, use-specific ways. What comes next is a broader coordination layer, one where capital can flow dynamically between networks and applications, supporting diverse forms of security, utility, and risk underwriting with customizable rules and shared infrastructure.
### **The Universal Staking Framework**
Through engaging with hundreds of builders over the last few months and launching 16 networks on mainnet, we realized that the underlying concept of shared security can be leveraged in ways far beyond what restaking and traditional shared security infrastructure envisioned. What started as a way to coordinate stakers and networks around Proof-of-Stake security revealed a broader design space for incentive alignment and capital coordination.
Universal Staking, as developed through Symbiotic, builds on this insight. It generalizes the shared security model into a modular coordination layer that can be applied across use cases, not just for securing consensus, but also for underwriting risk, bootstrapping new protocols, and aligning incentives between diverse actors. For example, lending markets can use it to backstop bad debt, enabling stakers to opt into specific risk profiles with customizable terms. This is no longer just about securing networks, but about unlocking new forms of programmable trust between capital and applications.
While the chart below shows that staking has outpaced total crypto market growth since 2021, it also underscores how early we still are. Symbiotic is built to push beyond traditional staking by allowing projects to bootstrap security from external assets, design modular staking systems, and apply staking to use cases like risk underwriting and insurance. The goal is not just to scale staking’s footprint, but to evolve it into a coordination layer for capital, security, and incentive alignment across the onchain economy.

#### **Key Metrics**
* Staking grew from 2.99% to 11.56% of total crypto market cap since 2021.
* Restaking emerged from 0 to nearly 1% of total crypto market cap in under 2 years.
* While crypto market cap grew 22% YoY since 2021, staking and restaking quietly doubled that at 45%.
* At the current trajectory, staking + restaking will reach 50% of crypto market cap in \~8.4 years (around early 2033).
*data from [**DefiLlama**](https://defillama.com/), [**StakingRewards**](https://www.stakingrewards.com/), and [**Coingecko**](https://www.coingecko.com/)*
### **Universal Staking Use Cases**
#### **Native Staking**
Native staking refers to the use of a protocol’s own token to secure and coordinate activity within its ecosystem. While traditionally tied to Proof-of-Stake consensus or governance, Universal Staking reframes native tokens as programmable trust assets, acting as flexible primitives for enabling coordination, enforcing rules, and aligning incentives across modular systems.
**Expanded Utility**
* Programmable Trust Layers: Native tokens are no longer limited to gas payments or voting power. They can encode slashing conditions, distribute rewards, and coordinate behaviors across trust-minimized components.
* Incentive Systems: Models like vote-escrow and revenue sharing allow protocols to design long-term alignment between users, contributors, and applications.
* Composable Security: Projects such as Hyperlane show how native staking can be combined with staking on Symbiotic to enforce custom slashing logic and strengthen inter-network security assumptions.
* Mesh Security and Cross-Ecosystem Coordination: Native tokens can participate in broader security meshes, where the same asset secures appchains, messaging layers, oracle networks, and more, all at once.
**Example**
Hyperlane uses HYPER for native staking to encode programmable trust logic within its modular interchain stack. Through Symbiotic, HYPER holders can stake their tokens and secure core components like ISMs. For a deeper look into how Universal Staking powers native trust models, [**check out our blog post on Hyperlane.**](https://blog.symbiotic.fi/hyperlane-native-staking-powered-by-symbiotic/)
#### **Insurance and Guarantees**
Universal Staking enables programmable collateralization to underwrite risks beyond protocol security, e.g., lending, insurance, or structured financial products. Capital can be orchestrated through slashing conditions, acting as automated enforcement mechanisms.
**Expanded Utility**
* Bad Debt Protection: Inspired by Aave's vision for shared insurance pools, protocols can create bad debt backstops by pooling staked capital and shared economic security from across the ecosystem. DAOs, curators and lending markets can customize slashing triggers based on default conditions or liquidity thresholds.
* Other Structured Products:
* Downtime insurance for validators and node operators.
* MEV protection funds, where actors stake against misbehavior and get slashed for proven attacks.
#### **PoS Implementations, as in Traditional Shared Security**
The most familiar application of Universal Staking. It brings PoS-style security to specific infrastructure components, allowing shared security to be applied at a modular level.
**Expanded Utility**
* **Interoperability protocols** (such as bridges and messaging layers): Stakers post collateral to guarantee message correctness and transaction finality across chains. Slashing enforces honest relaying.
* **Oracles:** Stake is used to guarantee accuracy or uptime for price feeds and other data. Misbehavior or failure to deliver correct data can trigger slashing. This extends to MEV-resistant oracle designs and similar integrity-critical systems.
* **Sequencers and rollups:** Rollups increasingly rely on shared sequencer and operator sets to decentralize. Universal Staking provides a pooled security layer that helps these systems bootstrap trust assumptions without needing to launch a native token or maintain an isolated validator set.
### **Conclusion**
Shared security introduced a powerful primitive. It allowed systems to align incentives and inherit trust without needing to bootstrap from scratch. By enabling networks to coordinate around pooled security, it lowered the capital barrier to decentralization and helped scale early rollups, appchains, and infrastructure layers.
Universal Staking is the natural next step. It does not replace shared security but expands its reach. By generalizing the concept beyond validator coordination, it applies the same principles to a broader set of use cases. This includes native staking, risk underwriting, insurance, MEV protection, and incentive design.
The result is a flexible and modular coordination layer. Capital, incentives, and enforcement can now be orchestrated across a wide range of applications. The same mechanism that once secured chains can now secure infrastructure, protocols, and entire ecosystems.
Symbiotic is the programmable layer that makes this possible. It enables builders to design staking flows, slashing conditions, and validator sets, while continuously enforcing the rules.
Universal Staking takes the core promise of shared security and evolves it into a universal building block for the next generation of crypto systems, now fully accessible through the Symbiotic framework.
import { Details } from "../../../components/Details";
## Relay Quickstart
This quickstart walks through the developer workflow that the repo enables: spinning up Symbiotic Core locally, preparing vaults and operators, wiring middleware, and bringing a relay-powered network online.
After completing this guide, you will learn how to:
1. Spin up Symbiotic Core locally
2. Set up test Vaults and Operators
3. Configure Your Relay-backed Network's Smart Contracts
4. Bring Your Network Online
```
symbiotic-super-sum
├─ network-scripts
│ ├─ deploy.sh
│ ├─ genesis-generator.sh
│ ├─ sidecar-start.sh
│ └─ sum-node-start.sh
├─ off-chain
│ ├─ abis/
│ ├─ cmd/
│ │ ├─ benchmark/
│ │ └─ node/
│ │ └─ main.go
│ └─ internal/
│ ├─ contracts/
│ │ └─ sumTask.go
│ └─ utils/
├─ script
│ ├─ MyRelayDeploy.sol
│ ├─ mocks/
│ ├─ my-relay-deploy.toml
│ └─ utils/
├─ src
│ ├─ SumTask.sol
│ └─ symbiotic
│ ├─ Driver.sol
│ ├─ KeyRegistry.sol
│ ├─ Settlement.sol
│ └─ VotingPowers.sol
├─ generate_network.sh
├─ package.json
└─ …
```
### Prerequisites
Make sure to have all the tools listed below installed before you start.
1. **Git** ([Installation Guide](https://git-scm.com/downloads))
2. **Foundry** - Ethereum development toolchain ([Installation Guide](https://book.getfoundry.sh/getting-started/installation))
3. **Node.js** (v18 or later) and **npm** ([Installation Guide](https://nodejs.org/en/download/))
4. **Docker** ([Installation Guide](https://docs.docker.com/get-docker/))
5. **Go** (v1.21 or later) ([Installation Guide](https://golang.org/doc/install))
6. Python (v3.11 or later) ([Installation Guide](https://www.python.org/downloads/))
### **1. Deploy Symbiotic Core and Setup Your First Vault**

#### **Deploy Symbiotic Core to your local chain**
Symbiotic Core comprises the foundational contracts that govern the Symbiotic ecosystem, offering a comprehensive suite for its administration and interaction. The repository provides pre-configured scripts to facilitate deployment to a local chain, as well as additional utilities designed to streamline ongoing workflows with the core contracts.
`SymbioticCoreInit.sol` is the integration script that spins up fresh factories, registries, vaults, and helper services, then exposes utilities for building test scenarios. `SymbioticCoreConstants.sol` is the address book library that returns the canonical contract set and supported collateral tokens for mainnet, Holešky, Sepolia, and Hoodi. `SymbioticCoreBindings.sol` contains the Foundry broadcast helpers used to create vaults, register operators/networks, manage opt-ins, and exercise slashing flows against those core contracts.
Core contracts can be deployed using `_initCore_SymbioticCore` function ([script details](https://github.com/symbioticfi/relay-contracts/blob/deploy-script-updates/script/RelayDeploy.sol#L101)):
```solidity [@symbioticfi/relay-contracts/script/deploy/RelayDeploy.sol#101]
function getCore() public withoutBroadcast loadConfig returns (SymbioticCoreConstants.Core memory) {
if (!SymbioticCoreConstants.coreSupported()) {
if (config.get("vault_factory").data.length == 0) {
SymbioticCoreConstants.Core memory core = _initCore_SymbioticCore(false); // [!code focus]
```
The console output lists every deployed Symbiotic Core contract (vault factory, registries, opt-in services, etc.). Persist these addresses—you’ll feed them into the rest of the quickstart.
#### **Deploy a vault**
Vaults are the delegation and restaking management layer of Symbiotic. They handle three crucial parts of the Symbiotic economy: accounting, delegation strategies and slashing processing
The vault is created during operator registration by VotingPowers contract ([see contract details](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/extensions/logic/OpNetVaultAutoDeployLogic.sol#L289)).
```solidity [@symbioticfi/relay-contracts/src/modules/voting-power/extensions/logic/OpNetVaultAutoDeployLogic.sol#289]
function createVault(
uint64 version,
address owner,
bytes memory vaultParams,
uint64 delegatorIndex,
bytes memory delegatorParams,
bool withSlasher,
uint64 slasherIndex,
bytes memory slasherParams
) public returns (address, address, address) {
return IVaultConfigurator(IOpNetVaultAutoDeploy(address(this)).VAULT_CONFIGURATOR())
.create(
IVaultConfigurator.InitParams({
version: version,
owner: owner,
vaultParams: vaultParams,
delegatorIndex: delegatorIndex,
delegatorParams: delegatorParams,
withSlasher: withSlasher,
slasherIndex: slasherIndex,
slasherParams: slasherParams
})
);
}
```
For testnet or mainnet vaults you can skip this step and create one directly via the Vault Factory UI at [https://app.symbiotic.fi/create](https://app.symbiotic.fi/create)
### **2. Opt-Ins and Stake Allocation**

#### **Required On-Chain Actions**
In Symbiotic, networks are represented through a network address (either an EOA or a contract) and a middleware contract. Network contract can be deployed using DeployNetworkBase script. During initialization Network will also be registered within NetworkRegistry ([script details](https://github.com/symbioticfi/symbiotic-super-sum/blob/5e7625c8fb16acdd30a7695050f2f7b5c8f44d32/script/MyRelayDeploy.sol#L101)).
```solidity [script/MyRelayDeploy.sol#101]
function getNetwork() public withoutBroadcast loadConfig returns (address) {
if (config.get("network").data.length == 0) {
address[] memory proposersAndExecutors = new address[](1);
proposersAndExecutors[0] = getDeployerAddress();
SymbioticCoreConstants.Core memory core = getCore();
vm.broadcast();
address networkImpl =
address(new Network(address(core.networkRegistry), address(core.networkMiddlewareService)));
config.set(
"network",
_deployContract(
NETWORK_SALT,
networkImpl,
abi.encodeCall(
INetwork.initialize,
(INetwork.NetworkInitParams({
globalMinDelay: 0,
delayParams: new INetwork.DelayParams[](0),
proposers: proposersAndExecutors,
executors: proposersAndExecutors,
name: "Example Network",
metadataURI: "https://example.network",
defaultAdminRoleHolder: getDeployerAddress(),
nameUpdateRoleHolder: getDeployerAddress(),
metadataURIUpdateRoleHolder: getDeployerAddress()
}))
),
getDeployerAddress(),
false
)
);
}
return config.get("network").toAddress();
}
```
The OperatorRegistry is responsible for maintaining a record of all registered operators.
Operators must register here before they can participate in network activities or receive stake allocations ([script details](https://github.com/symbioticfi/symbiotic-super-sum/blob/5e7625c8fb16acdd30a7695050f2f7b5c8f44d32/script/MyRelayDeploy.sol#L371)).
```solidity [script/MyRelayDeploy.sol#371]
getCore().operatorRegistry.registerOperator();
```
Opt-ins are crucial for establishing connections between different entities in the Symbiotic ecosystem. Through the OperatorNetworkOptInService, operators can opt into networks they wish to work with. This signifies their willingness to provide services to these networks.
Operators use the OperatorVaultOptInService to opt into specific vaults. This allows them to receive stake allocations from these vaults ([script details](https://github.com/symbioticfi/symbiotic-super-sum/blob/5e7625c8fb16acdd30a7695050f2f7b5c8f44d32/script/MyRelayDeploy.sol#L372)).
```solidity [script/MyRelayDeploy.sol#372]
getCore().operatorNetworkOptInService.optIn(address(getNetwork())); // [!code focus]
votingPowers.registerOperator();
IVault vault = IVault(votingPowers.getAutoDeployedVault(operator.addr));
getCore().operatorVaultOptInService.optIn(address(vault)); // [!code focus]
```
Network opt into desired vaults by calling `setMaxNetworkLimit()` on each vault’s delegator contract ([script details](https://github.com/symbioticfi/relay-contracts/blob/70dc1ae21bdebf08e2f01246a42e31aee6a1c39d/src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol#L69)).
```solidity [@symbioticfi/relay-contracts/src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol#69]
(address vault, address delegator,) = OpNetVaultAutoDeployLogic.createVault(operator);
_registerOperatorVault(operator, vault);
if (isSetMaxNetworkLimitHookEnabled()) {
ISetMaxNetworkLimitHook(NETWORK())
.setMaxNetworkLimit(delegator, SUBNETWORK_IDENTIFIER(), type(uint256).max); // [!code focus]
}
```
### **3. Network Middleware**

#### **Overview**
Relay Contracts use a modular architecture with five core modules that together manage validator networks, ensuring flexibility and clear separation of concerns.
* **Network** integrates Relay Contracts into the Symbiotic ecosystem, providing verifiable delays, standardized lifecycle management, and serving as the network address across the system.
* **VotingPowerProvider** connects to Symbiotic Core to calculate operator and vault voting power based on stake and rules. It supports extensible strategies for onboarding, slashing, rewards, and key management.
* **KeyRegistry** manages and verifies operators’ cryptographic keys (BLS BN254, ECDSA SECP256K1), supporting registration, verification, and lifecycle management.
* **ValSetDriver** derives and maintains validator sets for off-chain components, managing epoch transitions and linking on-chain voting power with off-chain consensus.
* **Settlement** commits compressed validator sets each epoch, verifies signatures, and supports multi-chain deployments for cross-chain validation.
#### **Deployment tooling**
The deployment tooling can be found at `@symbioticfi/relay-contracts/script/deploy/`folder. It consists of `RelayDeploy.sol` Foundry script template, `relay-deploy.sh` bash script (the Relay smart contracts use external libraries for their implementations, so that it's not currently possible to use solely Foundry script for multi-chain deployment).
* `RelayDeploy.sol` - abstract base that wires common Symbiotic Core helpers and exposes the four deployment hooks: KeyRegistry, VotingPowerProvider, Settlement, and ValVetDriver
* `relay-deploy.sh` - orchestrates per-contract multi-chain deployments
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) (it provides better control for production deployments and more simplified approaches for development).
#### **Deployment**
1. Implement your `MyRelayDeploy.sol` - this Foundry script should include the deployment configuration of your Relay modules
* you need to implement all virtual functions of `RelayDeploy.sol`
* constructor need to take the path of the `toml` file
* you are provided with additional helpers such as `getCore()`, `getKeyRegistry()`, `getVotingPowerProvider()`, etc. (see full list in [RelayDeploy.sol](https://github.com/symbioticfi/relay-contracts/blob/deploy-script-updates/script/RelayDeploy.sol))
2. Implement your `my-relay-deploy.toml` - this configuration file should include RPC URLs that will be needed for the deployment, and which modules should be deployed on which chains
3. Execute the deployment script, e.g.:
```bash
./lib/relay-contracts-new/script/deploy/relay-deploy.sh ./script/MyRelayDeploy.sol "$DEPLOY_CONFIG_PATH" --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```
At the end, your `toml` file will contain the addresses of the deployed Relay modules.
#### Middleware contract
Networks need middleware contract, which can incorporate custom logic and is required to include slashing logic.
The script sets middleware for the network in the following way ([script details](https://github.com/symbioticfi/symbiotic-super-sum/blob/5e7625c8fb16acdd30a7695050f2f7b5c8f44d32/script/MyRelayDeploy.sol#L291))
```solidity [script/MyRelayDeploy.sol#291]
Network(payable(network))
.execute(
address(core.networkMiddlewareService),
0,
abi.encodeWithSelector(INetworkMiddlewareService.setMiddleware.selector, votingPowerProvider),
bytes32(0),
bytes32(0)
);
```
### **4. Network Go Live**

The Symbiotic Relay is a peer-to-peer sidecar network that runs alongside main blockchain nodes using a stateless design based entirely on on-chain state. A built-in HTTP API allows querying validator data, tracking epochs, and managing quorum signature aggregation.
Symbiotic-super-sum spins up a mini Symbiotic relay network on your laptop: two local blockchains, a contract deployer, and as many operator nodes as you request. Once the contracts are live, a small genesis job hands every relay node the same starting snapshot so they agree on history. Each operator runs a relay sidecar that keeps them chatting over libp2p, watches both blockchains, and exposes a simple API. A matching sum node sits beside each relay, grabs the contract addresses, and handles the actual task submissions or aggregation work. Together, these containers mimic the full relay network
#### **Running network**
`generate_network.sh` allows to generate Docker configuration, after which the network can be started by running `docker compose --project-directory temp-network up -d`
There are several implementations of relay client - [ts](https://github.com/symbioticfi/relay-client-ts), [rust](https://github.com/symbioticfi/relay-client-rs) and [go](https://github.com/symbioticfi/relay).
Here is Go example of integration to sidecar network ([script details](https://github.com/symbioticfi/symbiotic-super-sum/blob/5e7625c8fb16acdd30a7695050f2f7b5c8f44d32/off-chain/cmd/node/main.go#L315)):
```go [off-chain/cmd/node/main.go#315]
relayClient = v1.NewSymbioticClient(conn)
...
suggestedEpoch := uint64(0)
epochInfos, err := relayClient.GetLastAllCommitted(ctx, &v1.GetLastAllCommittedRequest{}) // [!code focus]
if err != nil {
return err
} else {
for _, info := range epochInfos.EpochInfos {
if suggestedEpoch == 0 || info.GetLastCommittedEpoch() < suggestedEpoch {
suggestedEpoch = info.GetLastCommittedEpoch()
}
}
}
resp, err := relayClient.SignMessage(ctx, &v1.SignMessageRequest{ // [!code focus]
KeyTag: 15,
Message: msg,
RequiredEpoch: &suggestedEpoch,
})
if err != nil {
return err
}
```
Another example for cosmos-sdk can be found [here](https://github.com/symbioticfi/cosmos-relay-sdk).
## **Secure Attestations**
Secure attestations are **stake-backed signatures over a message hash** that contracts can verify against the active validator set header.
Concretely:
* The **validator set** for epoch `e` is fixed by a committed header (operators, keys, weights, threshold).
* Operators in that set sign a **message hash**.
* An aggregator combines these signatures into an aggregate proof.
* A **Settlement** contract on the destination chain verifies the proof against the header for epoch `e`.
### Message Contents (typical)
The protocol doesn’t hardcode a single message struct, but in practice you want something like:
* `networkId` – Relay network identifier
* `subnetworkId` – optional, for partitioned logic
* `epoch` or `valsetId` – which validator set header must be used
* `payloadType` – enum or tag (bridge, checkpoint, oracle, etc.)
* `payloadHash` – hash of the actual data your app cares about
* `dstChainId` – EVM chain where this will be verified
* `dstApp` or `dstContract` – target contract / app identifier
* `expiry` – timestamp or block after which the attestation is invalid
* `nonce` – monotonically increasing per channel / app
You encode this structure, compute `messageHash = keccak256(encodedMessage)`, and **only `messageHash` is signed** by operators.
### Aggregation and Verification
The flow is:
1. **Build the message**
Middleware or the app constructs the message struct, fills `epoch`, `dstChainId`, `dstApp`, `nonce`, `expiry`, etc., and computes `messageHash`.
2. **Operators sign**
Each operator in the **current validator set for `epoch`** signs `messageHash` with its registered key (BLS or ECDSA, depending on your Relay config).
3. **Aggregate off-chain**
An aggregator collects signatures and:
* for the **Simple** path:
* aggregates BLS signatures into `sigmaAgg`
* builds a participant bitmap / list
* for the **ZK** path:
* uses the individual signatures and weights to generate a zk proof that “signers’ voting power ≥ threshold for header H and messageHash M”
4. **Submit to Settlement**
On the destination chain, the aggregator (or any relayer) calls something like:
* `settlement.verifyAndConsume(message, epoch, sigmaAgg, participants)` for Simple, or
* `settlement.verifyAndConsume(message, epoch, zkProof)` for ZK.
5. **On-chain check**
Settlement:
* loads the **validator set header** for `epoch`
* reconstructs keys and weights from that header
* runs either:
* **SimpleVerifier**: check BLS aggregate against the participants and ensure their summed voting power ≥ threshold
* **ZKVerifier**: check the proof that encodes both signature validity and power ≥ threshold
If verification passes, your app logic (bridge, rollup, oracle, etc.) is allowed to execute.
### Safety Properties
Secure attestations are tied down in a few specific ways:
* **Bound to a validator set**
The message includes `epoch` (or a valset ID). Settlement only verifies against the header stored for that epoch. An attestation for epoch `e` cannot be validated against the header for epoch `e+1`.
* **Bound to destination**
`dstChainId` and `dstApp` are part of the signed payload. The same hash cannot be replayed on a different chain or different contract because the signature is over the full encoded message.
* **Replay protection**
Your app (or Settlement integration) tracks:
* `nonce`: reject messages with a nonce ≤ lastSeenNonce for that channel / app
* `expiry`: reject messages whose expiry is in the past
* **Slashable misbehavior**
If operators sign:
* two different payloads for the same `(networkId, subnetworkId, epoch, nonce)`
* or obviously invalid content (e.g. violates your protocol’s invariants),
that evidence can be fed into your Network’s middleware, which then submits a **slashing
request** to the relevant vaults in Symbiotic. The economic backing for those keys is what
makes the attestation “secure”.
So in short: a secure attestation is a message bound to a specific epoch, network, and destination, proven on-chain to have signatures from enough stake-weighted operators in that epoch’s validator set.
## **Settlement**
Settlement is the on-chain endpoint for Relay. It stores validator set headers (operators, keys, weights, thresholds) per network / subnetwork / epoch and verifies aggregated signatures (attestations) against those headers on the chains where apps live. Applications don’t talk to `VotingPowerProvider` or `ValSetDriver` directly; they call Settlement to check whether enough of the current validator set signed a given message.
#### Contract responsibilities
Settlement instances (one per Relay network per chain) are responsible for:
* **Committing headers**
Accept compressed validator set headers (for example, once per epoch) and store them keyed by `(network, subnetwork, epoch)`.
* **Verifying attestations**
Given:
* a message (or hash)
* an epoch / header ID
* an aggregate signature or zk proof
Verifier checks:
* the proof matches the message
* the participating validators’ total voting power is at least the threshold from the header
If both hold, it returns success so the calling app can continue.
#### Multi-chain
The same validator set can secure multiple chains. Each chain runs its own Settlement instance, and the Relay committer posts the same header to all replicas. Applications on different chains therefore verify against identical validator sets and thresholds for a given epoch, even though verification is performed locally on each chain.
#### Cost model (intuition)
Costs stay near-flat in validator set size. Header updates are small, infrequent writes because a compressed header is stored once per epoch. Verifying an attestation requires a single aggregate check: with the Simple verifier this is one BLS aggregate pairing plus summing the listed signers’ weights, while with the ZK verifier it is one zkSNARK verification where the signer set and weight check are already encoded in the proof. You pay per attestation, not per validator.
#### Failures
Verification fails (returns false / reverts) if:
* the referenced epoch or header is not committed or does not match the network
* the proof is invalid or does not match the message hash
* the signing validators’ total voting power is below the threshold
In all of these cases, the application must not execute the gated action (no unlock, no finalize, no state update).
## **Valset (Validator Set)**
The **validator set** is the current list of operators and their weights that a network uses for signing and verification during a given epoch. In Relay, this is represented by a **validator set header** that ValSetDriver helps derive and then commit to the Settlement contracts.
At any moment in an epoch, the validator set answers three questions:
* which operators are active
* which keys they use to sign
* how much **voting power** each one has (as computed by the VotingPowerProvider)
Applications and Settlement never recompute this themselves – they read the committed header and verify signatures against it.
### Epoch Formation
`ValSetDriver` is the on-chain “driver” the Relay binary uses to derive validator sets epoch by epoch. At the start of each network epoch (or whenever the network decides to rotate), the off-chain Relay nodes:
1. **Discover eligible operators**
* Read operator/vault relationships and voting power from `VotingPowerProvider`.
* Respect onboarding modules (whitelist/blacklist/jail, shared vs operator vaults, multi-token rules) so only **registered and permitted** operators are considered.
* Filter to operators that have opted into the network and meet minimum power / inclusion constraints configured in `VotingPowerProvider`.
2. **Select active key material**
* Fetch cryptographic keys for these operators from `KeyRegistry` (BLS BN254 or ECDSA secp256k1).
* Enforce key requirements: tags, key types, and quorum / threshold rules as configured via `ValSetDriver`.
3. **Assign weights**
* Call `VotingPowerProvider` to get each operator’s **voting power** for this network (stake → power, token weights, vault weights, etc.).
* Apply any network-side caps (e.g. max power per operator, max validator count) that `ValSetDriver` exposes for Relay config.
4. **Fix the decision threshold**
* Choose a decision rule like `> 50%` or `≥ 2/3` of total voting power.
* Encode this into the header metadata so `Settlement` and applications know what constitutes a valid quorum for verification.
5. **Produce a compact header**
* Compress: operator IDs, keys (or key hashes), weights, epoch number, network id, and the chosen threshold into a **ValSetHeader**.
* Compute a `headerHash = keccak256(abi.encode(header))` (conceptually – exact struct is handled inside the contracts).
This header is what gets committed on-chain and later used by `Settlement` and apps to verify aggregated signatures.
### Storage and Rotation
`ValSetDriver` and `Settlement` together manage **storage and rotation** of validator sets:
* **Epoch-based rotation**
* `ValSetDriver` tracks **epoch timing** and exposes the current epoch start / duration to Relay nodes.
* At each epoch boundary, Relay derives a new validator set and sends its header to the Settlement contracts.
* **On-chain storage**
* Settlement stores the current header (and usually some history) in **compressed form**, keyed by epoch or sequence.
* The driver and Settlement together act as the on-chain source of truth: “for epoch N, these are the validators, weights, and threshold”.
* **Design constraint**
* Network epochs should be long enough that the whole path
“observe stake → compute voting power → derive set → aggregate signatures → post header”
reliably fits inside the epoch window, otherwise headers risk arriving late.
### Cross-chain Commitment
Relay is designed to support **multiple chains** from a single validator set.
* `ValSetDriver` holds configuration for:
* which `Settlement` contracts (replicas) exist on which chain IDs
* verification type (Simple vs ZK) and per-replica parameters (e.g. quorum thresholds, gas-oriented constraints)
* For each epoch, the Relay binary:
* derives one validator set header
* commits that same header to all configured Settlement replicas
Applications on any of those chains read the **same header**, so verification of a given message is consistent everywhere.
### Enforcement and Verification
Once a header is committed, it becomes the **reference set** for signature checks until the next epoch’s header replaces it.
* **Verification contracts**
* Settlement uses either `SimpleVerifier` (compressed full set verification, good up to \~125 validators) or `ZKVerifier` (zkSNARK-based proof) to check that an aggregated signature meets the threshold for the committed set.
* **Enforcement properties**
* If a signature is produced using a key that is **not in the header**, verification fails – the key has no registered voting power for that epoch.
* If the aggregated signature does not correspond to a subset of validators whose **total voting power ≥ threshold**, verification fails.
* If a malicious or misconfigured app tries to verify against an old header, it will only succeed if that header is still the one committed for the relevant epoch / sequence.
From the network’s perspective, that means:
* you get deterministic, epoch-by-epoch validator sets derived from Symbiotic stake and operator status
* anyone on any connected chain can cheaply verify that “this message was signed by enough power in the active set for epoch N” using only the committed header and the verifier contracts.
So, if **VotingPowerProvider** defines *how much* power each operator has, **ValSetDriver + Settlement** define *which set* is active at a given time and enforce that only that set – with its weights and threshold – can authorize decisions.
## **Voting Power**
The `VotingPowerProvider` is the Relay contract that turns **delegated Symbiotic stake** into **operator voting power** inside a validator set. It sits between Symbiotic Core (vaults, operators, networks) and the Relay settlement layer, and exposes a clean interface for:
* which operators are in the validator set
* how much voting power each one has
* what that power was at a specific timestamp (for verifying old decisions)
This is what Relay uses to build validator sets and what Settlement uses to verify signatures.
#### Inputs
At a high level, VotingPowerProvider pulls three kinds of data:
* **Stake and vault state** from Symbiotic Core (how much collateral each operator has in which vaults / networks).
* **Onboarding / filtering modules**, e.g.
* OperatorsWhitelist / OperatorsBlacklist / OperatorsJail – which operators are even allowed in the set
* SharedVaults / OperatorVaults – which vaults are considered for this network
* MultiToken / OpNetVaultAutoDeploy – which tokens and “auto-created” vaults are in scope
* **Voting power calculators**, which define how raw stake → voting power.
The public view methods (like `getOperatorVotingPower` and `getOperatorVotingPowerAt`) are what off-chain tooling and Relay’s `ValSetDriver` actually call when they derive the active set and its weights.
### From Delegated Stake to Voting Power
The core idea: **delegated stake is the input**, but the contract lets you pick the function that maps “stake” to “voting power”.
Some standard derivations:
* **Equal** – every opted-in operator gets the same power, regardless of stake. Useful for “one node, one vote” or PoA-style governance.
* **Linear** – power proportional to stake. This is the vanilla PoS model: double the effective stake, double the voting power.
* **Capped / concave** – diminishing returns at higher stake. You can cap per-operator power or use a concave function to stop one operator from dominating the set even if they bring a lot of collateral.
* **Behavior-aware** – adjust weights based on uptime, freshness, or custom performance metrics. In practice you’d compute a “score” off-chain and feed it in via weights or parameters that sit on top of the base calculators.
`VotingPowerProvider` achieves this through a plug-in set of **VotingPowerCalculators**. The repo ships with several that you can compose or chain:
* `EqualStakeVPCalc`
* `NormalizedTokenDecimalsVPCalc` – normalize all tokens to 18 decimals
* `PricedTokensChainlinkVPCalc` – convert different tokens to a common value using Chainlink price feeds
* `WeightedTokensVPCalc` – apply token-level weights
* `WeightedVaultsVPCalc` – apply vault-level weights (e.g. “this vault counts 1.2×, that one 0.8×”)
Networks can pick a simple single calculator (e.g. “linear stake using normalized decimals”) or a pipeline (“normalize decimals → price everything in ETH → apply vault weights”).
### Multi-Token Considerations
In practice, stake can come from multiple collaterals across several vaults:
* LST A, LRT B, native token, etc.
* different decimals and potentially different prices
`VotingPowerProvider` does **not** impose one global rule here; it just provides building blocks. The network defines:
* which tokens are accepted (via MultiToken module and supported-token registration)
* how each token is converted into a single comparable number (e.g. price feeds, fixed haircuts, or simple 1:1)
* whether some tokens or vaults get higher or lower weight in the final voting power
The end result is a single voting power number per operator that already bakes in all these decisions.
### Quorum and Time Variation
Once voting power is defined, the network can reason about **quorums** and **thresholds**:
* decisions might require > 50% or ≥ 2/3 of total voting power
* some sub-protocols (e.g. light client, DA, bridge) can have their own minimum voting power requirements
Voting power is **time-varying**:
* stake moves in and out of vaults
* operators join, leave, or are jailed / unregistered
* token prices change if you use price-based calculators
* off-chain behavior metrics change over time
To keep things tractable, most networks **update the validator set once per epoch** and use that snapshot for all decisions in that period. Relay’s contracts are built around this:
* `ValSetDriver` uses `VotingPowerProvider` to derive the validator set at a chosen genesis and at subsequent epochs.
* `Settlement` verifies signatures against exactly that compressed validator set header, so verifiers and networks agree on which power distribution applied.
This gives you a clean, epoch-by-epoch history of “who had how much power when”.
### With and Without Relay
You can think of `VotingPowerProvider` as the **Relay version** of what a custom middleware might do.
* **Without Relay**
Your own middleware reads vault accounting and Delegator state directly from Symbiotic Core, applies your stake → voting power rules off-chain, and uses that to drive your protocol. You still need to handle cross-chain verification and efficient proof formats yourself.
* **With Relay**
`VotingPowerProvider` is the on-chain oracle of voting power for the Relay network. Relay’s off-chain sidecar and ValSetDriver:
* read operator/vault data from Symbiotic Core
* call `VotingPowerProvider` to get per-operator voting power
* compress that into a validator set header
* commit it into `Settlement`, which is then used to verify aggregated signatures on any connected chain
In other words: `VotingPowerProvider` is where you **define what “power” means** for your network, and Relay takes that definition and turns it into a cheap, verifiable validator set you can reuse everywhere.
## **Epochs and Delays**
Epochs are the time rules of Symbiotic. They tell you when validator sets update, when withdrawal requests can be claimed, and how long captured guarantees stay slashable. Grouping changes at epoch boundaries keeps the stake that networks rely on stable and easy to verify.
### Vault Epochs
Each vault has an **epoch duration** set at deployment (`epochDuration`). All epochs for that vault:
* are consecutive and equal length
* use the same duration unless the curator later increases it
Vault epochs drive two things:
1. When queued withdrawals become claimable
2. The maximum look-back window for slashing previously captured guarantees
#### Withdrawal Timing
Withdrawals are a two-step, epoch-based process.
* A user submits a withdrawal request at time `t` inside epoch `k`.
* The request becomes claimable **after epoch `k+1` ends**.
If the epoch length is `E`:
* the effective delay from request to claim is in `[E, 2E)` depending on when in the epoch the user requested
* until the boundary at the end of epoch `k+1`, the requested funds remain slashable
After that boundary, the withdrawal can be claimed and is no longer subject to new slashes.
#### Capture and Slashing Window
Networks do not slash against live state; they slash against **captures**.
* A **captureTimestamp** is the time a Network uses to snapshot stake and validator sets.
* At capture, the Network receives a guarantee that the captured amounts remain slashable for one **vault epoch** after that timestamp.
When a slashing request is executed, the Slasher enforces:
1. **Freshness**
If the capture is older than one epoch at execution time, the request is rejected: `now − captureTimestamp ≤ vaultEpoch`
2. **Bounded amount**
Let
* `G` = guarantee captured at `captureTimestamp`
* `C` = cumulative slashes already applied for that same capture
Then any new slash must satisfy: `slashAmount ≤ G − C`
This anchors penalties to a specific snapshot and prevents double-charging or overshooting the guarantee.
### Network Epochs and Buffers
Vault epochs need to be large enough to contain the **end-to-end slashing path** for a Network.
Roughly:
`validatorSetCaptureDelay + networkEpoch + vetoWindow + executionWindow ≪ vaultEpoch`
Where:
* `validatorSetCaptureDelay` – time to produce and publish the operator set / stake snapshot
* `networkEpoch` – how often your network rotates or commits a new set
* `vetoWindow` – VetoSlasher review period, if used
* `executionWindow` – operational buffer to actually call the Slasher and finalize the transaction
If the sum approaches the vault epoch, captures risk expiring before penalties can be executed. Either shrink the network-side timings or use a vault with a longer epoch.
#### Lifecycle Notes
Epoch changes and events interact like this:
* Freshness checks use the **current** vault epoch at verification time, not the epoch duration that was in effect when the capture was taken.
* Withdrawals are slashable until the first boundary where they become claimable (end of epoch `k+1` for a request in epoch `k`).
#### Examples
**7-day vault epoch, mid-epoch withdrawal**
* `E = 7 days`.
* User requests withdrawal on day 2 of epoch `k`.
* Claim is possible right after epoch `k+1` ends → between 7 and 14 days from the request, depending on where in the epoch they requested.
* Funds remain slashable until that boundary.
**Safe timing for slashing**
* Vault epoch `E = 8 days`.
* `validatorSetCaptureDelay = 6h`, `networkEpoch = 24h`, `vetoWindow = 12h`, `executionWindow = 6h`.
* Total = 48h, well below 8 days → captures stay fresh and enforceable with plenty of margin.
## **Registries and Opt-ins**
### Registries
Registries give Networks and Operators a canonical on-chain identity that the rest of Symbiotic can reference.
#### NetworkRegistry
Stores all Networks that can receive stake, be captured, and issue slashes or rewards. A Network registers once (for example via `registerNetwork()`), then:
* can be discovered by vaults, operators, and tooling
* can be linked to its middleware, which is the only address allowed to send slashing and rewards requests on its behalf
Only registered Networks can set per-vault limits and interact with Slasher and Delegator modules.
#### OperatorRegistry
Stores all Operators (EOAs or contracts) that can receive stake and be slashed. After registering (for example via `registerOperator()`), that operator ID is used everywhere:
* opt-in services track operator–vault and operator–network opt-ins
* vault Delegators use it when returning effective stake
* slashers reference it when enforcing penalties
Unregistered operators cannot be allocated stake.
(Other registries such as token or collateral registries are used similarly: they define which assets are valid and how they are handled, but they do not change the opt-in rules.)
### Opt-ins
Opt-ins establish **consent and scope**. They define which combinations of vault, operator, and network are actually allowed to interact, so that:
* a Network can only penalize stake that was explicitly made available to it
* a vault can only allocate to operators that agreed to serve it
* an operator can only be evaluated for Networks it chose to join
This keeps slashing and rewards precise and prevents accidental penalties.
#### Opt-in surfaces
Opt-ins live at the contact points between roles:
* **Operator → Vault** via `OperatorVaultOptInService`
The operator opts into a specific vault (and can later opt out). Without this, the vault
cannot allocate stake to that operator.
* **Operator → Network** via `OperatorNetworkOptInService`
The operator opts into a Network (and its subnetworks) it is willing to serve.
* **Network → Vault** via the vault’s Delegator
The Network expresses willingness to accept stake from a vault by setting a per-vault
maximum, e.g. `setMaxNetworkLimit(subnetwork, maxStake)`.
* **Vault → Network and Operator** via Delegator configuration
The curator allocates stake by setting non-zero limits or shares for a Network and for each
operator inside that Network (for example `setNetworkLimit()`, `setOperatorNetworkLimit()`,
or `setOperatorNetworkShares()` depending on Delegator type).
**Eligibility rule**
An operator is actually eligible for stake in a given Network through a given vault only if, at the relevant timestamp:
* the operator is opted into that vault
* the operator is opted into that Network
* the Network has set a non-zero max limit for that vault
* the vault’s Delegator has a non-zero limit or share for that operator in that Network
If any of these are missing, the Delegator returns zero stake and the Slasher will reject penalties for that pair.
#### Timing and capture
Opt-ins are time-aware. All checks are evaluated at the **capture timestamp** the Network includes in its request:
* when a Network captures stake at time *T*, it receives a guarantee that the reported amounts remain slashable for one vault epoch after *T*
* when a slashing request is executed, the Slasher verifies that the capture timestamp is no older than one vault epoch and that all required opt-ins and limits were in place at that time
Opt-outs and limit changes are **forward-looking**:
* if an operator opts out today, a Network can still slash for misbehavior tied to a capture from yesterday, as long as the capture is still inside the epoch window
* new captures taken after the opt-out will see zero stake and cannot be used for future penalties
#### Lifecycle and revocation
Each participant can change its opt-ins at any time:
* operators can opt in / opt out of vaults and Networks (or invalidate signatures)
* Networks can raise or lower per-vault max limits
* curators can adjust per-network and per-operator limits and shares
These changes affect **future** captures and allocations. Previously captured guarantees remain valid until they age out of the epoch window. This prevents last-minute exits from making valid penalties impossible to execute.
### Vault access vs opt-ins
Deposit access and opt-ins are separate:
* vault-level settings such as `depositWhitelist`, `depositLimit`, and their admin roles control **who can deposit** and **how much collateral** can be active
* opt-ins and Delegator limits control **who can be allocated stake** and **who can be captured, rewarded, or slashed**
A private, allowlisted vault still requires proper opt-ins and Delegator configuration before any operator can receive stake. A public vault can accept deposits from anyone but will not actually expose those deposits to a Network or operator unless all relevant opt-ins and limits are in place.
## **Curator**
Curators set and maintain a vault’s policy. They decide how stake is spread across networks and operators, what kind of slashing flow applies, and who can deposit. Stakers choose a vault because they trust the curator’s discipline on risk, timing, and counterparty selection.
In single-operator vaults, the operator can also act as curator. In immutable vaults, key parameters are locked at deployment, removing ongoing curator control: this reduces governance risk but also removes flexibility.
### Interactions and Vault Configuration
You don’t need every internal detail, but you should know the main pieces you are indirectly steering and the key functions involved.
* **Vault and VaultFactory / configurator**
The vault holds collateral, tracks deposits and withdrawals, and enforces epoch-based exits. New vaults are typically created through a configurator that wraps the factories, for example a helper like `VaultConfigurator.create(initParams)` which, under the hood, calls `VaultFactory` and related factories to deploy the `Vault`, its `Delegator`, and its `Slasher`.
* **Delegator (stake allocation)**
The Delegator decides how vault stake is allocated across networks and operators. As a curator you mainly use functions such as `setNetworkLimit()` to define how much stake this vault can send to a network, and `setOperatorNetworkLimit()` or `setOperatorNetworkShares()` to shape stake per operator, depending on the Delegator type.
* **Slasher (penalties)**
The Slasher applies penalties when a network requests them (via a function like `slash()`). As curator you choose the Slasher type (instant or vetoed) and its timing parameters, such as the veto window, when you create the vault.
* **Burner (what happens to slashed collateral)**
The Burner is a contract address you pass when the vault is created. It decides what happens to slashed collateral: burn, redistribute, send to a treasury or insurance pool, or route to custom logic.
You also rely on:
* an **OperatorRegistry** and **NetworkRegistry**, which define which operators and networks exist
* **opt-in services** (for example calls like `OperatorVaultOptInService.optIn(vault)` and `OperatorNetworkOptInService.optIn(network)`) so that operators can receive stake from your vault once you allocate it
### Vault Strategy
Think of your work in three phases: design, deploy, and wire.
#### Design the policy
First, decide what the vault is supposed to do, in plain language:
* which networks you want to support
* how diversified or concentrated you want to be across operators
* ceilings per network and per operator
* whether slashing should be instant or have a short veto window
* how you expect rewards and risk to trade off
This is the document stakers and operators will read. Everything else is just encoding this policy on chain.
#### Deploy the vault
Next, you create the actual vault and its modules in a single step with a configurator call, for example:
`solidity
(Vault vault, address delegator, address slasher) =
VaultConfigurator.create(initParams);
`
In the `initParams` you choose, among other things:
* the collateral token
* the vault epoch duration
* the Delegator type (multi-network, single-network, operator-specific, etc.)
* the Slasher type (instant or vetoed) and, for vetoed flows, the veto duration
* the Burner contract that will handle slashed collateral
* access control, such as whether deposits are public or allowlisted
This is where you lock in the big structural choices: what the vault secures, how fast people can exit, which delegation topology it uses, and how slashing is handled.
#### Wire stake limits and allocations
Once the vault exists, you configure how it actually allocates stake.
In practice that means:
* For each network you want to support, setting a vault-side limit with a call like `delegator.setNetworkLimit(subnetwork, amount)` which says “this vault can send up to this much stake to this network or subnetwork”.
* After operators have opted into your vault and into those networks, setting their allocations using, depending on the Delegator type: `setOperatorNetworkLimit(subnetwork, operator, amount)` for hard caps, or `setOperatorNetworkShares(subnetwork, operator, shares)` for share-based routing.
These limit and share calls are the core knobs you use to express your strategy on chain.
### Managing Stake
Once the vault is live, your job is mostly careful, occasional adjustments rather than constant tweaking.
Typical ongoing actions:
* revisiting network limits and operator allocations if performance, risk, or demand changes
* nudging the strategy toward more or less concentration, by changing limits or shares rather than redeploying the entire vault
* keeping the written policy up to date with any material changes you make on chain
You generally do **not** need to touch the factories again. Most day-to-day stewardship happens through the Delegator functions that set limits and shares, and through off-chain communication when you add or remove networks and operators.
### Risk and Timing
Even with a good strategy, the details of timing and partners matter. A few simple checks go a long way.
#### Collateral and reward quality
* Make sure the collateral token you pick at vault creation has clear economic value and reasonable liquidity.
* Prefer networks that offer rewards that match the risk taken: protocol fees, revenues from external clients, or controlled token inflation with a clear purpose.
If the collateral is low quality and networks do not pay fairly, you risk running a vault that takes real slashing risk while barely compensating stakers.
#### Epochs and veto windows
* The vault epoch duration you set at creation defines how long withdrawals take and how long stake remains slashable after it is “captured” by a network.
* If you choose a vetoed Slasher, keep the veto window well below the vault epoch. Networks need time to detect misbehavior, submit a slash, and wait out the veto period before the vault epoch ends.
A simple mental model:
> network’s own epoch and proof delay
>
> plus the veto window (if any)
>
> plus the time it takes to submit and finalize the slash
>
> should fit comfortably inside the vault epoch
If that does not hold, networks may not be able to slash in time, and the economic guarantees you think you are providing become weaker.
#### Network and operator choices
The settings you choose in `setNetworkLimit`, `setOperatorNetworkLimit`, and `setOperatorNetworkShares` express your risk appetite.
* Treat the network limit as a risk budget for that network. Conservative vaults use lower limits and fewer networks; more aggressive vaults use higher limits and more networks, but should be explicit about correlated risk.
* When you allocate to operators, avoid over-concentrating on a single one unless that is very clearly part of the thesis. Slashing events will hit stakers in proportion to those allocations.
Your operator and network choices affect not just returns, but your reputation as a curator.
#### Contract health and extreme cases
* Be careful when changing access control and deposit limits to avoid locking the vault unintentionally.
* If the vault ever experiences a full (one hundred percent) slashing event, it is often cleaner to deploy a new vault, rather than trying to reuse the same one repeatedly. The history stays clear and future stakers know exactly what they are opting into.
* If you use fee-on-transfer collateral together with redistribution of slashed funds, be aware that the fee logic will introduce unavoidable losses during redistribution; that trade-off should be explicit in your policy.
### Vault Profiles
The same contracts and functions can describe very different vault “shapes”. Two common ones:
#### Diversified and conservative
* Several networks with moderate network limits
* Many operators, each with modest per-operator limits or fairly even shares
* A vetoed Slasher with a resolver set and a longer vault epoch
* Focus on capital preservation and strong guarantees over maximum throughput
#### Throughput and concentration
* Fewer networks with higher network limits
* A smaller set of top-tier operators with larger limits or shares
* An instant Slasher and a medium or shorter epoch
* Focus on fast settlement, high utilization, and more aggressive risk taking
You can treat these as anchor points and position your own vault somewhere in between, depending on who it is for.
### When active curation is minimal or not needed
Some vault designs intentionally minimize ongoing curator work.
* **Single-network, single-operator designs** often use a Delegator type that effectively hard-codes the network and operator at creation time. After a basic network limit is set, there may be little left to adjust.
* **Immutable, pre-configured vaults** are created once with a fixed configuration and no roles that can change core behavior later. Users opt into a static design rather than a curator’s future decisions.
In those cases, your job as the original curator is mostly to make sure the initial configuration and documentation are correct and to be transparent that the vault will not change over time.
## **Network**

In Symbiotic, we define networks as any protocol that requires a decentralized infrastructure network to deliver a service in the crypto economy, e.g. enabling developers to launch decentralized applications by taking care of validating and ordering transactions, providing off-chain data to applications in the crypto economy, or providing users with guarantees about cross-network interactions, etc.
Decentralized infrastructure networks can utilize Symbiotic to flexibly source their security in the form of operators and economic backing. In some cases, protocols may consist of multiple sub-networks with different infrastructure roles. The Symbiotic protocol’s modular design allows developers of such protocols to define the rules of engagement that participants need to opt into for any of these sub-networks.
## **Technical Overview**
In Symbiotic, networks are represented through a network address (either a contract or multisig) and a middleware, which can incorporate custom and slashing logic. The core protocol’s fundamental functionalities encompass slashing operators and rewarding both stakers and operators.
The middleware contracts integrate with Symbiotic Core for stake capture, validator set management, slashing, and optional rewards accounting inside the middleware. Optional here means that rewards logic can live in the middleware, while the existence, funding, and source of rewards are always defined by the Network.
The network also has its own operator set, which provides services to the network. The network’s software produces work, emits messages to be attested, and participates in epochs. Here the network admin defines voting power rules and thresholds, message formats, participation and liveness requirements, dispute inputs, and Relay compatibility if it wants cross chain verification.
### **Epoch**
A network epoch (let’s name it `NETWORK_EPOCHNETWORK_EPOCH`) is a period while a certain operator set, obtained given the captured stake, operates for the good of the network. The epoch plus the vault’s veto and execute phases’ durations should not exceed the duration of the vault’s epoch to ensure that withdrawals do not impact the captured stake (however, the conditions can be softer in practice).
[See Vault Accounting Details](/learn/core-concepts/vault#accounting-and-epochs)

A valid operator set means the validator set captured for the current network epoch is the reference set used for verification and slashing during that epoch. While it remains valid, on chain checks verify signatures against that set and its associated weights, and any slashing decisions are made with respect to those same weights.
### **Staking**
The vault allocates stakes by setting limits for networks and operators.
Let the Vault be *V*, the Delegator module of the vault is *D* and the Slasher module is *S*.
[See Stake Allocating Details](/learn/core-concepts/vault#delegation)
Given the current active balance of the vault and the limits, we can capture the stake for the subsequent network epoch: `networkOperatorStake=D.stake(network,operator)`
#### **Subnetworks**
Instead of creating multiple instances of a network, the Symbiotic protocol allows the creation of multiple subnetworks within the same network. This is similar to an operator having multiple keys instead of creating several instances of the operator. All limits, stakes, and slashing requests are handled by subnetworks, not the main network. This approach diversifies the network’s stake across different staking mechanics. For example, one subnetwork can have high limits and a trusted resolver in the Slasher module, while another subnetwork can have lower limits but no resolver in the Slasher module.
The final ID is just a concatenation of the network’s address and the provided `identifier`, so collision is not possible.
For simplicity, we sometimes omit the presence of subnetworks and just use the term network.
#### **Limits**
The limits are set in the vault, and the network cannot control this process (unless the vault is managed by the network). However, the implementation prevents the vault from removing the previously given slashing guarantees.
Moreover, the network can limit the maximum amount of stake it wants to use via the `D.setMaxNetworkLimit()` method.
#### **Staking Lifecycle:**
1. The network registers by calling `NetworkRegistry.registerNetwork()`.
2. Operators register by calling `OperatorRegistry.registerOperator()`.
3. The operators must opt into the vault and the network.
4. Stakers deposit funds into the vault.
5. The network sets a maximum stake amount for the vault by calling `D.setMaxNetworkLimit(identifier, amount)`.
6. The `NETWORK_LIMIT_SET_ROLE` holder defines the stake limit for the network.
7. The `OPERATOR_NETWORK_LIMIT_SET_ROLE` holder defines the stake limit for the operator-network pair.
The current stake amount cannot be withdrawn for at least one epoch, although this restriction does not apply to cross-slashing.
#### **Operator Set**
The network has the flexibility to configure an operator set within the middleware, later to be used as a validator set (a.k.a. valset) for its validating.

The following functions could be useful:
* `D.stakeAt(subnetwork, operator, timestamp, hints)`: Determines minimum stake eligibility. Note that the sum of operators’ stakes may exceed the network’s total stake, depending on the network’s and operators’ limits in the delegator module.
* `OptInService.isOptedInAt(operator, subnetwork, timestamp, hint)`: Checks the opt-in status.
### **Slashing**
[See Slashing Details](/learn/core-concepts/slashing)
For each operator, the network can obtain its stake which will be valid during $d=vaultEpochd$. Through its middleware, the Network initiates slashing when provable misbehavior occurs according to Network‑defined rules. Slashing protects stakers from dishonest or idle operators and protects Networks from operators taking stake without performing required work. Symbiotic Core enforces objective bounds so only stake guaranteed at capture can be burned.
A slashing request must reference a capture timestamp that is no more than one vault epoch old, not exactly equal to the epoch boundary. Requests can arrive at any time within this sliding window. Requiring equality would cause legitimate slashes to fail around boundaries.
Note that the actual slashed amount may be less than the requested one.
1. This may be influenced by cross-slashing.

1. This may be influenced by slashings by the network itself, as the consequent valsets may depend on the stake used for the creation of the previous valsets.

1. In the case of a task-like system, where each task is backed by the corresponding operator’s stake, this may be influenced by slashings by the network itself if the operators have a pooled stake.

The network can slash the operator within the vault only if
1. The operator is opted into the vault
2. The operator is opted into the network
To initiate a slashing process, a network should call:
1. `slash(subnetwork, operator, amount, captureTimestamp, hints)` for the Slasher module.
2. `requestSlash(subnetwork, operator, amount, captureTimestamp, hints)` for the VetoSlasher module.
The module will check the provided guarantees at the $*captureTimestamp*$, denoted as $*G.*$ It also calculates cumulative slashings from the $captureTimestamp$ to the current moment, denoted as $*C*$. It is guaranteed that for every correct $captureTimestamp$, $C≤G$. The module will allow slashing no more than $G−C$ to justify the given guarantees.
### **Operating Lifecycle**
A network can use flexible mechanics to keep its operator set state up-to-date, e.g., it’s convenient to use a conveyor approach for updating the stakes while keeping slashing guarantees for every particular version of the operator set:
1. At the beginning of every epoch the network can capture the state from vaults and their stake amount (this doesn’t require any on-chain interactions).
2. After this, the network will have slashing guarantees for one vault epoch duration, so it can use this state at most for one vault epoch.
3. When the epoch finishes and a slashing incident has taken place, the network will have time equal to the vault epoch duration minus the network epoch to request-veto-execute slash and go back to step 1 in parallel.

### **Rewards**
In Symbiotic, rewards are categorized into:
* Operator rewards
* Staker rewards
#### **Operator Rewards**
The network distributes the operator rewards at its discretion. Here are three examples:
1. The network performs off-chain calculations to determine the reward distributions. After calculating the rewards, the network executes batch transfers to distribute the rewards in a consolidated manner.
2. The network performs off-chain calculations to determine rewards and generates a Merkle tree, allowing operators to claim their rewards.
3. The network performs on-chain reward calculations within its middleware to determine the distribution of rewards.
#### **Source of Data for Network On-Chain Reward Calculations**
[For each epoch, networks obtain their staking information through our system.](https://github.com/symbioticfi/rewards) Additionally, all operators register through the network, providing necessary details such as commission rates, fixed payments, and other relevant conditions. This registration process ensures that networks have the required data to perform accurate on-chain reward calculations in their middleware.
#### **Staker Rewards**
[See Staker Rewards Details](/learn/core-concepts/rewards)
### **Relay SDK Integration**
All of this can be cumbersome to scope, implement, and maintain from scratch. That is why Symbiotic provides the Relay SDK, a set of contracts and off chain components that let networks capture stake through Symbiotic, track operator sets and voting power, aggregate signatures, and plug into slashing without rebuilding their own verification layer.
Using the Relay SDK, a network can verify the same work across multiple EVM chains, aggregate operator signatures off chain and verify them once on chain, and significantly reduce verification costs while keeping its existing governance, message formats, and slashing rules unchanged.
## **Operator**
Operators run the software that keeps decentralized networks alive. They can be node operators or validators that run consensus and network specific binaries, sign messages for bridging and oracles, or strategy operators such as risk managers and AI agents that execute DeFi strategies on behalf of a network.
Within Symbiotic, operators can receive stake from different vaults and route it to the same set of nodes for a given network. The protocol maintains a registry of operators and records their activity so networks and curators can make informed choices. The registry covers which networks an operator has opted into, which vaults are connected and how much restaked collateral came from them, and a history of slashes and other on chain interactions.
This setup lets operators aggregate stake from many sources, including institutional vaults, operator specific vaults, or LRTs with different risk profiles, without spinning up separate infrastructure for each one. A single node stack per network can secure multiple partners, as long as all parties have opted in.

In Symbiotic, an operator can be either an externally owned account or a contract that is registered in the OperatorRegistry.
### Operator onboarding
At a high level, onboarding an operator involves three steps.
1. Register the operator entity in the operator registry so it can be referenced by vaults and networks: Call `OperatorRegistry.registerOperator()` in `OperatorRegistry`.
2. Opt into the networks the operator wants to serve. Each network decides whether to include the operator in its active set based on criteria such as performance history, reputation, stake, and reliability. This is achieved by calling the `optIn()` method in `OperatorNetworkOptInService` .
3. Opt into the vaults that may allocate stake to that operator. This is achieved by calling the `optIn()` method in `OperatorVaultOptInService`. Curators then configure limits or shares so the Delegator can route stake to the operator within each network’s bounds. The address that holds `OPERATOR_NETWORK_SHARES_SET_ROLE` or `OPERATOR_NETWORK_LIMIT_SET_ROLE` for the vault assigns stake to the operator by calling either:
* `D.setOperatorNetworkShares(...)`, or
* `D.setOperatorNetworkLimit(...)`
depending on the Delegator type used by the vault.
Stake becomes eligible for slashing only when the operator has opted into both the network and the vault at the time stake is captured for an epoch.

### Working with Vaults and Networks
#### Vaults
Vaults are where stake lives. Curators decide which operators are admissible for a vault and how much stake each one can receive. They set per operator limits or shares and may adjust them as conditions change. The Delegator module uses these settings, together with opt ins, to determine how much effective stake each operator has per network.
#### Networks
Networks are where operators perform work. An operator opts into a network in order to validate it or to provide a defined service. Based on its own criteria, each network independently decides whether to include the operator in the active operator set. The network’s software produces work, emits messages or commitments to be attested, and participates in epochs. Here the network defines voting power rules and thresholds, message formats, participation and liveness requirements, dispute inputs, and how it integrates with the Relay if it needs cross chain verification.
#### Aggregation
For a single network, an operator can combine stake from multiple vaults into one node stack as long as:
* the operator has opted into that network
* the operator has opted into those vaults
* curators have allocated stake to the operator within each network limit
This allows operators to build one hardened infrastructure per network and receive stake from many partners without fragmenting their setup.
#### Subnetworks and Keys
Some networks split responsibilities into subnetworks. Limits, stake capture, and any penalties apply per subnetwork. Operators should plan key management and operations with that boundary in mind, for example by running distinct keys or processes per subnetwork where needed.
### Relay integration
All of the above can be implemented with custom network logic, but wiring cross chain verification, aggregation, and stake capture from scratch is complex. Symbiotic provides the Relay SDK so networks and operators can plug into a common framework instead.
If a network uses the Relay SDK:
* The Relay uses the operator registry and voting power from Symbiotic to build the operator set for that network.
* Operators can run a small Relay sidecar that helps collect signatures, aggregate them, and submit commitments so verification remains efficient across EVM chains.
* The same operator set and stake that secure the network can be reused to attest on multiple chains, reducing costs and integration effort while keeping the network’s governance and rules unchanged.
From the operator perspective, Relay integration mainly means running an additional, lightweight process that works alongside their existing nodes and keys, rather than rewriting their own cross chain logic.
### Penalties and Slashing
Once an operator has opted into a vault and a network, and stake has been captured for an epoch, that stake becomes subject to slashing according to the network rules and the vault configuration.
If an operator fails to perform services according to those rules, the network middleware can raise a slashing request against the operator’s stake. On Ethereum style systems this includes faults such as double signing or other consensus violations. The vault’s Slasher module validates slashing requests and, if they are correct and within the defined guarantees, applies penalties to the operator’s stake and invokes the vault’s Burner to decide what happens to the penalized collateral.
Some setups allow immediate execution of valid slashes, while others introduce a short veto or review window, depending on the Slasher type chosen by the curator and the network.
### Rewards
Operators need to be compensated for the services they provide and the risk they take. Networks pay operators from the value they generate, for example protocol fees, payments from external clients who use their services, or token inflation allocated to security and operations.
Symbiotic’s rewards framework gives networks several ways to route these payments:
* the network can calculate rewards off chain and send periodic batch transfers to operators
* it can calculate rewards off chain and publish a Merkle tree so each operator claims its share
* or it can keep reward accounting fully on chain in its middleware and distribute directly from that state
In every case, the goal is the same: operators are paid in a way that matches the work they do, the stake they are trusted with, and the risk profile of the networks they secure.
## **Rewards**
Rewards are payments that Networks make to stakers and operators in exchange for security and work.
* **Stakers** provide collateral that backs operator behavior and is at risk of slashing.
* **Operators** run the infrastructure or strategies that the Network depends on: validators, relay/bridge nodes, risk engines, or DeFi execution logic.
Rewards compensate:
* stakers, for locking capital into a vault and accepting slashing risk, and
* operators, for running infrastructure and meeting performance and liveness requirements.
Rewards may come from protocol fees, scheduled token emissions, external client payments, or amounts routed from slashing (via Burner policy). Symbiotic does **not** dictate the economics; it only provides the plumbing so Networks can express their own reward logic and deliver it efficiently to stakers and operators.

Vaults themselves do not define rewards. They only hold collateral and enforce delegation and slashing. Rewards are defined and paid by Networks, and claimed through the Rewards V2 system.
### Rewards V2 architecture
Rewards V2 is Symbiotic’s standard mechanism for computing and distributing rewards across chains. It introduces a small set of on-chain contracts and an off-chain distribution script that together produce a Merkle-committed “cumulative distribution” from which all participants can claim.
#### On-chain contracts
Rewards V2 deploys three singleton contracts per chain that has Symbiotic Core:
**Rewards**
The main contract for distributions and claiming. It stores cumulative reward distributions as Merkle roots and exposes claim functions for stakers, operators, and curators. Networks (or their designated rewarder address) commit new distributions to this contract.
**FeeRegistry**
A registry that stores fee settings for operators and curators. Operators and curators configure their fees once (for example via the Symbiotic CLI). When a Network constructs a distribution, it reads this registry to apply fee splits correctly.
**CuratorRegistry**
A registry mapping each vault to its curator (the fee receiver). This ensures curator fees are routed to the correct address without per-network bespoke logic.
These contracts are shared by all Networks on that chain.
### Off-chain distribution model
Rewards V2 assumes an off-chain **distribution script** that reads Symbiotic state, computes who should be paid and how much, and then commits the result to the `Rewards` contract.
At a high level, that script is built from a set of modules:
* **OperatorsVaultsProvider** returns, for each subnetwork, the relevant operators, their vaults, and the distribution shares for each operator–vault pair (typically based on stake or Symbiotic Relay voting power).
* **FeesProvider** takes those operators and vaults and returns the associated curators and the fee configuration for operators and curators (read from FeeRegistry and CuratorRegistry).
* **StakersProvider** takes vault addresses and returns the stakers in each vault and their shares, based on vault balances at the chosen distribution timestamp.
* **Storage** stores and retrieves cumulative distributions in a data-availability layer. By default this is Symbiotic’s backend.
* **Committer** writes the new cumulative distribution to Storage and then commits its Merkle root and metadata on chain via the `Rewards` contract, potentially on multiple chains.
Symbiotic provides default implementations of all these modules, plus:
* a Go package (`rewards_constructor`) that takes the module outputs and constructs a new cumulative distribution, and
* a default Distribution Script that ties everything together.
Networks can adopt the defaults as-is, or replace individual modules when they need custom behavior.
Execution of the Distribution Script is up to the Network. It can run as a cron job, a validator-run daemon that reacts to epoch changes, or a manually triggered tool.
### What Rewards V2 provides
From the perspective of each participant:
#### Networks
Networks use Rewards V2 to turn their economic logic into on-chain payouts without custom infrastructure.
* They define what rewards pay for (for example, stake value, relay voting power, tasks completed) and plug that logic into the OperatorsVaultsProvider or a custom module.
* They use the default Distribution Script and `rewards_constructor` to generate a new cumulative distribution for each period (for example, each network epoch or at another cadence).
* They use a single on-chain call to `Rewards` to commit a Merkle root representing the updated cumulative distribution, and can do this on multiple chains at once.
This reduces gas costs (one on-chain commitment per distribution instead of many small transfers), reduces integration work, and allows the same distribution logic to be reused across chains.
#### Stakers
Stakers receive rewards for providing collateral and taking slashing risk through vaults.
In Rewards V2:
* the staker portion of rewards is computed based on their vault shares at the distribution timestamp
* a single claim against the `Rewards` contract can aggregate multiple distributions and multiple vaults, reducing gas per claim
* stakers use the Symbiotic UI or CLI to view and claim rewards, rather than interacting with a different rewards contract per Network
The underlying Merkle structure is abstracted away; stakers only need to know that their claims are validated against the latest committed root.
#### Operators
Operators receive rewards for running infrastructure or strategies for the Network.
With Rewards V2:
* operator fee parameters are stored centrally in `FeeRegistry`, set once via CLI or direct contract interaction
* the distribution script reads these settings and allocates operator fees as part of the cumulative distribution
* operators claim their rewards from the same `Rewards` contract using the Symbiotic CLI, instead of managing per-network custom flows
This shortens the path from “Network decides to pay operators” to “operator can claim” and standardizes the way fees are expressed.
#### Curators
Curators receive a fee in return for designing and managing vault policies.
Rewards V2:
* uses `CuratorRegistry` to map each vault to a curator address
* uses `FeeRegistry` to encode curator fee settings
* includes curator shares in the cumulative distribution built by the Distribution Script
Curators configure their fee levels once, and then receive rewards whenever Networks use the vaults they manage and include curator fees in their distribution logic.
### Key concepts and terminology
To read or write distribution code, a few terms matter:
* **Distribution timestamp** is the time at which on-chain data is read. All balances, voting powers, and fee settings used in a distribution are evaluated at this point.
* **Cumulative distribution** is the running total of all distributions for a Network. Each new distribution updates the cumulative state; claims compare what has already been claimed against this cumulative total.
* **Distribution script** is the off-chain program that runs all providers (operators/vaults, fees, stakers), constructs the new cumulative distribution with `rewards_constructor`, writes the data to Storage, and calls the Committer to commit the Merkle root to the `Rewards` contract.
Symbiotic provides the contracts, modules, tooling, backend, and UI so that Networks can focus on **what** to reward (their economics and incentives), while Rewards V2 standardizes **how** those rewards are delivered and claimed.
## **Slashing**
Slashing is how a Network penalizes operators for provable misbehavior. A Network’s middleware sends a slashing request to the vault; the vault’s Slasher module checks timing and amount constraints; if the request is valid, the vault reduces the operator’s effective stake and forwards the penalized collateral to a Burner, which applies the vault’s policy (burn, redistribute, route, etc.). The goal is for penalties to be **executable**, **bounded**, and **auditable**.
### Slasher module
The Slasher is the vault module that enforces penalties. It does not detect faults itself. Instead it:
* reads stake data from the Delegator (how much stake an operator had in a subnetwork at a given time)
* reads its own internal record of previous slashes for the same snapshot
* validates a new request against those guarantees
* if valid, updates its internal records, informs the Delegator if needed, and calls the vault/Burner to handle the tokens
A vault can be deployed with one of three slashing modes:
* **No slashing** — slasher address is zero; the vault can never be slashed
* **Slasher** — instant execution as soon as a valid request arrives
* **VetoSlasher** — a request plus a short veto window, then execution if no veto occurs
Once chosen at deployment, the slashing model for a vault is fixed.
The shared flag `isBurnerHook` controls whether the Burner must be invoked on each slashing event (for example, to unwrap derivatives or forward to another contract).
### Capture timestamp and guarantees
Networks do not slash against arbitrary state. They first **capture** stake at a particular time, then slash against that snapshot.
When a Network fetches stake at some point in time (the *capture timestamp*), it receives a guarantee that the captured amount of collateral will remain slashable for **one vault epoch** after that timestamp. When the Slasher later executes a request, it checks:
1. The capture timestamp is not older than one epoch. If it is, the request is considered stale and rejected.
2. The requested amount does not exceed the remaining guarantee for that capture after accounting for any earlier slashes that used the same snapshot.
This is what makes slashes bounded: you cannot request more than the guarantee tied to that capture.
In restaking setups, a slash on one Network can reduce the guarantee left for others, because they share collateral. That is a property of restaking, not a bug in the Slasher. The capture bound still applies: across all Networks together, you cannot take more than was guaranteed at that snapshot.
### Execution flow
Every penalty follows the same basic flow, regardless of Slasher type.
1. **Submit**
Network middleware calls the Slasher with a slashing request that includes the subnetwork, operator, amount, and capture timestamp.
2. **Check**
The Slasher pulls stake data for that capture from the Delegator, aggregates previous slashes for the same snapshot from its own storage, and verifies:
* freshness (capture within one epoch), and
* bounds (requested amount ≤ remaining guarantee).
3. **Optional veto (VetoSlasher only)**
If the vault uses VetoSlasher, the request enters a veto period. For `vetoDuration` seconds after creation, any configured resolver can veto the request. A `resolverSetEpochsDelay` parameter controls how long it takes for newly set resolvers to become active, measured in vault epochs.
4. **Apply**
If the request passes checks (and veto, if applicable), the Slasher:
* records the penalty so future requests against the same capture see reduced remaining guarantee
* triggers any Delegator hook if configured
* calls the vault/Burner to actually process the penalized collateral
### Slasher types
**Slasher (instant)**
A straightforward module: validate and execute in a single step. There is no on-chain dispute window. This is appropriate when fault conditions and evidence are clear and mature, and the Network is comfortable with immediate penalties.

**VetoSlasher**
Adds an on-chain review window. The flow is “request → veto window → execution”:
* Request: middleware submits and VetoSlasher validates.
* Veto: resolvers have `vetoDuration` seconds to veto.
* Execution: if no veto is recorded, the Network calls execute and the penalty is applied.
`resolverSetEpochsDelay` enforces that new resolvers only become active after a minimum number of vault epochs, giving users a chance to exit before a change in the dispute set takes effect.

**No slashing**
Slasher is set to address(0). The vault cannot be slashed at all. This degrades the economic security guarantees for Networks and should be an explicit design choice.
### Burner
Once a slash is approved, the Slasher delegates the token handling to the Burner. The Burner defines what happens to penalized collateral. Typical patterns include:
* unwrapping derivative collateral and burning the underlying
* redistributing all or part of the penalty to stakers or well-behaving operators
* sending funds to a treasury or insurance pool
* locking tokens or routing them to another contract for protocol-specific logic
The Burner is configured per vault at deployment and is not automatically changed by slashing events. Burning is optional; redistribution is a valid outcome if it matches the vault’s policy.
### Participation and isolation
A slashing request only applies if, at the capture timestamp:
* the operator had opted into both the vault and the Network (including the relevant subnetwork), and
* the Delegator reports positive effective stake for that operator in that subnetwork.
If either condition fails, the request is rejected. This ensures Networks cannot accidentally penalize non-participants.
Whether a slash affects only one Network or multiple depends on the vault’s delegation model:
* **Single-Network / single-operator vaults** give strong isolation: a penalty for one Network does not spill over to others because the collateral is not reused.
* **Multi-Network restaking vaults** share collateral across Networks. A penalty in one Network reduces what remains for others, but each individual penalty is still capped by its capture-time guarantee and checked by the Slasher.
### Timing constraints
To keep slashing executable, the following must fit inside the vault epoch:
* the Network’s own epoch and finality / detection delay
* any off-chain time to build and submit a slashing request
* the veto period (`vetoDuration`), if using VetoSlasher
* the time to send and finalize the execution transaction
If downstream systems (for example, a dispute layer) require longer resolution, the vault’s `epochDuration` should be set high enough so that valid slashes can still be committed and executed before the guarantee expires.
## **Vault**
A vault is the on chain container that holds collateral and connects it to networks. Each vault holds a single collateral token, keeps track of deposits and withdrawals, and exposes policy hooks for delegation and slashing. Delegation is pure accounting: collateral remains in the vault and only leaves through user withdrawals or executed slashing.
Vaults are built from three core modules:
1. **Accounting (Vault)**: handles deposits, withdrawal requests and claims, epoch timing, and processing of penalized collateral.
2. **Delegation (Delegator):** applies curator limits or shares for each network and each operator and implements the stake distribution logic.
3. **Slashing (Slasher or VetoSlasher)**: validates slashing requests against captured guarantees and applies penalties.

Rewards are not built into vaults. Networks can leverage Symbiotic’s rewards contract template, which is designed to facilitate interactions with vaults and capture stake.
### Accounting and Epochs
#### Lifecycle
Symbiotic makes most mechanics configurable but gives strict guarantees around the period when stake is slashable. The vault lifecycle revolves around four actions: deposit, withdraw, slash, and resolve. Collateral comes into the vault through deposits, can be requested for withdrawal, may be penalized through slashing, and is then processed according to the configured policy.

#### Epochs
Epochs are a core mechanism that balance user liquidity with network security. Networks rely on operators having a stable amount of slashable stake during a period, while users want to request withdrawals at any time. Vaults achieve this with an epoch based withdrawal system rather than simple time delays.
Users can submit withdrawal requests at any time. Those requests are collected and become claimable after the end of the next vault epoch. Until that boundary, the requested amount remains eligible for slashing. Epochs are consecutive and all have the same length. The epoch length is set at vault deployment. A longer epoch gives more time to observe networks and execute slashes but slows withdrawals; a shorter epoch has the opposite effect.
Requested withdrawals therefore remain slashable until the next epoch boundary. This is what allows networks to rely on the guarantees they receive from stake captures.
#### Deposits
Any address allowed by the vault access policy may deposit the collateral token. By depositing, a user opts into the vault configuration and curator, since the vault risk profile and returns depend on that management. Deposits increase the user balance and the vault active stake used for delegation and guarantees. Each vault is bound to a single collateral token.

#### Withdrawals
Depositors can request withdrawals at any time. The process has two stages. First, the user submits a withdrawal request and the amount is marked as pending but remains slashable until the end of the next epoch. Second, after that next epoch ends, the user can claim funds at any time without further slashing risk. This keeps operator stake effectively stable within an epoch while giving users predictable exit timing.

### Delegation
Delegation translates vault balances and curator policy into effective stake for each network and each operator. The Delegator module lets each network set a maximum amount of stake it is willing to accept from a given vault, lets curators set per network and per operator limits or shares within those bounds, and aggregates all inputs to return the stake of a given operator on a given network at a given time.
Stake always depends on three elements:
1. the vault active stake, meaning funds that have not been fully withdrawn
2. operator opt ins to the vault and to the network
3. the limit that the network set for this vault
Some Delegator types also take per operator limits or shares into account. After a slashing event, Delegators do not automatically change limits. If automatic reactions are desired, they can be introduced through hooks.

#### Delegator Types
Symbiotic supports several Delegator types to cover different delegation topologies.
1. **Network Restake Delegator**
Allows restaking across multiple networks while keeping operators inside the same network independent from each other. Curators set a limit for each network within the network maximum and set shares for each operator. Operator stake in a network is the vault and network stake multiplied by the operator share over the sum of shares. This is convenient for liquid restaking providers or curators whose main role is to raise and allocate funds rather than operate nodes.
2. **Full Restake Delegator**
Restakes across multiple networks and multiple operators at once. Curators set a limit for each network and a limit for each operator. Operator stake is capped by the active stake, the network limit, and the operator limit. This is useful for insurance style designs where a shared pool backs many parties.
3. **Operator Specific Delegator**
A simplified version of the Network Restake type with a single operator per vault. Curators set only the network limit. Stake per network is capped by the active stake and the network limit. This lets an operator run its own vault with restaking across networks while giving networks more confidence that allocations are under the operator direct control.
4. **Operator Network Specific Delegator**
The most conservative type with a single network and a single operator. Stake is capped by the active stake and the network maximum limit. From the network perspective this resembles a traditional single operator staking arrangement, although there can still be many vaults per network.
#### Delegation Topologies
These Delegator types correspond to different combinations of how many networks and how many operators a vault can serve.
1. **Multi Network and Multi Operator (MN, MO)** gives maximum capital reuse and restaking with more shared risk.

2. **Multi Network and Single Operator (MN, SO)** gives operator specific vaults with strong operator isolation while still supporting restaking.

3. **Single Network and Multi Operator (SN, MO)** isolates network risk but shares operator risk and is often used by liquid staking providers or network treasuries.

4. **Single Network and Single Operator (SN, SO)** gives maximum isolation and minimum reuse and is often used for curator free or immutable arrangements.

| **Properties \ Delegation type** | **MN, MO** | **MN, SO** | **SN, MO** | **SN, SO** |
| -------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
| Restaking supported | ✅ | ✅ | ❌ | ❌ |
| Potential curators | LRT, Institutional restaking | Operator | LST, Network DAO | Users |
| User delegation model | Delegate to the curator as an entity to use stake for multiple operators in multiple networks | Delegate to the operator as an entity to use stake in multiple networks | Delegate to curator to use stake in single network | Delegate to the operator in the network directly (No curators) |
| Stake isolation for networks | ❌ | ❌ | ✅ | ✅ |
| Stake isolation for operators | ❌ | ✅ | ❌ | ✅ |
### Slashing and Burner
#### Slasher Module
The Slasher module enforces slashing penalties. It does not detect misbehavior itself; instead it processes slashing requests from network middleware.
A slashing request names the subnetwork, the operator, the amount to penalize, and a capture timestamp. The capture timestamp is the moment when the network fetched stake and received a guarantee that those amounts would remain slashable for one epoch. When executing a request, the Slasher checks that the capture timestamp is not older than one vault epoch and that the requested penalty does not exceed the remaining guarantee for that snapshot after previous slashes that used the same capture.
When a request arrives, the Slasher retrieves stake information from the Delegator and prior slashes for the same snapshot, validates that the request respects the guarantee, and if it is valid, updates internal state, notifies the Delegator where needed, and calls the vault and Burner to process the penalized collateral.
In restaking scenarios, guarantees can be affected by slashing that happened on other networks. This comes from the nature of restaking and cannot be fully avoided.
#### Slasher Types
There are currently two Slasher types:
1. **Slasher**: executes valid slashing requests as soon as they are confirmed correct. It is simple and transparent but less flexible.

2. **VetoSlasher**: adds a veto period. The network middleware submits a request, the contract validates it, and then a resolver, if configured, has a window of time to veto the request. If no veto occurs, the middleware can execute the slash after the window expires. This design helps networks and stakers transition from early deployments to fully trusted settings with an extra layer of review.

#### Burner
Once a slash is approved and executed, the Burner decides what happens to the penalized collateral. The Burner is a configurable contract that can unwrap tokens, burn them, redistribute them to users or well behaved operators, send them to a treasury or insurance pool, or forward them to custom logic. Burning is not mandatory and redistribution is a valid outcome.

### Rewards
Vaults do not define reward logic. They only provide the stake that secures networks and operators. Each network decides how staker and operator rewards are funded and delivered, for example from protocol fees, revenues from external clients, or token inflation. Symbiotic reward extensions give networks standard ways to distribute these flows, but the vault itself remains focused on holding collateral and enforcing guarantees.
### Vault Types and Access
Vaults are configurable templates. Different collateral tokens, epoch lengths, Delegator types, access policies, and slashing settings produce different vault types. Each vault still holds a single collateral token; multi asset exposure is achieved by using multiple vaults.
#### Public and Private Vaults
Public vaults accept deposits from anyone who holds the collateral token, subject to any global caps defined by the curator. Private vaults accept deposits only from allowlisted addresses. Liquid restaking providers, liquid staking providers, funds, and institutions often run private vaults and allocate across several Symbiotic vaults on behalf of their users.
#### Immutability Options
Vaults can be deployed in two broad ways. They can be immutable, with key parameters locked at deployment and no ongoing curator discretion, which reduces governance risk. They can also be upgradable within constrained surfaces, where certain parameters can be updated under defined rules. These choices, together with the Delegator type, slashing style, and access policy, define the risk and behavior profile of each vault in the Symbiotic ecosystem.
import { Card1 } from "../../components/Card1";
## Introduction
Symbiotic protocol covers a highly wide range of use-cases, so that contains multiple separate counterparties involved at the whole process from different perspectives. After checking the **Prerequisites**, simply choose the counterparty you represent the most and create!
### Prerequisites
Throughout the **Integrate** section's pages, we'll be performing various actions using the tooling listed below. Make sure to have it installed:
* `Git` to download the needed codebases ([Download](https://git-scm.com/downloads))
* `Foundry` to interact with EVM ([Download](https://book.getfoundry.sh/getting-started/installation))
* `Python` to run diverse scripts ([Download](https://www.python.org/downloads))
### Counterparties
## Helpful Core Contracts' Endpoints
This page provides a list of useful in practice functions for a Network across Symbiotic Core contracts.
| Function | Use-case |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| [`OperatorRegistry.registerOperator()`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/IOperatorRegistry.sol#L12) | Register operator |
| [`OperatorNetworkOptInService.optIn(address where)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/service/IOptInService.sol#L76) | Opt into the network |
| [`OperatorNetworkOptInService.optOut(address where)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/service/IOptInService.sol#L91) | Opt out from the network |
| [`OperatorVaultOptInService.optIn(address where)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/service/IOptInService.sol#L76) | Opt into the vault |
| [`OperatorVaultOptInService.optOut(address where)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/service/IOptInService.sol#L91) | Opt out from the vault |
import { Card1 } from "../../../components/Card1";
## Get Started
In Symbiotic, Operators are the ones who process the logic provided by networks. This page provides you a high-level overview of an Operator's lifecycle in Symbiotic:
:::steps
### Register Operator
:::
## Opt Into Networks And Vaults
Before operators can start receiving delegations, they need to complete two important opt-in steps:
* Opt-in to networks they wish to interact with
* Opt-in to vaults they plan to receive delegations from, including operator-specific Vaults
:::note
Please note that some networks may require additional registration steps through their own middleware systems. These network-specific requirements are not covered in this document as they vary by network.
:::
### Opt-in to network
#### Using [Safe](https://app.safe.global/)
* Open “Transaction builder”
* Put `OperatorNetworkOptInService` as contract address
* Choose `optIn()` method
* Input the desired network’s address
* Sign & send transaction
#### Verify via Etherscan
* Open “Read Contract” tab in `OperatorNetworkOptInService` contract
* Open `isOptedIn()` method
* Put `OPERATOR_ADDRESS` in `who` parameter, `NETWORK_ADDRESS` in`where`, and click “Query”. It should return `True`

### Opt-in to vault
#### Using [Safe](https://app.safe.global/)
* Open “Transaction builder”
* Put `OperatorVaultOptInService` address as contract address
* Choose `optIn()` method
* Input the desired vault’s address
* Sign & send transaction
#### Verify via Etherscan
* Open “Read Contract” tab in `OperatorVaultOptInService` contract
* Open `isOptedIn()` method
* Put `OPERATOR_ADDRESS` in `who` parameter, `VAULT_ADDRESS` in `where`, and click “Query”. It should return `True`

## Register Operator
To start the journey within the Symbiotic system, you should register your Operator using `OperatorRegistry` smart contract. The registered address should be meant as a management address that will opt into the Vaults/Network to get allocations from/for.
### Using [Safe](https://app.safe.global/)
* Open “Transaction builder”
* Put `OperatorRegistry` as contract address
* Choose `optIn()` method
* Sign & send transaction
### Verify via Etherscan
* Open “Read Contract” tab in `OperatorRegistry` contract
* Open `isEntity()` method
* Put `OPERATOR_ADDRESS` in `account` parameter, and click “Query”. It should return `True`

## Submit Metadata
[Symbiotic UI](https://app.symbiotic.fi/deposit) provides users with accurate and up-to-date information about various data regarding TVL, allocations, relations between Curators, Vaults, Operators and Networks, etc. However, for the mentioned counterparties to be easily accessible and visible on the UI - their metadata should should be submitted to the corresponding repositories.
Once, the metadata is submitted, it should be reviewed and merged by the Symbiotic team. After that the new data starts to be shown publicly 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) |
| Sepolia | [https://github.com/symbioticfi/metadata-sepolia](https://github.com/symbioticfi/metadata-sepolia) |
| Holešky | [https://github.com/symbioticfi/metadata-holesky](https://github.com/symbioticfi/metadata-holesky) |
#### Repository Structure
The repository is organized as follows:
```
repository/
├── vaults/
│ ├── 0x/
│ │ ├── 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, there must be 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`, please be sure that it's collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, please 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.
Your PR will be reviewed by the Symbiotic team, and if approved, it will be merged into the repository. Please note that the PR will be reviewed only after the entity is checked with automated checks.
***
#### 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.
##### 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 an Operator
:::steps
##### Create a new folder in the `/operators` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "My Operator",
"description": "My Operator",
"tags": ["operator"],
"links": [{ "type": "website", "name": "Website", "url": "https://myoperator.com" }]
}
```
##### Save a logo of the Operator to `logo.png` of 256x256 pixels size
:::
## Helpful Core Contracts' Endpoints
This page provides a list of useful in practice functions for a Network 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 |
import { Card1 } from "../../../components/Card1";
## Get Started
Symbiotic protocol contains a wide range of supportive tooling and products for various types of Networks to either build on top of or integrate with. This page provides you a high-level overview of Symbiotic integration flow:
:::steps
### Register Network
:::
import { Card1 } from "../../../components/Card1";
## Deploy Pre-deposit Vault
In some cases the Network may want to curate or deploy the Vaults by itself, for example:
* A DAO-controlled Vault with native Network asset used as a collateral
* A Network needs a specific configuration of the Vaults to proceed with their onboarding
The Vault deployment guide is available [inside the section for Curators](/integrate/curators/deploy-vault).
### Next Steps
}
href="/integrate/networks/rewards"
/>
import { Card1 } from "../../../components/Card1";
## Register Network
To start the journey within the Symbiotic system, you should register your Network using `NetworkRegistry` smart contract. The registered address should be meant as a management address that will interact, e.g., with Symbiotic Vaults to accept stake allocations.
To simplify this step and make the management process more secure we provide [network repository](https://github.com/symbioticfi/network) that contains `Network.sol` contract and tooling to manage it. Basically, `Network.sol` contract is an [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 either `(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 repository's deployment scripting currently supports 2 scenarios:
1. Currently, only a Network is needed, while the opt-ins to Vaults are going to be handled later
2. A Network with Vaults' opt-ins is needed
:::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), you will see config like this:
```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 needed fields, and execute the script via:
```bash [bash]
forge script script/DeployNetwork.s.sol --rpc-url --private-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), you will see config like this:
```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 needed fields, and execute the script via:
```bash [bash]
forge script script/DeployNetworkForVaults.s.sol --rpc-url --private-key --etherscan-api-key --broadcast --verify
```
:::
### Manage Your Network
There are 5 predefined action-scripts, that you can use from the start:
* [SetMaxNetworkLimit](https://github.com/symbioticfi/network/blob/main/script/actions/SetMaxNetworkLimit.s.sol) - set new maximum network limit for the vault
* [SetResolver](https://github.com/symbioticfi/network/blob/main/script/actions/SetResolver.s.sol) - set a new resolver for the vault (only if the vault uses VetoSlasher)
* [SetMiddleware](https://github.com/symbioticfi/network/blob/main/script/actions/SetMiddleware.s.sol) - set a new 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
Interaction with different actions is similar. Let's consider [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), you will see config like this:
```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 needed fields, and choose an operation:
* `runS()` - schedule an action
* `runE` - execute an action
* `runSE()` - schedule and execute an action (possible only if a delay for the needed action is zero)
##### Execute the operation:
* If you use an EOA and want to execute the script:
```bash [bash]
forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url --private-key --broadcast
```
* If you use a [Safe](https://app.safe.global/) multisig and want to get a transaction calldata:
```bash [bash]
forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url --sender --unlocked
```
In the logs, you will see `callData` field like this:
```bash [Expected output]
callData:0x01d5062a00000000000000000000000025ed2ee6e295880326bdeca245ee4d8b72c8f103000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000005365744d61784e6574776f726b4c696d697400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004423f752d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6700000000000000000000000000000000000000000000000000000000
```
In [Safe](https://app.safe.global/)->TransactionBuilder, you should:
1. enable "Custom data"
2. enter **Network's address** as a target address
3. use the `callData` (e.g., `0x01d5062a0000000000000000000000...`) received earlier as a `Data (Hex encoded)`
:::
### Update Delays
Any action that can be made by the Network is protected by the corresponding delay (which can be any value from zero to infinity).
We provide "update delay" scripts for actions mentioned above, and also some additional ones:
* [SetMaxNetworkLimitUpdateDelay](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 [SetMiddlewareUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMiddlewareUpdateDelay.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 [SetMaxNetworkLimitUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMaxNetworkLimitUpdateDelay.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 example usage of similar scripts see [Manage Your Network](/integrate/networks/register-network#manage-your-network).
***
### Dashboard
:::warning
Work-in-progress, use with caution.
:::
`Network.sol` contract inherits [OpenZeppelin](https://www.openzeppelin.com/)'s `TimelockController`, while `TimelockController` inherits `AccessControl`. The similarity between `TimelockController` and `AccessControl` contracts' logic is that it is not possible to adequately determine their state (e.g., statuses of operations or holders of roles) using only the current chain's state via RPC calls.
Hence, we provide a Network Dashboard which allows you 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
}
href="/integrate/networks/submit-metadata"
/>
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 the code updates as well as 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:
```
##### 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
```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> {
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?;
}
```
:::
### 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
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 allows for provable attestation checks on any chain of an arbitrary data signed by the validator set quorum.
The system provides a modular smart contract framework that enables networks to manage validator sets dynamically, handle cryptographic keys, aggregate signatures, and commit cross-chain state
### Architecture
Symbiotic provides a set of predefined smart contracts, in general, representing the following modules:
* [`VotingPowerProvider`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/) - provides the basic data regarding operators, vaults and their voting power, it allows constructing 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/) - is used by the off-chain part of the Symbiotic Relay for validator set deriving and maintenance
* [`Settlement`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/settlement/) - requires a compressed validator set (header) to be committed each epoch, but allows verifying signatures made by the validator set; currently, it 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 to be inputted on the verification, but in a compressed and efficient way, so that it is the best choice to use up to around 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
In sense of Symbiotic Core's `NetworkMiddlewareService` contract exactly `VotingPowerProvider` contract should be set as a 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, developers must 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
There are 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
* Also, there are ready bindings 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 can be found at [`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 [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) bash script (the Relay smart contracts use external libraries for their implementations, so that 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 the four deployment hooks: KeyRegistry, VotingPowerProvider, Settlement, and ValVetDriver
* [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) - orchestrates per-contract multi-chain deployments (uses Python inside 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) (it provides better control for production deployments and more simplified 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))
* this Foundry script should include the deployment configuration of your Relay modules
* you need to implement all virtual functions of `RelayDeploy.sol`
* in constructor, need to input the path of the `toml` file
* you are provided with 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))
* this configuration file should include RPC URLs that will be needed for the deployment, and which modules should be deployed on which chains
* **do not replace \[1234567890] placeholder with endpoint\_url = ""**
* the contracts are deployed in such 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 `
:::
At the end, your `toml` file will contain the addresses of the deployed Relay modules.
::::
### Integrate
The Symbiotic Relay provides you a comprehensive tooling working on its own, so that you don't care about anything except only your stake-backed application logic.
#### Verify Message
Your application contract is able to verify any message using a validator set at any point of time needed 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 is able to use the validator set at any point of time using [SSZ](https://ethereum.org/developers/docs/data-structures-and-encoding/ssz/) proof verification via, e.g.:
```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
}
href="/integrate/networks/relay-offchain"
/>
import { Card1 } from "../../../components/Card1";
## Rewards
[Read Learn first](/learn/core-concepts/rewards)
Rewards is a encouraging mechanism provided by a network to motivate operators to do their work. The rewards are divided into Staker and Operator rewards:
* The Staker rewards can be provided depending purely on the provided stake’s value (the representation of value can differ from the standard "dollars view" depending on alignment, token distribution, or other factors)
* The Operator rewards can be provided depending on the economic factors similar to the above ones and on the operators’ performance metrics (e.g., number of tasks completed, liveness, or validators’ distribution).
### Staker Rewards
The rewards contracts are not a part of the core contracts. However, we provide a default implementation of Staker rewards, which is represented by a simple pro-rata rewards distribution concerning the collateral amounts provided by stakers at the capture time point and providing an ability to the Vault curator to receive fees.
Code: [`DefaultStakerRewards`](https://github.com/symbioticfi/rewards/blob/main/src/contracts/defaultStakerRewards/DefaultStakerRewards.sol)
:::info
An unlimited number of networks can use one `DefaultStakerRewards` contract in favor of one specific vault’s stakers.
:::
Factory deployment: [`DefaultStakerRewardsFactory`](/get-started/resources/addresses#rewards)
#### Counterparties
* Network:
1. Distributes the rewards via `distributeRewards()`
* Staker:
1. Claims the rewards via `claimRewards()`
* Curator:
1. Configures an admin fee via `setAdminFee()`
2. Claims an admin fee (it accumulates after each distribution) via `claimAdminFee()`
#### Example
This example walks you through setting up a test environment to simulate the staker rewards distribution process on Holešky.
::::steps
##### Prepare Mock Accounts
You'll need 6 EOAs:
* **Network Admin**: registers the network
* **Middleware**: set by the network to handle reward distribution and vault opt-ins
* **Vault Admin**: sets up the vault and allocates shares
* **Mock Operator**: receives delegated stake
* **Two Test Stakers**: deposit collateral
:::warning
For test purposes, EOAs are fine. On mainnet, use contracts for middleware logic.
:::
##### Register Network & Set Middleware
1. Register your network
* [Example tx](https://holesky.etherscan.io/tx/0xfaf4b1d5cd0ce1a34a796b53a330092584b3e5886ef0de6937fe9ab4b698fe59)
2. Set middleware address
* [Example tx](https://holesky.etherscan.io/tx/0x84459916991fd14762f49adfb958fd41d59b381c33c4e34bb26fba51aa12307d)
:::warning
On mainnet, avoid using EOAs for middleware.
:::
##### Create Vault & Register Operator
1. [Create a vault](https://app.holesky.symbiotic.fi/create) using `wstETH` as collateral.
* Sample Vault address: `0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0`
* [Creation tx](https://holesky.etherscan.io/tx/0xb28636cca9c561a4308ca9679b487fc2eb3b12850dabc54cd7fbb73cc3d44487)
2. Register operator in [Operator Registry](https://holesky.etherscan.io/address/0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548)
* [Sample tx](https://holesky.etherscan.io/tx/0x5ec21081d3f7f4b0a6f7abcb78a54d63fc8739be4f2e1be6f82324bcc8c6404e)
3. Opt operator into:
* [Network](https://holesky.etherscan.io/tx/0x19ef569b223f8876ccd508cde00fb1cb27744fcf07424314a08cebea66a2cd20)
* [Vault](https://holesky.etherscan.io/tx/0x72f68941e84b62f5f55282c60aaaeb5bfa706c803961713c9cbe9224e93d3bd2)
4. Allocate shares:
* [Sample tx](https://holesky.etherscan.io/tx/0x492c5a337775e2914abbdf521883acd7d84380db4512d2c8cae8c7b0116d8fd5)
5. Submit 3 PRs with metadata (network, vault, operator) to the [metadata-holesky](https://github.com/symbioticfi/metadata-holesky/) repo. Examples: [78](https://github.com/symbioticfi/metadata-holesky/pull/78), [79](https://github.com/symbioticfi/metadata-holesky/pull/79), [80](https://github.com/symbioticfi/metadata-holesky/pull/80)
##### Vault Opt-In (Network)
1. Opt-in to vault by calling `setMaxNetworkLimit(0, 1e18)`
* [Sample tx](https://holesky.etherscan.io/tx/0x010ba1ccd0aec56a38dc664358bbead3eb2b3e48961b42dc14cffa1b0cf5a698)
2. From emitted event, extract `subnetwork ID`
3. **Vault Admin:** accept opt-in by calling `setNetworkLimit`
* [Sample tx](https://holesky.etherscan.io/tx/0xe7a15e5961081d067964a554f2a5f0ff32dfe415b2848b832e665d81fca9b136)
##### Deploy Rewards Contract
1. Use [DefaultStakerRewardsFactory](https://holesky.etherscan.io/address/0x58e80fa5eb938525f2ca80c5bde724d7a99a7892#writeContract) to create `DefaultStakerRewards` contract (can be deployed by a Vault Admin or a Network)
* [Sample tx](https://holesky.etherscan.io/tx/0x4a9a56943a54179e89bf8c28e28bc5ada3d925d1964ee4907f22e8d1ccc45d7b)
2. Submit rewards metadata PR
* [Example](https://github.com/symbioticfi/metadata-holesky/pull/85)
##### Distribute Rewards
* Increase token allowance
* [Sample tx](https://holesky.etherscan.io/tx/0xd05afbd3d2cacda412c17f9a4ca08bf91c51efc429e5dd77d1cad3ace84177b9)
* Call `distributeRewards()`
* [Sample tx](https://holesky.etherscan.io/address/0x3CBc80E19d558a4012CfE93dD724c1a52ad41EF5#writeContract)
:::warning
On mainnet, call to `distributeRewards()` should be done from within your middleware contract.
:::
##### Encode `data` parameter
* To reproduce manually, use [ABI encoder](https://adibas03.github.io/online-ethereum-abi-encoder-decoder/encode) to cook it with:
* Input types: `uint48,uint256,bytes,bytes`
* Input values: `1752766520,1000,0x,0x`
* `timestamp` - use current timestamp
* `maxAdminShare` (10%) - anti-frontrun protection
* `bytes` inputs are [hints](/integrate/builders-researchers/hints) (set to `0x`)
* To reproduce in Solidity:
```solidity [DistributeRewards.s.sol]
address rewardsContract = 0x3CBc80E19d558a4012CfE93dD724c1a52ad41EF5;
address network = 0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0;
address token = 0x5FbDB2315678afecb367f032d93F642f64180aa3;
uint256 amount = 1000000000000000000;
uint48 timestamp = 1752766520;
uint256 maxAdminFee = 1000;
bytes memory activeSharesHint = new bytes(0);
bytes memory activeStakeHint = new bytes(0);
bytes memory data = abi.encode(timestamp, maxAdminFee, activeSharesHint, activeStakeHint);
IDefaultStakerRewards(rewardsContract).distributeRewards(network, token, amount, data);
```
This gives the `data` parameter:
```bash [Expected output]
0x00000000000000000000000000000000000000000000000000000000687942a500000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
* [Sample tx](https://holesky.etherscan.io/tx/0x842094f4c3b9f4b368daa3d6160239144f41c338e1dc176a904a12b486015423)
:::info
To identify that rewards were distributed in the past, open a [Vault Page](https://app.holesky.symbiotic.fi/vault/0x132A3c9c2403662d89DF034b8B11c145b90d0ddA). Find the overall Vault Reward data and rewards claimed earlier in the corresponding section.
:::

##### User Flow
* [Acquire wstETH](https://stake-holesky.testnet.fi/wrap)
* [Sample tx](https://holesky.etherscan.io/tx/0x2e4031b92696e1c1eb8e53e24f30981f76e90c45a40b4169ec5d4b7c4e60a5fe)
* Deposit to Vault (via UI)
* [Tx 1](https://holesky.etherscan.io/tx/0x7238e1ac735564ab09189fcd41497112e978d2fe933bad282a624ae040744df2)
* [Tx 2](https://holesky.etherscan.io/tx/0x58c1f88de345da80f9e1a16304932113f6f2baa0deedee63a7c945fc8114676f)
* Claim Rewards (after next distribution)
* Use the [Symbiotic Dashboard (Rewards tab)](https://app.holesky.symbiotic.fi/vault/0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0)

::::
### Operator Rewards
Since the rewards contracts are not a part of the core contracts, we allow users to provide their own implementations. Here are three example implementations:
1. The network performs off-chain calculations to determine the reward distributions. After calculating the rewards, the network executes batch transfers to distribute the rewards in a consolidated manner.
2. The network performs off-chain calculations to determine rewards and generates a Merkle tree, allowing operators to claim their rewards.
3. The network performs on-chain reward calculations within its middleware to determine the distribution of rewards.
We provide a default implementation of the operator rewards, which is represented by a simple Merkle tree rewards distribution, where each leaf represents a recipient (an operator’s treasury address) and the total amount of tokens earned for the whole period.
Code: [`DefaultOperatorRewards`](https://github.com/symbioticfi/rewards/blob/main/src/contracts/defaultOperatorRewards/DefaultOperatorRewards.sol)
:::info
An unlimited number of networks can use one `DefaultOperatorRewards` contract in favor of an unlimited number of operators.
:::
Factory deployment: [`DefaultOperatorRewardsFactory`](/get-started/resources/addresses#rewards)
#### Counterparties
* **Network:**
1. Calculates a Merkle root for the rewards distribution (we’ve implemented a [CLI](https://github.com/symbioticfi/rewards/blob/main/specs/OperatorRewards.md#cli) for that purpose)
2. Distributes the rewards via `distributeRewards()`
* **Operator:**
1. Claims the rewards via `claimRewards()` by the usage of a Merkle proof (it can be got with the help of [CLI](https://github.com/symbioticfi/rewards/blob/main/specs/OperatorRewards.md#cli))
### Notes
* In production, middleware logic should be implemented in a contract.
* This guide uses testnet (Holešky) with simplified EOAs for ease of reproduction.
* Vault curators are typically responsible for reward contract deployment and share allocations.
### Next Steps
import { Card1 } from "../../../components/Card1";
## Slashing
[Read Learn first](/learn/core-concepts/slashing)
Slashing is a penalty mechanism enforced by a network to deter operators from breaking their commitments. Such violations may include failing to complete tasks properly or accurately. Slashing typically results in the burning or redistribution of the operator’s staked funds.
### **Slasher Module**
Each Symbiotic Vault has an immutably set Slasher module implementation. In general, 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 an amount of collateral still slashable for the given `captureTimestamp` at the current moment.
:::warning
The provided slashable collateral amount may be inaccurate in practice in case of usage of **restaking** by the vault (hence, multiple network may slash the same amount of collateral).
:::
:::info
During the slashing request execution, the funds are transferred to an immutably set `Vault.burner()`.
:::
#### Slashing Guarantees
Each Symbiotic Vault has an epoch duration (can be obtained via `Vault.epochDuration()`), that determines the withdrawal delay and, also, provides a period during which the slashing guarantees are held.
Hence, the following inequality must hold:
#### Slasher (Type 0)
Slasher performs an instant execution of the slashing request 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
`NetworkMiddlewareService.middleware(network)` should call this function.
:::
#### 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:
:::info
`NetworkMiddlewareService.middleware(network)` should call this function.
:::
##### Days 1 to 5 - Veto Slashing
```solidity [Resolver]
IVetoSlasher(slasher).vetoSlash(slashIndex, hints)
```
:::info
`VetoSlasher.resolver(subnetwork, hint)` should call this function.
:::
##### 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 the Vault has a VetoSlasher type, there is a veto phase, whose duration is set during the vault's deployment, when the resolver can veto the request.
The resolver can be set by Network via `IVetoSlasher(slasher).setResolver(identifier, resolver, hints)`.
:::note
First time when the resolver is set, it is applied immediately. Otherwise, the update is applied after `VetoSlasher.resolverSetEpochsDelay()` epochs.
:::
### Next Steps
}
href="/integrate/networks/relay-onchain"
/>
import { Card1 } from "../../../components/Card1";
## Submit Metadata
[Symbiotic UI](https://app.symbiotic.fi/deposit) provides users with accurate and up-to-date information about various data regarding TVL, allocations, relations between Curators, Vaults, Operators and Networks, etc. However, for the mentioned counterparties to be easily accessible and visible on the UI - their metadata should should be submitted to the corresponding repositories.
Once, the metadata is submitted, it should be reviewed and merged by the Symbiotic team. After that the new data starts to be shown publicly 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) |
| Sepolia | [https://github.com/symbioticfi/metadata-sepolia](https://github.com/symbioticfi/metadata-sepolia) |
| Holešky | [https://github.com/symbioticfi/metadata-holesky](https://github.com/symbioticfi/metadata-holesky) |
#### Repository Structure
The repository is organized as follows:
```
repository/
├── vaults/
│ ├── 0x/
│ │ ├── 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, there must be 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`, please be sure that it's collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, please 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.
Your PR will be reviewed by the Symbiotic team, and if approved, it will be merged into the repository. Please note that the PR will be reviewed only after the entity is checked with automated checks.
***
#### 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 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
The Vault metadata submission guide is available [inside the section for Curators](/integrate/curators/submit-metadata).
### Next Steps
## Mainnet
### Core
Core commit: [3b6add23921d89dc364458b94e1c35bfb6736e27](https://github.com/symbioticfi/core/tree/3b6add23921d89dc364458b94e1c35bfb6736e27)
| Contract | Address | Description |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| VaultFactory | [0xAEb6bdd95c502390db8f52c8909F703E9Af6a346](https://etherscan.io/address/0xAEb6bdd95c502390db8f52c8909F703E9Af6a346) | Pure vaults’ creator (also allows their migrations) |
| DelegatorFactory | [0x985Ed57AF9D475f1d83c1c1c8826A0E5A34E8C7B](https://etherscan.io/address/0x985Ed57AF9D475f1d83c1c1c8826A0E5A34E8C7B) | Pure delegators’ creator |
| SlasherFactory | [0x685c2eD7D59814d2a597409058Ee7a92F21e48Fd](https://etherscan.io/address/0x685c2eD7D59814d2a597409058Ee7a92F21e48Fd) | Pure slashers’ creator |
| NetworkRegistry | [0xC773b1011461e7314CF05f97d95aa8e92C1Fd8aA](https://etherscan.io/address/0xC773b1011461e7314CF05f97d95aa8e92C1Fd8aA) | Networks’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| NetworkMiddlewareService | [0xD7dC9B366c027743D90761F71858BCa83C6899Ad](https://etherscan.io/address/0xD7dC9B366c027743D90761F71858BCa83C6899Ad) | Networks’ middleware addresses setter |
| OperatorRegistry | [0xAd817a6Bc954F678451A71363f04150FDD81Af9F](https://etherscan.io/address/0xAd817a6Bc954F678451A71363f04150FDD81Af9F) | Operators’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| OperatorVaultOptInService | [0xb361894bC06cbBA7Ea8098BF0e32EB1906A5F891](https://etherscan.io/address/0xb361894bC06cbBA7Ea8098BF0e32EB1906A5F891) | A contract for operators’ opt-ins to vaults |
| OperatorNetworkOptInService | [0x7133415b33B438843D581013f98A08704316633c](https://etherscan.io/address/0x7133415b33B438843D581013f98A08704316633c) | A contract for operators’ opt-ins to networks |
| VaultConfigurator | [0x29300b1d3150B4E2b12fE80BE72f365E200441EC](https://etherscan.io/address/0x29300b1d3150B4E2b12fE80BE72f365E200441EC) | Ready-to-work vaults’ creator |
### Rewards
Staker Rewards commit: [b5a1f5b46f33f31938fc0116086b3a75e748c8b1](https://github.com/symbioticfi/rewards/tree/b5a1f5b46f33f31938fc0116086b3a75e748c8b1) Operator Rewards commit: [6cca0f6564bb2a9fbc61a546ddb54b0caf6fa788](https://github.com/symbioticfi/rewards/tree/6cca0f6564bb2a9fbc61a546ddb54b0caf6fa788)
| Contract | Address | Description |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| DefaultStakerRewardsFactory | [0xFEB871581C2ab2e1EEe6f7dDC7e6246cFa087A23](https://etherscan.io/address/0xFEB871581C2ab2e1EEe6f7dDC7e6246cFa087A23) | Default staker rewards contracts’ creator |
| DefaultOperatorRewardsFactory | [0x6D52fC402b2dA2669348Cc2682D85c61c122755D](https://etherscan.io/address/0x6D52fC402b2dA2669348Cc2682D85c61c122755D) | Default operator rewards contracts’ creator |
### Burners
Burners commit: [7e887e75beb17e0c2c4df8396ee58dd6e0dd853e](https://github.com/symbioticfi/burners/tree/7e887e75beb17e0c2c4df8396ee58dd6e0dd853e)
| Contract | Address | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| BurnerRouterFactory | [0x99F2B89fB3C363fBafD8d826E5AA77b28bAB70a0](https://etherscan.io/address/0x99F2B89fB3C363fBafD8d826E5AA77b28bAB70a0) | Creator of routers redirecting slashed funds |
| wstETH\_Burner | [0xdCaC890b14121FD5D925E2589017Be68C2B5B324](https://etherscan.io/address/0xdCaC890b14121FD5D925E2589017Be68C2B5B324) | Pure wstETH burner |
| rETH\_Burner | [0x89e3915C9Eb07D1bfF5d78e24B28d409dba9B272](https://etherscan.io/address/0x89e3915C9Eb07D1bfF5d78e24B28d409dba9B272) | Pure rETH burner |
| mETH\_Burner | [0x919C4329Ed4D4A72c72c126ff8AE351C1E7Ce231](https://etherscan.io/address/0x919C4329Ed4D4A72c72c126ff8AE351C1E7Ce231) | Pure mETH burner |
| swETH\_Burner | [0x1Aca33aE8f57E2cdADd0375875AE12fb08c54529](https://etherscan.io/address/0x1Aca33aE8f57E2cdADd0375875AE12fb08c54529) | Pure swETH burner |
| sfrxETH\_Burner | [0xBe5821dB563311750f6295E3CDB40aBbDBfF0c4b](https://etherscan.io/address/0xBe5821dB563311750f6295E3CDB40aBbDBfF0c4b) | Pure sfrxETH burner |
| ETHx\_Burner | [0xCd669361D629380A70338d613D29c6F3a28A2B50](https://etherscan.io/address/0xCd669361D629380A70338d613D29c6F3a28A2B50) | Pure ETHx burner |
### Hooks
Hooks commit: [71ea3cea348fc4407766181f2183fee137442c63](https://github.com/symbioticfi/hooks/tree/71ea3cea348fc4407766181f2183fee137442c63)
| Contract | Address | Description |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| FullRestakeDecreaseHook | [0x0786ef079A0Fc3A2D9e62bf2E8c7aeF86B62d70A](https://etherscan.io/address/0x0786ef079A0Fc3A2D9e62bf2E8c7aeF86B62d70A) | Common delegations' decreasing hook for FullRestakeDelegator |
| NetworkRestakeDecreaseHook | [0xe46d876BA2F3C991F3AC3321B8C0A1c323ef8bCf](https://etherscan.io/address/0xe46d876BA2F3C991F3AC3321B8C0A1c323ef8bCf) | Delegations' redistribution hook for NetworkRestakeDelegator |
| NetworkRestakeRedistributeHook | [0x8A76a3b791D9cfCD17304D31e04304A54Bf07845](https://etherscan.io/address/0x8A76a3b791D9cfCD17304D31e04304A54Bf07845) | Common delegations' decreasing hook for NetworkRestakeDelegator |
| OperatorSpecificDecreaseHook | [0xCc7Fd9B9A37ba1e2b30243Ce5A52BDB1f56B006a](https://etherscan.io/address/0xCc7Fd9B9A37ba1e2b30243Ce5A52BDB1f56B006a) | Common delegations' decreasing hook for OperatorSpecificDelegator |
### Periphery
Periphery commit: [9cc6d3b6947dddadb66b2a9f8d8981c618be65e8](https://github.com/symbioticfi/periphery/tree/9cc6d3b6947dddadb66b2a9f8d8981c618be65e8)
| Contract | Address | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| DefaultCollateralMigrator | [0x8F152FEAA99eb6656F902E94BD4E7bCf563D4A43](https://etherscan.io/address/0x8F152FEAA99eb6656F902E94BD4E7bCf563D4A43) | Allows migration of funds from legacy vaults to new ones |
### Hints
:::warning
The hints provision contracts weren't audited and should be used only for gas costs **optimisation** purposes.
:::
Hints commit: [9c48ef17b8b973383667517a7db7131e44a811b8](https://github.com/symbioticfi/core/tree/9c48ef17b8b973383667517a7db7131e44a811b8/src/contracts/hints)
| Contract | Address |
| ------------------ | --------------------------------------------------------------------------------------------------------------------- |
| OptInServiceHints | [0xe58ED8D0788BD93d665552409Dc60d43c9E6A29f](https://etherscan.io/address/0xe58ED8D0788BD93d665552409Dc60d43c9E6A29f) |
| VaultHints | [0xeaDDC9F93a7d7B845084a30Da09400f0170fC9BC](https://etherscan.io/address/0xeaDDC9F93a7d7B845084a30Da09400f0170fC9BC) |
| BaseDelegatorHints | [0xa298E96FE9bD30cA6801d35Ba28f6d1C004123c7](https://etherscan.io/address/0xa298E96FE9bD30cA6801d35Ba28f6d1C004123c7) |
| SlasherHints | [0x234148646D8C1762C793FD04385AfAD94998a4C7](https://etherscan.io/address/0x234148646D8C1762C793FD04385AfAD94998a4C7) |
| VetoSlasherHints | [0x653815A6E2Accd3AE3eDC41d48Bec9192D5B8651](https://etherscan.io/address/0x653815A6E2Accd3AE3eDC41d48Bec9192D5B8651) |
### Legacy
#### Vaults
| Contract | Address |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| DefaultCollateralFactory | [0x1BC8FCFbE6Aa17e4A7610F51B888f34583D202Ec](https://etherscan.io/address/0x1BC8FCFbE6Aa17e4A7610F51B888f34583D202Ec) |
| DefaultCollateral: wstETH | [0xC329400492c6ff2438472D4651Ad17389fCb843a](https://etherscan.io/address/0xC329400492c6ff2438472D4651Ad17389fCb843a) |
| DefaultCollateral: cbETH | [0xB26ff591F44b04E78de18f43B46f8b70C6676984](https://etherscan.io/address/0xB26ff591F44b04E78de18f43B46f8b70C6676984) |
| DefaultCollateral: wBETH | [0x422F5acCC812C396600010f224b320a743695f85](https://etherscan.io/address/0x422F5acCC812C396600010f224b320a743695f85) |
| DefaultCollateral: rETH | [0x03Bf48b8A1B37FBeAd1EcAbcF15B98B924ffA5AC](https://etherscan.io/address/0x03Bf48b8A1B37FBeAd1EcAbcF15B98B924ffA5AC) |
| DefaultCollateral: mETH | [0x475D3Eb031d250070B63Fa145F0fCFC5D97c304a](https://etherscan.io/address/0x475D3Eb031d250070B63Fa145F0fCFC5D97c304a) |
| DefaultCollateral: swETH | [0x38B86004842D3FA4596f0b7A0b53DE90745Ab654](https://etherscan.io/address/0x38B86004842D3FA4596f0b7A0b53DE90745Ab654) |
| DefaultCollateral: sfrxETH | [0x5198CB44D7B2E993ebDDa9cAd3b9a0eAa32769D2](https://etherscan.io/address/0x5198CB44D7B2E993ebDDa9cAd3b9a0eAa32769D2) |
| DefaultCollateral: ETHx | [0xBdea8e677F9f7C294A4556005c640Ee505bE6925](https://etherscan.io/address/0xBdea8e677F9f7C294A4556005c640Ee505bE6925) |
| DefaultCollateral: ENA | [0xe39B5f5638a209c1A6b6cDFfE5d37F7Ac99fCC84](https://etherscan.io/address/0xe39B5f5638a209c1A6b6cDFfE5d37F7Ac99fCC84) |
| DefaultCollateral: sUSDe | [0x19d0D8e6294B7a04a2733FE433444704B791939A](https://etherscan.io/address/0x19d0D8e6294B7a04a2733FE433444704B791939A) |
| DefaultCollateral: WBTC | [0x971e5b5D4baa5607863f3748FeBf287C7bf82618](https://etherscan.io/address/0x971e5b5D4baa5607863f3748FeBf287C7bf82618) |
| DefaultCollateral: tBTC | [0x0C969ceC0729487d264716e55F232B404299032c](https://etherscan.io/address/0x0C969ceC0729487d264716e55F232B404299032c) |
| DefaultCollateral: LsETH | [0xB09A50AcFFF7D12B7d18adeF3D1027bC149Bad1c](https://etherscan.io/address/0xB09A50AcFFF7D12B7d18adeF3D1027bC149Bad1c) |
| DefaultCollateral: osETH | [0x52cB8A621610Cc3cCf498A1981A8ae7AD6B8AB2a](https://etherscan.io/address/0x52cB8A621610Cc3cCf498A1981A8ae7AD6B8AB2a) |
| DefaultCollateral: ETHFI | [0x21DbBA985eEA6ba7F27534a72CCB292eBA1D2c7c](https://etherscan.io/address/0x21DbBA985eEA6ba7F27534a72CCB292eBA1D2c7c) |
| DefaultCollateral: FXS | [0x940750A267c64f3BBcE31B948b67CD168f0843fA](https://etherscan.io/address/0x940750A267c64f3BBcE31B948b67CD168f0843fA) |
| DefaultCollateral: LBTC | [0x9C0823D3A1172F9DdF672d438dec79c39a64f448](https://etherscan.io/address/0x9C0823D3A1172F9DdF672d438dec79c39a64f448) |
| DefaultCollateral: SWELL | [0x544f45485418341C1a2B3a44404F12302277fFFC](https://etherscan.io/address/0x544f45485418341C1a2B3a44404F12302277fFFC) |
| DefaultCollateral: MANTA | [0x594380c06552A4136E2601F89E50b3b9Ad17bd4d](https://etherscan.io/address/0x594380c06552A4136E2601F89E50b3b9Ad17bd4d) |
#### Rewards
Staker Rewards commit: [6cca0f6564bb2a9fbc61a546ddb54b0caf6fa788](https://github.com/symbioticfi/rewards/tree/6cca0f6564bb2a9fbc61a546ddb54b0caf6fa788)
| Contract | Address | Description |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| DefaultStakerRewardsFactory | [0x290CAB97a312164Ccf095d75D6175dF1C4A0a25F](https://etherscan.io/address/0x290CAB97a312164Ccf095d75D6175dF1C4A0a25F) | Default staker rewards contracts’ creator |
## Testnet
### Hoodi
#### Core
Core commit: [3b6add23921d89dc364458b94e1c35bfb6736e27](https://github.com/symbioticfi/core/tree/3b6add23921d89dc364458b94e1c35bfb6736e27)
| Contract | Address | Description |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| VaultFactory | [0x407A039D94948484D356eFB765b3c74382A050B4](https://hoodi.etherscan.io/address/0x407A039D94948484D356eFB765b3c74382A050B4) | Pure vaults’ creator (also allows their migrations) |
| DelegatorFactory | [0x890CA3f95E0f40a79885B7400926544B2214B03f](https://hoodi.etherscan.io/address/0x890CA3f95E0f40a79885B7400926544B2214B03f) | Pure delegators’ creator |
| SlasherFactory | [0xbf34bf75bb779c383267736c53a4ae86ac7bB299](https://hoodi.etherscan.io/address/0xbf34bf75bb779c383267736c53a4ae86ac7bB299) | Pure slashers’ creator |
| NetworkRegistry | [0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9](https://hoodi.etherscan.io/address/0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9) | Networks’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| NetworkMiddlewareService | [0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3](https://hoodi.etherscan.io/address/0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3) | Networks’ middleware addresses setter |
| OperatorRegistry | [0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548](https://hoodi.etherscan.io/address/0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548) | Operators’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| OperatorVaultOptInService | [0x95CC0a052ae33941877c9619835A233D21D57351](https://hoodi.etherscan.io/address/0x95CC0a052ae33941877c9619835A233D21D57351) | A contract for operators’ opt-ins to vaults |
| OperatorNetworkOptInService | [0x58973d16FFA900D11fC22e5e2B6840d9f7e13401](https://hoodi.etherscan.io/address/0x58973d16FFA900D11fC22e5e2B6840d9f7e13401) | A contract for operators’ opt-ins to networks |
| VaultConfigurator | [0x94c344E816A53D07fC4c7F4a18f82b6Da87CFc8f](https://hoodi.etherscan.io/address/0x94c344E816A53D07fC4c7F4a18f82b6Da87CFc8f) | Ready-to-work vaults’ creator |
#### Rewards
Rewards commit: [b5a1f5b46f33f31938fc0116086b3a75e748c8b1](https://github.com/symbioticfi/rewards/tree/b5a1f5b46f33f31938fc0116086b3a75e748c8b1)
| Contract | Address | Description |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| DefaultStakerRewardsFactory | [0x1eA0b919721C20dae19aBc4391850D94eDbe9b1c](https://hoodi.etherscan.io/address/0x1eA0b919721C20dae19aBc4391850D94eDbe9b1c) | Default staker rewards contracts’ creator |
| DefaultOperatorRewardsFactory | [0xE7e597655C3F76117302ea6103f5F2B3F3D75c5d](https://hoodi.etherscan.io/address/0xE7e597655C3F76117302ea6103f5F2B3F3D75c5d) | Default operator rewards contracts’ creator |
#### Burners
Burners commit: [7e887e75beb17e0c2c4df8396ee58dd6e0dd853e](https://github.com/symbioticfi/burners/tree/7e887e75beb17e0c2c4df8396ee58dd6e0dd853e)
| Contract | Address | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| BurnerRouterFactory | [0xF619c99D166224B4AC008b14Cc67ac72C2E91D8a](https://hoodi.etherscan.io/address/0xF619c99D166224B4AC008b14Cc67ac72C2E91D8a) | Creator of routers redirecting slashed funds |
| wstETH\_Burner | [0xd80732420fF1C62A21bA11c83377F7a5d69AEF26](https://hoodi.etherscan.io/address/0xd80732420fF1C62A21bA11c83377F7a5d69AEF26) | Pure wstETH burner |
| rETH\_Burner | [0xC1F81485E05cc91EC1eBF556455de54F58675278](https://hoodi.etherscan.io/address/0xC1F81485E05cc91EC1eBF556455de54F58675278) | Pure rETH burner |
#### Hooks
Hooks commit: [71ea3cea348fc4407766181f2183fee137442c63](https://github.com/symbioticfi/hooks/tree/71ea3cea348fc4407766181f2183fee137442c63)
| Contract | Address | Description |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| FullRestakeDecreaseHook | [0x3224d9DF887ABdC10c1bCcECfd9EFC29A638a3E3](https://hoodi.etherscan.io/address/0x3224d9DF887ABdC10c1bCcECfd9EFC29A638a3E3) | Common delegations' decreasing hook for FullRestakeDelegator |
| NetworkRestakeDecreaseHook | [0x2C78B3A5de76161aee8e37d0E3b0E0EBb12BacCc](https://hoodi.etherscan.io/address/0x2C78B3A5de76161aee8e37d0E3b0E0EBb12BacCc) | Delegations' redistribution hook for NetworkRestakeDelegator |
| NetworkRestakeRedistributeHook | [0x45B188aBE45820aE130A2844649Faeb225096596](https://hoodi.etherscan.io/address/0x45B188aBE45820aE130A2844649Faeb225096596) | Common delegations' decreasing hook for NetworkRestakeDelegator |
| OperatorSpecificDecreaseHook | [0xF8ee812cc1E7C8eE94395E510098b36ff458E77d](https://hoodi.etherscan.io/address/0xF8ee812cc1E7C8eE94395E510098b36ff458E77d) | Common delegations' decreasing hook for OperatorSpecificDelegator |
#### Hints
:::warning
The hints provision contracts weren't audited and should be used only for gas costs **optimisation** purposes.
:::
Hints commit: [9c48ef17b8b973383667517a7db7131e44a811b8](https://github.com/symbioticfi/core/tree/9c48ef17b8b973383667517a7db7131e44a811b8/src/contracts/hints)
| Contract | Address |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| OptInServiceHints | [0x5a573b5Ecb9a1B988b0488B1B5A4B4B200536E39](https://hoodi.etherscan.io/address/0x5a573b5Ecb9a1B988b0488B1B5A4B4B200536E39) |
| VaultHints | [0x43C29B90e651860EB2963D54a40C371C75630c39](https://hoodi.etherscan.io/address/0x43C29B90e651860EB2963D54a40C371C75630c39) |
| BaseDelegatorHints | [0x88c5519016FC6F5F8dC53eb299fce691b8174C34](https://hoodi.etherscan.io/address/0x88c5519016FC6F5F8dC53eb299fce691b8174C34) |
| SlasherHints | [0x9C3F0Beb3A1Dfae975cE42571b7EE57dd3179351](https://hoodi.etherscan.io/address/0x9C3F0Beb3A1Dfae975cE42571b7EE57dd3179351) |
| VetoSlasherHints | [0x2012926262F5104DD2DADA544cB0DeE438a734F1](https://hoodi.etherscan.io/address/0x2012926262F5104DD2DADA544cB0DeE438a734F1) |
***
### Sepolia
#### Core
Core commit: [f38f1b16b8207dcff55d681a0d5ba28c66e785c8](https://github.com/symbioticfi/core/tree/f38f1b16b8207dcff55d681a0d5ba28c66e785c8)
| Contract | Address | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| VaultFactory | [0x407A039D94948484D356eFB765b3c74382A050B4](https://sepolia.etherscan.io/address/0x407A039D94948484D356eFB765b3c74382A050B4) | Pure vaults’ creator (also allows their migrations) |
| DelegatorFactory | [0x890CA3f95E0f40a79885B7400926544B2214B03f](https://sepolia.etherscan.io/address/0x890CA3f95E0f40a79885B7400926544B2214B03f) | Pure delegators’ creator |
| SlasherFactory | [0xbf34bf75bb779c383267736c53a4ae86ac7bB299](https://sepolia.etherscan.io/address/0xbf34bf75bb779c383267736c53a4ae86ac7bB299) | Pure slashers’ creator |
| NetworkRegistry | [0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9](https://sepolia.etherscan.io/address/0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9) | Networks’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| NetworkMiddlewareService | [0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3](https://sepolia.etherscan.io/address/0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3) | Networks’ middleware addresses setter |
| OperatorRegistry | [0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548](https://sepolia.etherscan.io/address/0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548) | Operators’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| OperatorVaultOptInService | [0x95CC0a052ae33941877c9619835A233D21D57351](https://sepolia.etherscan.io/address/0x95CC0a052ae33941877c9619835A233D21D57351) | A contract for operators’ opt-ins to vaults |
| OperatorNetworkOptInService | [0x58973d16FFA900D11fC22e5e2B6840d9f7e13401](https://sepolia.etherscan.io/address/0x58973d16FFA900D11fC22e5e2B6840d9f7e13401) | A contract for operators’ opt-ins to networks |
| VaultConfigurator | [0xD2191FE92987171691d552C219b8caEf186eb9cA](https://sepolia.etherscan.io/address/0xD2191FE92987171691d552C219b8caEf186eb9cA) | Ready-to-work vaults’ creator |
#### Rewards
Staker Rewards commit: [f4537d9207a05fdb3fee32f8c102506d5f2484c6](https://github.com/symbioticfi/rewards/tree/f4537d9207a05fdb3fee32f8c102506d5f2484c6) Operator Rewards commit: [7844a6ceaf4d740c7083a37e410194c1ef7867d3](https://github.com/symbioticfi/rewards/tree/7844a6ceaf4d740c7083a37e410194c1ef7867d3)
| Contract | Address | Description |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| DefaultStakerRewardsFactory | [0xE6381EDA7444672da17Cd859e442aFFcE7e170F0](https://sepolia.etherscan.io/address/0xE6381EDA7444672da17Cd859e442aFFcE7e170F0) | Default staker rewards contracts’ creator |
| DefaultOperatorRewardsFactory | [0x8D6C873cb7ffa6BE615cE1D55801a9417Ed55f9B](https://sepolia.etherscan.io/address/0x8D6C873cb7ffa6BE615cE1D55801a9417Ed55f9B) | Default operator rewards contracts’ creator |
#### Vaults
Core commit: [f38f1b16b8207dcff55d681a0d5ba28c66e785c8](https://github.com/symbioticfi/core/tree/f38f1b16b8207dcff55d681a0d5ba28c66e785c8)
##### Vault 1
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Vault | [0x77F170Dcd0439c0057055a6D7e5A1Eb9c48cCD2a](https://sepolia.etherscan.io/address/0x77F170Dcd0439c0057055a6D7e5A1Eb9c48cCD2a) | Collateral: [wstETH](https://sepolia.etherscan.io/address/0xB82381A3fBD3FaFA77B3a7bE693342618240067b) Curator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 Epoch Duration: 7 days |
| Delegator | [0xB4Dcf89f891E1F825B59880B470e2e6B6B1c2cE9](https://sepolia.etherscan.io/address/0xB4Dcf89f891E1F825B59880B470e2e6B6B1c2cE9) | NetworkRestakeDelegator (allows restaking only across networks) |
| Slasher | [0x942864Ed10bC8371CfA49aDeF341e2b9EFD1CacA](https://sepolia.etherscan.io/address/0x942864Ed10bC8371CfA49aDeF341e2b9EFD1CacA) | Slasher (performs instant slashings) |
##### Vault 2
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Vault | [0x1BAe55e4774372F6181DaAaB4Ca197A8D9CC06Dd](https://sepolia.etherscan.io/address/0x1BAe55e4774372F6181DaAaB4Ca197A8D9CC06Dd) | Collateral: [wstETH](https://sepolia.etherscan.io/address/0xB82381A3fBD3FaFA77B3a7bE693342618240067b) Curator: 0x7358828e46001F447177E8c642270c178493E496 Epoch Duration: 7 days |
| Delegator | [0xA4951c647F19De74967Ef8e4be49Bfa91811B84e](https://sepolia.etherscan.io/address/0xA4951c647F19De74967Ef8e4be49Bfa91811B84e) | FullRestakeDelegator (allows restaking across networks and across operators within a single network) |
| Slasher | [0x9010f89A817294B6E318ca21CA64a6726ea42418](https://sepolia.etherscan.io/address/0x9010f89A817294B6E318ca21CA64a6726ea42418) | VetoSlasher (allows vetoing slashings) Veto Duration: 1 day |
##### Vault 3
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Vault | [0x6415D3B5fc615D4a00C71f4044dEc24C141EBFf8](https://sepolia.etherscan.io/address/0x6415D3B5fc615D4a00C71f4044dEc24C141EBFf8) | Collateral: [wstETH](https://sepolia.etherscan.io/address/0xB82381A3fBD3FaFA77B3a7bE693342618240067b) Curator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 Epoch Duration: 7 days |
| Delegator | [0x74F35B89c040A37e307c84E36b37fd5EE598FD51](https://sepolia.etherscan.io/address/0x74F35B89c040A37e307c84E36b37fd5EE598FD51) | OperatorSpecificDelegator (allows an individual operator to enable restaking across networks) Operator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 |
| Slasher | [0xE04230d92982fF18b17CBBADD6eb18fd2aB96A0f](https://sepolia.etherscan.io/address/0xE04230d92982fF18b17CBBADD6eb18fd2aB96A0f) | VetoSlasher (allows vetoing slashings) Veto Duration: 1 day |
#### Burners
Burners commit: [60a5eb87f196b62d48406b45cc3b19ef4be0e906](https://github.com/symbioticfi/burners/tree/60a5eb87f196b62d48406b45cc3b19ef4be0e906)
| Contract | Address | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| BurnerRouterFactory | [0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b](https://sepolia.etherscan.io/address/0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b) | Router redirecting slashed funds |
| wstETH\_Burner | [0x58D347334A5E6bDE7279696abE59a11873294FA4](https://sepolia.etherscan.io/address/0x58D347334A5E6bDE7279696abE59a11873294FA4) | Pure wstETH burner |
| mETH\_Burner | [0xE7845Dd89F8b93924A279e58E448c5a8e7aCE675](https://sepolia.etherscan.io/address/0xE7845Dd89F8b93924A279e58E448c5a8e7aCE675) | Pure mETH burner |
#### Hooks
Hooks commit: [71ea3cea348fc4407766181f2183fee137442c63](https://github.com/symbioticfi/hooks/tree/71ea3cea348fc4407766181f2183fee137442c63)
| Contract | Address | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| FullRestakeDecreaseHook | [0x088c40869954806Cd1580eda3C2d866104d0b118](https://sepolia.etherscan.io/address/0x088c40869954806Cd1580eda3C2d866104d0b118) | Common delegations' decreasing hook for FullRestakeDelegator |
| NetworkRestakeDecreaseHook | [0x4EeA7269BC42feA87B4E92F4E4f7bCAF3dC81875](https://sepolia.etherscan.io/address/0x4EeA7269BC42feA87B4E92F4E4f7bCAF3dC81875) | Delegations' redistribution hook for NetworkRestakeDelegator |
| NetworkRestakeRedistributeHook | [0x5425D1604a4e01C34996cb662d831E0dEF66C210](https://sepolia.etherscan.io/address/0x5425D1604a4e01C34996cb662d831E0dEF66C210) | Common delegations' decreasing hook for NetworkRestakeDelegator |
| OperatorSpecificDecreaseHook | [0xeae1fCEe58Bd5c3EE9185b34E9f4481faB8FA939](https://sepolia.etherscan.io/address/0xeae1fCEe58Bd5c3EE9185b34E9f4481faB8FA939) | Common delegations' decreasing hook for OperatorSpecificDelegator |
#### Periphery
Periphery commit: [30ba028f683cfaa83c4a1338a44064702c531387](https://github.com/symbioticfi/periphery/tree/30ba028f683cfaa83c4a1338a44064702c531387)
| Contract | Address | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| DefaultCollateralMigrator | [0xD6BE794b3761fd2bA23fB054F1Fe1606Ae35de4e](https://sepolia.etherscan.io/address/0xD6BE794b3761fd2bA23fB054F1Fe1606Ae35de4e) | Allows migration of funds from legacy vaults to new ones |
#### Hints
:::warning
The hints provision contracts weren't audited and should be used only for gas costs **optimisation** purposes.
:::
Hints commit: [9c48ef17b8b973383667517a7db7131e44a811b8](https://github.com/symbioticfi/core/tree/9c48ef17b8b973383667517a7db7131e44a811b8/src/contracts/hints)
| Contract | Address |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| OptInServiceHints | [0x22C505eFf313CDd959e9D2240b6238F25ad8831b](https://sepolia.etherscan.io/address/0x22C505eFf313CDd959e9D2240b6238F25ad8831b) |
| VaultHints | [0x6e86527667e576FCf3425617C92E4c913375Ce97](https://sepolia.etherscan.io/address/0x6e86527667e576FCf3425617C92E4c913375Ce97) |
| BaseDelegatorHints | [0xA9500049fCfbE767Dcc5E7A4a6bb6e2E0c523e2A](https://sepolia.etherscan.io/address/0xA9500049fCfbE767Dcc5E7A4a6bb6e2E0c523e2A) |
| SlasherHints | [0xfd530c42e3e5507bB6fA81881817121e6256A32A](https://sepolia.etherscan.io/address/0xfd530c42e3e5507bB6fA81881817121e6256A32A) |
| VetoSlasherHints | [0xAb888A61684C20B96aDCD3F36B458574eb69f6a2](https://sepolia.etherscan.io/address/0xAb888A61684C20B96aDCD3F36B458574eb69f6a2) |
#### Legacy
##### Rewards
Staker Rewards commit: [7844a6ceaf4d740c7083a37e410194c1ef7867d3](https://github.com/symbioticfi/rewards/tree/7844a6ceaf4d740c7083a37e410194c1ef7867d3)
| Contract | Address | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| DefaultStakerRewardsFactory | [0x70C618a13D1A57f7234c0b893b9e28C5cA8E7f37](https://sepolia.etherscan.io/address/0x70C618a13D1A57f7234c0b893b9e28C5cA8E7f37) | Default staker rewards contracts’ creator |
***
### Holešky
#### Core
Core commit: [f38f1b16b8207dcff55d681a0d5ba28c66e785c8](https://github.com/symbioticfi/core/tree/f38f1b16b8207dcff55d681a0d5ba28c66e785c8)
| Contract | Address | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| VaultFactory | [0x407A039D94948484D356eFB765b3c74382A050B4](https://holesky.etherscan.io/address/0x407A039D94948484D356eFB765b3c74382A050B4) | Pure vaults’ creator (also allows their migrations) |
| DelegatorFactory | [0x890CA3f95E0f40a79885B7400926544B2214B03f](https://holesky.etherscan.io/address/0x890CA3f95E0f40a79885B7400926544B2214B03f) | Pure delegators’ creator |
| SlasherFactory | [0xbf34bf75bb779c383267736c53a4ae86ac7bB299](https://holesky.etherscan.io/address/0xbf34bf75bb779c383267736c53a4ae86ac7bB299) | Pure slashers’ creator |
| NetworkRegistry | [0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9](https://holesky.etherscan.io/address/0x7d03b7343BF8d5cEC7C0C27ecE084a20113D15C9) | Networks’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| NetworkMiddlewareService | [0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3](https://holesky.etherscan.io/address/0x62a1ddfD86b4c1636759d9286D3A0EC722D086e3) | Networks’ middleware addresses setter |
| OperatorRegistry | [0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548](https://holesky.etherscan.io/address/0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548) | Operators’ managing addresses (e.g., DAO contract, multisig, etc.) registrator |
| OperatorVaultOptInService | [0x95CC0a052ae33941877c9619835A233D21D57351](https://holesky.etherscan.io/address/0x95CC0a052ae33941877c9619835A233D21D57351) | A contract for operators’ opt-ins to vaults |
| OperatorNetworkOptInService | [0x58973d16FFA900D11fC22e5e2B6840d9f7e13401](https://holesky.etherscan.io/address/0x58973d16FFA900D11fC22e5e2B6840d9f7e13401) | A contract for operators’ opt-ins to networks |
| VaultConfigurator | [0xD2191FE92987171691d552C219b8caEf186eb9cA](https://holesky.etherscan.io/address/0xD2191FE92987171691d552C219b8caEf186eb9cA) | Ready-to-work vaults’ creator |
#### Rewards
Staker Rewards commit: [f4537d9207a05fdb3fee32f8c102506d5f2484c6](https://github.com/symbioticfi/rewards/tree/f4537d9207a05fdb3fee32f8c102506d5f2484c6) Operator Rewards commit: [7844a6ceaf4d740c7083a37e410194c1ef7867d3](https://github.com/symbioticfi/rewards/tree/7844a6ceaf4d740c7083a37e410194c1ef7867d3)
| Contract | Address | Description |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| DefaultStakerRewardsFactory | [0x58E80fA5Eb938525f2ca80C5bdE724D7a99A7892](https://holesky.etherscan.io/address/0x58E80fA5Eb938525f2ca80C5bdE724D7a99A7892) | Default staker rewards contracts’ creator |
| DefaultOperatorRewardsFactory | [0x00055dee9933F578340db42AA978b9c8B25640f6](https://holesky.etherscan.io/address/0x00055dee9933F578340db42AA978b9c8B25640f6) | Default operator rewards contracts’ creator |
#### Vaults
Core commit: [f38f1b16b8207dcff55d681a0d5ba28c66e785c8](https://github.com/symbioticfi/core/tree/f38f1b16b8207dcff55d681a0d5ba28c66e785c8)
##### Vault 1
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Vault | [0xd88dDf98fE4d161a66FB836bee4Ca469eb0E4a75](https://holesky.etherscan.io/address/0xd88dDf98fE4d161a66FB836bee4Ca469eb0E4a75) | Collateral: [wstETH](https://holesky.etherscan.io/address/0x8d09a4502Cc8Cf1547aD300E066060D043f6982D) Curator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 Epoch Duration: 7 days |
| Delegator | [0x85CF967A8DDFAf8C0DFB9c75d9E92a3C785A6532](https://holesky.etherscan.io/address/0x85CF967A8DDFAf8C0DFB9c75d9E92a3C785A6532) | NetworkRestakeDelegator (allows restaking only across networks) |
| Slasher | [0x57e5Fb61981fa1b43a074B2aeb47CCF157b19223](https://holesky.etherscan.io/address/0x57e5Fb61981fa1b43a074B2aeb47CCF157b19223) | Slasher (performs instant slashings) |
##### Vault 2
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Vault | [0xB118075733F3FF87184E96fb76dfa170326b47a5](https://holesky.etherscan.io/address/0xB118075733F3FF87184E96fb76dfa170326b47a5) | Collateral: [rETH](https://holesky.etherscan.io/address/0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1) Curator: 0x7358828e46001F447177E8c642270c178493E496 Epoch Duration: 7 days |
| Delegator | [0xC54610932b21Fb9897c623fBB336Ce7AdEC8F757](https://holesky.etherscan.io/address/0xC54610932b21Fb9897c623fBB336Ce7AdEC8F757) | FullRestakeDelegator (allows restaking across networks and across operators within a single network) |
| Slasher | [0x853f90DFBCA2FCCD8C84f3bDc489Eb36b93841Ba](https://holesky.etherscan.io/address/0x853f90DFBCA2FCCD8C84f3bDc489Eb36b93841Ba) | VetoSlasher (allows vetoing slashings) Veto Duration: 1 day |
##### Vault 3
| Contract | Address | Parameters |
| --------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Vault | [0xa4c81649c79f8378a4409178E758B839F1d57a54](https://holesky.etherscan.io/address/0xa4c81649c79f8378a4409178E758B839F1d57a54) | Collateral: [wstETH](https://holesky.etherscan.io/address/0x8d09a4502Cc8Cf1547aD300E066060D043f6982D) Curator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 Epoch Duration: 7 days |
| Delegator | [0xADc06FD4F589Eb7E81356a2A3E7Cf68cb9917cBA](https://holesky.etherscan.io/address/0xADc06FD4F589Eb7E81356a2A3E7Cf68cb9917cBA) | OperatorSpecificDelegator (allows an individual operator to enable restaking across networks) Operator: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 |
| Slasher | [0x64e81432517Df4DC63337b2874F358cdF3417697](https://holesky.etherscan.io/address/0x64e81432517Df4DC63337b2874F358cdF3417697) | VetoSlasher (allows vetoing slashings) Veto Duration: 1 day |
#### Burners
Burners commit: [60a5eb87f196b62d48406b45cc3b19ef4be0e906](https://github.com/symbioticfi/burners/tree/60a5eb87f196b62d48406b45cc3b19ef4be0e906)
| Contract | Address | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| BurnerRouterFactory | [0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b](https://holesky.etherscan.io/address/0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b) | Router redirecting slashed funds |
| wstETH\_Burner | [0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd](https://holesky.etherscan.io/address/0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd) | Pure wstETH burner |
| rETH\_Burner: | [0x1d39cB4382DFF536DC2Be4EEf9D99d5f9Cd76697](https://holesky.etherscan.io/address/0x1d39cB4382DFF536DC2Be4EEf9D99d5f9Cd76697) | Pure rETH burner |
| mETH\_Burner | [0x58D347334A5E6bDE7279696abE59a11873294FA4](https://holesky.etherscan.io/address/0x58D347334A5E6bDE7279696abE59a11873294FA4) | Pure mETH burner |
| ETHx\_Burner | [0xE7845Dd89F8b93924A279e58E448c5a8e7aCE675](https://holesky.etherscan.io/address/0xE7845Dd89F8b93924A279e58E448c5a8e7aCE675) | Pure ETHx burner |
#### Hooks
Hooks commit: [71ea3cea348fc4407766181f2183fee137442c63](https://github.com/symbioticfi/hooks/tree/71ea3cea348fc4407766181f2183fee137442c63)
| Contract | Address | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| FullRestakeDecreaseHook | [0x6Eb2768c9C47f4C05972A3311390830cB49f77A1](https://holesky.etherscan.io/address/0x6Eb2768c9C47f4C05972A3311390830cB49f77A1) | Common delegations' decreasing hook for FullRestakeDelegator |
| NetworkRestakeDecreaseHook | [0xe66fEC3e43ea682cF09A8E12433d90FfBDBF8E74](https://holesky.etherscan.io/address/0xe66fEC3e43ea682cF09A8E12433d90FfBDBF8E74) | Delegations' redistribution hook for NetworkRestakeDelegator |
| NetworkRestakeRedistributeHook | [0x30C46a40ed3DE2Fc997Ce58fB69FCE1f86a9205B](https://holesky.etherscan.io/address/0x30C46a40ed3DE2Fc997Ce58fB69FCE1f86a9205B) | Common delegations' decreasing hook for NetworkRestakeDelegator |
| OperatorSpecificDecreaseHook | [0xCD72e26CccD001167BC7859D9daE459C7CFE6E31](https://holesky.etherscan.io/address/0xCD72e26CccD001167BC7859D9daE459C7CFE6E31) | Common delegations' decreasing hook for OperatorSpecificDelegator |
#### Periphery
Periphery commit: [30ba028f683cfaa83c4a1338a44064702c531387](https://github.com/symbioticfi/periphery/tree/30ba028f683cfaa83c4a1338a44064702c531387)
| Contract | Address | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| DefaultCollateralMigrator | [0x1779C2277A61506b5BaB03Ab24782B8f5Bb6B287](https://holesky.etherscan.io/address/0x1779C2277A61506b5BaB03Ab24782B8f5Bb6B287) | Allows migration of funds from legacy vaults to new ones |
#### Hints
:::warning
The hints provision contracts weren't audited and should be used only for gas costs **optimisation** purposes.
:::
Hints commit: [9c48ef17b8b973383667517a7db7131e44a811b8](https://github.com/symbioticfi/core/tree/9c48ef17b8b973383667517a7db7131e44a811b8/src/contracts/hints)
| Contract | Address |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| OptInServiceHints | [0xcb0Cb061eB14bB71b268fceDeb8dF5Ed53013B4c](https://holesky.etherscan.io/address/0xcb0Cb061eB14bB71b268fceDeb8dF5Ed53013B4c) |
| VaultHints | [0x3Ce28E083f5540f1b03B688CcB7Ab7EC37dE185b](https://holesky.etherscan.io/address/0x3Ce28E083f5540f1b03B688CcB7Ab7EC37dE185b) |
| BaseDelegatorHints | [0x889D97181ef426FA85A3578CCE28Dc027E454EB4](https://holesky.etherscan.io/address/0x889D97181ef426FA85A3578CCE28Dc027E454EB4) |
| SlasherHints | [0x36d4A8423C374e7d2E8aF24A7DD3f499ce5ca89e](https://holesky.etherscan.io/address/0x36d4A8423C374e7d2E8aF24A7DD3f499ce5ca89e) |
| VetoSlasherHints | [0xAdfE972b1BBed018C0DD1a553b011Fb3CDB257C3](https://holesky.etherscan.io/address/0xAdfE972b1BBed018C0DD1a553b011Fb3CDB257C3) |
#### Legacy
##### Vaults
| Contract | Address |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| DefaultCollateralFactory | [0x7224eeF9f38E9240beA197970367E0A8CBDFDD8B](https://holesky.etherscan.io/address/0x7224eeF9f38E9240beA197970367E0A8CBDFDD8B) |
##### Rewards
Staker Rewards commit: [7844a6ceaf4d740c7083a37e410194c1ef7867d3](https://github.com/symbioticfi/rewards/tree/7844a6ceaf4d740c7083a37e410194c1ef7867d3)
| Contract | Address | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| DefaultStakerRewardsFactory | [0x698C36DE44D73AEfa3F0Ce3c0255A8667bdE7cFD](https://holesky.etherscan.io/address/0x698C36DE44D73AEfa3F0Ce3c0255A8667bdE7cFD) | Default staker rewards contracts’ creator |
import { Details } from "../../../components/Details";
import { Tabs, TabItem } from "../../../components/Tabs";
## Deploy Vault
Symbiotic is a highly modular protocol that already has a lot of separate parts and will have much more in the future. Therefore, this guide describes possible configurations of the Vault deployments.
### General-purpose deployment
The first step for the ready-to-go Vault deployment is to determine how it is going to be used:
1. As a very specific configuration inside some complex system of contracts that needs to be designed and created
2. As a very pure configuration with most of the parameters non-updatable that can be hardly manageable in practice
3. **As some common configuration that may cover most of the use cases**
For our needs, we choose the 3-rd option, and the steps to get a production-ready configuration are the following:
1. Deploy a **Burner Router** which is a specific implementation of the Burner module
2. Deploy **core modules such as Vault, Delegator, Slasher** using the deployed Burner Router address
3. Deploy **staker rewards** with the use of the Vault’s address got during the previous step
#### 1. Burner Router
Burner is a contract that receives slashed collateral tokens. Symbiotic does not specify the whole processing of the funds flow after the slashing. For example, there are some possible ways:
* Fully burn the funds (unwrap the underlying assets if needed)
* Redistribute to good operators
* Compensate the victims (in case of using the stake as a security deposit)
From our side, we provide:
* **DefaultBurners** - pure burner contracts for several ETH LSTs
* **BurnerRouter** - a router contract that allows redirection of the slashed funds to different addresses depending on the slashing networks and the slashed operators
Our pure burners have one advantage and disadvantage simultaneously - they are fully immutable, removing any trust assumptions in that direction. However, in case of the underlying LST’s upgrade of the contracts, their flow may break. Therefore, in general, we suggest using **BurnerRouter**, which contains the receivers’ update functionality, in pair with a **DefaultBurner** as a global receiver.

1. Clone the burners repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/burners.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd burners
```
3. Deploy a burner router contract using [a simple script](https://github.com/symbioticfi/burners/blob/main/script/deploy/BurnerRouter.s.sol):
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0xdCaC890b14121FD5D925E2589017Be68C2B5B324 # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0x8d09a4502Cc8Cf1547aD300E066060D043f6982D # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-hoodi.gateway.tatum.io \
--chain hoodi \
--broadcast
```
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0xB82381A3fBD3FaFA77B3a7bE693342618240067b # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0x58D347334A5E6bDE7279696abE59a11873294FA4 # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the burners repository by running the following command:
```bash [bash]
forge install symbioticfi/burners
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/burners/=lib/burners/
```
3. Create a burner router contract using [a BurnerRouterFactory contract](https://github.com/symbioticfi/burners/blob/main/src/contracts/router/BurnerRouterFactory.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0x99F2B89fB3C363fBafD8d826E5AA77b28bAB70a0; // address of the BurnerRouterFactory (see Deployments page)
// ...
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0xdCaC890b14121FD5D925E2589017Be68C2B5B324, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: new IBurnerRouter.NetworkReceiver[](0), // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0xF619c99D166224B4AC008b14Cc67ac72C2E91D8a; // address of the BurnerRouterFactory (see Deployments page)
// ...
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: new IBurnerRouter.NetworkReceiver[](0), // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b; // address of the BurnerRouterFactory (see Deployments page)
// ...
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0xB82381A3fBD3FaFA77B3a7bE693342618240067b, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0x58D347334A5E6bDE7279696abE59a11873294FA4, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: new IBurnerRouter.NetworkReceiver[](0), // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
#### 2. Core modules
##### Vault
Vault is a contract that:
* storages the collateral
* performs accounting in the sense of deposits and withdrawals
* processes slashing events by transferring the collateral to the burner
* allows deposit whitelisting and deposit limiting
For now, there are two types of Vaults we provide:
1. **Vault (version 1)** - is a standard version of the Vault that is responsible for all of the functions mentioned above
2. **Tokenized Vault (version 2)** - is an extended version of the Vault that represents stake shares as ERC-20 tokens
In general, we don’t need the tokenization of the stake as LRTs provide it. Therefore, we will use the common **Vault**.

:::info
It is also possible to deploy a Vault using our [form](https://app.symbiotic.fi/create).
:::
##### Delegator
Delegator is a contract that allows Vault curator to allocate the stake to networks and operators.
At the current moment, we have four types of it:
1. **NetworkRestakeDelegator (type 0)** - it accounts for allocations in absolute numbers for networks and in shares for operator-network pairs, so it allows having a staking and a common restaking across the networks (depending on the delegated amounts)
2. **FullRestakeDelegator (type 1)** - it accounts for allocations in absolute numbers for both: networks and operator-network pairs, so it allows everything that NetworkRestakeDelegator allows and restaking across the operators inside the networks as an addition
3. **OperatorSpecificDelegator (type 2)** - it is a simplified version of NetworkRestakeDelegator where only one specific operator has allocations
4. **OperatorNetworkSpecificDelegator (type 3)** - it is the most simple version where only one specific operator at one specific network has an allocation
FullRestakeDelegator is able to cover all the delegation use cases. However, it is also able to create highly risky configurations that need proper handling. OperatorSpecificDelegator limits the possible use cases for LRTs with a non-single number of operators, and OperatorNetworkSpecificDelegator has more limitations than the previous one by design. Hence, let’s choose **NetworkRestakeDelegator** for our needs.
:::info
Multi-operator Single-Network Vault can be achieved by having Network-Restake delegator with disabled NetworkLimitSet role
:::

##### Slasher
Slasher is a contract that is responsible for the proper penalty execution, preserving networks’ rights to be able to slash the captured stake and preserving stakers’ rights not to be slashed more than deserved.
There are two types of Slasher:
1. **Slasher (type 0)** - is a common Slasher that receives slashing requests and instantly executes them
2. **VetoSlasher (type 1)** - it allows to veto received slashing requests using resolvers
For the VetoSlasher, networks may propose resolvers that can veto the slashing requests. **It is also possible for the networks not to set a resolver that enables an instant slashing mechanic similar to Slasher’s.** If the Vault curator is not ready to provide a stake without the resolver, the curator may simply not allocate any stake to such networks. Since the **VetoSlasher** can be seen as an extension of the Slasher, we’ll choose it.

1. Clone the core contracts repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/core.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd core
```
3. Deploy core modules contracts using a simple script:
Open [DeployVault.s.sol](https://github.com/symbioticfi/core/blob/main/script/DeployVault.s.sol), you will see the following config:
```bash [bash]
// Address of the owner of the vault who can migrate the vault to new versions whitelisted by Symbiotic
address OWNER = 0x0000000000000000000000000000000000000000;
// Address of the collateral token
address COLLATERAL = 0x0000000000000000000000000000000000000000;
// Vault's burner to send slashed funds to (e.g., 0xdEaD or some unwrapper contract; not used in case of no slasher)
address BURNER = 0x000000000000000000000000000000000000dEaD;
// Duration of the vault epoch (the withdrawal delay for staker varies from EPOCH_DURATION to 2 * EPOCH_DURATION depending on when the withdrawal is requested)
uint48 EPOCH_DURATION = 7 days;
// Type of the delegator:
// 0. NetworkRestakeDelegator (allows restaking across multiple networks and having multiple operators per network)
// 1. FullRestakeDelegator (do not use without knowing what you are doing)
// 2. OperatorSpecificDelegator (allows restaking across multiple networks with only a single operator)
// 3. OperatorNetworkSpecificDelegator (allocates the stake to a specific operator and network)
uint64 DELEGATOR_INDEX = 0;
// Setting depending on the delegator type:
// 0. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 1. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 2. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 3. network (the only network that will receive the stake; should be an array with a single element)
address[] NETWORK_ALLOCATION_SETTERS_OR_NETWORK = [0x0000000000000000000000000000000000000000];
// Setting depending on the delegator type:
// 0. OperatorNetworkSharesSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 1. OperatorNetworkLimitSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 2. operator (the only operator that will receive the stake; should be an array with a single element)
// 3. operator (the only operator that will receive the stake; should be an array with a single element)
address[] OPERATOR_ALLOCATION_SETTERS_OR_OPERATOR = [0x0000000000000000000000000000000000000000];
// Whether to deploy a slasher
bool WITH_SLASHER = true;
// Type of the slasher:
// 0. Slasher (allows instant slashing)
// 1. VetoSlasher (allows having a veto period if the resolver is set)
uint64 SLASHER_INDEX = 1;
// Duration of a veto period (should be less than EPOCH_DURATION)
uint48 VETO_DURATION = 1 days;
// Optional
// Deposit limit (maximum amount of the active stake allowed in the vault)
uint256 DEPOSIT_LIMIT = 0;
// Addresses of the whitelisted depositors
address[] WHITELISTED_DEPOSITORS = new address[](0);
// Address of the hook contract which, e.g., can automatically adjust the allocations on slashing events (not used in case of no slasher)
address HOOK = 0x0000000000000000000000000000000000000000;
// Delay in epochs for a network to update a resolver
uint48 RESOLVER_SET_EPOCHS_DELAY = 3;
```
Edit needed fields, and execute the script via:
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://0xrpc.io/hoodi \
--chain hoodi \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the core contracts repository by running the following command:
```bash [bash]
forge install symbioticfi/core
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/core/=lib/core/
```
3. Create core modules using [a VaultConfigurator contract](https://github.com/symbioticfi/core/blob/main/src/contracts/VaultConfigurator.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DeployVault.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x29300b1d3150B4E2b12fE80BE72f365E200441EC; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
```solidity [DeployVault.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x94c344E816A53D07fC4c7F4a18f82b6Da87CFc8f; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
```solidity [DeployVault.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0xD2191FE92987171691d552C219b8caEf186eb9cA; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0xB82381A3fBD3FaFA77B3a7bE693342618240067b, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
#### 3. Staker rewards
Rewards logic is not enshrined in the core contract, and we allow anyone to create their own implementations if needed. However, it requires resources like time, knowledge, and money. Therefore, we provide a default implementation of the staker rewards named **DefaultStakerRewards**. Its main goals are:
* allow networks to distribute rewards for the stakers of the certain Vault
* allow stakers to claim these rewards
* allow Vault curators to receive fees from the distributed rewards
It is the only staker rewards implementation we provided, so let’s add it to our deployment configuration.

1. Clone the rewards contracts repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/rewards.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd rewards
```
3. Deploy a staker rewards contract using [a simple script](https://github.com/symbioticfi/rewards/blob/main/script/deploy/DefaultStakerRewards.s.sol):
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
```bash [bash]
VAULT= # address of the deployed Vault
ADMIN_FEE=1000 # admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
ADMIN=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the main admin (can manage all roles)
ADMIN_FEE_CLAIMER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee claimer
ADMIN_FEE_SETTER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee setter
forge script script/deploy/DefaultStakerRewards.s.sol:DefaultStakerRewardsScript \
$VAULT \
$ADMIN_FEE \
$ADMIN \
$ADMIN_FEE_CLAIMER \
$ADMIN_FEE_SETTER \
--sig "run(address,uint256,address,address,address)" \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
VAULT= # address of the deployed Vault
ADMIN_FEE=1000 # admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
ADMIN=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the main admin (can manage all roles)
ADMIN_FEE_CLAIMER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee claimer
ADMIN_FEE_SETTER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee setter
forge script script/deploy/DefaultStakerRewards.s.sol:DefaultStakerRewardsScript \
$VAULT \
$ADMIN_FEE \
$ADMIN \
$ADMIN_FEE_CLAIMER \
$ADMIN_FEE_SETTER \
--sig "run(address,uint256,address,address,address)" \
--rpc-url=https://ethereum-hoodi.gateway.tatum.io \
--chain hoodi \
--broadcast
```
```bash [bash]
VAULT= # address of the deployed Vault
ADMIN_FEE=1000 # admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
ADMIN=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the main admin (can manage all roles)
ADMIN_FEE_CLAIMER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee claimer
ADMIN_FEE_SETTER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the admin fee setter
forge script script/deploy/DefaultStakerRewards.s.sol:DefaultStakerRewardsScript \
$VAULT \
$ADMIN_FEE \
$ADMIN \
$ADMIN_FEE_CLAIMER \
$ADMIN_FEE_SETTER \
--sig "run(address,uint256,address,address,address)" \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the rewards contracts repository by running the following command:
```bash [bash]
forge install symbioticfi/rewards
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/rewards/=lib/rewards/
```
3. Create a staker rewards contract using [a DefaultStakerRewardsFactory contract](https://github.com/symbioticfi/rewards/blob/main/src/contracts/defaultStakerRewards/DefaultStakerRewardsFactory.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DefaultStakerRewards.s.sol]
import {IDefaultStakerRewardsFactory} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewardsFactory.sol";
import {IDefaultStakerRewards} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewards.sol";
// ...
address DEFAULT_STAKER_REWARDS_FACTORY = 0x290CAB97a312164Ccf095d75D6175dF1C4A0a25F; // address of the DefaultStakerRewardsFactory (see Deployments page)
// ...
address defaultStakerRewards = IDefaultStakerRewardsFactory(DEFAULT_STAKER_REWARDS_FACTORY).create(IDefaultStakerRewards.InitParams({
vault: , // address of the deployed Vault
adminFee: 1000, // admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the main admin (can manage all roles)
adminFeeClaimRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the admin fee claimer
adminFeeSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the admin fee setter
}));
// ...
```
```solidity [DefaultStakerRewards.s.sol]
import {IDefaultStakerRewardsFactory} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewardsFactory.sol";
import {IDefaultStakerRewards} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewards.sol";
// ...
address DEFAULT_STAKER_REWARDS_FACTORY = 0x698C36DE44D73AEfa3F0Ce3c0255A8667bdE7cFD; // address of the DefaultStakerRewardsFactory (see Deployments page)
// ...
address defaultStakerRewards = IDefaultStakerRewardsFactory(DEFAULT_STAKER_REWARDS_FACTORY).create(IDefaultStakerRewards.InitParams({
vault: , // address of the deployed Vault
adminFee: 1000, // admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the main admin (can manage all roles)
adminFeeClaimRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the admin fee claimer
adminFeeSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the admin fee setter
}));
// ...
```
```solidity [DefaultStakerRewards.s.sol]
import {IDefaultStakerRewardsFactory} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewardsFactory.sol";
import {IDefaultStakerRewards} from "@symbioticfi/rewards/src/interfaces/defaultStakerRewards/IDefaultStakerRewards.sol";
// ...
address DEFAULT_STAKER_REWARDS_FACTORY = 0x70C618a13D1A57f7234c0b893b9e28C5cA8E7f37; // address of the DefaultStakerRewardsFactory (see Deployments page)
// ...
address defaultStakerRewards = IDefaultStakerRewardsFactory(DEFAULT_STAKER_REWARDS_FACTORY).create(IDefaultStakerRewards.InitParams({
vault: , // address of the deployed Vault
adminFee: 1000, // admin fee percent to get from all the rewards distributions (10% = 1_000 | 100% = 10_000)
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the main admin (can manage all roles)
adminFeeClaimRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the admin fee claimer
adminFeeSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the admin fee setter
}));
// ...
```
### Advanced
#### Network-specific burners
The further text describes extended configurations that may bring risk reductions, wider support of the networks, and more capital efficiency for users.
Such a case is possible:
* In general, a Vault wants the slashed funds to be burnt.
* On the other hand, there is a highly reputable network that wants its slashings to be redistributed across the users who could suffer losses because of the operators’ malicious activity.
* The Vault decides to integrate such a network to increase its capital efficiency.
Right now, our configuration doesn’t contain such logic, but it can already support it. [As mentioned earlier](#1-burner-router), **BurnerRouter** allows splitting the slashed funds across any number of receivers depending on the slashing networks and the slashed operators. Therefore, given the network address that needs such functionality and the burner address to send the funds to, it is possible to either configure such behavior using an already existing burner router or take care of it during the deployment.
:::warning
In general, burning the slashed funds is one of the safest ways to go. Any other methodology for processing the slashed funds may create incentives for different parties to trigger the slashing, depending on many factors.
:::

1. Clone the burners repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/burners.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd burners
```
3. Deploy a burner router contract with a preconfigured network-specific burner using [a simple script](https://github.com/symbioticfi/burners/blob/main/script/deploy/BurnerRouter.s.sol):
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0xdCaC890b14121FD5D925E2589017Be68C2B5B324 # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[\(,\)] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0x8d09a4502Cc8Cf1547aD300E066060D043f6982D # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[\(,\)] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-hoodi.gateway.tatum.io \
--chain hoodi \
--broadcast
```
```bash [bash]
OWNER=0xe8616DEcea16b5216e805B0b8caf7784de7570E7 # address of the router’s owner
COLLATERAL=0xB82381A3fBD3FaFA77B3a7bE693342618240067b # address of the collateral - wstETH (MUST be the same as for the Vault to connect)
DELAY=1814400 # duration of the receivers’ update delay (= 21 days)
GLOBAL_RECEIVER=0x58D347334A5E6bDE7279696abE59a11873294FA4 # address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
NETWORK_RECEIVERS=[\(,\)] # array with elements like "\(network_address,receiver_address\)" meaning network-specific receivers
OPERATOR_NETWORK_RECEIVERS=[] # array with elements like "\(network_address,operator_address,receiver_address\)" meaning operator-network-specific receivers
forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript \
$OWNER \
$COLLATERAL \
$DELAY \
$GLOBAL_RECEIVER \
$NETWORK_RECEIVERS \
$OPERATOR_NETWORK_RECEIVERS \
--sig "run(address,address,uint48,address,(address,address)[],(address,address,address)[])" \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the burners repository by running the following command:
```bash [bash]
forge install symbioticfi/burners
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/burners/=lib/burners/
```
3. Create a burner router contract using [a BurnerRouterFactory contract](https://github.com/symbioticfi/burners/blob/main/src/contracts/router/BurnerRouterFactory.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0x99F2B89fB3C363fBafD8d826E5AA77b28bAB70a0; // address of the BurnerRouterFactory (see Deployments page)
// ...
IBurnerRouter.NetworkReceiver[] memory networkReceivers = new IBurnerRouter.NetworkReceiver[](1);
networkReceivers[0] = IBurnerRouter.NetworkReceiver({
network: ,
receiver:
});
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0xdCaC890b14121FD5D925E2589017Be68C2B5B324, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: networkReceivers, // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0xF619c99D166224B4AC008b14Cc67ac72C2E91D8a; // address of the BurnerRouterFactory (see Deployments page)
// ...
IBurnerRouter.NetworkReceiver[] memory networkReceivers = new IBurnerRouter.NetworkReceiver[](1);
networkReceivers[0] = IBurnerRouter.NetworkReceiver({
network: ,
receiver:
});
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0x25133c2c49A343F8312bb6e896C1ea0Ad8CD0EBd, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: networkReceivers, // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
```solidity [DeployBurnerRouter.s.sol]
import {IBurnerRouterFactory} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouterFactory.sol";
import {IBurnerRouter} from "@symbioticfi/burners/src/interfaces/router/IBurnerRouter.sol";
// ...
address BURNER_ROUTER_FACTORY = 0x32e2AfbdAffB1e675898ABA75868d92eE1E68f3b; // address of the BurnerRouterFactory (see Deployments page)
// ...
IBurnerRouter.NetworkReceiver[] memory networkReceivers = new IBurnerRouter.NetworkReceiver[](1);
networkReceivers[0] = IBurnerRouter.NetworkReceiver({
network: ,
receiver:
});
address burnerRouter = IBurnerRouterFactory(BURNER_ROUTER_FACTORY).create(
IBurnerRouter.InitParams({
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the router’s owner
collateral: 0xB82381A3fBD3FaFA77B3a7bE693342618240067b, // address of the collateral - wstETH (MUST be the same as for the Vault to connect)
delay: 1814400, // duration of the receivers’ update delay (= 21 days)
globalReceiver: 0x58D347334A5E6bDE7279696abE59a11873294FA4, // address of the pure burner corresponding to the collateral - wstETH_Burner (some collaterals are covered by us; see Deployments page)
networkReceivers: networkReceivers, // array with IBurnerRouter.NetworkReceiver elements meaning network-specific receivers
operatorNetworkReceivers: new IBurnerRouter.OperatorNetworkReceiver[](0) // array with IBurnerRouter.OperatorNetworkReceiver elements meaning network-specific receivers
})
);
// ...
```
Generally, all the changes inside the burner router can be performed in 2 steps:
1. Create a pending request to change some value
2. Accept the request after waiting for a configured `delay`
Therefore, to set a new receiver (which can be a network-specific burner or treasury or any address) for a particular network the further steps are needed:
1. Owner calls `setNetworkReceiver(network, receiver)`
2. Wait for `delay`
3. Anyone commits the change via `acceptNetworkReceiver(network)`
To set a new receiver for some exact operator inside a particular network:
1. Owner calls `setOperatorNetworkReceiver(network, operator, receiver)`
2. Wait for `delay`
3. Anyone commits the change via `acceptOperatorNetworkReceiver(network)`
To set a new global receiver that gets funds if no specific receivers for a network-operator pair are configured:
1. Owner calls `setGlobalReceiver(receiver)`
2. Wait for `delay`
3. Anyone commits the change via `acceptGlobalReceiver(network)`
To change a `delay`:
1. Owner calls `setDelay(newDelay)`
2. Wait for an old `delay`
3. Anyone commits the change via `acceptDelay()`
#### Hook
Hook is a contract that the Vault curator can set to receive `onSlash()` call on each slashing event. Symbiotic doesn’t specify any logic behind it. However, the basic idea of the hook is to allow the creation of any delegation adjustment mechanic during the slashing.
:::warning
Symbiotic Delegator contracts don’t update allocations on the slashing events in any way. This means that a malicious network or an operator may need only several blocks (depending on their allocated stake) to slash all of Vault’s funds.
:::
We provide pure **example** implementations of some standard adjustment mechanics for each Delegator type - [here](https://github.com/symbioticfi/hooks).

1. Clone the core contracts repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/core.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd core
```
3. Deploy core modules contracts using a simple script:
Open [DeployVault.s.sol](https://github.com/symbioticfi/core/blob/main/script/DeployVault.s.sol), you will see the following config:
```bash [bash]
// Address of the owner of the vault who can migrate the vault to new versions whitelisted by Symbiotic
address OWNER = 0x0000000000000000000000000000000000000000;
// Address of the collateral token
address COLLATERAL = 0x0000000000000000000000000000000000000000;
// Vault's burner to send slashed funds to (e.g., 0xdEaD or some unwrapper contract; not used in case of no slasher)
address BURNER = 0x000000000000000000000000000000000000dEaD;
// Duration of the vault epoch (the withdrawal delay for staker varies from EPOCH_DURATION to 2 * EPOCH_DURATION depending on when the withdrawal is requested)
uint48 EPOCH_DURATION = 7 days;
// Type of the delegator:
// 0. NetworkRestakeDelegator (allows restaking across multiple networks and having multiple operators per network)
// 1. FullRestakeDelegator (do not use without knowing what you are doing)
// 2. OperatorSpecificDelegator (allows restaking across multiple networks with only a single operator)
// 3. OperatorNetworkSpecificDelegator (allocates the stake to a specific operator and network)
uint64 DELEGATOR_INDEX = 0;
// Setting depending on the delegator type:
// 0. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 1. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 2. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 3. network (the only network that will receive the stake; should be an array with a single element)
address[] NETWORK_ALLOCATION_SETTERS_OR_NETWORK = [0x0000000000000000000000000000000000000000];
// Setting depending on the delegator type:
// 0. OperatorNetworkSharesSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 1. OperatorNetworkLimitSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 2. operator (the only operator that will receive the stake; should be an array with a single element)
// 3. operator (the only operator that will receive the stake; should be an array with a single element)
address[] OPERATOR_ALLOCATION_SETTERS_OR_OPERATOR = [0x0000000000000000000000000000000000000000];
// Whether to deploy a slasher
bool WITH_SLASHER = true;
// Type of the slasher:
// 0. Slasher (allows instant slashing)
// 1. VetoSlasher (allows having a veto period if the resolver is set)
uint64 SLASHER_INDEX = 1;
// Duration of a veto period (should be less than EPOCH_DURATION)
uint48 VETO_DURATION = 1 days;
// Optional
// Deposit limit (maximum amount of the active stake allowed in the vault)
uint256 DEPOSIT_LIMIT = 0;
// Addresses of the whitelisted depositors
address[] WHITELISTED_DEPOSITORS = new address[](0);
// Address of the hook contract which, e.g., can automatically adjust the allocations on slashing events (not used in case of no slasher)
address HOOK = ;
// Delay in epochs for a network to update a resolver
uint48 RESOLVER_SET_EPOCHS_DELAY = 3;
```
Edit needed fields, and execute the script via:
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://0xrpc.io/hoodi \
--chain hoodi \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the core contracts repository by running the following command:
```bash [bash]
forge install symbioticfi/core
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/core/=lib/core/
```
3. Create core modules with hook using [a VaultConfigurator contract](https://github.com/symbioticfi/core/blob/main/src/contracts/VaultConfigurator.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DeployVaultWithHook.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x29300b1d3150B4E2b12fE80BE72f365E200441EC; // address of the VaultConfigurator (see Deployments page)
// ...
address hook = ;
address[] memory networkLimitSetRoleHolders = new address[](2);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
networkLimitSetRoleHolders[1] = hook;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](2);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
operatorNetworkSharesSetRoleHolders[1] = hook;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: hook, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
```solidity [DeployVaultWithHook.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x94c344E816A53D07fC4c7F4a18f82b6Da87CFc8f; // address of the VaultConfigurator (see Deployments page)
// ...
address hook = ;
address[] memory networkLimitSetRoleHolders = new address[](2);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
networkLimitSetRoleHolders[1] = hook;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](2);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
operatorNetworkSharesSetRoleHolders[1] = hook;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: hook, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
```solidity [DeployVaultWithHook.s.sol]
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0xD2191FE92987171691d552C219b8caEf186eb9cA; // address of the VaultConfigurator (see Deployments page)
// ...
address hook = ;
address[] memory networkLimitSetRoleHolders = new address[](2);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
networkLimitSetRoleHolders[1] = hook;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](2);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
operatorNetworkSharesSetRoleHolders[1] = hook;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: false, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: hook, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
// ...
```
1. We need the address of the Vault’s Delegator contract. It can be obtained via `Vault.delegator()`
2. Make sure the caller has a `Delegator.HOOK_SET_ROLE()` role via [the OpenZeppelin’s `AccessControl` contract](https://docs.openzeppelin.com/contracts/5.x/access-control#using-access-control)
3. Call `Delegator.setHook(hook)`
#### Deposit whitelist
Symbiotic Vaults contain a feature called - deposit whitelist. It allows the restriction of making deposits to the Vault only by the whitelisted depositors. Several parties may need such functionality, e.g.:
1. LRTs that want to fully isolate their Vaults from the external users to have a strict logic flow depending only on them
2. Institutional entities that want to reduce the risks maximally and respect the legal side
3. Some third-party entities that want to integrate the Vaults with some specific logic on top of them

1. Clone the core contracts repository by running the following command:
```bash [bash]
git clone --recurse-submodules https://github.com/symbioticfi/core.git
```
2. Navigate into the cloned repository folder:
```bash [bash]
cd core
```
3. Deploy core modules contracts using a simple script:
Open [DeployVault.s.sol](https://github.com/symbioticfi/core/blob/main/script/DeployVault.s.sol), you will see the following config:
```bash [bash]
// Address of the owner of the vault who can migrate the vault to new versions whitelisted by Symbiotic
address OWNER = 0x0000000000000000000000000000000000000000;
// Address of the collateral token
address COLLATERAL = 0x0000000000000000000000000000000000000000;
// Vault's burner to send slashed funds to (e.g., 0xdEaD or some unwrapper contract; not used in case of no slasher)
address BURNER = 0x000000000000000000000000000000000000dEaD;
// Duration of the vault epoch (the withdrawal delay for staker varies from EPOCH_DURATION to 2 * EPOCH_DURATION depending on when the withdrawal is requested)
uint48 EPOCH_DURATION = 7 days;
// Type of the delegator:
// 0. NetworkRestakeDelegator (allows restaking across multiple networks and having multiple operators per network)
// 1. FullRestakeDelegator (do not use without knowing what you are doing)
// 2. OperatorSpecificDelegator (allows restaking across multiple networks with only a single operator)
// 3. OperatorNetworkSpecificDelegator (allocates the stake to a specific operator and network)
uint64 DELEGATOR_INDEX = 0;
// Setting depending on the delegator type:
// 0. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 1. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 2. NetworkLimitSetRoleHolders (adjust allocations for networks)
// 3. network (the only network that will receive the stake; should be an array with a single element)
address[] NETWORK_ALLOCATION_SETTERS_OR_NETWORK = [0x0000000000000000000000000000000000000000];
// Setting depending on the delegator type:
// 0. OperatorNetworkSharesSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 1. OperatorNetworkLimitSetRoleHolders (adjust allocations for operators inside networks; in shares, resulting percentage is operatorShares / totalOperatorShares)
// 2. operator (the only operator that will receive the stake; should be an array with a single element)
// 3. operator (the only operator that will receive the stake; should be an array with a single element)
address[] OPERATOR_ALLOCATION_SETTERS_OR_OPERATOR = [0x0000000000000000000000000000000000000000];
// Whether to deploy a slasher
bool WITH_SLASHER = true;
// Type of the slasher:
// 0. Slasher (allows instant slashing)
// 1. VetoSlasher (allows having a veto period if the resolver is set)
uint64 SLASHER_INDEX = 1;
// Duration of a veto period (should be less than EPOCH_DURATION)
uint48 VETO_DURATION = 1 days;
// Optional
// Deposit limit (maximum amount of the active stake allowed in the vault)
uint256 DEPOSIT_LIMIT = 0;
// Addresses of the whitelisted depositors
address[] WHITELISTED_DEPOSITORS = ;
// Address of the hook contract which, e.g., can automatically adjust the allocations on slashing events (not used in case of no slasher)
address HOOK = 0x0000000000000000000000000000000000000000;
// Delay in epochs for a network to update a resolver
uint48 RESOLVER_SET_EPOCHS_DELAY = 3;
```
Edit needed fields, and execute the script via:
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-rpc.publicnode.com \
--chain mainnet \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://0xrpc.io/hoodi \
--chain hoodi \
--broadcast
```
```bash [bash]
forge script script/DeployVault.s.sol:DeployVaultScript \
--rpc-url=https://ethereum-sepolia-rpc.publicnode.com \
--chain sepolia \
--broadcast
```
:::note
It is an **example** command, meaning you need to replace the given values with necessary ones.
***
In addition, you need to [choose a preferred wallet option](https://book.getfoundry.sh/reference/forge/forge-script?highlight=forge%20script#wallet-options---raw) and adjust the command accordingly.
:::
The following instruction assumes you have an already initialized Foundry repository ([read more here](https://book.getfoundry.sh/getting-started/first-steps)).
1. Install the core contracts repository by running the following command:
```bash [bash]
forge install symbioticfi/core
```
2. Update (or create if not yet) a `remappings.txt` file inside your repository accordingly:
```txt title="remappings.txt"
...
@symbioticfi/core/=lib/core/
```
3. Create core modules with deposit whitelist using [a VaultConfigurator contract](https://github.com/symbioticfi/core/blob/main/src/contracts/VaultConfigurator.sol):
:::note
It is an **example** code snippet, meaning you need to replace the given values with necessary ones.
:::
```solidity [DeployVaultWithWhitelist.s.sol]
import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol";
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x29300b1d3150B4E2b12fE80BE72f365E200441EC; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: true, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: address(this), // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
Vault(vault).grantRole(Vault(vault).DEFAULT_ADMIN_ROLE(), 0xe8616DEcea16b5216e805B0b8caf7784de7570E7);
Vault(vault).grantRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
IVault(vault).setDepositorWhitelistStatus(, true);
Vault(vault).renounceRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
Vault(vault).renounceRole(Vault(vault).DEFAULT_ADMIN_ROLE(), address(this));
// ...
```
```solidity [DeployVaultWithWhitelist.s.sol]
import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol";
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0x94c344E816A53D07fC4c7F4a18f82b6Da87CFc8f; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: true, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: address(this), // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
Vault(vault).grantRole(Vault(vault).DEFAULT_ADMIN_ROLE(), 0xe8616DEcea16b5216e805B0b8caf7784de7570E7);
Vault(vault).grantRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
IVault(vault).setDepositorWhitelistStatus(, true);
Vault(vault).renounceRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
Vault(vault).renounceRole(Vault(vault).DEFAULT_ADMIN_ROLE(), address(this));
// ...
```
```solidity [DeployVaultWithWhitelist.s.sol]
import {Vault} from "@symbioticfi/core/src/contracts/vault/Vault.sol";
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {INetworkRestakeDelegator} from "@symbioticfi/core/src/interfaces/delegator/INetworkRestakeDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
// ...
address VAULT_CONFIGURATOR = 0xD2191FE92987171691d552C219b8caEf186eb9cA; // address of the VaultConfigurator (see Deployments page)
// ...
address[] memory networkLimitSetRoleHolders = new address[](1);
networkLimitSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
address[] memory operatorNetworkSharesSetRoleHolders = new address[](1);
operatorNetworkSharesSetRoleHolders[0] = 0xe8616DEcea16b5216e805B0b8caf7784de7570E7;
(address vault, address networkRestakeDelegator, address vetoSlasher) = IVaultConfigurator(VAULT_CONFIGURATOR).create(
IVaultConfigurator.InitParams({
version: 1, // Vault’s version (= common one)
owner: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Vault’s owner (can migrate the Vault to new versions in the future)
vaultParams: abi.encode(IVault.InitParams({
collateral: 0xB82381A3fBD3FaFA77B3a7bE693342618240067b, // address of the collateral - wstETH
burner: , // address of the deployed burner router
epochDuration: 604800, // duration of the Vault epoch in seconds (= 7 days)
depositWhitelist: true, // if enable deposit whitelisting
isDepositLimit: false, // if enable deposit limit
depositLimit: 0, // deposit limit
defaultAdminRoleHolder: address(this), // address of the Vault’s admin (can manage all roles)
depositWhitelistSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit whitelisting
depositorWhitelistRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the depositors whitelister
isDepositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the enabler/disabler of the deposit limit
depositLimitSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the deposit limit setter
})),
delegatorIndex: 0, // Delegator’s type (= NetworkRestakeDelegator)
delegatorParams: abi.encode(INetworkRestakeDelegator.InitParams({
baseParams: IBaseDelegator.BaseParams({
defaultAdminRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7, // address of the Delegator’s admin (can manage all roles)
hook: 0x0000000000000000000000000000000000000000, // address of the hook (if not zero, receives onSlash() call on each slashing)
hookSetRoleHolder: 0xe8616DEcea16b5216e805B0b8caf7784de7570E7 // address of the hook setter
}),
networkLimitSetRoleHolders: networkLimitSetRoleHolders, // array of addresses of the network limit setters
operatorNetworkSharesSetRoleHolders: operatorNetworkSharesSetRoleHolders // array of addresses of the operator-network shares setters
})),
withSlasher: true, // if enable Slasher module
slasherIndex: 1, // Slasher’s type (= VetoSlasher)
slasherParams: abi.encode(IVetoSlasher.InitParams({
baseParams: IBaseSlasher.BaseParams({
isBurnerHook: true // if enable the `burner` to receive onSlash() call after each slashing (is needed for the burner router workflow)
}),
vetoDuration: 86400, // veto duration (= 1 day)
resolverSetEpochsDelay: 3 // number of Vault epochs needed for the resolver to be changed
}))
})
);
Vault(vault).grantRole(Vault(vault).DEFAULT_ADMIN_ROLE(), 0xe8616DEcea16b5216e805B0b8caf7784de7570E7);
Vault(vault).grantRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
IVault(vault).setDepositorWhitelistStatus(, true);
Vault(vault).renounceRole(Vault(vault).DEPOSITOR_WHITELIST_ROLE(), address(this));
Vault(vault).renounceRole(Vault(vault).DEFAULT_ADMIN_ROLE(), address(this));
// ...
```
1. Make sure the caller has a `Vault.DEPOSIT_WHITELIST_SET_ROLE()` role via [the OpenZeppelin’s `AccessControl` contract](https://docs.openzeppelin.com/contracts/5.x/access-control#using-access-control)
2. Call `Vault.setDepositWhitelist(true)`
3. Make sure the caller has a `Vault.DEPOSITOR_WHITELIST_ROLE()` role via [the OpenZeppelin’s `AccessControl` contract](https://docs.openzeppelin.com/contracts/5.x/access-control#using-access-control)
4. Call `Vault.setDepositorWhitelistStatus(account, true)`
## Helpful Core Contracts' Endpoints
This page provides a list of useful in practice functions for a Network across Symbiotic Core contracts.
| Function | Use-case |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| [`create(InitParams params) -> address, address, address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/IVaultConfigurator.sol#L52) | Create a new 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.stake(bytes32 subnetwork, address operator) → uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IBaseDelegator.sol#L150) | Get the operator-network's stake |
| [`NetworkRestakeDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L136) | Set a amount of collateral to allocate to the network |
| [`NetworkRestakeDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L84) | Check the network's allocation |
| [`NetworkRestakeDelegator.setOperatorNetworkShares(bytes32 subnetwork, address operator, uint256 shares) `](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L147) | Set the operator's share from the network's allocation |
| [`NetworkRestakeDelegator.operatorNetworkShares(bytes32 subnetwork, address operator) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/INetworkRestakeDelegator.sol#L128) | Check the operator-network's shares |
| [`FullRestakeDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L112) | Set a amount of collateral to allocate to the network |
| [`FullRestakeDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L81) | Check the network's allocation |
| [`NetworkRestakeDelegator.setOperatorNetworkLimit(bytes32 subnetwork, address operator, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L122) | Set the operator's limit over the network's allocation |
| [`NetworkRestakeDelegator.operatorNetworkLimit(bytes32 subnetwork, address operator) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IFullRestakeDelegator.sol#L104) | Check the operator-network's limit |
| [`OperatorSpecificDelegator.setNetworkLimit(bytes32 subnetwork, uint256 amount)`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L85) | Set a amount of collateral to allocate to the network |
| [`OperatorSpecificDelegator.networkLimit(bytes32 subnetwork) -> uint256`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L77) | Check the network's allocation |
| [`OperatorSpecificDelegator.operator() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorSpecificDelegator.sol#L60) | Check the operator who receive all the allocations |
| [`OperatorSpecificDelegator.network() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol#L44) | Check the network who receive all the allocations |
| [`OperatorSpecificDelegator.operator() -> address`](https://github.com/symbioticfi/core/blob/7cb06639c5cd656d1d212dafa2c270b5fde39306/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol#L50) | Check the operator who receive all the allocations |
| [`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) |
import { Card1 } from "../../../components/Card1";
## Get Started
Symbiotic protocol contains a wide range of supportive tooling for various curation needs. This page provides you a high-level overview of a Curator's lifecycle in Symbiotic:
:::steps
### Deploy Vault
}
href="/integrate/curators/deploy-vault"
/>
### Submit Metadata
}
href="/integrate/curators/submit-metadata"
/>
### Opt Into Networks And Vaults
}
href="/integrate/operators/opt-ins"
/>
:::
## Manage Allocations
Curators must perform two actions:
* Set network allocation - determining how much funds to delegate to each network
* Set operator shares within each network - specifying how the network's allocation is distributed among operators
### Set initial network delegation
#### Using [Safe](https://app.safe.global/)
* Open “Transaction builder”
* Get the delegator contract address of the desired vault (using UI, CLI, or etherscan)
* Put the delegator’s address as contract address
* Click “Use Implementation ABI”
* Choose `setNetworkLimit()` method
* the desired subnetwork (which is an address of the network concatenated with the uint96 identifier)
* the desired maximum amount of collateral to allocate to the subnetwork
* Sign & send transaction
#### Verify via Etherscan
* Open “Read Contract” tab in the delegator contract you used
* Open `networkLimit()` method
* Put `SUBNETWORK` (which is an address of the network concatenated with the uint96 identifier) in `subnetwork` parameter, and click “Query”. It should return the set amount

### Set initial operator delegation
#### Using [Safe](https://app.safe.global/)
* Open “Transaction builder”
* Get the delegator contract address of the desired vault (using UI, CLI, or etherscan)
* Put the delegator’s address as contract address
* Click “Use Implementation ABI”
* Choose `setOperatorNetworkShares()` method
* the desired subnetwork (which is an address of the network concatenated with the uint96 identifier)
* the desired operator address
* the desired amount of shares to allocate to the operator (e.g, the operator having 100 shares out of a total 1000 shares for the given subnetwork means having 10% of the stake allocated to the subnetwork)
* Sign & send transaction
#### Using CLI
* See [https://docs.symbiotic.fi/guides/cli/#set-operator-network-shares](https://docs.symbiotic.fi/guides/cli/#set-operator-network-shares)
Using CLI to check:
* See [https://docs.symbiotic.fi/guides/cli/#operator-network-shares](https://docs.symbiotic.fi/guides/cli/#operator-network-shares)
* Also, you may need [https://docs.symbiotic.fi/guides/cli/#total-operator-network-shares](https://docs.symbiotic.fi/guides/cli/#total-operator-network-shares)
#### Verify via Etherscan
* Open “Read Contract” tab in the delegator you used
* Open `operatorNetworkShares()` method (also, you may need totalOperatorNetworkShares)
* Put `SUBNETWORK` (which is an address of the network concatenated with the uint96 identifier) in `subnetwork` parameter, `OPERATOR_ADDRESS` in `operator`, and click “Query”. It should return the set amount

## Submit Metadata
[Symbiotic UI](https://app.symbiotic.fi/deposit) provides users with accurate and up-to-date information about various data regarding TVL, allocations, relations between Curators, Vaults, Operators and Networks, etc. However, for the mentioned counterparties to be easily accessible and visible on the UI - their metadata should should be submitted to the corresponding repositories.
Once, the metadata is submitted, it should be reviewed and merged by the Symbiotic team. After that the new data starts to be shown publicly 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) |
| Sepolia | [https://github.com/symbioticfi/metadata-sepolia](https://github.com/symbioticfi/metadata-sepolia) |
| Holešky | [https://github.com/symbioticfi/metadata-holesky](https://github.com/symbioticfi/metadata-holesky) |
#### Repository Structure
The repository is organized as follows:
```
repository/
├── vaults/
│ ├── 0x/
│ │ ├── 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, there must be 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`, please be sure that it's collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, please 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.
Your PR will be reviewed by the Symbiotic team, and if approved, it will be merged into the repository. Please note that the PR will be reviewed only after the entity is checked with automated checks.
***
#### 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 Tokens
* `cmcId` (string): The CoinMarketCap ID for the token. Used to fetch price of the token in USD.
* `permitName` (string): The `name` field for EIP-2612 support.
* `permitVersion` (string): The `version` field for EIP-2612 support.
##### Fields for Vaults
* `curatorId` (string): The ID of the curator of the vault.
* `vaultType` (string): The type of the vault. Can be one of:
* `eth-restaking`: Vaults with ETH-flavored collateral restaked across multiple networks
* `btc-restaking`: Vaults with BTC-flavored collateral restaked across multiple networks
* `network-exclusive`: Vaults exclusive to a single network
##### 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 Curator
:::steps
##### Create a new folder in the `/curators` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "My Curator",
"description": "My Curator is a curator that allows you to manage your vaults.",
"tags": ["curator", "staking"],
"links": [
{ "type": "website", "name": "Website", "url": "https://mycurator.com" },
{ "type": "twitter", "name": "Twitter", "url": "https://x.com/mycurator" },
{
"type": "explorer",
"name": "Explorer",
"url": "https://etherscan.io/address/0x1234567890abcdef1234567890abcdef12345678"
}
]
}
```
##### Save a logo of the Curator to `logo.png` of 256x256 pixels size
:::
### Add a Token
::::steps
##### Create a new folder in the `/tokens` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "My Token",
"description": "My Token is a token that allows you to earn rewards.",
"tags": ["token", "staking"],
"cmcId": "1234567890",
"links": [{ "type": "website", "name": "Website", "url": "https://mytoken.com" }]
}
```
:::warning
If the CMC ID is missing:
* The token’s price cannot be displayed
* TVL (Total Value Locked) in USD won’t be calculated
* Symbiotic Points cannot be calculated or distributed
* Points will be calculated from the date the CMC ID is added; retrospective recalculation for points accrued before this date will not occur.
:::
##### Save a logo of the Token to `logo.png` of 256x256 pixels size
::::
### Add a Vault
:::warning
If the Vault's collateral is not yet supported by Symbiotic, a separate **Token PR** must be submitted before the **Vault PR**.
:::
::::steps
##### Create a new folder in the `/vaults` directory
##### Create a new json file in the folder with the following structure:
```json [info.json]
{
"name": "DeFi Vault",
"description": "A secure vault for decentralized finance.",
"tags": ["vault", "DeFi"],
"curatorName": "My Curator",
"links": [
{
"type": "website",
"name": "Website",
"url": "https://example-vault.com/"
},
{
"type": "docs",
"name": "Vault Documentation",
"url": "https://example-vault.com/docs"
}
]
}
```
:::warning
If the CMC ID is missing:
* The token’s price cannot be displayed
* TVL (Total Value Locked) in USD won’t be calculated
* Symbiotic Points cannot be calculated or distributed
* Points will be calculated from the date the CMC ID is added; retrospective recalculation for points accrued before this date will not occur.
:::
##### Save a logo of the Vault to `logo.png` of 256x256 pixels size
::::
## Vault Wrapping
Sometimes, due to design choices made regarding the Symbiotic Vault to either hold security guarantees or optimize the whole interaction flow, it's not possible to implement some your ideas in a standard way. In such cases, it is possible to wrap the Symbiotic Vault in sense of, e.g., deposits, slashing, opt-ins, etc. This page presents such example cases:
### Mortgage-backed Security Example
A **mortgage-backed security (MBS)** is a financial instrument created by pooling together many individual home loans (mortgages) and selling them as a single tradable security. Instead of a bank holding a mortgage and collecting monthly payments, the cash flows (interest and principal) from thousands of mortgages are bundled, then redistributed to investors in the MBS.
* **Tranching**: To cater to different investor risk appetites, the pool is divided into **tranches**.
* Senior tranches: Get paid first, lower risk, lower yield.
* Junior tranches: Get paid later and absorb defaults first, higher risk, higher yield.
* **Risk distribution**: This structure spreads default risk across different investor groups and creates a market for varying levels of risk exposure.
Mortgage Backed Securities Structuring and Value Chain
#### Slashing Tranche-Based Vault Wrapper
In Symbiotic, **slashing vaults** are pools where collateral is staked to secure external networks or services. Just like mortgages carry **default risk**, staking carries **slashing risk** (collateral may be cut if operators misbehave).
Here’s how the analogy works:
* **Mortgages = Operator Collateral Positions**
Each mortgage in an MBS corresponds to an individual operator’s staked collateral in Symbiotic. Just as homeowners may default, operators may be slashed.
* **MBS Pool = Slashing Vault**
The pooled mortgages in an MBS map to the **vault of collateral** in Symbiotic. Both aggregate risk into a collective structure.
* **Tranches = Vault Risk Segmentation**
Symbiotic vaults could be designed with **tranches** similar to MBS:
* Senior tranche: Investors who want safer exposure get priority in withdrawals and protection against small slashes (absorbed by junior tranches first).
* Mezzanine tranche: Medium-risk exposure, takes losses only after juniors are hit.
* Junior tranche: Risk-seeking investors absorb slashing losses first but get higher yield (greater share of staking rewards).
* **Cash Flows = Staking Rewards**
Just as mortgages generate interest payments, collateral in slashing vaults generates staking rewards or fees. These flows are redistributed to participants, depending on their tranche.
* **Risk Transformation**
MBS transform mortgage default risk into tiered securities with different profiles. Symbiotic vaults could similarly transform **slashing risk** into structured exposure, letting risk-averse and risk-seeking participants coexist in the same vault.
Tranche-Based (or Slashing Insurance) Vault Segmentation + Redistribution
#### Implementation
A user (staker) would have 3 choices to deposit a single ERC20 asset (collateral) into a Symbiotic vault. They can either deposit into the junior, mezzanine or senior tranche, according to their risk-profile or portfolio fit. The vault wrapper contract would then deposit the collateral to the Symbiotic vault, and the user would receive (or not, depending on the curator choice) an LST.
From our understanding, there may be 2 possibilities to issue the receipt token:
**Model A — 3 Separate ERC20s (most common in structured products)**
* When a user deposits, they **choose the tranche** (junior, mezzanine, senior).
* The wrapper mints them **only that tranche token (LST)**.
* Example:
* Alice deposits 100 USDC → gets **100 tJNR**.
* Bob deposits 100 USDC → gets **100 tSNR**.
**Model B — 1 ERC20 + internal “tranche shares” accounting**
* Users deposit into the wrapper without selecting a tranche.
* The wrapper automatically allocates the deposit across junior, mezz, and senior according to some fixed ratio (e.g., 20/30/50).
* The user receives **one unified wrapper-LST** (e.g., `tWRAP`).
Tranche-Based Vault Proposed Implementation
The entire paper, co-authored with ReSquared can be found here: [https://github.com/dias-henrique/Slashing-Insurance-Vaults/blob/main/CESIV.pdf](https://github.com/dias-henrique/Slashing-Insurance-Vaults/blob/main/CESIV.pdf)
## ABIs And Bindings
import { ActionButtons } from "../../../components/ActionButtons";
import { AskChatGPTButton } from "../../../components/AskChatGPTButton";
import { OpenActionButton } from "../../../components/OpenActionButton";
import { CopyActionButton } from "../../../components/CopyActionButton";
## AI Resources
### Assistant
### MCP
|
|
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
### Materials
#### Documentation
| Description | Actions |
| ---------------------------- | -------------------------------------------------------------------------------------- |
| Navigation index | |
| Full documentation | |
| Full documentation With Code | |
| Network Integrate Context | |
| Curator Integrate Context | |
| Operator Integrate Context | |
#### Contracts
| Description | Actions | DeepWiki |
| ----------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| Core | | |
| Relay | | |
| Network | | |
| Rewards | | |
| Burners | | |
| Hooks | | |
#### Relay
| Description | Actions | DeepWiki |
| ----------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Relay (+ Go Client) | | |
| Relay TypeScript Client | | |
| Relay Rust Client | | |
#### Examples
| Description | Actions | DeepWiki |
| ----------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| Symbiotic Super Sum | | |
| Symbiotic Flight Delays | | |
#### CLI
| Description | Actions | DeepWiki |
| ----------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Python CLI | | |
## APIs
## Hints
Symbiotic core contracts were designed in such a way as to simplify the integration flow for networks or products with a different goal of utilizing the stake. One key aspect of this simplification is to provide flexibility to operate in a time flow that is not dependent on the Symbiotic contracts' mechanics. This achieved by enabling the receiving of any data related to the stake's calculation at any point.
From a more technical point of view, it is implemented by utilizing a mechanism named "Checkpoints". It is realized as an ordered-by-timestamps array of values, which can represent anything from the operators' opt-in statuses to the vaults' active stakes.
It allows for the efficient gathering of historical data by performing a binary search over the timestamps and returning the last value before the needed time point. However, this means that in the case of 1000 deposits and withdrawals, the algorithm may take up to 10 operations to retrieve a proper active stake at the needed timestamp. Such behavior results in the gradual growth of the gas costs for certain operations requiring historical data retrievals (e.g., slashing).

Fortunately, there is a solution - "hints". These are values calculated off-chain, providing a pointer to the exact "Checkpoint" we need to find. Further, the result is only verified by comparing the initial needed time point, the one determined by the provided value, and the next one. Hence, it makes the historical retrieval cheap enough and produces constant gas costs.

### How to Construct Hints
:::info
The Hints SDK is under development. Meanwhile, you can check the [deployed hints provision contracts on testnets](/get-started/resources/addresses#hints), which simplifies obtaining them.
:::
import { Card1 } from "../../../components/Card1";
## Get Started
Build anything on top of Symbiotic protocol, and access any data.
import { Card1 } from "../../components/Card1.tsx";
import { Card2 } from "../../components/Card2.tsx";
import { FeatureSpotlight } from "../../components/FeatureSpotlight.tsx";
## Shared security for Proof of Stake Networks
Symbiotic is a modular shared security protocol that turns stake into a flexible marketplace for economic security, while Relay extends it into a universal verification layer so any protocol can inherit stake-backed security, define custom slashing and rewards, and verify outcomes across chains without bootstrapping its own validator set.
With BLS aggregation and optional ZK compression to keep verification costs flat at scale, Relay connects stakers, operators, and on-chain settlement so builders can coordinate large validator sets, codify slashing conditions as on-chain resolvers, and trigger programmable outcomes everywhere — bridges, oracles, rollups, AI networks, and more.
## **What is Symbiotic?**
Symbiotic is a shared security protocol designed to create a marketplace for economic security. It enables networks that need security to access it from those who have assets to stake, creating an efficient ecosystem where stake can be shared and utilized across multiple networks. Through its flexible architecture, stake providers can maximize their returns while networks can obtain the security guarantees they need.
### **Key Components and Relations**
#### **Core Participants**

* **Stakers**: Entities looking to earn rewards by providing their assets as a stake through vault deposits. They can be individual token holders, institutions, or liquid (re)staking protocols. Stakers deposit funds into specialized smart contracts (vaults) managed by curators who handle delegation decisions.
* **Networks**: Systems that need economic security to operate safely. These can be Layer 1 blockchains, Layer 2 solutions, or other decentralized systems that require stake-based security guarantees.
* **Operators**: Professional entities that maintain network infrastructure by running validators, nodes, or other required systems. They receive stake allocations to perform their duties and are responsible for network operations.
* **Curators**: Entities that design and maintain a vault’s risk and allocation policy. They decide how stake is distributed across networks and operators, which slashing and withdrawal settings apply, and who can deposit into the vault.
#### **Participant Connections**
The core participants are connected through a sophisticated infrastructure layer. At the heart of these connections are Vaults, which serve as the primary interface between all participants.
Symbiotic coordinates and manages interactions in this ecosystem by:
* Enabling Stakers to deposit their assets into Vaults, where Curators manage delegation strategies and approve qualified Operators.
* Facilitating Networks' access to security by connecting them with Vaults and their associated stake.
* Allowing Operators to receive stake allocations through Curator-managed Vaults to perform their network duties.
This interconnected system is monitored by Resolvers, who validate activities and ensure security across all connections. In the following sections, we'll explore the key infrastructure components.
#### **System Relations**
The Symbiotic protocol facilitates several critical interactions between participants, creating a robust and efficient security marketplace. Here's how these key components work together:
#### **Stake Accounting**

1. Stakers deposit their assets into vaults
2. Each vault is managed by a curator who controls stake allocation
3. Curators delegate stake to qualified operators who run network infrastructure
4. A single vault can serve multiple networks simultaneously, allowing efficient stake distribution across different operators
The stake delegation system has important characteristics:
* Assets remain securely locked in the vaults without actual transfer
* Stake delegation works through an accounting system only
* Assets can only leave the vault through:
* Original staker withdrawals
* Validated slashing events from networks
#### **Network Operations**

Networks work with multiple vaults simultaneously, allowing them to aggregate security from different sources. This flexible architecture enables operators to accumulate a stake across different vaults, while networks can calculate their total stake by combining delegation from various vault sources.
#### **Slashing process**

1. Networks can initiate the slashing of operators by interacting with vaults where operators have a stake
2. Networks can choose which vaults to slash from if an operator has a stake in multiple vaults
3. Resolvers act as validators of slashing events with veto power
Resolvers can be automated contracts, slashing committees, dispute resolution frameworks, multisig wallets, or DAO governance systems. Networks and vault curators agree on which resolvers to use (or not to use any resolver at all) and slashing terms. During slashing, networks choose vaults to slash from, resolvers review the event and can veto invalid slashing attempts.
### **Benefits of the Architecture**
* Capital Efficiency: Assets can be utilized across multiple networks simultaneously
* Flexibility: Networks can customize their security model through different vault compositions
* Risk Management: Stake can be isolated or shared based on specific security requirements
* Scalability: The modular design allows for easy integration of new networks and operators
This architecture creates a sustainable ecosystem where security providers (stakers and operators) and security consumers (networks) can interact efficiently while maintaining their specific requirements and risk preferences.
## Relay SDK
### **The Framework for Stake-Secured Applications**
The Symbiotic Relay SDK is the trust layer for data and computation.
It turns any data, computation, or event into **money backed, stake secured attestations** that settle on chain and trigger programmable outcomes. With Relay you:
* **Reduce and keep costs constant at scale.** Validator-set verification uses BLS aggregation and optional ZK compression to keep EVM verify gas essentially flat, regardless of validator set size.
* **Put capital behind data.** Every attestation is secured by stake and can be subject to slashing.
* **Reduce integration friction.** One standardized attestation flow replaces bespoke oracles and middleware.
* **Automate across chains.** Verify once, then mint, swap, bridge, update feeds, or call adapters anywhere.
> Relay is the missing link between computation and consensus, the universal economically secured proof layer for the modular internet.
### The Problem that Relay Solves
Large validator sets became prohibitively expensive to verify across chains. Networks with hundreds of operators were facing millions per year in verification costs on Ethereum alone. At the same time, protocols that wanted to run multichain were pushed into Proof-of-Authority models because staking data was not available cross-chain in a usable, verifiable way.
### **How it Works**
1. ***Application Layer***
Any app or service performs a task: fetching prices, running an AI model, or monitoring transactions.
2. ***Relay Network***
Operators in the Relay Network generate cryptographic attestations that confirm the task was executed as claimed.
3. ***Relay Settlement***
These attestations are verified on-chain using validator stakes within Symbiotic Core contracts.
4. ***On-Chain Action***
Once verified, the attestation can trigger any programmable outcome:
* Mint a token
* Update a price feed
* Trigger a bridge transaction
* Perform a swap
* Feed data into a DeFi protocol

### **Key Value Proposition**
The Relay turns any external workload into a verifiable on-chain action. Networks plug in a lightweight client, inherit stake-backed security with slashing, and use a single attestation flow that works across chains and use cases. The result is less code to maintain, clearer guarantees, and a portable integration you can reuse everywhere.
#### Relay Advantages
* **Cheaper at scale**
Validator-set verification uses BLS aggregation (and optional ZK compression) to keep EVM verification costs essentially constant, independent of validator count. This removes the linear cost curve that made large decentralized sets impractical.
* **Ship faster**
Replace bespoke middleware with a small client + SDK. Fewer contracts to write and audit → shorter path to mainnet.
* **Cross-chain by default**
Verify and trigger outcomes on any EVM; plug into Hyperlane/DVN/others through adapters.
* **Stronger guarantees**
Attestations are backed by staked validators with slashing. You inherit economic security instead of trusting a vendor or multisig.
* **Unified interface**
One attestation format for any workload (AI, compute, data, bridge ops). No new pipeline per use case.
* **Smaller attack surface**
Less custom glue code, fewer moving pieces, clearer trust model.
* **Deterministic programmability**
Attestations can mint, swap, bridge, update feeds, call adapters → compose like Lego across verticals.
* **Cost predictability**
Pay for attestation + on-chain verify; avoid standing infra and surprise ops costs.
* **Vendor neutrality**
Bring your own operators/curators, swap them out, or add more. No lock-in.
#### Relay Features
| Feature | Benefit |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Universal Attestation Framework** | Any data, any computation, any chain → one system for proof generation |
| **Verifiable On-Chain** | Proofs backed by staked validators, ensuring economic security |
| **Fully Modular SDK** | Developers integrate using lightweight clients in Go, Rust, or TypeScript |
| **Chain-Agnostic** | Works across L1s, L2s, and rollups; interoperable with all EVMs. Cosmos integration is available out of the box through a dedicated [SDK](https://github.com/symbioticfi/cosmos-relay-sdk). |
| **Programmable & Application-Agnostic** | Plugs into any smart contract workflow; attestations act as a generic trigger for programmable outcomes. |
### System Architecture
Every operator runs:
* A **Relay Sidecar** → connects to other relay nodes via a p2p network
* An **Application Node** → runs arbitrary code (AI, oracle, bridge, etc.) and communicates with the Sidecar through an API
Together, these produce **verifiable proofs of arbitrary work**, enabling **on-chain action triggers** and **outcome settlement**.

#### How Relay Integrates with Symbiotic
Relay plugs into Symbiotic Vaults out of the box, so networks can adopt it immediately and still customize everything, including validator sets, quorum thresholds, collateral, and reward logic. The Relay contracts read staking state from the vaults each epoch to see who the active operators are and how much voting power they have.
The settlement contract receives this data, verifies the attestations, and then triggers the onchain outcome.

## **Curators**
Curators set and maintain a vault’s policy. They choose how stake is spread across networks and operators, which slashing flow applies, and who can deposit. Stakers pick a vault because they trust the curator’s discipline on risk and timing. While in single‑operator vaults the operator may act as curator, immutable vaults remove ongoing curator control after deployment.
### Responsibilities
A curator turns a staking strategy into on‑chain parameters and keeps the vault aligned as conditions change. They select a Delegator type and apply per‑network and per‑operator limits or shares so allocations match the stated thesis. They choose a Slasher (instant or vetoed) and, for vetoed flows, may appoint a resolver set. They configure the Burner to define outcomes for slashed collateral. At deployment, they also set the vault epoch and access control logic, keeping deposits public or allowlisted.

### Curator Types
Curators are the entities responsible for risk management in Symbiotic vaults, so they need a clear view of the inherent risks of each network they underwrite. In practice, curators can take several forms: liquid funds allocating capital across networks and operators, node operators who understand infrastructure and liveness risk first-hand, LRT / LST issuers extending their own risk frameworks into restaking, or specialized risk-management firms that design conservative, policy-driven strategies for third parties.
### Tools and Strategy
Together, the Slasher, Epoch and withdrawals, Delegator, and Burner define how the vault takes risk, how fast it can react, and what happens when things go wrong. Getting these right is essential to keeping the vault’s behavior aligned with its stated risk profile.
#### Slasher
The Slasher defines how and when collateral can be penalized when networks report misbehavior.
Curators choose between instant slashing, where penalties are applied as soon as a valid proof is delivered, and vetoed slashing, where a resolver set has a short window to challenge or veto a proposed slash. Instant slashing is cleaner and faster, but less forgiving if monitoring is imperfect. Vetoed flows add an extra layer of human or hybrid review, at the cost of latency and some operational overhead. The slashing mode should match the vault’s risk profile and the curator’s ability to monitor incidents in real time.

#### Epochs and Withdrawals
The vault epoch ties together guarantees, slashing timing, and liquidity for stakers. Withdrawals are directly tied to this: how quickly users can fully exit the vault depends on the epoch duration and where they are inside that cycle.
Curators pick an epoch length that comfortably covers the network’s own epoch/finality, any veto window, and the time needed to execute slashes. A longer epoch usually means stronger guarantees (more time to observe and act) but slower reaction for withdrawals and reallocations. A shorter epoch improves responsiveness but leaves less room for disputes. Withdrawal mechanics should be aligned with this: conservative vaults accept slower exit in exchange for robust slashing, while more aggressive ones may prioritize faster liquidity and shorter epochs.

#### Delegator
The Delegator encodes the allocation strategy and defines how stake is spread across networks and operators.
Curators choose a Delegator type based on the structure of the vault. For a single network and a single operator, the Delegator can simply route all stake to that operator. For a single network with multiple operators, the Delegator can enforce how stake is restaked across those operators, for example by applying ceilings for each one or by targeting specific operator shares. For multiple networks, the Delegator first decides how much stake each network receives, then how that stake is divided among the operators inside each network. These parameters are how curators express diversification rules, concentration limits, and risk budgets for each network and each operator on chain. In practice, most of the portfolio work a curator performs is captured in how they configure and update the Delegator over time.
One example is the “Multiple Networks, Multiple Operators” vault, which, as the name suggests, allows delegations to several operators across different networks, and lets stake be restaked across those networks.

#### Burner
The Burner decides **what happens to slashed collateral** once a penalty is applied.
Curators can route slashed funds to different sinks: pure burn (reduce supply), redistribution to remaining stakers, funding an insurance backstop, or sending value back to affected networks. This choice affects incentives: harsh burns are strong deterrents but fully socialize losses, while redirecting part of the slash to an insurance or remediation pool can help absorb shocks more gracefully. The Burner configuration should be consistent with how the vault markets itself: pure risk-taking, conservative insurance-like, or somewhere in between.

## **Networks**
Networks are fundamental components of the Symbiotic protocol that consume economic security and drive the demand for staking. They represent decentralized systems that require validation and security guarantees for their operations. As consumers of economic security, networks work in conjunction with other protocol elements to create customized security configurations that best suit their specific requirements.
What makes networks particularly powerful is their ability to choose different security models - whether direct security, shared security with other networks, or hybrid approaches - while maintaining sovereignty through the immutable core protocol. This flexibility allows any decentralized product to establish robust security from day one.
### **Technical Architecture of Networks**
From a technical perspective, a network in Symbiotic consists of two main components:
#### **1. On-chain Components**

The on-chain part of a network consists of two distinct entities:
* **Network Identity**: Represented by an Ethereum address, which can be:
* An Externally Owned Account (EOA)
* A Multi-Signature wallet
* A Decentralized Autonomous Organization (DAO)
* **Network Middleware**: A set of smart contracts that serves as the crucial interface between Symbiotic Core contracts and the network itself. Its responsibilities include:
* Managing operator selection and stake allocation
* Implementing slashing mechanisms
* Managing validator sets
* Handling reward distribution to operators and vaults
#### **2. Off-chain Components**

The off-chain part consists of:
* Client software run by network operators
* Network-specific validation logic
* Integration systems that connect with the on-chain middleware
* The Symbiotic Relay SDK binaries, if in place
### **Network Middleware Deep Dive**
Network Middleware is distinct from the network itself and plays a crucial role in the ecosystem. While a network is represented by an address, the middleware is always a set of contracts deployed on Ethereum, and / or other chains. This separation serves several important purposes:
* It provides a standardized interface for interacting with Symbiotic Core contracts
* It handles all staking-related operations and state management
* It enables flexible implementation of network-specific logic while maintaining compatibility with the core protocol
#### **Interaction with Symbiotic Protocol**

The interaction between networks, middleware, and the Symbiotic protocol follows a specific flow:
* **Stake Management**: Networks interact with multiple vaults to:
* Receive stake delegations
* Set delegation limits
* Process slashing events
* Distribute rewards to stakers
* **Operator Management**: The middleware handles:
* Operator selection based on stake
* Validator set updates
* Performance monitoring and slashing conditions
#### **Middleware Development**

Building the network middleware from scratch can be challenging due to the complex responsibilities of managing operators, stakes, and security mechanisms while ensuring perfect reliability. Networks can rely on the [Relay SDK](https://github.com/symbioticfi/relay), a framework for executing and managing all these actions.
#### **Key Features of the Relay SDK**
* **Universal Attestation Framework:** Any data, any computation, any chain → one system for proof generation.
* **Verifiable on-chain:** Proofs are backed by staked validators, ensuring economic security.
* **Fully modular SDK:** Developers integrate using lightweight clients in Go, Rust, or TypeScript.
* **Chain-agnostic:** Works across L1s, L2s, and rollups; interoperable with all EVM chains. Cosmos support is available out of the box via a dedicated adapter.
* **Programmable & application-agnostic:** Plugs into any smart-contract workflow; attestations act as a generic trigger for programmable outcomes.
## **Operators**
Operators are entities running infrastructure for decentralized networks within and outside of the Symbiotic ecosystem. The Symbiotic protocol creates a registry of operators, logs interactions with the protocol, and protocol participants can attach credentials and other data to operator entities. In the initial version, this encompasses operator entity metadata provided by the operators themselves, as well as data created by interacting with the Symbiotic protocol, such as:
* Networks that the operator opted into
* Associated vaults and restaked collateral from vaults
* Historical logs of slashings and all other interactions with the Symbiotic ecosystem
An important benefit of the Symbiotic protocol and its enshrined vault system is the ability for operators to receive a stake from different partners (through vaults) to the same set of node infrastructure per supported network. This system allows node operators to acquire the stake from a diverse set of stakers with differing risk profiles without needing to set up isolated infrastructure for them.

In the future, we envision the Symbiotic protocol to contain a rich set of verifiable data and curated credentials about node operators. This will enable future networks using Symbiotic to source security for their use case to utilize innovative and maximally capital-efficient reputation-based operator selection mechanisms.
### **Network Integration**
An operator opts into a network in order to provide specific services. Each network independently decides whether to include that operator in the active set, based on criteria such as reputation, performance history, stake delegated to the operator, and any network specific requirements.
Operators can take different forms depending on the network. They may be node operators or validators that run the consensus algorithm for L1s, maintain network specific binaries, and produce or sign messages for bridging, oracles, and other middleware. They can also be strategy operators such as risk managers or AI agents whose task is to execute a defined DeFi strategy efficiently under the rules of the network. In all cases, once admitted, operators are responsible for meeting uptime, correctness, and security expectations, and failures can result in removal from the active set and slashing according to the network policy.
### **Slashing**
The operator’s stake becomes active and subject to slashing immediately after the opt-in process to both the network and the vault. However, the corresponding role in the vault can apply the timelock for allocating a stake for additional guarantees for operators. The slashing process is implemented in the vault’s Slasher module.
[See Slashing Details](/learn/core-concepts/slashing)
### **Rewards**
Operators provide services to networks, as discussed. This can include running consensus clients and other binaries, managing DeFi strategies, or operating offchain infrastructure that the network depends on. In return, they need to be compensated for the risk and operational effort they take. Networks pay operators using the revenues they generate from offering their services to external clients, from protocol fees, or from token inflation earmarked for security and operations. Symbiotic provides a flexible rewards framework that routes these payments to operators and stakers, so incentives align with the work being performed on each network.
[See Operator Rewards Details](/learn/core-concepts/rewards)
## **Rewards**
Symbiotic can be considered an exchange hub between basically 3 parties: stakers, operators, and networks.
* The stakers provide capital for the operators to use in favor of the networks
* The operators provide maintenance of the networks’ liveness in a valid manner
* The networks receive a security for their products depending on the economic side provided by the stakers and on the functioning side provided by the operators
Based on these exchange statements, it can be seen that the stakers and the operators provide services to the networks. Therefore, the networks are responsible for giving them something in exchange, and these are **rewards**.

### **Rewards Distribution**
Symbiotic Core contracts don’t contain the rewards logic enshrined. However, they provide enough data for external contracts to be able to create a rewards distribution, so anyone can create their own implementation of it.
Rewards can be divided into staker and operator rewards:
* The staker rewards can be provided depending purely on the provided stake’s value (the representation of value can differ from the standard $ view depending on alignment / token distribution / other factors)
* The operator rewards can be provided depending on the economic factors similar to the above ones and on the operators’ performance metrics (e.g., number of tasks completed / liveness / validators’ distribution)

We provide en extensive framework implementation to facilitate rewards distribution.
[See Rewards Integration Guide](../../../integrate/networks/rewards)
#### **Staker rewards**
Stakers provide the collateral that backs operators’ actions on each network. By depositing into a vault, they are taking on the risk that operators or networks may misbehave and that part of their stake could be slashed. In return, they should be compensated for supplying this economic security and for locking capital into a specific strategy or risk profile.
Networks pay stakers using the value they generate. This can come from protocol revenues such as fees and spreads, from payments made by external clients who consume the network’s services, or from token inflation that is explicitly allocated to security and growth. Through Symbiotic’s rewards contracts, these streams are routed back to stakers in a way that matches the vault’s configuration and the networks it secures.
#### **Operator Rewards**
Operators keep validators online, run middleware binaries, sign messages for bridging and oracle updates, or execute DeFi strategies on behalf of a network. Because they are spending time, capital, and operational effort to provide these services, they need to be compensated for them. Networks pay operators out of the value they generate, for example protocol fees, revenues from external clients that use their services, or token inflation allocated to operations and security.
Symbiotic’s rewards framework is flexible enough to route operator payments in different ways, for example:
* The network calculates rewards off chain and sends periodic batch transfers to operators.
* The network calculates rewards off chain and publishes a Merkle tree, allowing each operator to claim its own share.
* The network keeps reward accounting fully on chain inside its middleware and distributes rewards directly from that on chain state.
In every case, the goal is the same: make sure operators are paid in a way that matches the work they do and the risk they take.
## **Slashing**
Operators have stake assigned to them in each network they serve. Every network defines rules for correct behavior, such as producing valid blocks, signing messages only once per slot, or executing a strategy within specified limits. If an operator fails to perform these services according to the rules, the network middleware can raise a slashing request against them. On Ethereum, for example, this includes faults like double signing.
The Slasher module is an optional component of the Vault structure that handles the enforcement of slashing penalties. It doesn't perform slashings by itself but processes the requests received from the network middlewares.
### **How it Works**
In general, when a network fetches the stakes at some point in time, called the "capture timestamp", it receives the guarantee that the received amounts of collateral will be slashable during one epoch after it. Hence, the Slasher module always checks that the capture timestamp is not older than one epoch when executing the slashing.
In case of restaking, the guarantee might not be valid because of other networks' slashing. There is nothing to do about it because it's the nature of restaking itself.

Like the Delegator module, the Slasher module also has a types mechanic, where different Slasher types may be used for various purposes. Currently, there are two types (position indexes in the list below correspond to the on-chain types):
#### **0. Slasher**
This type performs an instant execution of the slashing request when received and validated. It is a simple and easy-to-understand implementation. However, it has too low flexibility compared with the next Slasher type.

#### **1. VetoSlasher**
VetoSlasher is a more complex type whose goal is to provide an in-house mechanism to handle a smooth transition for both networks and stakers from the just deployed versions of the networks to the battle-tested ones without additional development risks.
Its flow consists of three stages:
1. Request of the slashing, which is performed by the network middleware and validated by the VetoSlasher contract
2. Veto phase, whose duration is set during the vault's deployment, when the resolver (if set by the network) can veto the request
3. Execution of the slashing, which can be performed only by the network middleware if the veto was not issued

### **Burner**
Once slashing is approved and enforced, the actual processing of the affected stake is delegated to a configurable Burner contract. This contract determines what happens to the slashed tokens – whether they are unwrapped (e.g., from LSTs), burned, or even redistributed. For the example Burner, see the [wstETH unwrap / burn implementation](https://github.com/symbioticfi/burners/blob/main/src/contracts/burners/wstETH_Burner.sol).
## **Vaults**
A vault is the on chain container that holds collateral and connects it to networks. Each vault holds a single collateral token, keeps track of who has deposited and who can withdraw, and exposes the configuration points that let curators define how delegation, slashing, and rewards work. Delegation itself is purely an accounting layer: collateral stays inside the vault and only leaves when users withdraw or when a valid slashing event is executed.
### Core modules
Every Symbiotic vault is built from a small set of modules:
1. **Accounting (Vault)**: deposits, withdrawals, epochs, and penalties
2. **Delegation (Delegator)**: stake per network and per operator, based on curator policy
3. **Slashing (Slasher)**: checks and applies penalties requested by networks

### Accounting
#### Deposits
Any address that passes the vault access policy can deposit the collateral token. By depositing, a staker opts into that vault’s strategy and risk profile.
The vault:
* records the deposit
* updates the user balance and total active stake
* keeps collateral in the vault contract
Each vault uses a single collateral token. Multi asset exposure is achieved by using multiple vaults.

#### Withdrawals and epochs
Withdrawals use an epoch based flow. The goal is to let users exit while keeping operator stake stable inside each epoch.
At a high level:
1. A user submits a withdrawal request at any time.
2. The request becomes claimable after the end of the next vault epoch.
3. Until that epoch boundary, the requested amount is still eligible for slashing.
Epoch length is chosen at deployment and stays constant. Longer epochs give more time for networks to report misbehavior but make withdrawals slower. Shorter epochs make exits faster but leave less room for disputes.

### Delegation
Delegation is how a vault’s stake becomes effective security for networks and operators.
Curators:
* choose which networks the vault supports
* set limits or target shares per network and per operator
* select a Delegator type that matches the vault thesis
The Delegator looks at the vault active balance, which operators and networks opted into this vault, and the configured limits or shares. From this it returns how much stake a given operator has for a given network at a point in time.
Different Delegator types cover patterns like:
* one operator across many networks
* many operators inside one network
* multiple networks and multiple operators in a single portfolio
The vault holds collateral in one place. The Delegator decides how that collateral is counted as stake across Symbiotic.
### Slashing
When an operator breaks the rules, part of the vault collateral can be penalized.
Networks do not slash directly. They send a slashing request to the Slasher module that includes which network or subnetwork is affected, which operator is at fault, how much to penalize, and which snapshot this refers to.
The Slasher:
1. Checks that the request is fresh enough and consistent with the vault guarantees.
2. Verifies that there is enough stake tied to that snapshot to cover the penalty.
3. If valid, applies the penalty to vault balances and calls the configured Burner to decide where penalized collateral goes, for example a burn, redistribution to users, a treasury, or an insurance pool.
Some configurations apply valid slashes immediately. Others introduce a short review window where a resolver can veto or challenge.

### Rewards
Vaults do not hard code rewards. They only provide stake that secures networks and operators.
Each network decides:
* how stakers and operators are paid
* whether rewards come from fees, external clients, token inflation, or a mix
* which reward contracts or extensions they use
Symbiotic’s rewards framework gives networks standard ways to send value back to stakers, who provide collateral and take slashing risk, and to operators, who run the services the network depends on.
### Vault types
Vaults are configurable templates for different strategies and use cases.
Anyone who holds the collateral token can deposit, subject to any global caps the curator defines. These are usually used for broad, permissionless participation.
**Private vaults**
Only allowlisted addresses can deposit. LRT and LST providers, funds, or DAOs often run private vaults, aggregate user funds on their own balance sheet, and then allocate across several Symbiotic vaults on behalf of their users.
import GetInTouchButton from "../../../components/GetInTouchButton";
## Bridges and Cross-chain Messaging
### **Problem**
Cross chain protocols typically run isolated validator sets or oracle committees per route, which is expensive, slow, and does not scale. Costs grow with validator count, so verifying hundreds of operators on the EVM becomes prohibitive, while committee signatures and relayer hops add latency.
Security is fragmented because every bridge ships its own trust model and attack surface, and operators often have weak economic alignment with unclear slashing paths.
Finality differences across chains complicate safe verification, and each new chain or pair demands bespoke integrations, audits, and ongoing operations, creating vendor lock in and brittle user experience when messages are delayed or stuck.
### **Solution**
The Relay gives you one validation layer for everything: turn any cross-chain message into a **money backed, stake secured attestation** you can verify on any destination chain. You ship faster, spend less, and gain clearer guarantees.
Some of the Relay advantages can be found below:
* **Cheaper at scale.** BLS aggregation with optional ZK keeps EVM verify gas essentially flat, even with large validator sets.
* **Stronger security.** Attestations are backed by bonded stake with explicit slashing and configurable quorum.
* **Faster to market.** Lightweight client and SDK replace bespoke relayers and committees, reducing code and audits.
* **Portable across chains.** One attestation format, one verifier; add a chain by deploying the verifier and an adapter.
* **Works with existing stacks.** Thin adapters feed DVN, Hyperlane, governance, feeds, or your app logic.
* **Full control.** Customize validator sets, quorum thresholds, stake types and amounts, challenge windows, and slashing rules.
### **How it Works**
1. **Observe and package.** An event or message is observed on the source chain and packaged with block height, domain, nonce, and expiry.
2. **Attest and aggregate.** A configurable quorum of operators signs the package; signatures are aggregated with BLS and backed by bonded stake.
3. **Verify on destination.** The verifier contract checks quorum and weights, validates metadata, enforces replay and time bounds, and verifies the aggregate. With optional ZK, verification remains near constant in gas even as the validator set grows.
4. **Settle the outcome.** After verification, adapters execute the intended action: mint or burn, update a feed, trigger a bridge transfer, call governance or settlement, or hand a standard proof to DVN or Hyperlane. Each attestation emits a unique ID and events for auditability and monitoring.

### **Application Examples**
1. **Economic-secured bridge (DVN, ISM, etc.) for LSTs/stablecoins**
Asset issuers use their governance token as slashable collateral to secure bridging routes and enforce mint/burn discipline.
2. **Cross-chain collateralized lending**
Let users borrow on Chain A while holding collateral on Chain B, with Relay attestations guaranteeing state and liquidations.
3. **Canonical mint/burn across rollups**
Fast, verifiable attestations to burn on the origin and mint on the destination to keep a single canonical supply for tokens.
4. **Cross-chain governance execution**
Pass a proposal on the home chain and execute upgrades or parameter changes on connected chains via attested messages.
5. **DEX settlement & order routing**
Attest trade fills or intent resolutions on one chain and finalize accounting on another without custom oracles.
6. **NFT & identity portability**
Verifiably transfer ownership/metadata across chains for collections, game items, or credentials.
7. **Cross-chain payments & payouts**
Batch attest deposits/withdrawals to move balances instantly between chains for wallets, fintech, and exchanges.
### References
* [Bridges Cross Chain Networks](https://www.notion.so/Bridges-Cross-Chain-Networks-28b81c079c178048aa47caed85bcdbc9?pvs=21)
* [Build DVN backed by Symbiotic’s Economic Security Framework](https://www.notion.so/Build-DVN-backed-by-Symbiotic-s-Economic-Security-Framework-27081c079c1780c185dee9212d1702b3?pvs=21)
* [Github Relay Contracts](https://github.com/symbioticfi/relay-contracts)
## Chain Agnostic Applications
### **Problem**
Cosmos appchains often spin up bespoke validator sets, multisigs, or IBC-only paths per use-case (governance messages, bridges, feeds). Each new route brings another committee, relayer and audit. Latency creeps in through off-chain hops; costs grow with validator counts; and security fragments across custom trust assumptions. Meanwhile, CometBFT finality and slashing exist, but slashing paths for cross-chain outcomes are typically indirect or out-of-band, and every extra chain or pairing demands new glue code and operations.
### **Solution**
Relay gives Cosmos chains a single validation layer for cross-chain outcomes: turn any source-chain event into a stake-secured attestation that you can verify natively on your Cosmos app (module or contract) and act on immediately.
Why this is a fit for Cosmos:
* **Cheaper at scale.** BLS aggregation (and optional ZK) keeps on-chain verify cost near-constant, even as the operator set grows → useful when verifying large, Ethereum-sourced validator sets on a Cosmos chain.
* **Clearer guarantees.** Attestations are backed by bonded stake and explicit slashing rules in Symbiotic; you set the quorum and weights that must sign.
* **Faster to production.** A thin Cosmos adapter (native module or contract) replaces ad-hoc relayers / committees; you deploy a single verifier and wire it to your app logic.
* **Portable across stacks.** One attestation format, many destinations → verify on a Cosmos chain today and an EVM rollup tomorrow with the same cryptographic proof.
* **Works with IBC.** Keep using IBC where it shines; feed Relay attestations into modules that need Ethereum (or other) state with explicit slashable guarantees, or hand the proof to existing routing / governance logic.
* **Operator control.** Customize validator sets, quorum thresholds, stake types, challenge windows, and slashing rules per appchain or per route.
### How it Works
1. **Observe & package.** Off-chain Relay nodes watch a source chain (EVM or Cosmos), pick up your event / message, and package it with `{source domain, block/height, nonce, expiry}`.
2. **Attest & aggregate.** A configurable quorum of operators signs; signatures are aggregated with BLS and linked to bonded stake in Symbiotic.
3. **Verify on Cosmos.** Your Cosmos app verifies the attestation through a light verifier (part of the example in `cosmos-relay-sdk/simapp`), checking weights / quorum, metadata, replay protection, and the aggregate signature. With optional ZK, verify cost remains flat as the set grows.
4. **Settle the outcome.** After verification, an adapter module executes: mint / burn, update a price / feed, finalize a bridge transfer, trigger governance, or emit an event for downstream modules - exactly like your EVM adapters, but idiomatic for Cosmos.

### Application Examples
1. **Secure your L1 consensus at genesis (no bootstrap from 0)**
Launch without resorting to a centralized multisig or a tiny, weak validator set. Your chain imports slashable economic security directly from a Symbiotic vault: the Relay delivers an attested operator set and weights; your adapter maps those weights to consensus voting power and emits `ValidatorUpdates`. Mis-attestations are slashable at the vault, so security is real on day one - no “trust us until we decentralize” phase.
**Why it matters**: you avoid the bootstrapping trap, ship safely on day 1, and can
progressively add native stake over time (dual-sourcing security or switching entirely when
ready).
2. **Canonical mint / burn across two Cosmos L1s**
Keep a single canonical supply without bespoke multisigs. Burns on Chain A are attested via Relay; your adapter on Chain B verifies and mints, with nonces / expiries for replay protection.
3. **DEX settlement & intent routing across Cosmos L1s**
Resolve on Chain A, finalize accounting on Chain B. The adapter verifies once and updates balances / positions in your DEX or settlement module.
4. **Cross-domain oracle / State feeds into a Cosmos module**
Import external state (e.g., LST rates, rollup headers) into a Cosmos oracle with explicit, slashable guarantees and sane expiries / challenge windows.
import GetInTouchButton from "../../../components/GetInTouchButton";
## Decentralized Compute and AI Verification
### **Problem**
Decentralized compute today is **costly, brittle, and easy to game**. Most systems rely on ad-hoc coordinators, TEEs, or multisig committees that don’t provide chain-agnostic, slashing-enforced guarantees. Notable shortcomings include:
* **High cost:** bespoke committees/light clients per network, many sig verifications on-chain, custom relayers, repeated audits, and over-provisioned capacity drive unit economics up.
* **Attack surface:** forged results, equivocation (conflicting outputs), replay of old results, censorship/withholding, collusion among runners, coordinator DoS, key compromise, MEV/front-running on result publication, and TEE quote spoofing without on-chain anchoring.
* **Weak incentives:** runners often have little or no bonded stake; slashing paths are unclear or social, so bad behavior is cheap.
* **Operational opacity & lock-in:** logs and receipts are off-chain/opaque, integrations are bespoke per chain or vendor, and portability is poor.
### **Solution**
Relay turns each off chain computation, including container jobs, into a stake backed, verifiable receipt. These receipts can be checked on chain and, once approved, automatically trigger payments, unlocks, or workflow steps. There are no custom committees or heavy coordination, only clear proof that a job was done, with built in penalties for cheating or missed deadlines, lower costs at scale, and portability across any cloud or chain.
Some of the Relay advantages can be found below:
* **Usage-based, provable billing:** verifiable receipts include runtime/metrics so you can meter, invoice, and settle on-chain per job or per epoch.
* **SLA enforcement:** late, missing, or conflicting results are objectively slashable; clients get deterministic inclusion and dispute windows.
* **Lower verification cost:** aggregate many job receipts once per epoch → one on-chain verify for hundreds/thousands of tasks.
* **Input/Output integrity:** bind container image digest, parameters, data CIDs, and output/artifact hashes into the receipt to prevent tampering or replay.
* **TEE or ZK, your choice:** attach a TEE quote hash or a zk proof of execution when available; Relay’s stake guarantees still secure the base path.
* **Multi-cloud portability:** same receipt format and Verifier across L1s/rollups; run workers on any infra (K8s, bare-metal, cloud) without vendor lock-in.
* **Fair marketplace for runners:** bonded operators with reputations and slashing create credible supply; optional per-capability whitelists (GPU, RAM, CUDA).
* **Composable callbacks:** post-verify adapters can release escrow, mint compute credits, advance workflows, or trigger subsequent jobs.
### How it Works
1. **Register and bond**: Operators enroll for the compute task, publish keys and capabilities, and lock stake that can be slashed.
2. **Submit job**: The client posts a job with an input commitment that binds image or runtime, parameters, and data.
3. **Execute off chain**: A worker runs the job. A small Sidecar measures runtime and resources, and derives an output commitment for results and artifacts.
4. **Attest**: Operators sign a job receipt that includes task id, job id, input hash, output hash, metrics, epoch, and nonce. Receipts can also include a TEE quote hash or a zk proof.
5. **Aggregate**: Receipts are BLS-aggregated and optionally batched per epoch to amortize costs.
6. **Verify on chain**: The Verifier contract checks quorum, stake weight, freshness, and anti-replay.
7. **Trigger action**: After verification, an Adapter releases escrow or payment, mints compute credits, advances a workflow, or calls back the app.
8. **Challenge and slash**: Within the challenge window anyone can submit evidence of fraud, equivocation, replay, or missed SLA. Proven faults slash operator stake and can revert or remediate actions per policy.

### Application Examples
1. **AI inference marketplace**
Each inference container runs a Relay Sidecar that signs an attestation with: model ID/version, input hash, output hash, latency, and compute meter. Buyers verify the attestation on-chain before releasing payment; misbehavior can be slashed against the operator’s staked collateral.
2. **Model training and fine-tuning**
Trainers emit Relay attestations at checkpoints (per epoch or per N steps) containing dataset/version hashes and metrics (loss/accuracy). Milestone payouts stream only when the on-chain verifier accepts the attested checkpoint; failed or missing checkpoints pause funding and can trigger slashing.
3. **ZK prover network**
Prover nodes attach Relay to the proving container. When a proof is generated, the Sidecar signs an attestation with the proof commitment and job ID. The consumer contract verifies both: (1) the proof itself and (2) the Relay signature tied to a bonded operator, then releases payment atomically.
4. **Indexing and ETL pipelines**
Indexers process ranges (e.g., blocks 10M–10.1M) and emit Relay attestations with range coverage, schema version, and result checksum. Consumers (subgraphs, data apps) pay per attested range and can reconstruct a full index by verifying a sequence of signed ranges from a quorum.
5. **Edge Compute**
Edge devices process shards of a job and sign shard-level Relay attestations (shard ID, input/output hashes, timing). An aggregator contract verifies a threshold of shard attestations, reconstructs the job result, and then settles payments pro-rata; faulty shards are isolated and penalized.
### References
* [Cloud Compute Decentralized Docker](https://www.notion.so/Cloud-Compute-Decentralized-Docker-28b81c079c1780f59256daa4e8b090c9?pvs=21)
* [Relay Collateral](https://www.notion.so/Relay-Collateral-28b81c079c1780bb99e7e7cf66a0e15f?pvs=21)
* [Github Relay Contracts](https://github.com/symbioticfi/relay-contracts)
import GetInTouchButton from "../../../components/GetInTouchButton";
## General Attestation Layers
### **Problem**
Off-chain agents and many L2 systems do not have a native trust layer. You cannot easily prove that a check was performed, a condition held true, or a message is safe to act on. Current approaches are permissioned, costly to extend, and lack clear economic guarantees or dispute paths.
### **Solution**
Relay lets any agent or system produce a **stake-backed, verifiable attestation** about external state or completed actions. Attestations are checked on chain for quorum, freshness, and consistency, and bad behavior is slashable. Once verified, adapters can trigger actions such as mint, transfer, unlock, vote, or update state. One receipt format and one verifier work across L1s and rollups, so you can add new domains without rebuilding trust from scratch.
### How it Works
1. **Register and bond.** Agents or operators enroll for a task and lock stake that can be slashed.
2. **Define the condition.** Specify what must be checked, the cadence or event trigger, and the dispute window.
3. **Observe and decide.** Agents perform the check or computation and determine the outcome.
4. **Attest and aggregate.** Agents sign the result with timing and context, and signatures are combined into one proof.
5. **Verify on chain.** A verifier checks quorum, stake weight, freshness, and anti-replay.
6. **Trigger action.** An adapter executes the approved action or writes the result for other contracts to consume.

### Application Examples
1. **L2 fast finality**
Operators attest that an L2 block or batch is safe after specific checks, giving near-instant usable finality for bridges and apps while full finality catches up.
2. **Autonomous agent receipts**
AI or automation agents attest to tasks they performed such as compliance checks, data validation, or workflow steps, unlocking funds or advancing pipelines only when receipts pass verification.
3. **Uptime and SLA monitors**
Watchdogs attest liveness and performance of services such as sequencers or keepers and automatically apply penalties, rebates, or failover when thresholds are missed.
4. **Decentralized sequencer**
A set of bonded operators attest that a given L2 block or batch is available, correctly ordered, and built under the declared rules. The attestation is stake-backed and verified on chain, then a small adapter accepts the batch, releases bridge messages, or advances state. Misbehavior such as equivocation, censorship beyond policy, invalid ordering, or missed slots can be disputed and slashed. You also get usable fast-finality receipts for bridges, liveness SLAs with automatic failover, and optional hooks to enforce fairness policies (e.g., inclusion lists or MEV limits) via the same attestation flow.
5. **Circuit-breaker signals**
Publish slash-backed alerts for depeg risk, abnormal volatility, or halted markets that protocols use to tighten limits or pause actions.
### References
* [General Attestation Layers](https://www.notion.so/General-Attestation-Layers-28b81c079c178072af48f99f444266c6?pvs=21)
* [Relay Collateral](https://www.notion.so/Relay-Collateral-28b81c079c1780bb99e7e7cf66a0e15f?pvs=21)
import { Card2 } from "../../../components/Card2.tsx";
## Use Cases
Symbiotic's shared security and Relay attestation layer enable a wide range of protocols. Explore a few high-impact patterns below.
import GetInTouchButton from "../../../components/GetInTouchButton";
## Liquidity Management
### **Problem**
Overcollateralized designs trap capital and do not scale. Many eligible assets, especially RWAs, are illiquid or settle slowly, so redemptions either take a haircut through discounts and slippage or require waiting through withdrawal periods.
### **Solution**
Symbiotic lets you unlock the liquidity already sitting in the Symbiotic vault and turn it into production credit. No new collateral posted upfront. You get capital efficiency on day one while keeping real economic guarantees because the vault can be slashed if policy is breached.
For stablecoin issuers and lending markets this means instant liquidity for otherwise illiquid RWAs and smoother redemptions without forced discounts. For intent and execution use cases this means you can run the action now and settle later with a clear rebalance window. Fees flow to the operator on verified completion and the system enforces that the vault balance is restored on time, or slashing applies. The result is more volume, faster time to market, and stronger trust with borrowers and regulators since every action is covered by stake secured guarantees.
Symbiotic can also help bridge policy across chains through the Symbiotic Relay. It carries the attestation from the chain where users deposit to the chain where they receive access, so you can originate on any network and serve users everywhere with one verifier and one format. Add a new chain by deploying a thin adapter and keep your existing issuer or lending stack unchanged.
In short, Symbiotic turns idle vault liquidity into safe productive credit, gives you instant usability for slow to settle assets, and backs every promise with real money at risk.
### How it Works
Here’s the exact flow for Symbiotic using the Relay SDK for epoch management:
1. The network defines the vault to draw from, the rebalance window, and the payment rules.
2. The network slashes the Symbiotic vault to access liquidity for the action.
3. Liquidity is used for the intended purpose, to early-redeem illiquid RWAs or to fulfill an intent.
4. The associated operator executes the intent, and funds are delivered to the user

5. The network manager or operator rebalances the Symbiotic vault by adding the collateral deposited by the user when expressing the intent.
6. The operator produces an attestation that the intent was executed and the user received the funds.
7. The settlement contract verifies the attestation and receives the current vault state for collateral valuation in the same epoch.
8. If policy is satisfied, the contract triggers payment to the operator or solver.
9. If policy fails or the restore window is missed, the operator or solver is slashed. If they have a protection layer in another Symbiotic vault, slashing is applied there according to policy.

### Application Examples
1. **Intent Fulfillment**
An application or network needs to execute a user intent, for example settling an order, bridging a payment leg, or performing a market action, without waiting for fresh collateral. The network designates a Symbiotic vault as the backstop, sets a restore window and payment rules, and draws liquidity by slashing the vault to execute the intent immediately so the user receives the funds or outcome.
The associated operator then produces an attestation that the intent was executed correctly and on time. The settlement contract verifies the attestation and, before the epoch ends, the manager or network admin replenishes the vault.
If everything checks out, the contract releases the operator fee. However, if the proof is missing, late, or inconsistent with the vault state, the operator is slashed. If the operator has a protection layer in another Symbiotic vault, slashing is applied there according to the configured rules.
2. **Illiquid RWA Early Redemption**
A stablecoin issuer or lender faces a redemption request while part of the reserves sit in illiquid or slow-to-settle RWAs. Instead of forcing users to wait through withdrawal periods, the issuer taps the Symbiotic vault as a secured liquidity buffer. The network defines the qualified vault, the maximum early redemption headroom, a restore window aligned to the RWA settlement horizon, and the fee model. Liquidity is drawn from the vault to pay the user immediately, in return for a small fee.
An operator or designated agent executes the redemption flow and produces an attestation that the user received funds. The settlement contract verifies the attestation and, before the epoch ends, reads the current vault state to confirm the required collateral is present for that same epoch. The network manager must deposit the funds back into the Symbiotic vault before the epoch ends; once that balance is observed in-epoch, the contract releases the operator’s fee and the restore window closes. If the deposit is not observed before epoch end, slashing applies to the responsible party or their protection layer.
### References
* [Relay Collateral](https://www.notion.so/Relay-Collateral-28b81c079c1780bb99e7e7cf66a0e15f?pvs=21)
import GetInTouchButton from "../../../components/GetInTouchButton";
## Oracle Networks and Data Feeds
### **Problem**
Most oracle systems are rigid and permissioned, with fixed committees and bespoke integrations per chain. Expanding coverage is expensive, updates can be slow or stale, and manipulation risk remains due to weak incentives, limited slashing, MEV at publication time, and unclear dispute processes. Portability across chains is poor and auditability is fragmented.
### **Solution**
Relay acts as a **universal oracle engine**. Any approved operator can fetch off-chain data and produce a **stake-backed attestation** that is:
* **Verifiable on chain** with BLS aggregation and anti-replay.
* **Backed by bonded validators** with explicit slashing for bad data, equivocation, or missed SLAs.
* **Programmable** via schemas for prices, TWAPs, risk scores, proof-of-reserves, or custom metrics.
* **Cheaper at scale** by batching many feed updates into one verification.
* **Composable across EVMs** and compatible with CCIP-style routing through thin adapters.
* **Auditable** with on-chain receipts and clear freshness guarantees.
### How it Works
1. **Register and bond.** Operators join the feed and lock stake as collateral.
2. **Define the feed.** You set what data to track, how often to update, how to combine sources, and the service levels.
3. **Collect and compute.** Operators fetch data from chosen sources and calculate the feed’s current value.
4. **Attest.** Each operator signs the result with timing and round details.
5. **Aggregate.** The signatures are combined into a single proof for that update window.
6. **Verify on chain.** A verifier checks that enough staked operators signed, the update is fresh, and it is not a replay.
7. **Publish or trigger.** The value is written on chain or passed to protocols that use it.
8. **Dispute and slash.** If an update is wrong, late, or inconsistent, anyone can dispute within a window and dishonest operators are slashed.

### Application Examples
1. **DeFi price feeds**
Pull quotes from major CEX and DEX venues, compute a median or short TWAP with venue weighting and outlier filters, then attest the value with a timestamp and deviation flag. Set a heartbeat and a max staleness window so lending and perp engines only accept fresh rounds. If an attested value is outside the allowed deviation band or uses stale sources, operators are slashable and the adapter will refuse the update.
2. **Perp funding and index price**
Define an index basket per asset, sample every few seconds, and publish round values on a fixed cadence. Funding is derived from index minus mark with clamps and a rolling window, then attested and verified on chain so funding transfers and insurance accounting execute deterministically. Any missing interval or conflicting rounds within the window is disputable and can lead to slashing.
3. **Proof of reserves**
Bonded operators produce a **stake-backed, verifiable attestation** of total reserves versus circulating liabilities, with timestamp, heartbeat, and deviation guards. The attestation is checked on chain for quorum and freshness; misreporting, conflicting rounds, or missed SLAs can be **slashed** against bonded collateral. After verification, adapters gate mint and burn so supply cannot exceed attested reserves, pause on staleness, and record every round for auditability.
4. **LST risk score**
Compute a composite score from on chain metrics such as pool depth, oracle deviation to spot, withdrawal queue length, historical depeg distance, and validator set concentration. Publish the score on a regular cadence with thresholds that protocols map to collateral factors or caps. Large moves require multiple consecutive rounds to prevent whipsaw, while clear breaches can immediately tighten risk parameters.
5. **NFT floor price**
Aggregate bids and sales from leading marketplaces, remove wash trades and self matches, and compute a robust floor using median of top bids with liquidity filters. Per collection feeds are attested with collection id, floor, and liquidity score; NFT backed lending vaults use the value with conservative haircuts and a freshness check. If market data is thin, the adapter can hold the last good value until quorum resumes.
6. **CCIP routing data**
Publish per chain gas prices, route health, and token exchange rates that cross chain routers consume to select paths and set fees. Attest route liveness and recent failure counts so routers can avoid degraded links. Deviation guards and freshness windows ensure routers never act on stale or manipulated signals.
### References
* [Oracles Data Feeds](https://www.notion.so/Oracles-Data-Feeds-28b81c079c1780d284fff271a7b9e7f0?pvs=21)
* [EXTERNAL GUIDE Symbiotic Relay SDK](https://www.notion.so/EXTERNAL-GUIDE-Symbiotic-Relay-SDK-1f981c079c17802090f6db09a4b7b7e2?pvs=21)
import { AddressWithCopy } from "../../../components/AddressWithCopy";
import { OpenActionButton } from "../../../components/OpenActionButton";
## Addresses
A comprehensive list of Symbiotic official smart contract deployments.
### Core
:::code-group
:::
## **Analytics**
Symbiotic exposes a set of public dashboards that track the protocol’s growth, rewards, and users in real time. This page aggregates the main views so teams can quickly monitor what matters without rebuilding queries from scratch.
All dashboards are updated live and can be filtered by time range, chain, vault, or other parameters directly in the UI.
### 1. Protocol overview
#### 1.1 Core protocol stats
**Dashboard:** [https://dune.com/symbiotic/symbiotic-core-stats](https://dune.com/symbiotic/symbiotic-core-stats)
This view is the main entry point for Symbiotic protocol health. It typically includes:
* Total value locked (TVL) across all vaults
* Distribution of TVL by collateral, vault type, and chain
* Number of active vaults, networks, and operators
* Historical evolution of TVL and activity over time
Use this dashboard to answer questions like:
* How fast is Symbiotic growing?
* Which assets and vaults are driving most of the TVL?
* How many networks and operators are active at any point in time?
#### 1.2 Network analytics
**Dashboard:** [https://analytics.symbiotic.fi/](https://analytics.symbiotic.fi/)
This analytics workspace provides a more granular breakdown of networks consuming Symbiotic security, including:
* Per-network secured value / stake backed by Symbiotic
* Restaking ratios and economic security per network
* How stake is sourced (which vaults and collaterals back each network)
* Network activity over time (captures, attestations, messages, etc., depending on integration)
It’s the right place when you need per-network views rather than aggregate protocol numbers—for example, to see how much security a specific network is consuming and how that evolves over time.
### 2. Rewards
#### 2.1 Rewards paid via Symbiotic
**Dashboard:** [https://dune.com/symbiotic/symbiotic-rewards](https://dune.com/symbiotic/symbiotic-rewards)
This dashboard tracks how rewards flow through the protocol:
* Total rewards paid over time
* Rewards by vault and by network
* Breakdown by asset / reward token (e.g. native tokens, points, incentives)
* Historical reward schedules and emission trends
Use this to:
* Understand which vaults or networks are currently incentivized
* Compare reward intensity across different configurations
* Monitor the effectiveness of incentive programs over time
### 3. Users and stakers
#### 3.1 Symbiotic stakers overview
**Dashboard:** [https://dune.com/symbiotic/symbiotic-users](https://dune.com/symbiotic/symbiotic-users)
This dashboard focuses on user behavior and the staking side of the protocol:
* Number of unique stakers interacting with Symbiotic
* Growth of new addresses over time
* Distribution of stake per user (small vs large stakers)
* Activity across chains and vaults
It gives a high-level picture of how broad and diversified the staker base is.
#### 3.2 New vs. returning users (point 2.1)
**Dashboard section:** see section 2.1 on [https://dune.com/symbiotic/symbiotic-users](https://dune.com/symbiotic/symbiotic-users)
This section highlights:
* New stakers entering the protocol in each time period
* Returning stakers that continue to deposit, restake, or interact
* Basic retention dynamics (how many users come back after their first interaction)
This view is useful for:
* Measuring how well incentive programs convert into long-term stakers
* Understanding if growth is driven mostly by net-new users or by existing users increasing positions
* Tracking the “stickiness” of the protocol over time
***
If you need, we can later add more specialized dashboards here (e.g. per-network analytics, specific vault families, or integration-specific views) and group them under additional sections.
import { Entity } from "../../../components/Entity";
import { ReportActions } from "../../../components/ReportActions";
## Audits - Security Reviews
| Auditor | Scope | Date | Report |
| ------------------------------------------------- | ----------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| | [Relay Contracts](https://github.com/symbioticfi/relay-contracts) | 09-2025 | |
| | [Relay Contracts](https://github.com/symbioticfi/relay-contracts) | 09-2025 | |
| | [Relay Contracts](https://github.com/symbioticfi/relay-contracts) | 07-2025 | |
| | [Relay Contracts](https://github.com/symbioticfi/relay-contracts) | 05-2025 | |
| | [Relay Contracts](https://github.com/symbioticfi/relay-contracts) | 05-2025 | |
| | [Network](https://github.com/symbioticfi/network) | 09-2025 | |
| | [Network](https://github.com/symbioticfi/network) | 09-2025 | |
| | [Network](https://github.com/symbioticfi/network) | 07-2025 | |
| | [Core](https://github.com/symbioticfi/core) | 09-2024 | |
| | [Core](https://github.com/symbioticfi/core) | 09-2024 | |
| | [Core](https://github.com/symbioticfi/core) | 09-2024 | |
| | [Core](https://github.com/symbioticfi/core) | 08-2024 | |
| | [Core](https://github.com/symbioticfi/core) | 07-2024 | |
| | [Core](https://github.com/symbioticfi/core) | 06-2024 - 12-2024 | |
| | [Rewards V1](https://github.com/symbioticfi/rewards) | 09-2024 | |
| | [Rewards V1](https://github.com/symbioticfi/rewards) | 08-2024 | |
| | [Rewards V1](https://github.com/symbioticfi/rewards) | 06-2024 - 12-2024 | |
| | [Burners](https://github.com/symbioticfi/burners) | 08-2024 | |
| | [Hooks](https://github.com/symbioticfi/hooks) | 08-2024 | |
| | [Periphery](https://github.com/symbioticfi/periphery) | 08-2024 | |
| | [Legacy Vaults](https://github.com/symbioticfi/collateral) | 05-2024 | |
| | [Legacy Vaults](https://github.com/symbioticfi/collateral) | 04-2024 | |
import { Entity } from "../../../components/Entity";
import { OpenActionButton } from "../../../components/OpenActionButton";
## **Ecosystem**
### Networks
### Curators
### Operators
## **Points Program**
Symbiotic Points reward participants that provide useful economic security through the protocol. They are earned by depositing collateral into vaults and, in Season 2, by delegating that collateral to secure networks.
You can view your points by connecting your wallet at `https://app.symbiotic.fi`. If you participate through wrappers such as LRTs, some or all of your points may be shown in the provider’s own interface instead of the Symbiotic app.
Participation in the Points Program is subject to Symbiotic’s Terms of Use, Points Program Terms, and Risk Factor Disclosure Statement.
### Seasons
#### Season 1: Pre-Deposit phase
Season 1 covers the initial rollout of Symbiotic from June 2024 until the deployment of feature complete core contracts on Ethereum mainnet.
During this phase, Pre-Deposit (default collateral) vaults were deployed for assets such as wstETH, mETH, wBTC and others. These vaults did not yet delegate stake to networks. Depositors earned points based mainly on the size and duration of their collateral. Over this period, Pre-Deposit vaults accumulated roughly 2B USD of TVL.
#### Season 2: Actively delegated stake
Season 2 starts with the mainnet deployment of core contracts. From this point, vaults can be deployed that delegate collateral to operators on Symbiotic networks.
Season 2 is designed as a transition from idle collateral into fully deployed security. The key changes are:
* Delegated collateral earns a higher points rate than idle collateral in Pre-Deposit vaults
* Points for Pre-Deposit vaults continue at a lower rate and are intended to phase out over time
* Depositors are encouraged to move into actively delegated vaults curated by LRTs, operators, institutions and network foundations
If you use Symbiotic via an LRT, your provider may manage this migration on your behalf. If you deposit directly, the Symbiotic app guides you through moving from Pre-Deposit vaults to actively delegated vaults.
### Who Earns Points
Points are assigned on a per-network basis and then split across three groups:
1. The network itself
2. Operators on that network
3. Vaults that delegate stake to the network and their depositors
Networks can receive up to 5% of total allocated points, while allocating another up to 5% to operators. The remaining points go to vaults, where curators can charge an additional admin fee of up to 5%, with the rest distributed to depositors pro rata to their share of the vault’s TVL.
This ensures that all contributors to shared security are rewarded, while the strongest incentives remain aligned with staked capital.

### How Points Are Calculated in Season 2 and Points 2.1
Points 2.1 refines Season 2 by tying rewards more tightly to how capital is actually deployed and how safely it is used.
At a high level, each network receives:
`
Points per hour = NetworkStake × PointsRate × 0.001`
`PointsRate = MiningRate × SecurityRate`
Everything is computed per network, then split to networks, operators, and vaults as described above.
#### Mining Rate: stake relative to target
Each network has a target stake, in USD terms. This is the amount of collateral that is considered appropriate for its security needs.
* When a network is below its target stake, the mining rate is high and each extra unit of stake earns close to the maximum number of points
* As the network approaches and exceeds its target, the mining rate is reduced so additional stake earns fewer or no extra points
This discourages over-staking on a single network purely for points and helps push capital toward networks that still need security.

#### Security Rate: how stake is used and distributed
The security rate measures how risk aware a network’s stake is. It combines two ideas:
1. Restaking score of the underlying vaults
2. How decentralised stake is across those vaults
#### Restaking score
Restaking is measured as the ratio between:
`Restaking ratio = Total delegated stake of the vault / Vault TVL`
A higher ratio means the same collateral is used to secure more networks. This can be capital efficient, but also increases potential correlated slashing risk.
Points 2.1 uses a target restaking ratio (currently 3). Around this ratio, the restaking score is high. When a vault’s ratio climbs significantly above this, its restaking score falls quickly. This affects both:
* The network’s security rate if it relies heavily on that vault
* The vault’s own share of points from the network, since vault rewards are multiplied by their restaking score

#### Stake decentralisation across vaults
To avoid having one vault dominate a network’s security, Points 2.1 uses a decentralisation score derived from the complement of the Herfindahl–Hirschman Index. It ranges from 0 (all stake effectively in a single vault) to 1 (stake spread across many vaults).
The security rate is a stake-weighted combination of restaking scores and this decentralisation score. Networks that rely on sane restaking and multiple vaults earn a higher security rate and therefore more points for the same amount of stake.
### Vault Behaviour and Delegation
From the perspective of a depositor, the main rules are simple:
* Points are only accrued on collateral that is actively delegated from a vault to networks
* The effective points per unit of collateral depend on how much of the vault’s TVL is delegated, how many networks it supports, and how aggressive its restaking ratio is
This implies:
* A well-utilised delegated vault will generally earn more points than a Pre-Deposit vault
* A vault that barely delegates, or that is very concentrated on a single network, may earn fewer points than a better balanced alternative
* A vault that pushes its restaking ratio far above the target can see its points reduced, even if it holds a large TVL
The Symbiotic app shows vault-level information such as TVL, delegated stake, and expected points, to help depositors choose where to allocate collateral.
### Pre-Deposit Vaults and Migration
Season 1 Pre-Deposit vaults remain part of the system in Season 2, but with reduced incentives. They continue to earn points at a lower rate for a transition period. Over time, rewards are intended to shift more fully toward vaults that actively delegate stake to networks.
A typical migration path for a direct depositor is:
1. Withdraw or migrate from a Pre-Deposit vault
2. Deposit into an Actively Delegated vault
3. The curator allocates stake from that vault across one or more networks
4. Points accrue based on delegated stake and each network’s points rate under Points 2.1
Wrappers and LRTs may perform equivalent steps internally for their users.
### Tracking Your Points
You can track your points directly in the Symbiotic app by connecting your wallet.
For a more detailed view under Points 2.1, including how your capital is distributed across networks and vaults and how that affects your effective points rate, you can also use the Symbiotic Points dashboards on Dune.
import { Card1 } from "../../../components/Card1.tsx";
import { Card2 } from "../../../components/Card2.tsx";
## Developers Hub
### Integrate
import { Details } from "../../../components/Details";
import { Card1 } from "../../../components/Card1";
## Relay Quickstart
Symbiotic Super Sum spins up a relay network that runs simple sum computations. Schedule a job
on any supported chain and the result is posted to every supported destination chain.
The `symbiotic-super-sum/` directory is created and includes initialized submodules.
### Generate Network Configuration
Generate the local network definition and helper artifacts Docker uses to start the stack.
```bash [bash]
./generate_network.sh
```
The script prompts for operator counts and creates a new `temp-network/` directory with `docker-compose.yml` and writable data directories.
### Start Network
Launch the Anvil chains, deployer, and relay services defined in the generated Compose file.
```bash [bash]
docker compose --project-directory temp-network up -d
```
This command launches the network services in Docker containers.
```bash [Expected output]
symbiotic-super-sum % docker compose --project-directory temp-network up -d
[+] Running 9/9
✔ Network temp-network_symbiotic-network Created 0.1s
✔ Container symbiotic-anvil-settlement Healthy 4.2s
✔ Container symbiotic-anvil Healthy 4.2s
✔ Container symbiotic-deployer Exited 128.5s
✔ Container symbiotic-genesis-generator Exited 138.2s
✔ Container symbiotic-relay-1 Started 138.4s
✔ Container symbiotic-relay-2 Started 138.4s
✔ Container symbiotic-sum-node-1 Started 138.6s
✔ Container symbiotic-sum-node-2 Started
```
This creates a task for the network, which later collects the required number of attestations and broadcasts the result to every supported destination chain
### Verify Task Result
It is possible to verify result on the first chain:
:::
---
## /integrate/networks/pre-deposit
import { Card1 } from "../../../components/Card1";
# Deploy Pre-deposit Vault
In some cases the Network may want to curate or deploy the Vaults by itself, for example:
- A DAO-controlled Vault with native Network asset used as a collateral
- A Network needs a specific configuration of the Vaults to proceed with their onboarding
The Vault deployment guide is available [inside the section for Curators](/integrate/curators/deploy-vault).
## Next Steps
}
href="/integrate/networks/rewards"
/>
---
## /integrate/networks/register-network
import { Card1 } from "../../../components/Card1";
# Register Network
To start the journey within the Symbiotic system, you should register your Network using `NetworkRegistry` smart contract. The registered address should be meant as a management address that will interact, e.g., with Symbiotic Vaults to accept stake allocations.
To simplify this step and make the management process more secure we provide [network repository](https://github.com/symbioticfi/network) that contains `Network.sol` contract and tooling to manage it. Basically, `Network.sol` contract is an [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 either `(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 repository's deployment scripting currently supports 2 scenarios:
1. Currently, only a Network is needed, while the opt-ins to Vaults are going to be handled later
2. A Network with Vaults' opt-ins is needed
:::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), you will see config like this:
```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 needed fields, and execute the script via:
```bash [bash]
forge script script/DeployNetwork.s.sol --rpc-url --private-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), you will see config like this:
```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 needed fields, and execute the script via:
```bash [bash]
forge script script/DeployNetworkForVaults.s.sol --rpc-url --private-key --etherscan-api-key --broadcast --verify
```
:::
## Manage Your Network
There are 5 predefined action-scripts, that you can use from the start:
- [SetMaxNetworkLimit](https://github.com/symbioticfi/network/blob/main/script/actions/SetMaxNetworkLimit.s.sol) - set new maximum network limit for the vault
- [SetResolver](https://github.com/symbioticfi/network/blob/main/script/actions/SetResolver.s.sol) - set a new resolver for the vault (only if the vault uses VetoSlasher)
- [SetMiddleware](https://github.com/symbioticfi/network/blob/main/script/actions/SetMiddleware.s.sol) - set a new 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
Interaction with different actions is similar. Let's consider [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), you will see config like this:
```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 needed fields, and choose an operation:
- `runS()` - schedule an action
- `runE` - execute an action
- `runSE()` - schedule and execute an action (possible only if a delay for the needed action is zero)
##### Execute the operation:
- If you use an EOA and want to execute the script:
```bash [bash]
forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url --private-key --broadcast
```
- If you use a [Safe](https://app.safe.global/) multisig and want to get a transaction calldata:
```bash [bash]
forge script script/actions/SetMaxNetworkLimit.s.sol:SetMaxNetworkLimit --sig "runS()" --rpc-url --sender --unlocked
```
In the logs, you will see `callData` field like this:
```bash [Expected output]
callData:0x01d5062a00000000000000000000000025ed2ee6e295880326bdeca245ee4d8b72c8f103000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000005365744d61784e6574776f726b4c696d697400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004423f752d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6700000000000000000000000000000000000000000000000000000000
```
In [Safe](https://app.safe.global/)->TransactionBuilder, you should:
1. enable "Custom data"
2. enter **Network's address** as a target address
3. use the `callData` (e.g., `0x01d5062a0000000000000000000000...`) received earlier as a `Data (Hex encoded)`
:::
## Update Delays
Any action that can be made by the Network is protected by the corresponding delay (which can be any value from zero to infinity).
We provide "update delay" scripts for actions mentioned above, and also some additional ones:
- [SetMaxNetworkLimitUpdateDelay](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 [SetMiddlewareUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMiddlewareUpdateDelay.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 [SetMaxNetworkLimitUpdateDelay](https://github.com/symbioticfi/network/blob/main/script/update-delay/SetMaxNetworkLimitUpdateDelay.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 example usage of similar scripts see [Manage Your Network](/integrate/networks/register-network#manage-your-network).
***
## Dashboard
:::warning
Work-in-progress, use with caution.
:::
`Network.sol` contract inherits [OpenZeppelin](https://www.openzeppelin.com/)'s `TimelockController`, while `TimelockController` inherits `AccessControl`. The similarity between `TimelockController` and `AccessControl` contracts' logic is that it is not possible to adequately determine their state (e.g., statuses of operations or holders of roles) using only the current chain's state via RPC calls.
Hence, we provide a Network Dashboard which allows you 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
}
href="/integrate/networks/submit-metadata"
/>
---
## /integrate/networks/relay-offchain
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 the code updates as well as 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:
```
#### 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
```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> {
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?;
}
```
:::
## 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
---
## /integrate/networks/relay-onchain
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 allows for provable attestation checks on any chain of an arbitrary data signed by the validator set quorum.
The system provides a modular smart contract framework that enables networks to manage validator sets dynamically, handle cryptographic keys, aggregate signatures, and commit cross-chain state
## Architecture
Symbiotic provides a set of predefined smart contracts, in general, representing the following modules:
- [`VotingPowerProvider`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/voting-power/) - provides the basic data regarding operators, vaults and their voting power, it allows constructing 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/) - is used by the off-chain part of the Symbiotic Relay for validator set deriving and maintenance
- [`Settlement`](https://github.com/symbioticfi/relay-contracts/blob/main/src/modules/settlement/) - requires a compressed validator set (header) to be committed each epoch, but allows verifying signatures made by the validator set; currently, it 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 to be inputted on the verification, but in a compressed and efficient way, so that it is the best choice to use up to around 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
In sense of Symbiotic Core's `NetworkMiddlewareService` contract exactly `VotingPowerProvider` contract should be set as a 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, developers must 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
There are 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
- Also, there are ready bindings 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 can be found at [`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 [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) bash script (the Relay smart contracts use external libraries for their implementations, so that 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 the four deployment hooks: KeyRegistry, VotingPowerProvider, Settlement, and ValVetDriver
- [`relay-deploy.sh`](https://github.com/symbioticfi/relay-contracts/tree/main/script/relay-deploy.sh) - orchestrates per-contract multi-chain deployments (uses Python inside 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) (it provides better control for production deployments and more simplified 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))
- this Foundry script should include the deployment configuration of your Relay modules
- you need to implement all virtual functions of `RelayDeploy.sol`
- in constructor, need to input the path of the `toml` file
- you are provided with 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))
- this configuration file should include RPC URLs that will be needed for the deployment, and which modules should be deployed on which chains
- **do not replace \[1234567890] placeholder with endpoint\_url = ""**
- the contracts are deployed in such 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 `
:::
At the end, your `toml` file will contain the addresses of the deployed Relay modules.
::::
## Integrate
The Symbiotic Relay provides you a comprehensive tooling working on its own, so that you don't care about anything except only your stake-backed application logic.
### Verify Message
Your application contract is able to verify any message using a validator set at any point of time needed 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 is able to use the validator set at any point of time using [SSZ](https://ethereum.org/developers/docs/data-structures-and-encoding/ssz/) proof verification via, e.g.:
```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
}
href="/integrate/networks/relay-offchain"
/>
---
## /integrate/networks/rewards
import { Card1 } from "../../../components/Card1";
# Rewards
[Read Learn first](/learn/core-concepts/rewards)
Rewards is a encouraging mechanism provided by a network to motivate operators to do their work. The rewards are divided into Staker and Operator rewards:
- The Staker rewards can be provided depending purely on the provided stake’s value (the representation of value can differ from the standard "dollars view" depending on alignment, token distribution, or other factors)
- The Operator rewards can be provided depending on the economic factors similar to the above ones and on the operators’ performance metrics (e.g., number of tasks completed, liveness, or validators’ distribution).
## Staker Rewards
The rewards contracts are not a part of the core contracts. However, we provide a default implementation of Staker rewards, which is represented by a simple pro-rata rewards distribution concerning the collateral amounts provided by stakers at the capture time point and providing an ability to the Vault curator to receive fees.
Code: [`DefaultStakerRewards`](https://github.com/symbioticfi/rewards/blob/main/src/contracts/defaultStakerRewards/DefaultStakerRewards.sol)
:::info
An unlimited number of networks can use one `DefaultStakerRewards` contract in favor of one specific vault’s stakers.
:::
Factory deployment: [`DefaultStakerRewardsFactory`](/get-started/resources/addresses#rewards)
### Counterparties
- Network:
1. Distributes the rewards via `distributeRewards()`
- Staker:
1. Claims the rewards via `claimRewards()`
- Curator:
1. Configures an admin fee via `setAdminFee()`
2. Claims an admin fee (it accumulates after each distribution) via `claimAdminFee()`
### Example
This example walks you through setting up a test environment to simulate the staker rewards distribution process on Holešky.
::::steps
#### Prepare Mock Accounts
You'll need 6 EOAs:
- **Network Admin**: registers the network
- **Middleware**: set by the network to handle reward distribution and vault opt-ins
- **Vault Admin**: sets up the vault and allocates shares
- **Mock Operator**: receives delegated stake
- **Two Test Stakers**: deposit collateral
:::warning
For test purposes, EOAs are fine. On mainnet, use contracts for middleware logic.
:::
#### Register Network & Set Middleware
1. Register your network
- [Example tx](https://holesky.etherscan.io/tx/0xfaf4b1d5cd0ce1a34a796b53a330092584b3e5886ef0de6937fe9ab4b698fe59)
2. Set middleware address
- [Example tx](https://holesky.etherscan.io/tx/0x84459916991fd14762f49adfb958fd41d59b381c33c4e34bb26fba51aa12307d)
:::warning
On mainnet, avoid using EOAs for middleware.
:::
#### Create Vault & Register Operator
1. [Create a vault](https://app.holesky.symbiotic.fi/create) using `wstETH` as collateral.
- Sample Vault address: `0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0`
- [Creation tx](https://holesky.etherscan.io/tx/0xb28636cca9c561a4308ca9679b487fc2eb3b12850dabc54cd7fbb73cc3d44487)
2. Register operator in [Operator Registry](https://holesky.etherscan.io/address/0x6F75a4ffF97326A00e52662d82EA4FdE86a2C548)
- [Sample tx](https://holesky.etherscan.io/tx/0x5ec21081d3f7f4b0a6f7abcb78a54d63fc8739be4f2e1be6f82324bcc8c6404e)
3. Opt operator into:
- [Network](https://holesky.etherscan.io/tx/0x19ef569b223f8876ccd508cde00fb1cb27744fcf07424314a08cebea66a2cd20)
- [Vault](https://holesky.etherscan.io/tx/0x72f68941e84b62f5f55282c60aaaeb5bfa706c803961713c9cbe9224e93d3bd2)
4. Allocate shares:
- [Sample tx](https://holesky.etherscan.io/tx/0x492c5a337775e2914abbdf521883acd7d84380db4512d2c8cae8c7b0116d8fd5)
5. Submit 3 PRs with metadata (network, vault, operator) to the [metadata-holesky](https://github.com/symbioticfi/metadata-holesky/) repo. Examples: [78](https://github.com/symbioticfi/metadata-holesky/pull/78), [79](https://github.com/symbioticfi/metadata-holesky/pull/79), [80](https://github.com/symbioticfi/metadata-holesky/pull/80)
#### Vault Opt-In (Network)
1. Opt-in to vault by calling `setMaxNetworkLimit(0, 1e18)`
- [Sample tx](https://holesky.etherscan.io/tx/0x010ba1ccd0aec56a38dc664358bbead3eb2b3e48961b42dc14cffa1b0cf5a698)
2. From emitted event, extract `subnetwork ID`
3. **Vault Admin:** accept opt-in by calling `setNetworkLimit`
- [Sample tx](https://holesky.etherscan.io/tx/0xe7a15e5961081d067964a554f2a5f0ff32dfe415b2848b832e665d81fca9b136)
#### Deploy Rewards Contract
1. Use [DefaultStakerRewardsFactory](https://holesky.etherscan.io/address/0x58e80fa5eb938525f2ca80c5bde724d7a99a7892#writeContract) to create `DefaultStakerRewards` contract (can be deployed by a Vault Admin or a Network)
- [Sample tx](https://holesky.etherscan.io/tx/0x4a9a56943a54179e89bf8c28e28bc5ada3d925d1964ee4907f22e8d1ccc45d7b)
2. Submit rewards metadata PR
- [Example](https://github.com/symbioticfi/metadata-holesky/pull/85)
#### Distribute Rewards
- Increase token allowance
- [Sample tx](https://holesky.etherscan.io/tx/0xd05afbd3d2cacda412c17f9a4ca08bf91c51efc429e5dd77d1cad3ace84177b9)
- Call `distributeRewards()`
- [Sample tx](https://holesky.etherscan.io/address/0x3CBc80E19d558a4012CfE93dD724c1a52ad41EF5#writeContract)
:::warning
On mainnet, call to `distributeRewards()` should be done from within your middleware contract.
:::
##### Encode `data` parameter
- To reproduce manually, use [ABI encoder](https://adibas03.github.io/online-ethereum-abi-encoder-decoder/encode) to cook it with:
- Input types: `uint48,uint256,bytes,bytes`
- Input values: `1752766520,1000,0x,0x`
- `timestamp` - use current timestamp
- `maxAdminShare` (10%) - anti-frontrun protection
- `bytes` inputs are [hints](/integrate/builders-researchers/hints) (set to `0x`)
- To reproduce in Solidity:
```solidity [DistributeRewards.s.sol]
address rewardsContract = 0x3CBc80E19d558a4012CfE93dD724c1a52ad41EF5;
address network = 0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0;
address token = 0x5FbDB2315678afecb367f032d93F642f64180aa3;
uint256 amount = 1000000000000000000;
uint48 timestamp = 1752766520;
uint256 maxAdminFee = 1000;
bytes memory activeSharesHint = new bytes(0);
bytes memory activeStakeHint = new bytes(0);
bytes memory data = abi.encode(timestamp, maxAdminFee, activeSharesHint, activeStakeHint);
IDefaultStakerRewards(rewardsContract).distributeRewards(network, token, amount, data);
```
This gives the `data` parameter:
```bash [Expected output]
0x00000000000000000000000000000000000000000000000000000000687942a500000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
- [Sample tx](https://holesky.etherscan.io/tx/0x842094f4c3b9f4b368daa3d6160239144f41c338e1dc176a904a12b486015423)
:::info
To identify that rewards were distributed in the past, open a [Vault Page](https://app.holesky.symbiotic.fi/vault/0x132A3c9c2403662d89DF034b8B11c145b90d0ddA). Find the overall Vault Reward data and rewards claimed earlier in the corresponding section.
:::

#### User Flow
- [Acquire wstETH](https://stake-holesky.testnet.fi/wrap)
- [Sample tx](https://holesky.etherscan.io/tx/0x2e4031b92696e1c1eb8e53e24f30981f76e90c45a40b4169ec5d4b7c4e60a5fe)
- Deposit to Vault (via UI)
- [Tx 1](https://holesky.etherscan.io/tx/0x7238e1ac735564ab09189fcd41497112e978d2fe933bad282a624ae040744df2)
- [Tx 2](https://holesky.etherscan.io/tx/0x58c1f88de345da80f9e1a16304932113f6f2baa0deedee63a7c945fc8114676f)
- Claim Rewards (after next distribution)
- Use the [Symbiotic Dashboard (Rewards tab)](https://app.holesky.symbiotic.fi/vault/0x0351bE785c8Abfc81e8d8C2b6Ef06A7fc62478a0)

::::
## Operator Rewards
Since the rewards contracts are not a part of the core contracts, we allow users to provide their own implementations. Here are three example implementations:
1. The network performs off-chain calculations to determine the reward distributions. After calculating the rewards, the network executes batch transfers to distribute the rewards in a consolidated manner.
2. The network performs off-chain calculations to determine rewards and generates a Merkle tree, allowing operators to claim their rewards.
3. The network performs on-chain reward calculations within its middleware to determine the distribution of rewards.
We provide a default implementation of the operator rewards, which is represented by a simple Merkle tree rewards distribution, where each leaf represents a recipient (an operator’s treasury address) and the total amount of tokens earned for the whole period.
Code: [`DefaultOperatorRewards`](https://github.com/symbioticfi/rewards/blob/main/src/contracts/defaultOperatorRewards/DefaultOperatorRewards.sol)
:::info
An unlimited number of networks can use one `DefaultOperatorRewards` contract in favor of an unlimited number of operators.
:::
Factory deployment: [`DefaultOperatorRewardsFactory`](/get-started/resources/addresses#rewards)
### Counterparties
- **Network:**
1. Calculates a Merkle root for the rewards distribution (we’ve implemented a [CLI](https://github.com/symbioticfi/rewards/blob/main/specs/OperatorRewards.md#cli) for that purpose)
2. Distributes the rewards via `distributeRewards()`
- **Operator:**
1. Claims the rewards via `claimRewards()` by the usage of a Merkle proof (it can be got with the help of [CLI](https://github.com/symbioticfi/rewards/blob/main/specs/OperatorRewards.md#cli))
## Notes
- In production, middleware logic should be implemented in a contract.
- This guide uses testnet (Holešky) with simplified EOAs for ease of reproduction.
- Vault curators are typically responsible for reward contract deployment and share allocations.
## Next Steps
---
## /integrate/networks/slashing
import { Card1 } from "../../../components/Card1";
# Slashing
[Read Learn first](/learn/core-concepts/slashing)
Slashing is a penalty mechanism enforced by a network to deter operators from breaking their commitments. Such violations may include failing to complete tasks properly or accurately. Slashing typically results in the burning or redistribution of the operator’s staked funds.
## **Slasher Module**
Each Symbiotic Vault has an immutably set Slasher module implementation. In general, 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 an amount of collateral still slashable for the given `captureTimestamp` at the current moment.
:::warning
The provided slashable collateral amount may be inaccurate in practice in case of usage of **restaking** by the vault (hence, multiple network may slash the same amount of collateral).
:::
:::info
During the slashing request execution, the funds are transferred to an immutably set `Vault.burner()`.
:::
### Slashing Guarantees
Each Symbiotic Vault has an epoch duration (can be obtained via `Vault.epochDuration()`), that determines the withdrawal delay and, also, provides a period during which the slashing guarantees are held.
Hence, the following inequality must hold:
### Slasher (Type 0)
Slasher performs an instant execution of the slashing request 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
`NetworkMiddlewareService.middleware(network)` should call this function.
:::
### 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:
:::info
`NetworkMiddlewareService.middleware(network)` should call this function.
:::
#### Days 1 to 5 - Veto Slashing
```solidity [Resolver]
IVetoSlasher(slasher).vetoSlash(slashIndex, hints)
```
:::info
`VetoSlasher.resolver(subnetwork, hint)` should call this function.
:::
#### 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 the Vault has a VetoSlasher type, there is a veto phase, whose duration is set during the vault's deployment, when the resolver can veto the request.
The resolver can be set by Network via `IVetoSlasher(slasher).setResolver(identifier, resolver, hints)`.
:::note
First time when the resolver is set, it is applied immediately. Otherwise, the update is applied after `VetoSlasher.resolverSetEpochsDelay()` epochs.
:::
## Next Steps
}
href="/integrate/networks/relay-onchain"
/>
---
## /integrate/networks/submit-metadata
import { Card1 } from "../../../components/Card1";
# Submit Metadata
[Symbiotic UI](https://app.symbiotic.fi/deposit) provides users with accurate and up-to-date information about various data regarding TVL, allocations, relations between Curators, Vaults, Operators and Networks, etc. However, for the mentioned counterparties to be easily accessible and visible on the UI - their metadata should should be submitted to the corresponding repositories.
Once, the metadata is submitted, it should be reviewed and merged by the Symbiotic team. After that the new data starts to be shown publicly 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) |
| Sepolia | [https://github.com/symbioticfi/metadata-sepolia](https://github.com/symbioticfi/metadata-sepolia) |
| Holešky | [https://github.com/symbioticfi/metadata-holesky](https://github.com/symbioticfi/metadata-holesky) |
### Repository Structure
The repository is organized as follows:
```
repository/
├── vaults/
│ ├── 0x/
│ │ ├── 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, there must be 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`, please be sure that it's collateral token entity is registered in the `tokens` folder before adding the vault metadata. If not, please 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.
Your PR will be reviewed by the Symbiotic team, and if approved, it will be merged into the repository. Please note that the PR will be reviewed only after the entity is checked with automated checks.
***
### 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 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
The Vault metadata submission guide is available [inside the section for Curators](/integrate/curators/submit-metadata).
## Next Steps
---
## Relay Contracts
This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix.
The content has been processed where content has been compressed (code blocks are separated by ⋮---- delimiter).
# File Summary
## Purpose
This file contains a packed representation of a subset of the repository's contents that is considered the most important context.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
## File Format
The content is organized as follows:
1. This summary section
2. Repository information
3. Directory structure
4. Repository files (if enabled)
5. Multiple file entries, each consisting of:
a. A header with the file path (## File: path/to/file)
b. The full contents of the file in a code block
## Usage Guidelines
- This file should be treated as read-only. Any changes should be made to the
original repository files, not this packed version.
- When processing this file, use the file path to distinguish
between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
the same level of security as you would the original repository.
## Notes
- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Files matching these patterns are excluded: docs/
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Content has been compressed - code blocks are separated by ⋮---- delimiter
- Files are sorted by Git change count (files with more changes are at the bottom)
# Directory Structure
```
.github/
ISSUE_TEMPLATE/
BUG_REPORT.yaml
FEATURE_IMPROVEMENT.yaml
workflows/
pre-commit.yaml
test.yaml
trufflehog.yml
CODEOWNERS
PULL_REQUEST_TEMPLATE.md
audits/
Bailsec-RelaySmartContracts.pdf
Cyfrin-RelayContracts&Network.pdf
Sherlock-RelayContracts&Network.pdf
SigmaPrime-RelayContracts&Network.pdf
StatemindAI-RelayContracts.pdf
examples/
MyKeyRegistry.sol
MySettlement.sol
MyValSetDriver.sol
MyVotingPowerProvider.sol
script/
examples/
my-relay-deploy.toml
MyRelayDeploy.sol
utils/
sort_errors.py
sort_imports.py
relay-deploy.sh
RelayDeploy.sol
snapshots/
gas.txt
sizes.txt
src/
interfaces/
modules/
base/
INetworkManager.sol
IOzEIP712.sol
IPermissionManager.sol
common/
permissions/
IOzAccessControl.sol
IOzAccessManaged.sol
IOzOwnable.sol
key-registry/
IKeyRegistry.sol
settlement/
sig-verifiers/
zk/
IVerifier.sol
ISigVerifier.sol
ISigVerifierBlsBn254Simple.sol
ISigVerifierBlsBn254ZK.sol
ISettlement.sol
valset-driver/
IEpochManager.sol
IValSetDriver.sol
voting-power/
base/
IVotingPowerCalcManager.sol
common/
voting-power-calc/
libraries/
AggregatorV3Interface.sol
IEqualStakeVPCalc.sol
INormalizedTokenDecimalsVPCalc.sol
IPricedTokensChainlinkVPCalc.sol
IWeightedTokensVPCalc.sol
IWeightedVaultsVPCalc.sol
extensions/
IBaseRewards.sol
IBaseSlashing.sol
IMultiToken.sol
IOperatorsBlacklist.sol
IOperatorsJail.sol
IOperatorsWhitelist.sol
IOperatorVaults.sol
IOpNetVaultAutoDeploy.sol
ISharedVaults.sol
IVotingPowerProvider.sol
libraries/
keys/
KeyBlsBn254.sol
KeyEcdsaSecp256k1.sol
sigs/
SigBlsBn254.sol
SigEcdsaSecp256k1.sol
structs/
Checkpoints.sol
PersistentSet.sol
utils/
BN254.sol
InputNormalizer.sol
KeyTags.sol
Scaler.sol
ValSetVerifier.sol
modules/
base/
NetworkManager.sol
OzEIP712.sol
PermissionManager.sol
common/
permissions/
OzAccessControl.sol
OzAccessManaged.sol
OzOwnable.sol
key-registry/
KeyRegistry.sol
settlement/
sig-verifiers/
libraries/
ExtraDataStorageHelper.sol
SigVerifierBlsBn254Simple.sol
SigVerifierBlsBn254ZK.sol
Settlement.sol
valset-driver/
EpochManager.sol
ValSetDriver.sol
voting-power/
base/
VotingPowerCalcManager.sol
common/
voting-power-calc/
libraries/
ChainlinkPriceFeed.sol
EqualStakeVPCalc.sol
NormalizedTokenDecimalsVPCalc.sol
PricedTokensChainlinkVPCalc.sol
WeightedTokensVPCalc.sol
WeightedVaultsVPCalc.sol
extensions/
logic/
BaseRewardsLogic.sol
BaseSlashingLogic.sol
OpNetVaultAutoDeployLogic.sol
BaseRewards.sol
BaseSlashing.sol
MultiToken.sol
OperatorsBlacklist.sol
OperatorsJail.sol
OperatorsWhitelist.sol
OperatorVaults.sol
OpNetVaultAutoDeploy.sol
SharedVaults.sol
logic/
VotingPowerProviderLogic.sol
VotingPowerProvider.sol
test/
data/
zk/
Verifier_10.sol
Verifier_100.sol
Verifier_1000.sol
genesis_header.json
examples/
MyVotingPowerProvider.t.sol
helpers/
blsTestGenerator.py
BN254G2.sol
ed25519TestData.json
ed25519TestGenerator.js
libraries/
keys/
KeyBlsBn254.t.sol
KeyEcdsaSecp256k1.t.sol
sigs/
SigBlsBn254.t.sol
SigEcdsaSecp256k1.t.sol
structs/
Checkpoints.t.sol
PersistentSet.t.sol
utils/
InputNormalizer.t.sol
KeyTag.t.sol
ValSetVerifier.t.sol
mocks/
KeyBlsBn254Mock.sol
KeyEcdsaSecp256k1Mock.sol
KeyRegistryWithKey64.sol
NoPermissionManager.sol
RewarderMock.sol
SigVerifierFalseMock.sol
SigVerifierMock.sol
SlasherMock.sol
ValSetVerifierMock.sol
VotingPowerProviderFull.sol
VotingPowerProviderSemiFull.sol
VotingPowerProviderSharedVaults.sol
modules/
base/
NetworkManager.t.sol
OzEIP712.t.sol
PermissionManager.t.sol
VotingPowerCalcManager.t.sol
common/
permissions/
NoPermissionManager.t.sol
OzAccessControl.t.sol
OzAccessManaged.t.sol
OzOwnable.t.sol
key-registry/
KeyRegistry.t.sol
settlement/
sig-verifiers/
libraries/
ExtraDataStorageHelper.t.sol
SigVerifierBlsBn254Simple.t.sol
SigVerifierBlsBn254ZK.t.sol
Settlement.t.sol
valset-driver/
EpochManager.t.sol
ValSetDriver.t.sol
voting-power/
common/
voting-power-calc/
NormalizedTokenDecimalsVPCalc.t.sol
PricedTokensChainlinkVPCalc.t.sol
WeightedTokensVPCalc.t.sol
WeightedVaultsVPCalc.t.sol
extensions/
BaseRewards.t.sol
BaseSlashing.t.sol
EqualStakeVPCalc.t.sol
MultiToken.t.sol
OperatorsBlacklist.t.sol
OperatorsJail.t.sol
OperatorsWhitelist.t.sol
OperatorVaults.t.sol
OpNetVaultAutoDeploy.t.sol
SharedVaults.t.sol
VotingPowerProvider.t.sol
InitSetup.sol
MasterGenesisSetup.sol
MasterSetup.sol
.env.example
.gitignore
.gitmodules
.nvmrc
.pre-commit-config.yaml
.prettierignore
.prettierrc
codecov.yml
CONTRIBUTING.md
foundry.lock
foundry.toml
LICENSE
package.json
README.md
remappings.txt
```
# Files
## File: .github/ISSUE_TEMPLATE/BUG_REPORT.yaml
````yaml
name: Bug report
description: File a bug report to help us improve the code
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Please check that the bug is not already being tracked.
- type: textarea
attributes:
label: Describe the bug
description: Provide a clear and concise description of what the bug is and which contracts it affects.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: Provide a clear and concise description of the desired fix.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: If you have written tests to showcase the bug, what can we run to reproduce the issue?
placeholder: "git checkout / forge test --isolate --mt "
- type: textarea
attributes:
label: Additional context
description: If there is any additional context needed like a dependency or integrating contract that is affected please describe it below.
````
## File: .github/ISSUE_TEMPLATE/FEATURE_IMPROVEMENT.yaml
````yaml
name: Feature Improvement
description: Suggest an improvement.
labels: ["triage"]
body:
- type: markdown
attributes:
value: |
Please ensure that the feature has not already been requested.
- type: dropdown
attributes:
label: Component
description: Which area of code does your idea improve?
multiple: true
options:
- Gas Optimization
- General design optimization (improving efficiency, cleanliness, or developer experience)
- Testing
- Documentation
- type: textarea
attributes:
label: Describe the suggested feature and problem it solves.
description: Provide a clear and concise description of what feature you would like to see, and what problems it solves.
validations:
required: true
- type: textarea
attributes:
label: Describe the desired implementation.
description: If possible, provide a suggested architecture change or implementation.
- type: textarea
attributes:
label: Describe alternatives.
description: If possible, describe the alternatives you've considered, or describe the current functionality and how it may be sub-optimal.
- type: textarea
attributes:
label: Additional context.
description: Please list any additional dependencies or integrating contacts that are affected.
````
## File: .github/workflows/pre-commit.yaml
````yaml
# checks that pre-commit hooks pass before allowing to merge a PR
name: pre-commit
on:
pull_request:
branches: [main, master, staging, dev, feat/**, fix/**]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FOUNDRY_PROFILE: ${{ github.event_name == 'push' && 'ci' || 'pr' }}
ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }}
jobs:
pre-commit:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
submodules: recursive
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.11"
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
with:
version: stable
- name: Install pre-commit
run: python -m pip install --upgrade pip pre-commit
- name: Run pre-commit
run: pre-commit run --all-files --color always --show-diff-on-failure
env:
SKIP: forge-snapshots,doc
````
## File: .github/workflows/test.yaml
````yaml
name: test
on:
pull_request:
branches: [main, master, staging, dev, feat/**, fix/**]
push:
branches: [main, master, staging, dev]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FOUNDRY_PROFILE: ${{ github.event_name == 'push' && 'ci' || 'pr' }}
ETH_RPC_URL: ${{ secrets.ETH_RPC_URL }}
jobs:
forge-test:
name: Foundry project
runs-on: ubuntu-latest
timeout-minutes: 180
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
with:
version: stable
- name: Run Forge fmt check
run: forge fmt --check
- name: Run Forge tests
run: forge test --isolate
- name: Run Forge coverage
run: |
forge coverage --report lcov
id: coverage
env:
COVERAGE: true
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
````
## File: .github/workflows/trufflehog.yml
````yaml
name: TruffleHog
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
id-token: write
issues: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: bullfrogsec/bullfrog@1831f79cce8ad602eef14d2163873f27081ebfb3 # v0.8.4
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: TruffleHog OSS
id: trufflehog
uses: trufflesecurity/trufflehog@0f58ae7c5036094a1e3e750d18772af92821b503 # v3.90.5
with:
path: .
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --results=verified,unknown
````
## File: .github/CODEOWNERS
````
* @symbioticfi/contracts
````
## File: .github/PULL_REQUEST_TEMPLATE.md
````markdown
# Pull Request
## Description
Please include a summary of the change and which feature was implemented or which issue was fixed. Also, include relevant motivation and context. List any dependencies that are required for this change.
Fixes # (issue)
### How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.
# Checklist:
- [ ] 100% test and branch coverage
- [ ] check slither or other analyzer for severe issues
- [ ] fuzz and invariant tests (when applicable)
---
### Considerations
- I have followed the [contributing guidelines](../CONTRIBUTING.md).
- My code follows the style guidelines of this project and I have run `forge fmt` and prettier to ensure the code style is valid
- I have performed a self-review of my own code
- I have commented my code, particularly in hard-to-understand areas
- I have made corresponding changes to the documentation
- I have added tests that prove my fix is effective or that my feature works
- New and existing unit tests pass locally with my changes
### Additional context
Add any other context about the pull request here.
````
## File: examples/MyKeyRegistry.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyRegistry} from "../src/modules/key-registry/KeyRegistry.sol";
⋮----
/// @title MyKeyRegistry
/// @notice Example implementation of the KeyRegistry contract.
contract MyKeyRegistry is KeyRegistry {
function initialize(KeyRegistryInitParams memory keyRegistryInitParams) public virtual initializer {
````
## File: examples/MySettlement.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {OzAccessControl} from "../src/modules/common/permissions/OzAccessControl.sol";
import {Settlement} from "../src/modules/settlement/Settlement.sol";
⋮----
import {ISettlement} from "../src/interfaces/modules/settlement/ISettlement.sol";
⋮----
/// @title MySettlement
/// @notice Example implementation of the Settlement contract.
contract MySettlement is Settlement, OzAccessControl {
⋮----
function initialize(SettlementInitParams memory settlementInitParams, address defaultAdmin)
````
## File: examples/MyValSetDriver.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {OzAccessControl} from "../src/modules/common/permissions/OzAccessControl.sol";
import {ValSetDriver} from "../src/modules/valset-driver/ValSetDriver.sol";
⋮----
import {IEpochManager} from "../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {IValSetDriver} from "../src/interfaces/modules/valset-driver/IValSetDriver.sol";
⋮----
/// @title MyValSetDriver
/// @notice Example implementation of the ValSetDriver contract.
contract MyValSetDriver is ValSetDriver, OzAccessControl {
⋮----
function initialize(ValSetDriverInitParams memory valSetDriverInitParams, address defaultAdmin)
````
## File: examples/MyVotingPowerProvider.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {EqualStakeVPCalc} from "../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../src/modules/voting-power/extensions/OperatorVaults.sol";
import {OzOwnable} from "../src/modules/common/permissions/OzOwnable.sol";
import {VotingPowerProvider} from "../src/modules/voting-power/VotingPowerProvider.sol";
⋮----
/// @title MyVotingPowerProvider
/// @notice Example implementation of the VotingPowerProvider contract.
contract MyVotingPowerProvider is VotingPowerProvider, OzOwnable, EqualStakeVPCalc, OperatorVaults {
⋮----
function initialize(
````
## File: script/examples/my-relay-deploy.toml
````toml
[31337]
endpoint_url = "http://127.0.0.1:8545"
[31338]
endpoint_url = "http://127.0.0.1:8546"
[1234567890]
endpoint_url = ""
keyRegistry = 31337
votingPowerProvider = [31337]
settlement = [
31337,
31338,
]
valSetDriver = 31337
````
## File: script/examples/MyRelayDeploy.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {SigVerifierBlsBn254Simple} from "../../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol";
import {RelayDeploy} from "../RelayDeploy.sol";
import {IVotingPowerProvider} from "../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../src/interfaces/modules/base/IOzEIP712.sol";
import {IOzOwnable} from "../../src/interfaces/modules/common/permissions/IOzOwnable.sol";
import {MyVotingPowerProvider} from "../../examples/MyVotingPowerProvider.sol";
import {MyKeyRegistry} from "../../examples/MyKeyRegistry.sol";
import {IKeyRegistry} from "../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
import {MyValSetDriver} from "../../examples/MyValSetDriver.sol";
import {IValSetDriver} from "../../src/interfaces/modules/valset-driver/IValSetDriver.sol";
import {IEpochManager} from "../../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {MySettlement} from "../../examples/MySettlement.sol";
import {ISettlement} from "../../src/interfaces/modules/settlement/ISettlement.sol";
⋮----
// ./script/relay-deploy.sh ./script/examples/MyRelayDeploy.sol ./script/examples/my-relay-deploy.toml --broadcast
⋮----
contract MyRelayDeploy is RelayDeploy {
⋮----
// Key registry parameters
⋮----
// Voting power parameters
⋮----
// Settlement parameters
⋮----
// ValSet driver parameters
⋮----
function _keyRegistryParams() internal override returns (address implementation, bytes memory initData) {
⋮----
function _votingPowerProviderParams() internal override returns (address implementation, bytes memory initData) {
⋮----
function _settlementParams() internal override returns (address implementation, bytes memory initData) {
⋮----
function _valSetDriverParams() internal override returns (address implementation, bytes memory initData) {
⋮----
function runDeployKeyRegistry() public override {
⋮----
function runDeployVotingPowerProvider() public override {
⋮----
function runDeploySettlement() public override {
⋮----
function runDeployValSetDriver() public override {
````
## File: script/utils/sort_errors.py
````python
#!/usr/bin/env python3
⋮----
def _error_sort_key(error_line: str) -> str
⋮----
signature = error_line.strip()[len("error ") :]
name = signature.split("(", 1)[0].strip()
⋮----
def _extract_entries(block_text: str) -> List[Tuple[int, int, str, int]]
⋮----
entries: List[Tuple[int, int, str, int]] = []
offset = 0
entry_start: Optional[int] = None
last_content_end: Optional[int] = None
current_error: Optional[str] = None
⋮----
def finalize() -> None
⋮----
entry_start = None
last_content_end = None
current_error = None
⋮----
newline_idx = block_text.find("\n", offset)
⋮----
line_end = len(block_text)
⋮----
line_end = newline_idx + 1
line = block_text[offset:line_end]
stripped = line.strip()
⋮----
last_content_end = line_end
offset = line_end
⋮----
entry_start = offset
⋮----
current_error = line.strip()
⋮----
def _sort_error_block(text: str) -> Tuple[str, bool]
⋮----
marker = "/* ERRORS */"
search_pos = 0
changed = False
⋮----
marker_idx = text.find(marker, search_pos)
⋮----
block_start = text.find("\n", marker_idx)
⋮----
cursor = block_start
first_block_idx: Optional[int] = None
last_block_idx = block_start
⋮----
newline_idx = text.find("\n", cursor)
⋮----
line_end = len(text)
⋮----
line = text[cursor:line_end]
⋮----
cursor = line_end
⋮----
first_block_idx = cursor
last_block_idx = line_end
⋮----
search_pos = cursor
⋮----
block_text = text[first_block_idx:last_block_idx]
entries = _extract_entries(block_text)
⋮----
search_pos = last_block_idx
⋮----
prefix = block_text[:entries[0][0]]
suffix = block_text[entries[-1][1]:]
sorted_entries = sorted(entries, key=lambda item: (item[2], item[3]))
sorted_chunks = [block_text[start:end].rstrip("\n") for start, end, _, _ in sorted_entries]
⋮----
new_block = prefix + "\n\n".join(sorted_chunks)
⋮----
stripped_suffix = suffix.lstrip("\n")
⋮----
text = text[:first_block_idx] + new_block + text[last_block_idx:]
changed = True
search_pos = first_block_idx + len(new_block)
⋮----
def sort_errors_in_file(path: Path)
⋮----
original = path.read_text(encoding="utf-8")
⋮----
def iter_solidity_files(targets: Iterable[Path]) -> Iterable[Path]
⋮----
def resolve_targets(path_args: Iterable[str]) -> List[Path]
⋮----
defaults = [Path(name) for name in ("src", "examples") if Path(name).exists()]
⋮----
def sort_from_stdin() -> None
⋮----
errors = sys.stdin.read()
sorted_errors = sorted(x.strip() for x in errors.splitlines())
⋮----
def main() -> int
⋮----
parser = argparse.ArgumentParser(
⋮----
args = parser.parse_args()
⋮----
targets = resolve_targets(args.paths)
````
## File: script/utils/sort_imports.py
````python
#!/usr/bin/env python3
⋮----
FROM_IMPORT_RE = re.compile(r'from\s+["\']([^"\']+)["\']', re.IGNORECASE | re.MULTILINE)
DIRECT_IMPORT_RE = re.compile(r'import\s+["\']([^"\']+)["\']', re.IGNORECASE | re.MULTILINE)
WHITESPACE_RE = re.compile(r"\s+")
⋮----
@dataclass
class ImportEntry
⋮----
start: int
end: int
text: str
path: str
order: int
⋮----
def extract_path(import_text: str) -> str
⋮----
match = FROM_IMPORT_RE.search(import_text)
⋮----
match = DIRECT_IMPORT_RE.search(import_text)
⋮----
def collect_import_entries(lines: Sequence[str]) -> List[ImportEntry]
⋮----
entries: List[ImportEntry] = []
index = 0
⋮----
stripped = lines[index].lstrip()
⋮----
start = index
statement_lines = [lines[index].rstrip()]
⋮----
end = index
text = "\n".join(statement_lines)
path = extract_path(text)
⋮----
def normalize_import_text(import_text: str) -> str
⋮----
"""Flatten whitespace so multi-line imports sort identically to single-line ones."""
compact = WHITESPACE_RE.sub(" ", import_text.strip())
compact = compact.replace("{ ", "{").replace(" }", "}")
compact = compact.replace("( ", "(").replace(" )", ")")
⋮----
def classify_import(path: str) -> str
⋮----
normalized = path.lstrip("./")
lower = normalized.lower()
⋮----
library = normalized.split("/", 1)[0]
⋮----
def build_sorted_block(entries: Sequence[ImportEntry]) -> List[str]
⋮----
grouped: Dict[str, List[ImportEntry]] = defaultdict(list)
⋮----
ordered_groups: List[List[ImportEntry]] = []
⋮----
external_groups = sorted(
⋮----
block_text = "\n\n".join("\n".join(entry.text for entry in group) for group in ordered_groups)
⋮----
def sort_imports_in_file(path: Path) -> None
⋮----
original_text = path.read_text(encoding="utf-8")
has_trailing_newline = original_text.endswith("\n")
lines = original_text.splitlines()
⋮----
entries = collect_import_entries(lines)
⋮----
block_start = entries[0].start
block_end = entries[-1].end
covered_indexes = set()
⋮----
new_block_lines = build_sorted_block(entries)
new_lines = lines[:block_start] + new_block_lines + lines[block_end + 1 :]
new_text = "\n".join(new_lines)
⋮----
def iter_solidity_files(targets: Iterable[Path]) -> Iterable[Path]
⋮----
def resolve_targets(path_args: Iterable[str]) -> List[Path]
⋮----
defaults = [Path(name) for name in ("src", "examples") if Path(name).exists()]
⋮----
def main() -> int
⋮----
parser = argparse.ArgumentParser(
⋮----
args = parser.parse_args()
⋮----
targets = resolve_targets(args.paths)
````
## File: script/relay-deploy.sh
````bash
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage: relay-deploy.sh [forge-script-args...]
Arguments:
Path to the Forge deployment script (.s.sol)
Path to the deployment configuration TOML file
[args...] Additional arguments forwarded to every forge script invocation
USAGE
}
if [[ $# -lt 2 ]]; then
usage
exit 1
fi
script_path=$1
shift
config_path=$1
shift
extra_args=("$@")
if [[ ! -f "$script_path" ]]; then
echo "Error: script not found at '$script_path'" >&2
exit 1
fi
if [[ ! -f "$config_path" ]]; then
echo "Error: config not found at '$config_path'" >&2
exit 1
fi
for bin in forge python3 cast; do
if ! command -v "$bin" >/dev/null 2>&1; then
echo "Error: required command '$bin' is not available in PATH" >&2
exit 1
fi
done
get_contract_chains() {
local config_file=$1
local contract_key=$2
python3 - "$config_file" "$contract_key" <<'PY'
import sys
try:
import tomllib # Python 3.11+
except ModuleNotFoundError: # pragma: no cover - fallback for older versions
import tomli as tomllib
config_path, contract_key = sys.argv[1:3]
with open(config_path, "rb") as fh:
config = tomllib.load(fh) or {}
def extract_chains(raw_value):
if isinstance(raw_value, dict):
raw_value = raw_value.get("chains")
if isinstance(raw_value, list):
return [str(item) for item in raw_value if item is not None]
if raw_value is None:
return []
return [str(raw_value)]
contracts_section = {}
for key in ("1234567890", 1234567890):
value = config.get(key)
if isinstance(value, dict):
contracts_section = value
break
else:
legacy_contracts = config.get("contracts")
if isinstance(legacy_contracts, dict):
contracts_section = legacy_contracts
chains = extract_chains(contracts_section.get(contract_key))
if not chains:
legacy_contracts = config.get("contracts")
if isinstance(legacy_contracts, dict):
chains = extract_chains(legacy_contracts.get(contract_key))
for chain in chains:
print(chain)
PY
}
get_chain_rpc_url() {
local config_file=$1
local chain_id=$2
python3 - "$config_file" "$chain_id" <<'PY'
import sys
try:
import tomllib # Python 3.11+
except ModuleNotFoundError: # pragma: no cover
import tomli as tomllib
config_path, requested_chain = sys.argv[1:3]
with open(config_path, "rb") as fh:
config = tomllib.load(fh) or {}
def normalize_chain_mapping(raw):
chains = {}
if isinstance(raw, dict):
for key, value in raw.items():
key_str = str(key)
chains[key_str] = value
return chains
chains = {}
chains.update(normalize_chain_mapping(config.get("chains")))
for key, value in config.items():
if key in ("chains", "contracts") or key in ("0", 0):
continue
key_str = str(key)
if not key_str.isdigit():
continue
if isinstance(value, (dict, str)):
chains[key_str] = value
candidates = []
candidates.append(requested_chain)
try:
candidates.append(int(requested_chain))
except ValueError:
pass
candidates.append(str(requested_chain))
entry = None
seen = set()
for candidate in candidates:
key_variants = []
if isinstance(candidate, int):
key_variants.extend([candidate, str(candidate)])
else:
key_variants.append(candidate)
for key in key_variants:
key_str = str(key)
if key_str in seen:
continue
seen.add(key_str)
if key_str in chains:
entry = chains[key_str]
break
if entry is not None:
break
if isinstance(entry, dict):
url = entry.get("endpoint_url") or entry.get("rpc_url")
if url:
print(url)
elif isinstance(entry, str) and entry:
print(entry)
PY
}
createx_address="0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"
createx_deployer="0xeD456e05CaAb11d66C4c797dD6c1D6f9A7F352b5"
createx_tx="0xf92f698085174876e800832dc6c08080b92f1660a06040523060805234801561001457600080fd5b50608051612e3e6100d860003960008181610603015281816107050152818161082b015281816108d50152818161127f01528181611375015281816113e00152818161141f015281816114a7015281816115b3015281816117d20152818161183d0152818161187c0152818161190401528181611ac501528181611c7801528181611ce301528181611d2201528181611daa01528181611fe901528181612206015281816122f20152818161244d015281816124a601526125820152612e3e6000f3fe60806040526004361061018a5760003560e01c806381503da1116100d6578063d323826a1161007f578063e96deee411610059578063e96deee414610395578063f5745aba146103a8578063f9664498146103bb57600080fd5b8063d323826a1461034f578063ddda0acb1461036f578063e437252a1461038257600080fd5b80639c36a286116100b05780639c36a28614610316578063a7db93f214610329578063c3fe107b1461033c57600080fd5b806381503da1146102d0578063890c283b146102e357806398e810771461030357600080fd5b80632f990e3f116101385780636cec2536116101125780636cec25361461027d57806374637a7a1461029d5780637f565360146102bd57600080fd5b80632f990e3f1461023757806331a7c8c81461024a57806342d654fc1461025d57600080fd5b806327fe18221161016957806327fe1822146101f15780632852527a1461020457806328ddd0461461021757600080fd5b8062d84acb1461018f57806326307668146101cb57806326a32fc7146101de575b600080fd5b6101a261019d366004612915565b6103ce565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101a26101d9366004612994565b6103e6565b6101a26101ec3660046129db565b610452565b6101a26101ff3660046129db565b6104de565b6101a2610212366004612a39565b610539565b34801561022357600080fd5b506101a2610232366004612a90565b6106fe565b6101a2610245366004612aa9565b61072a565b6101a2610258366004612aa9565b6107bb565b34801561026957600080fd5b506101a2610278366004612b1e565b6107c9565b34801561028957600080fd5b506101a2610298366004612a90565b610823565b3480156102a957600080fd5b506101a26102b8366004612b4a565b61084f565b6101a26102cb3660046129db565b611162565b6101a26102de366004612b74565b6111e8565b3480156102ef57600080fd5b506101a26102fe366004612bac565b611276565b6101a2610311366004612bce565b6112a3565b6101a2610324366004612994565b611505565b6101a2610337366004612c49565b6116f1565b6101a261034a366004612aa9565b611964565b34801561035b57600080fd5b506101a261036a366004612cd9565b6119ed565b6101a261037d366004612c49565b611a17565b6101a2610390366004612bce565b611e0c565b6101a26103a3366004612915565b611e95565b6101a26103b6366004612bce565b611ea4565b6101a26103c9366004612b74565b611f2d565b60006103dd8585858533611a17565b95945050505050565b6000806103f2846120db565b90508083516020850134f59150610408826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a35092915050565b60006104d86104d260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b836103e6565b92915050565b600081516020830134f090506104f3816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a2919050565b600080610545856120db565b905060008460601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f593505073ffffffffffffffffffffffffffffffffffffffff8316610635576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660048201526024015b60405180910390fd5b604051829073ffffffffffffffffffffffffffffffffffffffff8516907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808473ffffffffffffffffffffffffffffffffffffffff1634876040516106a19190612d29565b60006040518083038185875af1925050503d80600081146106de576040519150601f19603f3d011682016040523d82523d6000602084013e6106e3565b606091505b50915091506106f382828961247d565b505050509392505050565b60006104d87f00000000000000000000000000000000000000000000000000000000000000008361084f565b60006107b36107aa60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b85858533611a17565b949350505050565b60006107b3848484336112a3565b60006040518260005260ff600b53836020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b20601452806040525061d694600052600160345350506017601e20919050565b60006104d8827f00000000000000000000000000000000000000000000000000000000000000006107c9565b600060607f9400000000000000000000000000000000000000000000000000000000000000610887600167ffffffffffffffff612d45565b67ffffffffffffffff16841115610902576040517f3c55ab3b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b836000036109c7576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f800000000000000000000000000000000000000000000000000000000000000060368201526037015b6040516020818303038152906040529150611152565b607f8411610a60576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16602283015260f886901b1660368201526037016109b1565b60ff8411610b1f576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b1660228301527f8100000000000000000000000000000000000000000000000000000000000000603683015260f886901b1660378201526038016109b1565b61ffff8411610bff576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f086901b1660378201526039016109b1565b62ffffff8411610ce0576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e886901b166037820152603a016109b1565b63ffffffff8411610dc2576040517fda0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e086901b166037820152603b016109b1565b64ffffffffff8411610ea5576040517fdb0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f850000000000000000000000000000000000000000000000000000000000000060368201527fffffffffff00000000000000000000000000000000000000000000000000000060d886901b166037820152603c016109b1565b65ffffffffffff8411610f89576040517fdc0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f860000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffff000000000000000000000000000000000000000000000000000060d086901b166037820152603d016109b1565b66ffffffffffffff841161106e576040517fdd0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f870000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffff0000000000000000000000000000000000000000000000000060c886901b166037820152603e016109b1565b6040517fde0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f880000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffffff00000000000000000000000000000000000000000000000060c086901b166037820152603f0160405160208183030381529060405291505b5080516020909101209392505050565b60006104d86111e260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b83611505565b600061126f61126860408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b8484610539565b9392505050565b600061126f83837f00000000000000000000000000000000000000000000000000000000000000006119ed565b60008451602086018451f090506112b9816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808273ffffffffffffffffffffffffffffffffffffffff168560200151876040516113279190612d29565b60006040518083038185875af1925050503d8060008114611364576040519150601f19603f3d011682016040523d82523d6000602084013e611369565b606091505b5091509150816113c9577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001631156114fb578373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611495576040519150601f19603f3d011682016040523d82523d6000602084013e61149a565b606091505b509092509050816114fb577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b5050949350505050565b600080611511846120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff81166115e0576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a361162c83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1634876040516116569190612d29565b60006040518083038185875af1925050503d8060008114611693576040519150601f19603f3d011682016040523d82523d6000602084013e611698565b606091505b505090506116a681866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a25050505092915050565b6000806116fd876120db565b9050808651602088018651f59150611714826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808373ffffffffffffffffffffffffffffffffffffffff168660200151886040516117849190612d29565b60006040518083038185875af1925050503d80600081146117c1576040519150601f19603f3d011682016040523d82523d6000602084013e6117c6565b606091505b509150915081611826577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611958578473ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d80600081146118f2576040519150601f19603f3d011682016040523d82523d6000602084013e6118f7565b606091505b50909250905081611958577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b50505095945050505050565b60006107b36119e460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b858585336116f1565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b600080611a23876120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff8116611af2576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a3611b3e83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1687600001518a604051611b6c9190612d29565b60006040518083038185875af1925050503d8060008114611ba9576040519150601f19603f3d011682016040523d82523d6000602084013e611bae565b606091505b50509050611bbc81866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a260608573ffffffffffffffffffffffffffffffffffffffff1688602001518a604051611c299190612d29565b60006040518083038185875af1925050503d8060008114611c66576040519150601f19603f3d011682016040523d82523d6000602084013e611c6b565b606091505b50909250905081611ccc577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611dfe578673ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611d98576040519150601f19603f3d011682016040523d82523d6000602084013e611d9d565b606091505b50909250905081611dfe577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050505095945050505050565b60006103dd611e8c60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b868686866116f1565b60006103dd85858585336116f1565b60006103dd611f2460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b86868686611a17565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f092505073ffffffffffffffffffffffffffffffffffffffff8216612016576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808373ffffffffffffffffffffffffffffffffffffffff1634866040516120809190612d29565b60006040518083038185875af1925050503d80600081146120bd576040519150601f19603f3d011682016040523d82523d6000602084013e6120c2565b606091505b50915091506120d282828861247d565b50505092915050565b60008060006120e9846125b3565b9092509050600082600281111561210257612102612e02565b1480156121205750600081600281111561211e5761211e612e02565b145b1561215e57604080513360208201524691810191909152606081018590526080016040516020818303038152906040528051906020012092506123cc565b600082600281111561217257612172612e02565b1480156121905750600181600281111561218e5761218e612e02565b145b156121b0576121a9338560009182526020526040902090565b92506123cc565b60008260028111156121c4576121c4612e02565b03612233576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b600182600281111561224757612247612e02565b1480156122655750600081600281111561226357612263612e02565b145b1561227e576121a9468560009182526020526040902090565b600182600281111561229257612292612e02565b1480156122b0575060028160028111156122ae576122ae612e02565b145b1561231f576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b61239a60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b84036123a657836123c9565b604080516020810186905201604051602081830303815290604052805190602001205b92505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff8116158061240b575073ffffffffffffffffffffffffffffffffffffffff81163b155b1561247a576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b50565b82158061249f575073ffffffffffffffffffffffffffffffffffffffff81163b155b156124fa577f0000000000000000000000000000000000000000000000000000000000000000826040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050565b811580612520575073ffffffffffffffffffffffffffffffffffffffff8116155b80612540575073ffffffffffffffffffffffffffffffffffffffff81163b155b156125af576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b5050565b600080606083901c3314801561261057508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b1561262057506000905080915091565b606083901c3314801561265a57507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561266b5750600090506001915091565b33606084901c036126825750600090506002915091565b606083901c1580156126db57508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b156126ec5750600190506000915091565b606083901c15801561272557507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561273557506001905080915091565b606083901c61274a5750600190506002915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000036127a55750600290506000915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000036127e15750600290506001915091565b506002905080915091565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261282c57600080fd5b813567ffffffffffffffff80821115612847576128476127ec565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561288d5761288d6127ec565b816040528381528660208588010111156128a657600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000604082840312156128d857600080fd5b6040516040810181811067ffffffffffffffff821117156128fb576128fb6127ec565b604052823581526020928301359281019290925250919050565b60008060008060a0858703121561292b57600080fd5b84359350602085013567ffffffffffffffff8082111561294a57600080fd5b6129568883890161281b565b9450604087013591508082111561296c57600080fd5b506129798782880161281b565b92505061298986606087016128c6565b905092959194509250565b600080604083850312156129a757600080fd5b82359150602083013567ffffffffffffffff8111156129c557600080fd5b6129d18582860161281b565b9150509250929050565b6000602082840312156129ed57600080fd5b813567ffffffffffffffff811115612a0457600080fd5b6107b38482850161281b565b803573ffffffffffffffffffffffffffffffffffffffff81168114612a3457600080fd5b919050565b600080600060608486031215612a4e57600080fd5b83359250612a5e60208501612a10565b9150604084013567ffffffffffffffff811115612a7a57600080fd5b612a868682870161281b565b9150509250925092565b600060208284031215612aa257600080fd5b5035919050565b600080600060808486031215612abe57600080fd5b833567ffffffffffffffff80821115612ad657600080fd5b612ae28783880161281b565b94506020860135915080821115612af857600080fd5b50612b058682870161281b565b925050612b1585604086016128c6565b90509250925092565b60008060408385031215612b3157600080fd5b82359150612b4160208401612a10565b90509250929050565b60008060408385031215612b5d57600080fd5b612b6683612a10565b946020939093013593505050565b60008060408385031215612b8757600080fd5b612b9083612a10565b9150602083013567ffffffffffffffff8111156129c557600080fd5b60008060408385031215612bbf57600080fd5b50508035926020909101359150565b60008060008060a08587031215612be457600080fd5b843567ffffffffffffffff80821115612bfc57600080fd5b612c088883890161281b565b95506020870135915080821115612c1e57600080fd5b50612c2b8782880161281b565b935050612c3b86604087016128c6565b915061298960808601612a10565b600080600080600060c08688031215612c6157600080fd5b85359450602086013567ffffffffffffffff80821115612c8057600080fd5b612c8c89838a0161281b565b95506040880135915080821115612ca257600080fd5b50612caf8882890161281b565b935050612cbf87606088016128c6565b9150612ccd60a08701612a10565b90509295509295909350565b600080600060608486031215612cee57600080fd5b8335925060208401359150612b1560408501612a10565b60005b83811015612d20578181015183820152602001612d08565b50506000910152565b60008251612d3b818460208701612d05565b9190910192915050565b67ffffffffffffffff828116828216039080821115612d8d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260008251806040840152612dcf816060850160208701612d05565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c6343000817000a1ca005f70bf8a1493291468f36ef23b05eb3a4f1807f6b4022942a4104b7537bfc36a029528c0c29546c81e7d78b0277ef87031541bdc96427b246ecedb6d74cd3ed62"
ensure_createx_deployed() {
local rpc_url=$1
local existing_code
if ! existing_code=$(cast code "$createx_address" --rpc-url "$rpc_url" 2>/dev/null); then
echo "Warning: failed to fetch CreateX code on ${rpc_url}; skipping bootstrap." >&2
return
fi
if [[ "$existing_code" == "0x" || "$existing_code" == "0x0" ]]; then
echo "Bootstrapping CreateX on ${rpc_url}" >&2
cast rpc --rpc-url "$rpc_url" anvil_setBalance "$createx_deployer" 10000000000000000000
cast rpc --rpc-url "$rpc_url" anvil_setNonce "$createx_deployer" 0x0
cast publish "$createx_tx" --rpc-url "$rpc_url"
fi
}
run_contract_deploy() {
local contract_key=$1
local signature=$2
local description=$3
local chains=()
while IFS= read -r line; do
[[ -n "$line" ]] && chains+=("$line")
done < <(get_contract_chains "$config_path" "$contract_key")
if [[ ${#chains[@]} -eq 0 ]]; then
echo "Skipping ${description}: no chains configured."
return
fi
for chain_id in "${chains[@]}"; do
local endpoint_url
endpoint_url=$(get_chain_rpc_url "$config_path" "$chain_id")
if [[ -z "$endpoint_url" ]]; then
echo "Warning: no endpoint_url configured for chain ${chain_id}; skipping ${description}." >&2
continue
fi
ensure_createx_deployed "$endpoint_url"
echo "Running ${description} on chain ${chain_id} (rpc: ${endpoint_url})"
cmd=(forge script "$script_path" --sig "$signature" --chain-id "$chain_id" --rpc-url "$endpoint_url")
if [[ ${#extra_args[@]} -gt 0 ]]; then
cmd+=("${extra_args[@]}")
fi
"${cmd[@]}"
done
}
run_contract_deploy "keyRegistry" "runDeployKeyRegistry()" "KeyRegistry deployment"
run_contract_deploy "votingPowerProvider" "runDeployVotingPowerProvider()" "VotingPowerProvider deployment"
run_contract_deploy "settlement" "runDeploySettlement()" "Settlement deployment"
run_contract_deploy "valSetDriver" "runDeployValSetDriver()" "ValSetDriver deployment"
````
## File: script/RelayDeploy.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Vm, VmSafe} from "forge-std/Vm.sol";
import {Script, console2} from "forge-std/Script.sol";
import {Config} from "forge-std/Config.sol";
import {Variable} from "forge-std/LibVariable.sol";
⋮----
import {CreateXWrapper} from "@symbioticfi/core/script/utils/CreateXWrapper.sol";
import {Logs} from "@symbioticfi/core/script/utils/Logs.sol";
import {SymbioticCoreConstants} from "@symbioticfi/core/test/integration/SymbioticCoreConstants.sol";
import {SymbioticCoreInit} from "@symbioticfi/core/script/integration/SymbioticCoreInit.sol";
import "@symbioticfi/core/test/integration/SymbioticCoreImports.sol";
⋮----
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
⋮----
import {IOpNetVaultAutoDeploy} from "../src/interfaces/modules/voting-power/extensions/IOpNetVaultAutoDeploy.sol";
import {VotingPowerProvider} from "../src/modules/voting-power/VotingPowerProvider.sol";
import {IValSetDriver} from "../src/interfaces/modules/valset-driver/IValSetDriver.sol";
⋮----
/**
* @title RelayDeploy
* @notice Abstract base contract for deploying relay contracts using CREATE3
* @dev This contract provides a standardized deployment pattern for relay contracts
*
* The contract supports both guarded and non-guarded salt deployments.
* See https://github.com/pcaversaccio/createx?tab=readme-ov-file#security-considerations
*
* This script requires a deployed CreateX instance.
*/
abstract contract RelayDeploy is SymbioticCoreInit, Config, CreateXWrapper {
⋮----
modifier loadConfig() {
⋮----
modifier withBroadcast() {
⋮----
modifier withoutBroadcast() {
⋮----
/**
* @notice Returns deployment parameters for the KeyRegistry contract
* @dev Must be implemented by concrete deployment contracts
* @return implementation The implementation contract address
* @return initData The initialization data for the proxy
*/
function _keyRegistryParams() internal virtual returns (address implementation, bytes memory initData);
⋮----
/**
* @notice Returns deployment parameters for the VotingPowerProvider contract
* @dev Must be implemented by concrete deployment contracts
* @return implementation The implementation contract address
* @return initData The initialization data for the proxy
*/
function _votingPowerProviderParams() internal virtual returns (address implementation, bytes memory initData);
⋮----
/**
* @notice Returns deployment parameters for the Settlement contract
* @dev Must be implemented by concrete deployment contracts
* @return implementation The implementation contract address
* @return initData The initialization data for the proxy
*/
function _settlementParams() internal virtual returns (address implementation, bytes memory initData);
⋮----
/**
* @notice Returns deployment parameters for the ValSetDriver contract
* @dev Must be implemented by concrete deployment contracts
* @return implementation The implementation contract address
* @return initData The initialization data for the proxy
*/
function _valSetDriverParams() internal virtual returns (address implementation, bytes memory initData);
⋮----
function runDeployKeyRegistry() public virtual;
⋮----
function runDeployVotingPowerProvider() public virtual;
⋮----
function runDeploySettlement() public virtual;
⋮----
function runDeployValSetDriver() public virtual;
⋮----
function getCore() public withoutBroadcast loadConfig returns (SymbioticCoreConstants.Core memory) {
⋮----
function getKeyRegistry()
⋮----
function getVotingPowerProvider() public virtual withoutBroadcast loadConfig returns (address) {
⋮----
function getVotingPowerProviders()
⋮----
function getSettlement() public virtual withoutBroadcast loadConfig returns (address) {
⋮----
function getSettlements()
⋮----
function getValSetDriver()
⋮----
/**
* @notice Deploy the KeyRegistry contract using CREATE3
* @dev Deploys a transparent upgradeable proxy for the KeyRegistry
* @param proxyOwner The owner of the proxy contract
* @param isDeployerGuarded Whether to deploy with guarded salt for enhanced security
* @return The address of the deployed KeyRegistry contract
*/
function deployKeyRegistry(address proxyOwner, bool isDeployerGuarded, bytes11 salt)
⋮----
/**
* @notice Deploy the VotingPowerProvider contract using CREATE3
* @dev Deploys a transparent upgradeable proxy for the VotingPowerProvider
* @param proxyOwner The owner of the proxy contract
* @param isDeployerGuarded Whether to deploy with guarded salt for enhanced security
* @return The address of the deployed VotingPowerProvider contract
*/
function deployVotingPowerProvider(address proxyOwner, bool isDeployerGuarded, bytes11 salt)
⋮----
// Validate deployment
⋮----
/**
* @notice Deploy the Settlement contract using CREATE3
* @dev Deploys a transparent upgradeable proxy for the Settlement
* @param proxyOwner The owner of the proxy contract
* @param isDeployerGuarded Whether to deploy with guarded salt for enhanced security
* @return The address of the deployed Settlement contract
*/
function deploySettlement(address proxyOwner, bool isDeployerGuarded, bytes11 salt)
⋮----
/**
* @notice Deploy the ValSetDriver contract using CREATE3
* @dev Deploys a transparent upgradeable proxy for the ValSetDriver
* @param proxyOwner The owner of the proxy contract
* @param isDeployerGuarded Whether to deploy with guarded salt for enhanced security
* @return The address of the deployed ValSetDriver contract
*/
function deployValSetDriver(address proxyOwner, bool isDeployerGuarded, bytes11 salt)
⋮----
/**
* @notice Internal function to deploy a contract using CREATE3 with optional initialization
* @dev Creates a transparent upgradeable proxy and optionally initializes it
* @param salt The CREATE3 salt for deterministic deployment
* @param implementation The implementation contract address
* @param initData The initialization data for the proxy (empty bytes if no initialization)
* @param owner The owner of the proxy contract
* @param isDeployerGuarded Whether to use guarded salt deployment
* @return The address of the deployed contract
*/
function _deployContract(
````
## File: snapshots/gas.txt
````
No files changed, compilation skipped
Ran 3 tests for test/modules/common/permissions/OzAccessManaged.t.sol:OzAccessManagedTest
[PASS] testCannotChangeAuthority() (gas: 32030)
[PASS] testProtectedAction_RevertsForNonAdmin() (gas: 40731)
[PASS] testProtectedAction_SucceedsForAdmin() (gas: 40292)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 6.27ms (892.37µs CPU time)
Ran 4 tests for test/modules/common/permissions/OzOwnable.t.sol:OzOwnableTest
[PASS] testProtectedAction_RevertsForNonOwner() (gas: 34468)
[PASS] testProtectedAction_SucceedsForOwner() (gas: 34042)
[PASS] testReinitializeReverts() (gas: 34167)
[PASS] testTransferOwnership() (gas: 91093)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 6.27ms (903.63µs CPU time)
Ran 6 tests for test/modules/common/permissions/OzAccessControl.t.sol:OzAccessControlTest
[PASS] testChangeRoleForProtectedFunction() (gas: 137387)
[PASS] testGetRoleForFunctionSelector() (gas: 64891)
[PASS] testProtectedFunction_RevertIfCallerDoesNotHaveRole() (gas: 36907)
[PASS] testSetNoRoleForSelector() (gas: 92605)
[PASS] test_Location() (gas: 458)
[PASS] test_ProtectedFunction_DefaultAdminCanCall() (gas: 31147)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 6.31ms (868.33µs CPU time)
Ran 5 tests for test/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.t.sol:PricedTokensChainlinkVPCalcTest
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPrice() (gas: 3466)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceHistorical() (gas: 8108)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceHistoricalZero() (gas: 8131)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceStale() (gas: 3400)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceWithInvert() (gas: 3400)
Suite result: FAILED. 0 passed; 5 failed; 0 skipped; finished in 6.74ms (1.07ms CPU time)
Ran 2 tests for test/modules/base/PermissionManager.t.sol:PermissionManagerTest
[PASS] test_ProtectedAction_RevertIfNotOwner() (gas: 32486)
[PASS] test_ProtectedAction_SucceedsForOwner() (gas: 28627)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 285.29µs (24.00µs CPU time)
Ran 5 tests for test/modules/base/NetworkManager.t.sol:NetworkManagerTest
[PASS] test_DefaultsBeforeInit() (gas: 18077)
[PASS] test_InitializeAndCheckGetters() (gas: 95114)
[PASS] test_Location() (gas: 522)
[PASS] test_ReinitializeReverts() (gas: 104707)
[PASS] test_RevertNetworkManager_InvalidNetwork() (gas: 123081)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 348.08µs (87.21µs CPU time)
Ran 1 test for test/modules/common/permissions/NoPermissionManager.t.sol:NoPermissionManagerTest
[PASS] test_NoPermissionCheck() (gas: 29615)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 214.58µs (9.96µs CPU time)
Ran 18 tests for test/modules/valset-driver/EpochManager.t.sol:EpochManagerTest
[PASS] test_AdvanceTimeAndCheckEpoch() (gas: 207469)
[PASS] test_DirectSetEpochDuration() (gas: 244617)
[PASS] test_GetCurrentEpochDurationData() (gas: 161233)
[PASS] test_GetCurrentValue_MultipleCheckpoints() (gas: 245317)
[PASS] test_GetCurrentValue_NoCheckpoint() (gas: 10727)
[PASS] test_GetCurrentValue_SingleCheckpoint() (gas: 97941)
[PASS] test_GetEpochDurationAndStart() (gas: 421185)
[PASS] test_GetEpochDurationDataByIndex() (gas: 152442)
[PASS] test_GetEpochDurationDataByTimestamp() (gas: 152822)
[PASS] test_GetEpochIndex() (gas: 152449)
[PASS] test_GetEpochIndex_RevertIfTooOldTimestamp() (gas: 165031)
[PASS] test_Initialize_RevertOnPastTimestamp() (gas: 54021)
[PASS] test_Initialize_RevertOnZeroEpochDuration() (gas: 53671)
[PASS] test_Initialize_SetsEpochDuration() (gas: 228758)
[PASS] test_Initialize_SetsEpochDuration_WithZeroTimestamp() (gas: 204726)
[PASS] test_SerializeDeserializeEpochDurationData() (gas: 9810)
[PASS] test_SetEpochDuration_RevertIfIndexLessThanCurrent() (gas: 291563)
[PASS] test_SetEpochDuration_RevertOnZeroDuration() (gas: 180257)
Suite result: ok. 18 passed; 0 failed; 0 skipped; finished in 7.36ms (2.21ms CPU time)
Ran 1 test for test/modules/voting-power/extensions/EqualStakeVPCalc.t.sol:EqualStakeVPCalcTest
[PASS] test_create() (gas: 143)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 291.67µs (4.67µs CPU time)
Ran 8 tests for test/modules/settlement/Settlement.t.sol:SettlementRawTest
[PASS] testCommitValSetHeader_Basic() (gas: 1082819)
[PASS] testInitParams() (gas: 29336)
[PASS] testSetGenesis_Permission() (gas: 383545)
[PASS] testSetGenesis_Revert_ValSetHeaderAlreadySubmitted() (gas: 240426)
[PASS] testVersion() (gas: 5714)
[PASS] test_commitValSetHeader_VerificationFailed() (gas: 931578)
[PASS] test_setSigVerifier() (gas: 321900)
[PASS] test_setSigVerifier_Revert_InvalidSigVerifier() (gas: 34441)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 1.54ms (993.29µs CPU time)
Ran 14 tests for test/modules/valset-driver/ValSetDriver.t.sol:ValSetDriverTest
[PASS] test_AddRemoveQuorumThreshold() (gas: 441186)
[PASS] test_AddRemoveSettlement() (gas: 466129)
[PASS] test_AddRemoveVotingPowerProvider() (gas: 348594)
[PASS] test_GetValSetConfig() (gas: 130897)
[PASS] test_InitialConfig() (gas: 351786)
[PASS] test_Location() (gas: 589)
[PASS] test_PermissionChecks() (gas: 276042)
[PASS] test_SetKeysProvider() (gas: 97383)
[PASS] test_SetNumAggregators() (gas: 638425)
[PASS] test_SetNumCommitters() (gas: 638430)
[PASS] test_SetVerificationType() (gas: 75644)
[PASS] test_TimeBasedConfig() (gas: 116652)
[PASS] test_TimeBasedQueries() (gas: 366953)
[PASS] test_UpdateAllConfigs() (gas: 1052365)
Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 3.75ms (3.13ms CPU time)
Ran 8 tests for test/libraries/structs/PersistentSet.t.sol:PersistentSetTest
[PASS] test_AddressSetAddRemoveAndContains() (gas: 204274)
[PASS] test_AddressSetAllValues() (gas: 185014)
[PASS] test_AddressSetLengthAndValuesAt() (gas: 239766)
[PASS] test_Bytes32SetAddRemoveAndContains() (gas: 221727)
[PASS] test_Bytes32SetAllValues() (gas: 184889)
[PASS] test_Bytes32SetValuesAt() (gas: 245622)
[PASS] test_LargeAddressSetExceed256Elements() (gas: 16698398)
[PASS] test_RevertPersistentSet_InvalidKey() (gas: 184062)
Suite result: ok. 8 passed; 0 failed; 0 skipped; finished in 11.38ms (5.93ms CPU time)
Ran 4 tests for test/modules/base/VotingPowerCalcManager.t.sol:VotingPowerCalcManagerTest
[PASS] testReInitializeReverts() (gas: 31722)
[PASS] testStakeToVotingPower() (gas: 6387)
[PASS] testStakeToVotingPowerAt() (gas: 9400)
[PASS] testWithExtraData() (gas: 6595)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 272.67µs (46.83µs CPU time)
Ran 5 tests for test/libraries/utils/ValSetVerifier.t.sol:ValSetVerifierDataTest
[PASS] test_VerifyIsActive() (gas: 425714)
[PASS] test_VerifyKey() (gas: 535277)
[PASS] test_VerifyOperator() (gas: 423626)
[PASS] test_VerifyVault() (gas: 688276)
[PASS] test_VerifyVotingPower() (gas: 423627)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 3.10ms (2.81ms CPU time)
Ran 5 tests for test/modules/base/OzEIP712.t.sol:OzEIP712Test
[PASS] test_HashTypedDataV4() (gas: 121509)
[PASS] test_InitializeSetsDomain() (gas: 125433)
[PASS] test_Location() (gas: 525)
[PASS] test_ReInitialize() (gas: 133758)
[PASS] test_SignatureRecovery() (gas: 121973)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 14.70ms (9.26ms CPU time)
Ran 12 tests for test/libraries/keys/KeyEcdsaSecp256k1.t.sol:KeyEcdsaSecp256k1Test
[PASS] test_DeserializeRevertsIfNot20Bytes() (gas: 10139)
[PASS] test_Equal() (gas: 20457)
[PASS] test_EqualFalse() (gas: 20456)
[PASS] test_FromBytesRevertsIfNot20Bytes() (gas: 10138)
[PASS] test_FromBytesRevertsInvalidBytes() (gas: 12982)
[PASS] test_FuzzSerializeDeserialize(address) (runs: 1000, μ: 1171, ~: 1171)
[PASS] test_FuzzToBytesFromBytes(address) (runs: 1000, μ: 1513, ~: 1513)
[PASS] test_FuzzWrapUnwrap(address) (runs: 1000, μ: 685, ~: 685)
[PASS] test_SerializeDeserialize() (gas: 4798)
[PASS] test_ToBytesFromBytes() (gas: 5282)
[PASS] test_WrapUnwrap() (gas: 4363)
[PASS] test_ZeroKey() (gas: 5910)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 28.40ms (23.25ms CPU time)
Ran 4 tests for test/libraries/sigs/SigBlsBn254.t.sol:SigBlsBn254Test
[PASS] test_BLSRegisterOperator() (gas: 1121825)
[PASS] test_BLSRegisterOperatorInvalid() (gas: 1121897)
[PASS] test_InvalidMessageLength() (gas: 7664)
[PASS] test_ZeroKey() (gas: 5008)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 16.31ms (16.07ms CPU time)
Ran 7 tests for test/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.t.sol:ExtraDataStorageHelperTest
[PASS] testFuzz_Uniqueness(uint32,uint32,uint8,uint8,bytes32,bytes32,uint256,uint256) (runs: 1000, μ: 6484, ~: 6566)
[PASS] test_BaseKey() (gas: 1081)
[PASS] test_IndexedKey() (gas: 4680)
[PASS] test_IndexedTagOnlyKey() (gas: 4441)
[PASS] test_SimpleKey() (gas: 1018)
[PASS] test_TagOnlyKey() (gas: 1151)
[PASS] test_TaggedKey() (gas: 1572)
Suite result: ok. 7 passed; 0 failed; 0 skipped; finished in 26.38ms (26.11ms CPU time)
Ran 12 tests for test/modules/key-registry/KeyRegistry.t.sol:KeyRegistryTest
[PASS] test_GetKeysAt_TimeCheckpoints() (gas: 835723)
[PASS] test_GetKeysOperators_MultipleOperators() (gas: 1026730)
[PASS] test_GetOperator_UnknownKey() (gas: 8664)
[PASS] test_Location() (gas: 633)
[PASS] test_SetBLSKey() (gas: 856175)
[PASS] test_SetECDSAKey() (gas: 482827)
[PASS] test_SetECDSAKey_RevertOnInvalidSignature() (gas: 59183)
[PASS] test_SetKey64() (gas: 488767)
[PASS] test_SetKey_AlreadyUsedKeyDifferentOperator() (gas: 395671)
[PASS] test_SetKey_RevertOnInvalidKeyType() (gas: 40960)
[PASS] test_SetKey_SameOperatorDifferentTags() (gas: 616254)
[PASS] test_SetKey_SameOperatorSameTag_Overwrite() (gas: 497188)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 5.91ms (5.39ms CPU time)
Ran 6 tests for test/libraries/utils/InputNormalizer.t.sol:InputNormalizerTest
[PASS] test_normalizeDoubleDimEmpty() (gas: 1701)
[PASS] test_normalizeDoubleDimExact() (gas: 7134)
[PASS] test_normalizeDoubleDimMismatchRevert() (gas: 10039)
[PASS] test_normalizeSingleDimEmpty() (gas: 2037)
[PASS] test_normalizeSingleDimExact() (gas: 6924)
[PASS] test_normalizeSingleDimMismatchRevert() (gas: 9196)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 312.25µs (94.42µs CPU time)
Ran 12 tests for test/libraries/utils/KeyTag.t.sol:KeyTagTest
[PASS] test_AddMultiple() (gas: 1857)
[PASS] test_ContainsAddRemove() (gas: 1141)
[PASS] test_DeserializeBitmask() (gas: 31921)
[PASS] test_GetKeyTagInvalidIdentifier() (gas: 4264)
[PASS] test_GetKeyTagInvalidType() (gas: 4180)
[PASS] test_GetKeyTagValid() (gas: 453)
[PASS] test_GetTag() (gas: 441)
[PASS] test_GetTagRevertWhenTooLarge() (gas: 4046)
[PASS] test_GetType() (gas: 380)
[PASS] test_GetTypeRevertWhenTooLarge() (gas: 4081)
[PASS] test_SerializeRevertOnDuplicate() (gas: 6095)
[PASS] test_SerializeUniqueKeyTags() (gas: 3469)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 370.71µs (153.58µs CPU time)
Ran 5 tests for test/libraries/sigs/SigEcdsaSecp256k1.t.sol:SigEcdsaSecp256k1Test
[PASS] test_CorrectSignature() (gas: 13094)
[PASS] test_FuzzVerification(uint256,bytes) (runs: 1000, μ: 16849, ~: 16825)
[PASS] test_IncorrectSignature() (gas: 22938)
[PASS] test_InvalidMessageLength() (gas: 6500)
[PASS] test_ZeroKey() (gas: 2104)
Suite result: ok. 5 passed; 0 failed; 0 skipped; finished in 166.36ms (166.14ms CPU time)
Ran 11 tests for test/modules/voting-power/extensions/OperatorsWhitelist.t.sol:OperatorsWhitelistTest
[PASS] test_DisableWhitelistAndRegister() (gas: 188486)
[PASS] test_DisableWhitelistAndRegisterOperatorVault() (gas: 468611)
[PASS] test_Location() (gas: 569)
[PASS] test_RegisterOperator_RevertIfNotWhitelisted() (gas: 36811)
[PASS] test_SetWhitelistStatus_RevertIfAlreadySet() (gas: 133365)
[PASS] test_SetWhitelistStatus_RevertIfNotWhitelisted() (gas: 36503)
[PASS] test_UnwhitelistOperator_RegisteredOperatorGetsUnregistered() (gas: 306437)
[PASS] test_UnwhitelistOperator_RevertIfNotWhitelisted() (gas: 34355)
[PASS] test_WhitelistEnabledByDefault() (gas: 7738)
[PASS] test_WhitelistOperatorAndRegister() (gas: 220687)
[PASS] test_WhitelistOperator_RevertIfAlreadyWhitelisted() (gas: 80347)
Suite result: ok. 11 passed; 0 failed; 0 skipped; finished in 188.63ms (3.05ms CPU time)
Ran 12 tests for test/modules/voting-power/extensions/OpNetVaultAutoDeploy.t.sol:OpNetVaultAutoDeployTest
[PASS] test_AutoDeployOnRegister() (gas: 1755847)
[PASS] test_AutoDeployOnRegister_SetMaxNetworkLimitHook() (gas: 1522149)
[PASS] test_AutoDeployOnRegister_WithoutSlasher() (gas: 1288671)
[PASS] test_BasicFlags() (gas: 33675)
[PASS] test_Location() (gas: 547)
[PASS] test_SetAutoDeployConfig_InvalidBurnerHook() (gas: 83764)
[PASS] test_SetAutoDeployConfig_InvalidBurnerParamsWithSlasher() (gas: 81640)
[PASS] test_SetAutoDeployConfig_InvalidCollateral() (gas: 39635)
[PASS] test_SetAutoDeployConfig_InvalidEpochDurationLessThanMinVaultEpochDuration() (gas: 59745)
[PASS] test_SetAutoDeployConfig_InvalidEpochDurationZero() (gas: 39940)
[PASS] test_SetAutoDeployConfig_InvalidWithSlasher() (gas: 48729)
[PASS] test_SetAutoDeployStatus() (gas: 59408)
Suite result: ok. 12 passed; 0 failed; 0 skipped; finished in 191.57ms (4.10ms CPU time)
Ran 10 tests for test/modules/voting-power/extensions/BaseSlashing.t.sol:BaseSlashingTest
[PASS] test_ExecuteSlashVaul_NotVetoSlasher() (gas: 489962)
[PASS] test_ExecuteSlashVault_NoSlasher() (gas: 1398945)
[PASS] test_Location() (gas: 569)
[PASS] test_RevertWhen_SlashVault_NoSlashing() (gas: 497850)
[PASS] test_RevertWhen_SlashVault_UnknownSlasherType() (gas: 513933)
[PASS] test_SlashVault() (gas: 918317)
[PASS] test_SlashVaultUnsafe() (gas: 1851089)
[PASS] test_SlashVault_EpochDurationPassed() (gas: 517298)
[PASS] test_SlashVault_VetoSlasher() (gas: 3614815)
[PASS] test_SlashVault_WithHints() (gas: 887970)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 198.67ms (6.86ms CPU time)
Ran 3 tests for test/modules/voting-power/extensions/BaseRewards.t.sol:BaseRewardsTest
[PASS] test_Location() (gas: 569)
[PASS] test_OperatorRewards() (gas: 981074)
[PASS] test_StakerRewards() (gas: 1266470)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 200.37ms (1.95ms CPU time)
Ran 21 tests for test/libraries/keys/KeyBlsBn254.t.sol:KeyBlsBn254Test
[PASS] test_DeserializeEmptyBytesIsIdentity() (gas: 893)
[PASS] test_DeserializeRevertsInvalidLength() (gas: 10314)
[PASS] test_Equal() (gas: 14779)
[PASS] test_EqualFalse() (gas: 19066)
[PASS] test_FromBytesRevertsInvalidBytes() (gas: 13146)
[PASS] test_FromBytesRevertsInvalidLength() (gas: 10338)
[PASS] test_FuzzSerializeDeserialize(uint256) (runs: 1000, μ: 5798, ~: 8321)
[PASS] test_FuzzSerializeDeserializeNonZeroNegate(uint256) (runs: 1000, μ: 6079, ~: 9120)
[PASS] test_FuzzToBytesFromBytes(uint256) (runs: 1000, μ: 3892, ~: 4987)
[PASS] test_FuzzWrapUnwrap(uint256) (runs: 1000, μ: 3056, ~: 3440)
[PASS] test_OutOfBounds() (gas: 27427)
[PASS] test_SerializeDeserializeIdentity() (gas: 1399)
[PASS] test_SerializeDeserializeNonZero() (gas: 8155)
[PASS] test_SerializeDeserializeNonZeroNegate() (gas: 8997)
[PASS] test_SerializeRevertsInvalidKey() (gas: 12594)
[PASS] test_ToBytesFromBytesIdentity() (gas: 2264)
[PASS] test_ToBytesFromBytesNonZero() (gas: 4799)
[PASS] test_WrapRevertsInvalidKey(uint256) (runs: 1000, μ: 12833, ~: 12833)
[PASS] test_WrapUnwrapIdentity() (gas: 839)
[PASS] test_WrapUnwrapNonZero() (gas: 3231)
[PASS] test_ZeroKey() (gas: 6278)
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 170.96ms (170.69ms CPU time)
Ran 6 tests for test/modules/voting-power/extensions/OperatorsJail.t.sol:OperatorsJailTest
[PASS] test_BasicEnvironment() (gas: 10198)
[PASS] test_JailOperator() (gas: 512213)
[PASS] test_JailOperator_RevertIfAlreadyJailed() (gas: 134944)
[PASS] test_Location() (gas: 526)
[PASS] test_UnjailOperator() (gas: 273471)
[PASS] test_UnjailOperator_RevertIfNotJailed() (gas: 34416)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 210.46ms (6.77ms CPU time)
Ran 2 tests for test/modules/voting-power/extensions/SharedVaults.t.sol:SharedVaultsTest
[PASS] test_RegisterSharedVault_OnlyOwnerCanCall() (gas: 180177)
[PASS] test_RegisterUnregisterSharedVault_VaultManagerSide() (gas: 277358)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 210.68ms (635.79µs CPU time)
Ran 1 test for test/modules/voting-power/extensions/OperatorVaults.t.sol:OperatorVaultsTest
[PASS] test_RegisterOperatorVault_OnlyOwnerCanCall() (gas: 1992389)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 221.74ms (795.79µs CPU time)
Ran 2 tests for test/modules/voting-power/extensions/MultiToken.t.sol:MultiTokenTest
[PASS] test_RegisterToken_OnlyOwnerCanCall() (gas: 85980)
[PASS] test_RegisterUnregisterToken_VaultManagerSide() (gas: 187414)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 216.04ms (514.96µs CPU time)
Ran 13 tests for test/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.t.sol:SigVerifierBlsBn254ZKTest
[PASS] test_Create() (gas: 4410955)
[PASS] test_FalseQuorumThreshold() (gas: 6971559)
[PASS] test_RevertInvalidLength() (gas: 4273)
[PASS] test_RevertInvalidTotalActiveValidators() (gas: 7225027)
[PASS] test_Revert_InvalidMaxValidators() (gas: 4411164)
[PASS] test_Revert_InvalidMaxValidatorsOrder() (gas: 4411206)
[PASS] test_Revert_InvalidMessageLength() (gas: 4428613)
[PASS] test_Revert_InvalidProofLength() (gas: 4434737)
[PASS] test_Revert_InvalidVerifier() (gas: 2943085)
[PASS] test_Revert_UnsupportedKeyTag() (gas: 4428462)
[PASS] test_ZeroValidators() (gas: 7240530)
[PASS] test_verifyQuorumSig() (gas: 7338033)
[PASS] test_verifyQuorumSig_FalseZkProof() (gas: 17595493375392676910)
Suite result: ok. 13 passed; 0 failed; 0 skipped; finished in 207.48ms (39.24ms CPU time)
Ran 6 tests for test/modules/voting-power/extensions/OperatorsBlacklist.t.sol:OperatorsBlacklistTest
[PASS] test_BasicEnvironment() (gas: 10071)
[PASS] test_BlacklistOperator() (gas: 314932)
[PASS] test_BlacklistOperator_RevertIfAlreadyBlacklisted() (gas: 93498)
[PASS] test_Location() (gas: 504)
[PASS] test_UnblacklistOperator() (gas: 250902)
[PASS] test_UnblacklistOperator_RevertIfNotBlacklisted() (gas: 34324)
Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 198.72ms (2.75ms CPU time)
Ran 4 tests for test/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.t.sol:WeightedVaultsVPCalcTest
[PASS] test_CheckStakesVaultWeight() (gas: 85079230)
[PASS] test_GetVaultWeightAt_UsesHistoricalVaultWeight() (gas: 6758546)
[PASS] test_SetVaultWeight_RevertIfTooLarge() (gas: 99612)
[PASS] test_StakeToVotingPowerAt_UsesHistoricalVaultWeight() (gas: 7976122)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 234.21ms (49.09ms CPU time)
Ran 21 tests for test/examples/MyVotingPowerProvider.t.sol:MyVotingPowerProviderTest
[PASS] testGetOperatorsAt_withTime() (gas: 465284)
[PASS] test_CheckStakes() (gas: 101206176)
[PASS] test_DistributeRewards() (gas: 207)
[PASS] test_IncreaseNonce() (gas: 64127)
[PASS] test_IsOperatorRegisteredAt_withTime() (gas: 190985)
[PASS] test_RegisterOperator() (gas: 1730463)
[PASS] test_RegisterOperatorValid() (gas: 162784)
[PASS] test_RegisterOperatorVault() (gas: 1896716)
[PASS] test_RegisterOperatorVaultExternal() (gas: 1776681)
[PASS] test_RegisterOperatorVault_RevertIfOperatorNotRegistered() (gas: 1342433)
[PASS] test_RegisterOperator_RevertIfAlreadyRegistered() (gas: 192924)
[PASS] test_RegisterOperator_RevertIfNotEntity() (gas: 41922)
[PASS] test_SlashVault_InstantSlasher() (gas: 252)
[PASS] test_SlashVault_RevertIfNoSlasher() (gas: 251)
[PASS] test_SlashVault_VetoSlasherFlow() (gas: 188)
[PASS] test_SlashingData() (gas: 45917)
[PASS] test_UnregisterOperator() (gas: 281328)
[PASS] test_UnregisterOperator_RevertIfNotRegistered() (gas: 40281)
[PASS] test_registerOperatorWithSignature() (gas: 1641531)
[PASS] test_registerOperatorWithSignature_RevertIfInvalidSig() (gas: 1214036)
[PASS] test_unregisterOperatorWithSignature() (gas: 284862)
Suite result: ok. 21 passed; 0 failed; 0 skipped; finished in 283.43ms (88.04ms CPU time)
Ran 3 tests for test/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.t.sol:WeightedTokensVPCalcTest
[PASS] test_CheckStakesTokenWeight() (gas: 89189896)
[PASS] test_SetTokenWeight_RevertIfTooLarge() (gas: 99727)
[PASS] test_StakeToVotingPowerAt_UsesHistoricalTokenWeightAndNormalization() (gas: 8161652)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 307.35ms (75.05ms CPU time)
Ran 30 tests for test/modules/voting-power/VotingPowerProvider.t.sol:VotingPowerProviderTest
[PASS] testGetOperatorsAt_withTime() (gas: 436503)
[PASS] test_CheckStakes() (gas: 318490684)
[PASS] test_DistributeRewards() (gas: 229)
[PASS] test_IncreaseNonce() (gas: 63999)
[PASS] test_IsOperatorRegisteredAt_withTime() (gas: 168206)
[PASS] test_Location() (gas: 611)
[PASS] test_RegisterOperator() (gas: 1845486)
[PASS] test_RegisterOperatorValid() (gas: 137749)
[PASS] test_RegisterOperatorVault() (gas: 1984637)
[PASS] test_RegisterOperatorVaultExternal() (gas: 1888865)
[PASS] test_RegisterOperatorVault_RevertIfOperatorNotRegistered() (gas: 1453363)
[PASS] test_RegisterOperator_RevertIfAlreadyRegistered() (gas: 169881)
[PASS] test_RegisterOperator_RevertIfNotEntity() (gas: 41446)
[PASS] test_RegisterSharedVault() (gas: 609131)
[PASS] test_RegisterSharedVault_RevertIfInvalidVault() (gas: 41387)
[PASS] test_RegisterSharedVault_RevertIfTokenNotRegistered() (gas: 11634350)
[PASS] test_RegisterToken() (gas: 517267)
[PASS] test_RegisterToken_RevertOnZeroAddress() (gas: 35174)
[PASS] test_SlashVault_InstantSlasher() (gas: 185)
[PASS] test_SlashVault_RevertIfNoSlasher() (gas: 273)
[PASS] test_SlashVault_VetoSlasherFlow() (gas: 277)
[PASS] test_SlashingData() (gas: 120491)
[PASS] test_UnregisterOperator() (gas: 256356)
[PASS] test_UnregisterOperator_RevertIfNotRegistered() (gas: 39873)
[PASS] test_UnregisterToken() (gas: 232892)
[PASS] test_ValidateVault() (gas: 1315114)
[PASS] test_ValidateVaultSlashingFailsIfLessThanMinVaultEpochDuration() (gas: 1306034)
[PASS] test_registerOperatorWithSignature() (gas: 1753924)
[PASS] test_registerOperatorWithSignature_RevertIfInvalidSig() (gas: 1213952)
[PASS] test_unregisterOperatorWithSignature() (gas: 285011)
Suite result: ok. 30 passed; 0 failed; 0 skipped; finished in 548.65ms (337.19ms CPU time)
Ran 14 tests for test/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.t.sol:SigVerifierBlsBn254SimpleTest
[PASS] test_FalseQuorumThreshold() (gas: 30731605)
[PASS] test_FalseValidatorSet() (gas: 34771549)
[PASS] test_RevertInvalidMessageLength() (gas: 34766028)
[PASS] test_RevertInvalidNonSignerIndex() (gas: 34770513)
[PASS] test_RevertInvalidNonSignersOrder() (gas: 34790079)
[PASS] test_RevertInvalidProofLength() (gas: 34760466)
[PASS] test_RevertInvalidProofOffset() (gas: 34785281)
[PASS] test_RevertTooManyValidators() (gas: 34766010)
[PASS] test_RevertUnsupportedKeyTag() (gas: 34765824)
[PASS] test_Revert_InvalidNonSignersOrder() (gas: 34781415)
[PASS] test_ZeroValidators() (gas: 18160576)
[PASS] test_verifyQuorumSig1() (gas: 35000314)
[PASS] test_verifyQuorumSig2() (gas: 39374545)
[PASS] test_verifyQuorumSig3() (gas: 33359383)
Suite result: ok. 14 passed; 0 failed; 0 skipped; finished in 1.94s (1.70s CPU time)
Ran 3 tests for test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol:NormalizedTokenDecimalsVPCalcTest
[PASS] test_CheckStakes_18() (gas: 84803926)
[PASS] test_CheckStakes_24() (gas: 84819127)
[PASS] test_CheckStakes_8() (gas: 84819864)
Suite result: ok. 3 passed; 0 failed; 0 skipped; finished in 6.93s (144.85ms CPU time)
Ran 10 tests for test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace256Test
[PASS] testAt(uint48[],uint256[],uint32) (runs: 1000, μ: 8337268, ~: 8750320)
[PASS] testLatest(uint48[],uint256[]) (runs: 1000, μ: 8356459, ~: 8891083)
[PASS] testLatestCheckpoint(uint48[],uint256[]) (runs: 1000, μ: 8385751, ~: 8902772)
[PASS] testLength(uint48[],uint256[]) (runs: 1000, μ: 8106193, ~: 8621765)
[PASS] testLookup(uint48[],uint256[],uint48) (runs: 1000, μ: 8188515, ~: 8720919)
[PASS] testPop(uint48[],uint256[]) (runs: 1000, μ: 4105280, ~: 3693909)
[PASS] testPush(uint48[],uint256[],uint48) (runs: 1000, μ: 8626515, ~: 9065594)
[PASS] testUpperLookupRecentCheckpoint(uint48[],uint256[],uint48) (runs: 1000, μ: 8273169, ~: 8831078)
[PASS] testUpperLookupRecentCheckpointWithHint(uint48[],uint256[],uint48,uint32) (runs: 1000, μ: 7969843, ~: 8404782)
[PASS] testUpperLookupRecentWithHint(uint48[],uint256[],uint48,uint32) (runs: 1000, μ: 7948317, ~: 8473184)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 8.02s (33.52s CPU time)
Ran 10 tests for test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace512Test
[PASS] testAt(uint48[],uint256[],uint32) (runs: 1000, μ: 12497237, ~: 13221764)
[PASS] testLatest(uint48[],uint256[]) (runs: 1000, μ: 11878733, ~: 12418264)
[PASS] testLatestCheckpoint(uint48[],uint256[]) (runs: 1000, μ: 11978852, ~: 12721837)
[PASS] testLength(uint48[],uint256[]) (runs: 1000, μ: 11826008, ~: 12374852)
[PASS] testLookup(uint48[],uint256[],uint48) (runs: 1000, μ: 11626488, ~: 12269187)
[PASS] testPop(uint48[],uint256[]) (runs: 1000, μ: 6041219, ~: 5252925)
[PASS] testPush(uint48[],uint256[],uint48) (runs: 1000, μ: 12758244, ~: 13258136)
[PASS] testUpperLookupRecentCheckpoint(uint48[],uint256[],uint48) (runs: 1000, μ: 12017920, ~: 12695010)
[PASS] testUpperLookupRecentCheckpointWithHint(uint48[],uint256[],uint48,uint32) (runs: 1000, μ: 11951614, ~: 12578711)
[PASS] testUpperLookupRecentWithHint(uint48[],uint256[],uint48,uint32) (runs: 1000, μ: 11876758, ~: 12681553)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 9.53s (35.90s CPU time)
Ran 10 tests for test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace208Test
[PASS] testAt(uint48[],uint208[],uint32) (runs: 1000, μ: 4418581, ~: 4659634)
[PASS] testLatest(uint48[],uint208[]) (runs: 1000, μ: 4389648, ~: 4660768)
[PASS] testLatestCheckpoint(uint48[],uint208[]) (runs: 1000, μ: 4312608, ~: 4568256)
[PASS] testLength(uint48[],uint208[]) (runs: 1000, μ: 4327551, ~: 4563549)
[PASS] testLookup(uint48[],uint208[],uint48) (runs: 1000, μ: 4273568, ~: 4511401)
[PASS] testPop(uint48[],uint208[]) (runs: 1000, μ: 2340183, ~: 2053897)
[PASS] testPush(uint48[],uint208[],uint48) (runs: 1000, μ: 4737182, ~: 5059570)
[PASS] testUpperLookupRecentCheckpoint(uint48[],uint208[],uint48) (runs: 1000, μ: 4500541, ~: 4805784)
[PASS] testUpperLookupRecentCheckpointWithHint(uint48[],uint208[],uint48,uint32) (runs: 1000, μ: 4176160, ~: 4402590)
[PASS] testUpperLookupRecentWithHint(uint48[],uint208[],uint48,uint32) (runs: 1000, μ: 4176408, ~: 4357005)
Suite result: ok. 10 passed; 0 failed; 0 skipped; finished in 9.97s (25.74s CPU time)
╭---------------------------------------------------+-----------------+--------+--------+--------+---------╮
| examples/MyKeyRegistry.sol:MyKeyRegistry Contract | | | | | |
+==========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3353463 | 15288 | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| hashTypedDataV4 | 6730 | 6730 | 6730 | 6730 | 4356 |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 100690 | 100690 | 100690 | 100690 | 141 |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| setKey | 414935 | 418370 | 417209 | 453694 | 4356 |
╰---------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------+-----------------+--------+--------+--------+---------╮
| examples/MySettlement.sol:MySettlement Contract | | | | | |
+========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2660648 | 12086 | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| SET_GENESIS_ROLE | 316 | 316 | 316 | 316 | 40 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| VALIDATOR_SET_VERSION | 293 | 293 | 293 | 293 | 13 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| getExtraDataAt | 2699 | 2699 | 2699 | 2699 | 29 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| getLastCommittedHeaderEpoch | 2417 | 2417 | 2417 | 2417 | 16 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSigVerifier | 7624 | 7624 | 7624 | 7624 | 31 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| getTotalVotingPowerFromValSetHeaderAt | 2666 | 2666 | 2666 | 2666 | 5 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| grantRole | 51664 | 51664 | 51664 | 51664 | 40 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 244584 | 244584 | 244584 | 244584 | 40 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| setGenesis | 156404 | 173786 | 174424 | 174436 | 28 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| verifyQuorumSig | 15379 | 43893 | 15918 | 218376 | 9 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| verifyQuorumSigAt | 217091 | 232502 | 236873 | 243542 | 3 |
╰-------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-----------------------------------------------------+-----------------+---------+---------+---------+---------╮
| examples/MyValSetDriver.sol:MyValSetDriver Contract | | | | | |
+===============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3767660 | 18845 | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| MAX_QUORUM_THRESHOLD | 306 | 306 | 306 | 306 | 13 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| getCurrentEpoch | 5862 | 5862 | 5862 | 5862 | 13 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| getCurrentEpochStart | 7438 | 7438 | 7438 | 7438 | 13 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| getEpochStart | 6115 | 6115 | 6115 | 6115 | 43 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| getQuorumThresholds | 10812 | 10812 | 10812 | 10812 | 13 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRequiredHeaderKeyTag | 4867 | 4867 | 4867 | 4867 | 13 |
|-----------------------------------------------------+-----------------+---------+---------+---------+---------|
| initialize | 1332424 | 1332432 | 1332436 | 1332436 | 40 |
╰-----------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| examples/MyVotingPowerProvider.sol:MyVotingPowerProvider Contract | | | | | |
+=============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 2857916 | 13188 | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| NETWORK | 2449 | 2449 | 2449 | 2449 | 32 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| OPERATOR_REGISTRY | 261 | 261 | 261 | 261 | 45 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| SUBNETWORK | 661 | 2230 | 2661 | 2661 | 288 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| SUBNETWORK_IDENTIFIER | 2436 | 2436 | 2436 | 2436 | 32 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| VAULT_FACTORY | 306 | 306 | 306 | 306 | 38 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakes | 78880 | 78880 | 78880 | 78880 | 32 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakesAt | 85178 | 85178 | 85178 | 85178 | 32 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaults | 14584 | 15370 | 15370 | 16157 | 2 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaultsAt | 15293 | 15293 | 15293 | 15293 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowers | 91190 | 91845 | 91845 | 92501 | 64 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowersAt | 98147 | 98803 | 98803 | 99459 | 64 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperators | 14012 | 16294 | 14798 | 21567 | 4 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorsAt | 19709 | 21300 | 21300 | 22891 | 2 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 8 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingDataAt | 10150 | 10328 | 10328 | 10507 | 2 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowers | 2485344 | 2485344 | 2485344 | 2485344 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowersAt | 2719064 | 2719064 | 2719064 | 2719064 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| hashTypedDataV4 | 6786 | 6786 | 6786 | 6786 | 3 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| initialize | 293992 | 293992 | 293992 | 293992 | 22 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| invalidateOldSignatures | 43532 | 43532 | 43532 | 43532 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegistered | 8422 | 9187 | 8422 | 10718 | 9 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegisteredAt | 6709 | 8348 | 9168 | 9168 | 3 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address) | 8435 | 8894 | 8435 | 10731 | 5 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address,address) | 8756 | 9138 | 8756 | 11052 | 6 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,address,uint48) | 9558 | 9558 | 9558 | 9558 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,uint48) | 9120 | 9120 | 9120 | 9120 | 1 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| nonces | 2662 | 2662 | 2662 | 2662 | 5 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperator | 30726 | 113167 | 108840 | 143040 | 44 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperatorVault | 86465 | 233307 | 236467 | 270667 | 38 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperatorWithSignature | 39115 | 98985 | 98985 | 158856 | 2 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| stakeToVotingPower | 870 | 870 | 870 | 870 | 96 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| stakeToVotingPowerAt | 961 | 961 | 961 | 961 | 96 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperator | 27152 | 61651 | 78901 | 78901 | 3 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperatorVault | 125247 | 125355 | 125355 | 125463 | 2 |
|-------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperatorWithSignature | 94671 | 94671 | 94671 | 94671 | 1 |
╰-------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭----------------------------------------------+-----------------+-------+--------+-------+---------╮
| lib/core/test/mocks/Token.sol:Token Contract | | | | | |
+===================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| 519682 | 3161 | | | | |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| approve | 46306 | 46356 | 46366 | 46366 | 488 |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| balanceOf | 559 | 1980 | 2559 | 2559 | 1695 |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| decimals | 176 | 176 | 176 | 176 | 692 |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| totalSupply | 2325 | 2325 | 2325 | 2325 | 709 |
|----------------------------------------------+-----------------+-------+--------+-------+---------|
| transfer | 51553 | 51553 | 51553 | 51553 | 2 |
╰----------------------------------------------+-----------------+-------+--------+-------+---------╯
╭----------------------------------------------+-----------------+--------+--------+--------+---------╮
| lib/network/src/Network.sol:Network Contract | | | | | |
+=====================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| 2726533 | 12607 | | | | |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| execute | 70058 | 70058 | 70058 | 70058 | 12 |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 312525 | 312525 | 312525 | 312525 | 12 |
|----------------------------------------------+-----------------+--------+--------+--------+---------|
| schedule | 64876 | 64876 | 64876 | 64876 | 12 |
╰----------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------╮
| src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol:SigVerifierBlsBn254Simple Contract | | | | | |
+=============================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| 0 | 4974 | | | | |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| AGGREGATED_PUBLIC_KEY_G1_HASH | 161 | 161 | 161 | 161 | 15 |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| VALIDATOR_SET_HASH_KECCAK256_HASH | 183 | 183 | 183 | 183 | 15 |
|-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------|
| verifyQuorumSig | 1265 | 52186 | 8494 | 181913 | 15 |
╰-------------------------------------------------------------------------------------------------------+-----------------+-------+--------+--------+---------╯
╭-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------╮
| src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol:SigVerifierBlsBn254ZK Contract | | | | | |
+=================================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| 0 | 4094 | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| TOTAL_ACTIVE_VALIDATORS_HASH | 205 | 205 | 205 | 205 | 15 |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| VALIDATOR_SET_HASH_MIMC_HASH | 227 | 227 | 227 | 227 | 13 |
|-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------|
| verifyQuorumSig | 1281 | 2199436671923268638 | 15113 | 17595493375385706077 | 8 |
╰-----------------------------------------------------------------------------------------------+-----------------+---------------------+--------+----------------------+---------╯
╭------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| src/modules/voting-power/extensions/logic/BaseRewardsLogic.sol:BaseRewardsLogic Contract | | | | | |
+=================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 321585 | 1658 | | | | |
|------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| distributeOperatorRewards | 147122 | 147122 | 147122 | 147122 | 1 |
|------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| distributeStakerRewards | 215666 | 215666 | 215666 | 215666 | 1 |
╰------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| src/modules/voting-power/extensions/logic/BaseSlashingLogic.sol:BaseSlashingLogic Contract | | | | | |
+===================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 878339 | 4439 | | | | |
|--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| executeSlashVault | 12081 | 115521 | 29372 | 391259 | 4 |
|--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| slashVault | 12235 | 171484 | 79920 | 373690 | 9 |
╰--------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| src/modules/voting-power/extensions/logic/OpNetVaultAutoDeployLogic.sol:OpNetVaultAutoDeployLogic Contract | | | | | |
+=================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 1139807 | 5745 | | | | |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| getAutoDeployConfig | 5052 | 5052 | 5052 | 5052 | 1 |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| getAutoDeployedVault | 2588 | 2588 | 2588 | 2588 | 10 |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| isAutoDeployEnabled | 2393 | 2393 | 2393 | 2393 | 6 |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| isSetMaxNetworkLimitHookEnabled | 437 | 937 | 437 | 2437 | 4 |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setAutoDeployStatus | 6508 | 19333 | 23608 | 23608 | 4 |
|------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setSetMaxNetworkLimitHookStatus | 23613 | 23613 | 23613 | 23613 | 1 |
╰------------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| src/modules/voting-power/logic/VotingPowerProviderLogic.sol:VotingPowerProviderLogic Contract | | | | | |
+=========================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3129075 | 15680 | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| _validateVault | 35606 | 40104 | 40104 | 44603 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStake | 77113 | 77113 | 77113 | 77113 | 96 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakeAt | 84068 | 84068 | 84068 | 84068 | 96 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakes | 74403 | 178283 | 178283 | 282163 | 64 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakesAt | 80612 | 195639 | 195639 | 310667 | 64 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaults | 10435 | 10462 | 10435 | 12266 | 201 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaultsAt | 10968 | 10968 | 10968 | 10968 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaultsLength | 2694 | 2694 | 2694 | 2694 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPower | 14717 | 65425 | 78190 | 88025 | 384 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowerAt | 15017 | 69461 | 95724 | 95724 | 298 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowers | 86090 | 249173 | 252252 | 315078 | 2148 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowersAt | 92953 | 219506 | 219506 | 346060 | 128 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperators | 10120 | 12402 | 11035 | 17417 | 8 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorsAt | 15619 | 17081 | 17081 | 18543 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorsLength | 2424 | 2424 | 2424 | 2424 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaults | 10097 | 21955 | 24691 | 24691 | 10 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaultsAt | 10793 | 10793 | 10793 | 10793 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaultsLength | 2448 | 2448 | 2448 | 2448 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingData | 925 | 4708 | 4925 | 4925 | 222 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingDataAt | 5974 | 6455 | 6331 | 8786 | 14 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokens | 19264 | 19264 | 19264 | 19264 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokensAt | 7797 | 14473 | 14618 | 20862 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokensLength | 2484 | 2484 | 2484 | 2484 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowers | 2398854 | 3265574 | 3750354 | 5646383 | 49 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowersAt | 2660793 | 4658079 | 4658079 | 6655366 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegistered | 2810 | 5309 | 5046 | 7342 | 36 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegisteredAt | 3142 | 4781 | 5601 | 5601 | 6 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address) | 5069 | 5834 | 5069 | 7365 | 15 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address,address) | 5199 | 5552 | 5199 | 7495 | 13 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,address,uint48) | 5878 | 5878 | 5878 | 5878 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,uint48) | 5599 | 5599 | 5599 | 5599 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSharedVaultRegistered | 5090 | 5855 | 5090 | 7386 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSharedVaultRegisteredAt | 5622 | 5622 | 5622 | 5622 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isTokenRegistered | 4996 | 5761 | 4996 | 7292 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isTokenRegisteredAt | 8429 | 8429 | 8429 | 8429 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperator | 6552 | 64356 | 62495 | 96695 | 1392 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperatorVault | 17136 | 206040 | 208990 | 243212 | 251 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerSharedVault | 6648 | 118148 | 111583 | 145827 | 135 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerToken | 426 | 73088 | 90466 | 90466 | 16 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setSlashingData | 9808 | 15374 | 9808 | 32074 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperator | 2924 | 44748 | 54313 | 54313 | 12 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperatorVault | 34188 | 97072 | 107553 | 107553 | 7 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterSharedVault | 7390 | 38628 | 54247 | 54247 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterToken | 7405 | 42547 | 54262 | 54262 | 4 |
╰-----------------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------╮
| test/data/zk/Verifier_100.sol:Verifier Contract | | | | | |
+================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------|
| 1435489 | 6421 | | | | |
|-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------|
| | | | | | |
|-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------|
| verifyProof | 309915 | 8797746687692979367 | 8797746687692979367 | 17595493375385648819 | 2 |
╰-------------------------------------------------+-----------------+---------------------+---------------------+----------------------+---------╯
╭----------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/libraries/sigs/SigBlsBn254.t.sol:SigBlsBn254Test Contract | | | | | |
+===================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------------------+-----------------+------+--------+------+---------|
| 2386169 | 11754 | | | | |
|----------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|----------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------------------+-----------------+------+--------+------+---------|
| verify | 1799 | 1799 | 1799 | 1799 | 1 |
╰----------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭----------------------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/libraries/sigs/SigEcdsaSecp256k1.t.sol:SigEcdsaSecp256k1Test Contract | | | | | |
+===============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| 1610499 | 7880 | | | | |
|----------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|----------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| verify | 1775 | 1775 | 1775 | 1775 | 1 |
╰----------------------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace208Test Contract | | | | | |
+================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 2713553 | 13389 | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| pop | 23586 | 23586 | 23586 | 23586 | 2 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| push | 26412 | 26536 | 26496 | 26736 | 256 |
╰---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace256Test Contract | | | | | |
+================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 2738984 | 13516 | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| pop | 23596 | 23596 | 23596 | 23596 | 3 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| push | 29733 | 29866 | 29793 | 30129 | 256 |
╰---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/libraries/structs/Checkpoints.t.sol:CheckpointsTrace512Test Contract | | | | | |
+================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 3141073 | 15524 | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| pop | 23674 | 23674 | 23674 | 23674 | 2 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| push | 32861 | 32881 | 32885 | 32885 | 256 |
╰---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/libraries/structs/PersistentSet.t.sol:PersistentSetTest Contract | | | | | |
+============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 2778830 | 13715 | | | | |
|-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| remove | 26607 | 48119 | 48119 | 69632 | 2 |
╰-----------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-------------------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/libraries/utils/InputNormalizer.t.sol:InputNormalizerTest Contract | | | | | |
+============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| 1602692 | 7841 | | | | |
|-------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|-------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| normalizeDoubleDim | 2940 | 2940 | 2940 | 2940 | 1 |
|-------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| normalizeSingleDim | 2361 | 2361 | 2361 | 2361 | 1 |
╰-------------------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭-------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/libraries/utils/KeyTag.t.sol:KeyTagTest Contract | | | | | |
+==========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| 1494374 | 7300 | | | | |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| getKeyTag | 552 | 582 | 582 | 613 | 2 |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| getTag | 482 | 482 | 482 | 482 | 1 |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| getType | 483 | 483 | 483 | 483 | 1 |
|-------------------------------------------------------+-----------------+------+--------+------+---------|
| serialize | 1787 | 1787 | 1787 | 1787 | 1 |
╰-------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/libraries/utils/ValSetVerifier.t.sol:ValSetVerifierContract Contract | | | | | |
+================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 539296 | 2276 | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| verifyIsActive | 56160 | 56301 | 56160 | 57120 | 7 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| verifyKey | 70130 | 70404 | 70130 | 71090 | 7 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| verifyOperator | 55860 | 56005 | 55860 | 56820 | 7 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| verifyVault | 78930 | 79177 | 78960 | 79890 | 8 |
|---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| verifyVotingPower | 55860 | 56005 | 55860 | 56820 | 7 |
╰---------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭---------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/mocks/KeyBlsBn254Mock.sol:KeyBlsBn254Mock Contract | | | | | |
+============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| 628154 | 2687 | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| deserialize | 828 | 828 | 828 | 828 | 1 |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| equal | 1180 | 1193 | 1193 | 1207 | 2 |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| fromBytes | 807 | 1379 | 1379 | 1952 | 2 |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| wrap | 788 | 1022 | 1021 | 1182 | 264 |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| zeroKey | 562 | 562 | 562 | 562 | 1 |
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/mocks/KeyEcdsaSecp256k1Mock.sol:KeyEcdsaSecp256k1Mock Contract | | | | | |
+========================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| 347774 | 1390 | | | | |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| deserialize | 755 | 755 | 755 | 755 | 1 |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| equal | 837 | 837 | 837 | 837 | 2 |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| fromBytes | 776 | 1087 | 1087 | 1399 | 2 |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| wrap | 575 | 575 | 575 | 575 | 4 |
|---------------------------------------------------------------------+-----------------+------+--------+------+---------|
| zeroKey | 374 | 374 | 374 | 374 | 1 |
╰---------------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/mocks/RewarderMock.sol:RewarderMock Contract | | | | | |
+==========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| 211160 | 758 | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| distributeOperatorRewards | 154018 | 154018 | 154018 | 154018 | 1 |
|---------------------------------------------------+-----------------+--------+--------+--------+---------|
| distributeStakerRewards | 222446 | 222446 | 222446 | 222446 | 1 |
╰---------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/mocks/SigVerifierFalseMock.sol:SigVerifierFalseMock Contract | | | | | |
+======================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------+-----------------+------+--------+------+---------|
| 179999 | 614 | | | | |
|-------------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|-------------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------+-----------------+------+--------+------+---------|
| verifyQuorumSig | 1093 | 1093 | 1093 | 1093 | 1 |
╰-------------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭---------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/mocks/SigVerifierMock.sol:SigVerifierMock Contract | | | | | |
+============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| 180215 | 615 | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------+-----------------+------+--------+------+---------|
| verifyQuorumSig | 1094 | 1094 | 1094 | 1094 | 10 |
╰---------------------------------------------------------+-----------------+------+--------+------+---------╯
╭-------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/mocks/SlasherMock.sol:SlasherMock Contract | | | | | |
+========================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| 326654 | 1292 | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| executeSlashVault | 44234 | 146097 | 61846 | 416462 | 4 |
|-------------------------------------------------+-----------------+--------+--------+--------+---------|
| slashVault | 45374 | 202802 | 114874 | 400244 | 9 |
╰-------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| test/mocks/VotingPowerProviderSemiFull.sol:VotingPowerProviderSemiFull Contract | | | | | |
+===========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3709156 | 17124 | | | | |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| NETWORK | 2443 | 2443 | 2443 | 2443 | 6 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| OPERATOR_REGISTRY | 350 | 350 | 350 | 350 | 1124 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| SUBNETWORK | 719 | 1136 | 719 | 2719 | 9931 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| VAULT_FACTORY | 284 | 284 | 284 | 284 | 121 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| distributeOperatorRewards | 24854 | 24854 | 24854 | 24854 | 1 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| distributeStakerRewards | 27110 | 27110 | 27110 | 27110 | 1 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowers | 258357 | 258357 | 258357 | 258357 | 2020 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRewarder | 2432 | 2432 | 2432 | 2432 | 4 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaults | 29142 | 29142 | 29142 | 29142 | 8 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlasher | 2519 | 2519 | 2519 | 2519 | 4 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingData | 8273 | 8273 | 8273 | 8273 | 3 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowers | 2456108 | 3310040 | 3840067 | 3840067 | 47 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| initialize | 345805 | 345805 | 345805 | 345805 | 40 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperator | 113472 | 114689 | 113472 | 147672 | 1124 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerSharedVault | 138549 | 149883 | 138549 | 172749 | 121 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setRewarder | 25218 | 36288 | 36288 | 47358 | 4 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setSlasher | 25228 | 32460 | 30268 | 47368 | 11 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| slashVault | 25676 | 25676 | 25676 | 25676 | 1 |
|---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| stakeToVotingPower | 915 | 915 | 915 | 915 | 9924 |
╰---------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭--------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/base/NetworkManager.t.sol:TestNetworkManager Contract | | | | | |
+=========================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 346454 | 1384 | | | | |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| NETWORK | 2329 | 2329 | 2329 | 2329 | 2 |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| SUBNETWORK | 2572 | 2572 | 2572 | 2572 | 2 |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| SUBNETWORK_IDENTIFIER | 2435 | 2435 | 2435 | 2435 | 2 |
|--------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 24220 | 55579 | 69627 | 69639 | 5 |
╰--------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭--------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/base/OzEIP712.t.sol:TestOzEIP712 Contract | | | | | |
+=============================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 607189 | 2590 | | | | |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| eip712Domain | 10880 | 10880 | 10880 | 10880 | 1 |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| hashTypedDataV4 | 6652 | 6652 | 6652 | 6652 | 2 |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| hashTypedDataV4CrossChain | 6543 | 6543 | 6543 | 6543 | 1 |
|--------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 25314 | 84794 | 99667 | 99667 | 5 |
╰--------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/base/PermissionManager.t.sol:TestPermissionManager Contract | | | | | |
+===============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 177603 | 603 | | | | |
|--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 67820 | 67820 | 67820 | 67820 | 2 |
|--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| protectedAction | 23348 | 23394 | 23394 | 23440 | 2 |
╰--------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/base/VotingPowerCalcManager.t.sol:TestVotingPowerCalcManager Contract | | | | | |
+=========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 250232 | 939 | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 23666 | 58589 | 67320 | 67320 | 5 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| stakeToVotingPower | 774 | 786 | 786 | 798 | 2 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| stakeToVotingPowerAt | 880 | 880 | 880 | 880 | 1 |
╰------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/common/permissions/NoPermissionManager.t.sol:TestNoPermissionManager Contract | | | | | |
+=================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 125551 | 362 | | | | |
|--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| actionRequiringNoPermission | 21161 | 21161 | 21161 | 21161 | 1 |
|--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 45141 | 45141 | 45141 | 45141 | 1 |
╰--------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/common/permissions/OzAccessControl.t.sol:TestOzAccessControl Contract | | | | | |
+=========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 428368 | 1763 | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| ADMIN_ROLE | 304 | 304 | 304 | 304 | 1 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| getRole | 2640 | 2640 | 2640 | 2640 | 2 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| grantRole | 51417 | 51417 | 51417 | 51417 | 1 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 73689 | 73689 | 73689 | 73689 | 6 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| protectedFunction | 25889 | 25915 | 25889 | 25954 | 5 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| setSelectorRole | 27977 | 41499 | 48261 | 48261 | 3 |
╰------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭------------------------------------------------------------------------------+-----------------+------+--------+------+---------╮
| test/modules/common/permissions/OzAccessManaged.t.sol:MockAuthority Contract | | | | | |
+=================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| 133454 | 424 | | | | |
|------------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| | | | | | |
|------------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------+-----------------+------+--------+------+---------|
| canCall | 2629 | 2629 | 2629 | 2629 | 2 |
╰------------------------------------------------------------------------------+-----------------+------+--------+------+---------╯
╭------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/common/permissions/OzAccessManaged.t.sol:TestOzAccessManaged Contract | | | | | |
+=========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 453845 | 1881 | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 23962 | 58212 | 69629 | 69629 | 4 |
|------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| protectedAction | 29746 | 29784 | 29784 | 29822 | 2 |
╰------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/common/permissions/OzOwnable.t.sol:TestOzOwnable Contract | | | | | |
+=============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 263112 | 999 | | | | |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| initialize | 23940 | 60684 | 69871 | 69871 | 5 |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| protectedAction | 23395 | 23421 | 23421 | 23447 | 4 |
|------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| transferOwnership | 28412 | 28412 | 28412 | 28412 | 1 |
╰------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭----------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/key-registry/KeyRegistry.t.sol:TestKeyRegistry Contract | | | | | |
+=============================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3714257 | 16956 | | | | |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKey | 781 | 6428 | 8559 | 10714 | 9 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeyAt | 956 | 5869 | 5178 | 11556 | 6 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeyTags | 35892 | 35892 | 35892 | 35892 | 3 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeyTagsAt | 36726 | 37254 | 36726 | 39181 | 5 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeys() | 107285 | 107285 | 107285 | 107285 | 1 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeys(address) | 44674 | 47588 | 44674 | 53418 | 3 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeysAt(address,uint48) | 48594 | 52075 | 52075 | 55556 | 2 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeysAt(uint48) | 111136 | 111136 | 111136 | 111136 | 1 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeysOperators | 17334 | 17334 | 17334 | 17334 | 1 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeysOperatorsAt | 18549 | 18549 | 18549 | 18549 | 1 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getKeysOperatorsLength | 2439 | 2439 | 2439 | 2439 | 1 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperator | 2989 | 2995 | 2995 | 3001 | 4 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| hashTypedDataV4 | 6752 | 6752 | 6752 | 6752 | 13 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 100160 | 100160 | 100160 | 100160 | 12 |
|----------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setKey | 31211 | 225048 | 293623 | 449515 | 16 |
╰----------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/settlement/Settlement.t.sol:TestSettlement Contract | | | | | |
+=========================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2401040 | 10886 | | | | |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VALIDATOR_SET_VERSION | 249 | 249 | 249 | 249 | 9 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| commitValSetHeader | 26385 | 94056 | 54835 | 193392 | 14 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCaptureTimestampFromValSetHeader | 4728 | 4728 | 4728 | 4728 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCaptureTimestampFromValSetHeaderAt | 2676 | 2676 | 2676 | 2676 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getExtraData | 4768 | 4768 | 4768 | 4768 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getExtraDataAt | 2655 | 2655 | 2655 | 2655 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getLastCommittedHeaderEpoch | 2417 | 2417 | 2417 | 2417 | 2 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getQuorumThresholdFromValSetHeader | 4699 | 4699 | 4699 | 4699 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getQuorumThresholdFromValSetHeaderAt | 2603 | 2603 | 2603 | 2603 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getRequiredKeyTagFromValSetHeader | 4730 | 4730 | 4730 | 4730 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getRequiredKeyTagFromValSetHeaderAt | 2654 | 2654 | 2654 | 2654 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSigVerifier | 4700 | 5553 | 4700 | 10354 | 10 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSigVerifierAt | 6140 | 6958 | 6140 | 8595 | 3 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getTotalVotingPowerFromValSetHeader | 4633 | 4633 | 4633 | 4633 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getTotalVotingPowerFromValSetHeaderAt | 2644 | 2644 | 2644 | 2644 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValSetHeader | 11830 | 11830 | 11830 | 11830 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValSetHeaderAt | 9633 | 9633 | 9633 | 9633 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValSetHeaderHash | 11842 | 11842 | 11842 | 11842 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValSetHeaderHashAt | 9786 | 9786 | 9786 | 9786 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValidatorsSszMRootFromValSetHeader | 4635 | 4635 | 4635 | 4635 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getValidatorsSszMRootFromValSetHeaderAt | 2647 | 2647 | 2647 | 2647 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getVersionFromValSetHeader | 4675 | 4675 | 4675 | 4675 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getVersionFromValSetHeaderAt | 2622 | 2622 | 2622 | 2622 | 1 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 124545 | 159328 | 159328 | 194112 | 16 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isValSetHeaderCommittedAt | 2614 | 2614 | 2614 | 2614 | 3 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setGenesis | 25641 | 107018 | 147068 | 147068 | 6 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setSigVerifier | 23864 | 46268 | 57470 | 57470 | 3 |
|------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| verifyQuorumSigAt | 3887 | 3887 | 3887 | 3887 | 1 |
╰------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/valset-driver/EpochManager.t.sol:TestEpochManager Contract | | | | | |
+================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 988967 | 4355 | | | | |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| deserializeEpochDurationData | 632 | 632 | 632 | 632 | 1 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCurrentEpoch | 2597 | 5167 | 5863 | 5863 | 10 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCurrentEpochDuration | 5544 | 5544 | 5544 | 5544 | 1 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCurrentEpochDurationData | 2529 | 4055 | 4055 | 5581 | 2 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCurrentEpochStart | 7409 | 7409 | 7409 | 7409 | 2 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getCurrentValuePublic | 2614 | 6491 | 5496 | 8270 | 11 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getEpochDuration | 5772 | 6999 | 6999 | 8227 | 2 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getEpochDurationDataByIndex | 5792 | 5792 | 5792 | 5792 | 2 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getEpochDurationDataByTimestamp | 5842 | 5842 | 5842 | 5842 | 1 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getEpochIndex | 5374 | 5815 | 6036 | 6036 | 3 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getEpochStart | 6039 | 7266 | 7266 | 8494 | 2 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getNextEpoch | 5208 | 6041 | 6041 | 6875 | 6 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getNextEpochDuration | 5169 | 5809 | 5793 | 7793 | 8 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getNextEpochStart | 5249 | 8463 | 9793 | 14120 | 7 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 44826 | 124127 | 137341 | 137341 | 14 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| pushTestCheckpoint | 51895 | 59250 | 59250 | 66606 | 4 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| serializeEpochDurationData | 701 | 701 | 701 | 701 | 1 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setEpochDuration(uint48) | 33754 | 59387 | 40422 | 91169 | 5 |
|-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setEpochDuration(uint48,uint48,uint48) | 82394 | 82394 | 82394 | 82394 | 1 |
╰-------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| test/modules/valset-driver/ValSetDriver.t.sol:TestValSetDriver Contract | | | | | |
+===================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3639013 | 16609 | | | | |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| addQuorumThreshold | 24252 | 44576 | 25534 | 102986 | 4 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| addSettlement | 24275 | 40523 | 24368 | 103030 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| addVotingPowerProvider | 24284 | 56252 | 26630 | 103033 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getConfig | 120171 | 120171 | 120171 | 120171 | 4 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getConfigAt | 128433 | 129486 | 128433 | 130892 | 7 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getKeysProvider | 7428 | 7428 | 7428 | 7428 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getKeysProviderAt | 8281 | 8281 | 8281 | 8281 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMaxValidatorsCount | 4882 | 4882 | 4882 | 4882 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMaxValidatorsCountAt | 5715 | 6534 | 5715 | 8174 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMaxVotingPower | 7122 | 7122 | 7122 | 7122 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMaxVotingPowerAt | 7909 | 8892 | 7909 | 10368 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMinInclusionVotingPower | 7056 | 7056 | 7056 | 7056 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getMinInclusionVotingPowerAt | 7887 | 8706 | 7887 | 10346 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getNumAggregators | 4858 | 4858 | 4858 | 4858 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getNumAggregatorsAt | 5714 | 6943 | 6943 | 8173 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getNumCommitters | 4881 | 4881 | 4881 | 4881 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getNumCommittersAt | 5670 | 6899 | 6899 | 8129 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getQuorumThresholds | 18665 | 19336 | 19336 | 20007 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getQuorumThresholdsAt | 19835 | 19835 | 19835 | 19835 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRequiredHeaderKeyTag | 4823 | 4823 | 4823 | 4823 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRequiredHeaderKeyTagAt | 5681 | 6910 | 6910 | 8140 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRequiredKeyTags | 35784 | 35878 | 35878 | 35972 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getRequiredKeyTagsAt | 36600 | 37545 | 36788 | 39247 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSettlements | 10828 | 16484 | 18668 | 19956 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSettlementsAt | 19841 | 19841 | 19841 | 19841 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVerificationType | 4890 | 4890 | 4890 | 4890 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVerificationTypeAt | 5704 | 6933 | 6933 | 8163 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowerProviders | 18669 | 24871 | 26509 | 27797 | 4 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowerProvidersAt | 19908 | 19908 | 19908 | 19908 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| initialize | 1066319 | 1066319 | 1066319 | 1066319 | 14 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isQuorumThresholdRegistered | 3187 | 4305 | 4305 | 5423 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isQuorumThresholdRegisteredAt | 5979 | 5979 | 5979 | 5979 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSettlementRegistered | 3145 | 4263 | 4263 | 5381 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSettlementRegisteredAt | 5962 | 5962 | 5962 | 5962 | 1 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isVotingPowerProviderRegistered | 3124 | 4614 | 5360 | 5360 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isVotingPowerProviderRegisteredAt | 3419 | 5157 | 6026 | 6026 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| removeQuorumThreshold | 24227 | 44734 | 31271 | 78704 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| removeSettlement | 24253 | 44767 | 31288 | 78760 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| removeVotingPowerProvider | 24286 | 44799 | 31321 | 78790 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setKeysProvider | 24252 | 30298 | 30298 | 36345 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setMaxValidatorsCount | 23869 | 37231 | 32780 | 55046 | 3 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setMaxVotingPower | 23791 | 51087 | 35277 | 80553 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setMinInclusionVotingPower | 52419 | 66513 | 66513 | 80607 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setNumAggregators | 23827 | 33614 | 32715 | 54981 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setNumCommitters | 23826 | 33619 | 32725 | 54991 | 5 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setRequiredHeaderKeyTag | 32796 | 43929 | 43929 | 55062 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setRequiredKeyTags | 35608 | 46269 | 46269 | 56930 | 2 |
|-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setVerificationType | 23822 | 37142 | 32669 | 54935 | 3 |
╰-------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╮
| test/modules/voting-power/VotingPowerProvider.t.sol:TestVotingPowerProvider Contract | | | | | |
+================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| 3260870 | 15051 | | | | |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| | | | | | |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| NETWORK | 2427 | 2427 | 2427 | 2427 | 33 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| OPERATOR_REGISTRY | 328 | 328 | 328 | 328 | 46 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| SUBNETWORK | 683 | 1602 | 683 | 2683 | 1536 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| SUBNETWORK_IDENTIFIER | 2502 | 2502 | 2502 | 2502 | 32 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| VAULT_FACTORY | 306 | 306 | 306 | 306 | 58 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStake | 80662 | 80662 | 80662 | 80662 | 96 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakeAt | 87663 | 87663 | 87663 | 87663 | 96 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakes | 288005 | 288005 | 288005 | 288005 | 32 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorStakesAt | 316687 | 316687 | 316687 | 316687 | 32 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaults | 14584 | 15370 | 15370 | 16157 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaultsAt | 15250 | 15250 | 15250 | 15250 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVaultsLength | 6016 | 6016 | 6016 | 6016 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPower | 18893 | 55547 | 55547 | 92201 | 192 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowerAt | 19342 | 73146 | 100049 | 100049 | 288 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowers | 320341 | 320998 | 320998 | 321655 | 64 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorVotingPowersAt | 351395 | 352052 | 352052 | 352709 | 64 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperators | 14057 | 16339 | 14843 | 21612 | 4 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorsAt | 19754 | 21345 | 21345 | 22936 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getOperatorsLength | 5597 | 5597 | 5597 | 5597 | 3 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaults | 14077 | 14863 | 14863 | 15650 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaultsAt | 14929 | 14929 | 14929 | 14929 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSharedVaultsLength | 5623 | 5623 | 5623 | 5623 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 12 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getSlashingDataAt | 10551 | 11778 | 11778 | 13006 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokens | 23199 | 23199 | 23199 | 23199 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokensAt | 11697 | 18631 | 18905 | 25020 | 4 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getTokensLength | 5613 | 5613 | 5613 | 5613 | 3 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowers | 5752113 | 5752113 | 5752113 | 5752113 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| getVotingPowersAt | 6761210 | 6761210 | 6761210 | 6761210 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| hashTypedDataV4 | 6743 | 6743 | 6743 | 6743 | 3 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| initialize | 178640 | 181555 | 178640 | 269031 | 31 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| invalidateOldSignatures | 43554 | 43554 | 43554 | 43554 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegistered | 8488 | 9253 | 8488 | 10784 | 9 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorRegisteredAt | 6687 | 8326 | 9146 | 9146 | 3 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address) | 8435 | 8894 | 8435 | 10731 | 5 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegistered(address,address) | 8712 | 9094 | 8712 | 11008 | 6 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,address,uint48) | 9470 | 9470 | 9470 | 9470 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isOperatorVaultRegisteredAt(address,uint48) | 9120 | 9120 | 9120 | 9120 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSharedVaultRegistered | 8466 | 8466 | 8466 | 8466 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isSharedVaultRegisteredAt | 9188 | 9188 | 9188 | 9188 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isTokenRegistered | 8373 | 8373 | 8373 | 8373 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| isTokenRegisteredAt | 11996 | 11996 | 11996 | 11996 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| nonces | 2598 | 2598 | 2598 | 2598 | 5 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperator() | 143163 | 143163 | 143163 | 143163 | 4 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperator(address) | 31090 | 90354 | 87175 | 121375 | 41 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperatorVault | 42340 | 213918 | 234213 | 268413 | 44 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerOperatorWithSignature | 39159 | 99068 | 99068 | 158978 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerSharedVault | 31138 | 90142 | 72657 | 170550 | 12 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| registerToken | 24886 | 100171 | 115181 | 115181 | 14 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| setSlashingData | 56782 | 56782 | 56782 | 56782 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| stakeToVotingPower | 893 | 893 | 893 | 893 | 480 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| stakeToVotingPowerAt | 961 | 961 | 961 | 961 | 576 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperator() | 78857 | 78857 | 78857 | 78857 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperator(address) | 27461 | 50763 | 50763 | 74065 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperatorVault | 123003 | 123111 | 123111 | 123219 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterOperatorWithSignature | 94671 | 94671 | 94671 | 94671 | 1 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterSharedVault | 32143 | 53179 | 53179 | 74215 | 2 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| unregisterToken | 32135 | 61711 | 74207 | 78791 | 3 |
|--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------|
| validateVault | 39049 | 43547 | 43547 | 48046 | 2 |
╰--------------------------------------------------------------------------------------+-----------------+---------+---------+---------+---------╯
╭-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╮
| test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol:MockToken Contract | | | | | |
+================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| 543826 | 3105 | | | | |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| approve | 46294 | 46315 | 46318 | 46318 | 162 |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| balanceOf | 559 | 2074 | 2559 | 2559 | 669 |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| decimals | 182 | 182 | 182 | 182 | 165 |
|-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------|
| totalSupply | 2325 | 2325 | 2325 | 2325 | 345 |
╰-----------------------------------------------------------------------------------------------------------+-----------------+-------+--------+-------+---------╯
╭-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol:TestVotingPowerProvider Contract | | | | | |
+================================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3413163 | 15755 | | | | |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| NETWORK | 2494 | 2494 | 2494 | 2494 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 306 | 306 | 306 | 306 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK | 2661 | 2661 | 2661 | 2661 | 192 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK_IDENTIFIER | 2480 | 2480 | 2480 | 2480 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 306 | 306 | 306 | 306 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVaults | 14584 | 14584 | 14584 | 14584 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVotingPower | 81966 | 82238 | 82371 | 82377 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 178618 | 223813 | 223813 | 269009 | 6 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 87153 | 88221 | 87153 | 121353 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperatorVault | 234179 | 235257 | 234191 | 268391 | 96 |
|-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stakeToVotingPower | 6535 | 6807 | 6940 | 6946 | 96 |
╰-------------------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.t.sol:TestVotingPowerProvider Contract | | | | | |
+=======================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3833106 | 17697 | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| NETWORK | 2427 | 2427 | 2427 | 2427 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 328 | 328 | 328 | 328 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK | 2661 | 2661 | 2661 | 2661 | 102 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK_IDENTIFIER | 2524 | 2524 | 2524 | 2524 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 306 | 306 | 306 | 306 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVaults | 14584 | 14584 | 14584 | 14584 | 64 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVotingPower | 87024 | 88169 | 88169 | 89315 | 64 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVotingPowerAt | 93614 | 96260 | 96388 | 98843 | 5 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 178640 | 214796 | 178640 | 269031 | 5 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 87197 | 89269 | 87197 | 121397 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperatorVault | 234201 | 236283 | 234213 | 268413 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setTokenWeight | 22209 | 56411 | 68502 | 68682 | 5 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stakeToVotingPower | 11571 | 12716 | 12716 | 13862 | 64 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stakeToVotingPowerAt | 11737 | 14383 | 14511 | 16966 | 5 |
╰----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.t.sol:TestVotingPowerProvider Contract | | | | | |
+=======================================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3688414 | 17028 | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| NETWORK | 2427 | 2427 | 2427 | 2427 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 306 | 306 | 306 | 306 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK | 2661 | 2661 | 2661 | 2661 | 71 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| SUBNETWORK_IDENTIFIER | 2502 | 2502 | 2502 | 2502 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 306 | 306 | 306 | 306 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVaults | 14584 | 14584 | 14584 | 14584 | 33 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVotingPower | 78905 | 78976 | 78905 | 81190 | 32 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorVotingPowerAt | 85516 | 88162 | 88290 | 90745 | 5 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getVaultWeightAt | 3097 | 6120 | 5871 | 8326 | 6 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 178618 | 217357 | 178618 | 269009 | 7 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 87153 | 90170 | 87153 | 121353 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperatorVault | 234201 | 237228 | 234213 | 268413 | 34 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setVaultWeight | 22140 | 57779 | 68433 | 68661 | 7 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stakeToVotingPower | 3474 | 3545 | 3474 | 5759 | 32 |
|----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| stakeToVotingPowerAt | 3639 | 6285 | 6413 | 8868 | 5 |
╰----------------------------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/MultiToken.t.sol:TestMultiToken Contract | | | | | |
+======================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2700660 | 12461 | | | | |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 269030 | 269030 | 269030 | 269030 | 2 |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isTokenRegistered | 8372 | 9520 | 9520 | 10668 | 2 |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerToken | 80730 | 80730 | 80730 | 80730 | 2 |
|-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unregisterToken | 78801 | 78801 | 78801 | 78801 | 1 |
╰-------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------╮
| test/modules/voting-power/extensions/OpNetVaultAutoDeploy.t.sol:TestOpNetVaultAutoDeploy Contract | | | | | |
+============================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| 3278762 | 15203 | | | | |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| | | | | | |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| NETWORK | 413 | 1413 | 1413 | 2413 | 6 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| OPERATOR_REGISTRY | 306 | 306 | 306 | 306 | 4 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| SUBNETWORK | 2712 | 2712 | 2712 | 2712 | 1 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| VAULT_CONFIGURATOR | 327 | 327 | 327 | 327 | 3 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| VAULT_FACTORY | 284 | 284 | 284 | 284 | 3 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| getAutoDeployConfig | 9118 | 9118 | 9118 | 9118 | 1 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| getAutoDeployedVault | 6024 | 6024 | 6024 | 6024 | 5 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| getOperatorVaults | 14562 | 14955 | 14562 | 16135 | 4 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| getSlashingData | 1751 | 3917 | 1751 | 8251 | 18 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| initialize | 329544 | 329544 | 329544 | 329544 | 12 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| isAutoDeployEnabled | 5567 | 5567 | 5567 | 5567 | 2 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| isSetMaxNetworkLimitHookEnabled | 5655 | 5655 | 5655 | 5655 | 1 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| registerOperator | 78448 | 958443 | 1178938 | 1397450 | 4 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| setAutoDeployConfig | 26834 | 34105 | 35955 | 40939 | 7 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| setAutoDeployStatus | 30961 | 43786 | 48061 | 48061 | 4 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| setSetMaxNetworkLimitHookStatus | 48077 | 48077 | 48077 | 48077 | 1 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| setSlashingData | 34482 | 34482 | 34482 | 34482 | 3 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| unregisterOperator | 78879 | 78879 | 78879 | 78879 | 1 |
|---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------|
| unregisterOperatorVault | 128129 | 128129 | 128129 | 128129 | 1 |
╰---------------------------------------------------------------------------------------------------+-----------------+--------+---------+---------+---------╯
╭---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/OperatorVaults.t.sol:TestOperatorVaults Contract | | | | | |
+==============================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2875023 | 13282 | | | | |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 283 | 283 | 283 | 283 | 1 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 328 | 328 | 328 | 328 | 2 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 1 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 268986 | 268986 | 268986 | 268986 | 1 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorVaultRegistered | 8457 | 10179 | 10753 | 10753 | 4 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 143118 | 143118 | 143118 | 143118 | 1 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperatorVault | 24556 | 151263 | 158545 | 270689 | 3 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unregisterOperatorVault(address) | 49385 | 49385 | 49385 | 49385 | 1 |
|---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unregisterOperatorVault(address,address) | 24600 | 75031 | 75031 | 125463 | 2 |
╰---------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/OperatorsBlacklist.t.sol:TestOperatorsBlacklist Contract | | | | | |
+======================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2900473 | 13385 | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 283 | 283 | 283 | 283 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| blacklistOperator | 24118 | 56516 | 51266 | 99414 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 6 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 268986 | 268986 | 268986 | 268986 | 6 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorBlacklisted | 2619 | 2619 | 2619 | 2619 | 5 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorRegistered | 8422 | 9187 | 8422 | 10718 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 23635 | 104821 | 145415 | 145415 | 3 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unblacklistOperator | 23541 | 23838 | 23838 | 24136 | 2 |
╰-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/OperatorsJail.t.sol:TestOperatorsJail Contract | | | | | |
+============================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2951948 | 13623 | | | | |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 283 | 283 | 283 | 283 | 3 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getOperatorJailedUntil | 2666 | 2666 | 2666 | 2666 | 5 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 268986 | 268986 | 268986 | 268986 | 6 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorJailed | 2713 | 2713 | 2713 | 2713 | 7 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorRegistered | 8422 | 9187 | 8422 | 10718 | 3 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| jailOperator | 22400 | 47399 | 43071 | 99769 | 6 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 23685 | 86571 | 94556 | 145465 | 5 |
|-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unjailOperator | 23592 | 23889 | 23889 | 24187 | 2 |
╰-------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/OperatorsWhitelist.t.sol:TestOperatorsWhitelist Contract | | | | | |
+======================================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 3002526 | 13857 | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| OPERATOR_REGISTRY | 327 | 327 | 327 | 327 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 328 | 328 | 328 | 328 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| getSlashingData | 8251 | 8251 | 8251 | 8251 | 11 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 292872 | 292872 | 292872 | 292872 | 11 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorRegistered | 8443 | 9017 | 8443 | 10739 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorVaultRegistered(address) | 8457 | 8457 | 8457 | 8457 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorVaultRegistered(address,address) | 8734 | 8734 | 8734 | 8734 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isOperatorWhitelisted | 2686 | 2686 | 2686 | 2686 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isWhitelistEnabled | 2401 | 2401 | 2401 | 2401 | 4 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperator | 25797 | 106270 | 145394 | 147621 | 6 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerOperatorVault | 268468 | 268468 | 268468 | 268468 | 1 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| setWhitelistStatus | 23091 | 26973 | 23433 | 45003 | 6 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unwhitelistOperator | 24114 | 51888 | 51888 | 79663 | 2 |
|-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| whitelistOperator | 24096 | 40079 | 45407 | 45407 | 4 |
╰-----------------------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
╭-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╮
| test/modules/voting-power/extensions/SharedVaults.t.sol:TestSharedVaults Contract | | | | | |
+==========================================================================================================================================+
| Deployment Cost | Deployment Size | | | | |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| 2722913 | 12564 | | | | |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| | | | | | |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| Function Name | Min | Avg | Median | Max | # Calls |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| VAULT_FACTORY | 328 | 328 | 328 | 328 | 2 |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| initialize | 269008 | 269008 | 269008 | 269008 | 2 |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| isSharedVaultRegistered | 8465 | 9613 | 9613 | 10761 | 2 |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| registerSharedVault | 170594 | 170594 | 170594 | 170594 | 2 |
|-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------|
| unregisterSharedVault | 74215 | 74215 | 74215 | 74215 | 1 |
╰-----------------------------------------------------------------------------------+-----------------+--------+--------+--------+---------╯
Ran 42 test suites in 10.74s (40.30s CPU time): 334 tests passed, 5 failed, 0 skipped (339 total tests)
Failing tests:
Encountered 5 failing tests in test/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.t.sol:PricedTokensChainlinkVPCalcTest
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPrice() (gas: 3466)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceHistorical() (gas: 8108)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceHistoricalZero() (gas: 8131)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceStale() (gas: 3400)
[FAIL: vm.createSelectFork: environment variable `ETH_RPC_URL` not found] test_ChainlinkCalcTracksRealPriceWithInvert() (gas: 3400)
Encountered a total of 5 failing tests, 334 tests succeeded
````
## File: snapshots/sizes.txt
````
No files changed, compilation skipped
╭------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╮
| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |
+====================================================================================================================================================================================================+
| Address | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| AuthorityUtils | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| BN254 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| BN254G2 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| BaseRewardsLogic | 1,606 | 1,658 | 22,970 | 47,494 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| BaseSlashingLogic | 4,387 | 4,439 | 20,189 | 44,713 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Bytes | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ChainlinkPriceFeed | 6,072 | 6,124 | 18,504 | 43,028 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Checkpoints (lib/core/src/contracts/libraries/Checkpoints.sol) | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Checkpoints (lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol) | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Checkpoints (src/libraries/structs/Checkpoints.sol) | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Create2 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| CreateXWrapper | 2,764 | 2,792 | 21,812 | 46,360 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ECDSA | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC1967Proxy | 122 | 935 | 24,454 | 48,217 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC1967Utils | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ERC4626Math | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| EnumerableSet | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Errors | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ExtraDataStorageHelper | 123 | 173 | 24,453 | 48,979 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| FeeOnTransferToken | 1,785 | 3,197 | 22,791 | 45,955 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| InputNormalizer | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyBlsBn254 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyBlsBn254Mock | 2,659 | 2,687 | 21,917 | 46,465 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyEcdsaSecp256k1 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyEcdsaSecp256k1Mock | 1,362 | 1,390 | 23,214 | 47,762 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyRegistry | 14,970 | 14,998 | 9,606 | 34,154 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyRegistryWithKey64 | 16,359 | 16,387 | 8,217 | 32,765 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| KeyTags | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Logs | 4,290 | 4,342 | 20,286 | 44,810 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Math | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MessageHashUtils | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MockAuthority | 258 | 392 | 24,318 | 48,760 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MockToken (test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol) | 1,757 | 2,881 | 22,819 | 46,271 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MockToken (test/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.t.sol) | 1,757 | 2,881 | 22,819 | 46,271 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MockToken (test/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.t.sol) | 1,757 | 2,881 | 22,819 | 46,271 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MyKeyRegistry | 15,260 | 15,288 | 9,316 | 33,864 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MySettlement | 12,058 | 12,086 | 12,518 | 37,066 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MyValSetDriver | 18,817 | 18,845 | 5,759 | 30,307 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| MyVotingPowerProvider | 12,956 | 13,124 | 11,620 | 36,028 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Network | 12,351 | 12,543 | 12,225 | 36,609 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| OpNetVaultAutoDeployLogic | 5,693 | 5,745 | 18,883 | 43,407 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Panic | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| PersistentSet | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ProxyAdmin | 977 | 1,213 | 23,599 | 47,939 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| RewarderMock | 730 | 758 | 23,846 | 48,394 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SafeCast | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SafeERC20 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Scaler | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigBlsBn254 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigEcdsaSecp256k1 | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigVerifierBlsBn254Simple | 4,946 | 4,974 | 19,630 | 44,178 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigVerifierBlsBn254ZK | 2,694 | 3,774 | 21,882 | 45,378 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigVerifierFalseMock | 586 | 614 | 23,990 | 48,538 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SigVerifierMock | 587 | 615 | 23,989 | 48,537 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SignatureChecker | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SignedMath | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Simulation | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SlasherMock | 1,264 | 1,292 | 23,312 | 47,860 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| StorageSlot | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Strings | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Subnetwork | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticCoreBytecode | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticCoreConstants | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| SymbioticUtils | 80 | 109 | 24,496 | 49,043 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestEpochManager | 4,327 | 4,355 | 20,249 | 44,797 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestKeyRegistry | 16,928 | 16,956 | 7,648 | 32,196 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestMultiToken | 12,229 | 12,397 | 12,347 | 36,755 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestNetworkManager | 1,356 | 1,384 | 23,220 | 47,768 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestNoPermissionManager | 334 | 362 | 24,242 | 48,790 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOpNetVaultAutoDeploy | 14,899 | 15,107 | 9,677 | 34,045 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOperatorVaults | 12,916 | 13,218 | 11,660 | 35,934 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOperatorsBlacklist | 13,153 | 13,321 | 11,423 | 35,831 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOperatorsJail | 13,391 | 13,559 | 11,185 | 35,593 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOperatorsWhitelist | 13,625 | 13,793 | 10,951 | 35,359 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOzAccessControl | 1,735 | 1,763 | 22,841 | 47,389 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOzAccessManaged | 1,853 | 1,881 | 22,723 | 47,271 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOzEIP712 | 2,562 | 2,590 | 22,014 | 46,562 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestOzOwnable | 971 | 999 | 23,605 | 48,153 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestPermissionManager | 575 | 603 | 24,001 | 48,549 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestSettlement | 10,858 | 10,886 | 13,718 | 38,266 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestSharedVaults | 12,332 | 12,500 | 12,244 | 36,652 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestValSetDriver | 16,581 | 16,609 | 7,995 | 32,543 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerCalcManager | 911 | 939 | 23,665 | 48,213 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerProvider (test/modules/voting-power/VotingPowerProvider.t.sol) | 14,819 | 14,987 | 9,757 | 34,165 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerProvider (test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol) | 15,523 | 15,691 | 9,053 | 33,461 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerProvider (test/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.t.sol) | 19,206 | 19,374 | 5,370 | 29,778 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerProvider (test/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.t.sol) | 17,465 | 17,633 | 7,111 | 31,519 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TestVotingPowerProvider (test/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.t.sol) | 16,796 | 16,964 | 7,780 | 32,188 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Time | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TimelockControllerUpgradeable | 7,683 | 7,711 | 16,893 | 41,441 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Token | 1,723 | 3,065 | 22,853 | 46,087 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| TransparentUpgradeableProxy | 1,074 | 3,447 | 23,502 | 45,705 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ValSetVerifier | 44 | 94 | 24,532 | 49,058 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ValSetVerifierContract | 2,248 | 2,276 | 22,328 | 46,876 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| ValSetVerifierMock | 1,170 | 1,198 | 23,406 | 47,954 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Verifier (test/data/zk/Verifier_10.sol) | 6,391 | 6,419 | 18,185 | 42,733 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Verifier (test/data/zk/Verifier_100.sol) | 6,393 | 6,421 | 18,183 | 42,731 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| Verifier (test/data/zk/Verifier_1000.sol) | 6,391 | 6,419 | 18,185 | 42,733 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| VotingPowerProviderFull | 24,286 | 24,494 | 290 | 24,658 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| VotingPowerProviderLogic | 15,628 | 15,680 | 8,948 | 33,472 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| VotingPowerProviderSemiFull | 16,892 | 17,060 | 7,684 | 32,092 |
|------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------|
| VotingPowerProviderSharedVaults | 12,819 | 12,987 | 11,757 | 36,165 |
╰------------------------------------------------------------------------------------------------------------------+------------------+-------------------+--------------------+---------------------╯
````
## File: src/interfaces/modules/base/INetworkManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title INetworkManager
* @notice Interface for the NetworkManager contract.
*/
interface INetworkManager {
/**
* @notice Reverts when the network is zero address.
*/
⋮----
/**
* @notice The storage of the NetworkManager contract.
* @param _network The address of the network.
* @param _subnetworkID The identifier of the subnetwork.
* @dev The whole set of contracts supports only a single subnetwork per network.
* @custom:storage-location erc7201:symbiotic.storage.NetworkManager
*/
⋮----
/**
* @notice The parameters for the initialization of the NetworkManager contract.
* @param network The address of the network.
* @param subnetworkId The identifier of the subnetwork.
* @dev `network` is not obligated to be registered in NetworkRegistry contract, it can be any non-zero address.
*/
⋮----
/**
* @notice Emitted during the NetworkManager initialization.
* @param network The address of the network.
* @param subnetworkId The identifier of the subnetwork.
*/
event InitSubnetwork(address network, uint96 subnetworkId);
⋮----
/**
* @notice Returns the address of the network.
* @return The address of the network.
*/
function NETWORK() external view returns (address);
⋮----
/**
* @notice Returns the identifier of the subnetwork.
* @return The identifier of the subnetwork.
*/
function SUBNETWORK_IDENTIFIER() external view returns (uint96);
⋮----
/**
* @notice Returns the subnetwork (a concatenation of the network and the subnetwork ID).
* @return The subnetwork.
*/
function SUBNETWORK() external view returns (bytes32);
````
## File: src/interfaces/modules/base/IOzEIP712.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
⋮----
/**
* @title IOzEIP712
* @notice Interface for the OzEIP712 contract.
*/
interface IOzEIP712 is IERC5267 {
/**
* @notice The parameters for the initialization of the OzEIP712 contract.
* @param name The name for EIP712.
* @param version The version for EIP712.
*/
⋮----
/**
* @notice Emitted during the OzEIP712 initialization.
* @param name The name for EIP712.
* @param version The version for EIP712.
*/
event InitEIP712(string name, string version);
⋮----
/**
* @notice Returns the EIP712 hash of the typed data.
* @param structHash The hash of the typed data struct.
* @return The EIP712 formatted hash.
*/
function hashTypedDataV4(bytes32 structHash) external view returns (bytes32);
⋮----
/**
* @notice Wraps the `structHash` to the EIP712 format for cross-chain usage.
* @param structHash The hash of the typed data struct.
* @return The EIP712 formatted hash.
* @dev It doesn't include `chainId` and `verifyingContract` fields for the domain separator.
*/
function hashTypedDataV4CrossChain(bytes32 structHash) external view returns (bytes32);
````
## File: src/interfaces/modules/base/IPermissionManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IPermissionManager
* @notice Interface for the PermissionManager contract.
*/
interface IPermissionManager {}
````
## File: src/interfaces/modules/common/permissions/IOzAccessControl.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IPermissionManager} from "../../../modules/base/IPermissionManager.sol";
⋮----
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
⋮----
/**
* @title IOzAccessControl
* @notice Interface for the OzAccessControl contract.
*/
interface IOzAccessControl {
/**
* @notice The storage of the OzAccessControl contract.
* @param _selectorRoles The mapping from the function selector to the required role.
* @custom:storage-location erc7201:symbiotic.storage.OzAccessControl
*/
⋮----
/**
* @notice Emitted when the required role is set for a selector.
* @param selector The function selector.
* @param role The required role.
*/
event SetSelectorRole(bytes4 indexed selector, bytes32 indexed role);
⋮----
/**
* @notice Returns the required role for a selector.
* @param selector The function selector.
* @return The required role.
*/
function getRole(bytes4 selector) external view returns (bytes32);
````
## File: src/interfaces/modules/common/permissions/IOzAccessManaged.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IPermissionManager} from "../../../modules/base/IPermissionManager.sol";
⋮----
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
⋮----
/**
* @title IOzAccessManaged
* @notice Interface for the OzAccessManaged contract.
*/
interface IOzAccessManaged {
/**
* @notice The parameters for the initialization of the OzAccessManaged contract.
* @param authority The address of the authority that will check the access.
*/
````
## File: src/interfaces/modules/common/permissions/IOzOwnable.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IPermissionManager} from "../../../modules/base/IPermissionManager.sol";
⋮----
/**
* @title IOzOwnable
* @notice Interface for the OzOwnable contract.
*/
interface IOzOwnable {
/**
* @notice The parameters for the initialization of the OzOwnable contract.
* @param owner The address of the owner.
*/
````
## File: src/interfaces/modules/key-registry/IKeyRegistry.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IOzEIP712} from "../../modules/base/IOzEIP712.sol";
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
import {PersistentSet} from "../../../libraries/structs/PersistentSet.sol";
⋮----
/**
* @title IKeyRegistry
* @notice Interface for the KeyRegistry contract.
*/
interface IKeyRegistry {
/**
* @notice Reverts when the key is already used by another operator or with another tag.
*/
⋮----
/**
* @notice Reverts when the key ownership signature is invalid.
*/
⋮----
/**
* @notice Reverts when the key type is not supported.
*/
⋮----
/**
* @notice The storage of the KeyRegistry contract.
* @param _keys32 The mapping from the operator and the key tag to the 32 bytes key.
* @param _keys64 The mapping from the operator and the key tag to the 64 bytes key.
* @param _operatorByKeyHash The mapping from the key hash to the operator.
* @param _operatorByTypeAndKeyHash The mapping from the key type and the key hash to the operator.
* @param _operatorByTagAndKeyHash The mapping from the key type and the key hash to the operator.
* @param _operators The set of operators with registered keys.
* @param _operatorKeyTags The mapping from the operator to the registered key tags.
* @custom:storage-location erc7201:symbiotic.storage.KeyRegistry
*/
⋮----
/**
* @notice The parameters for the initialization of the KeyRegistry contract.
* @param ozEip712InitParams The parameters for the initialization of the OzEIP712 contract.
*/
⋮----
/**
* @notice The key with the tag and the payload.
* @param tag The tag of the key.
* @param payload The payload of the key.
*/
⋮----
/**
* @notice The operator with the keys.
* @param operator The address of the operator.
* @param keys The operator's keys.
*/
⋮----
/**
* @notice Emitted when the key is set.
* @param operator The address of the operator.
* @param tag The tag of the key.
* @param key The payload of the key.
* @param extraData The extra data of the key (e.g., the G2 key for BLS keys).
*/
event SetKey(address indexed operator, uint8 indexed tag, bytes indexed key, bytes extraData);
⋮----
/**
* @notice Returns the operator's keys at a specific timestamp.
* @param operator The address of the operator.
* @param timestamp The timestamp.
* @return The operator's keys.
*/
function getKeysAt(address operator, uint48 timestamp) external view returns (Key[] memory);
⋮----
/**
* @notice Returns the current operator's keys.
* @param operator The address of the operator.
* @return The operator's keys.
*/
function getKeys(address operator) external view returns (Key[] memory);
⋮----
/**
* @notice Returns the key at a specific timestamp.
* @param operator The address of the operator.
* @param tag The tag of the key.
* @param timestamp The timestamp.
* @return The key.
* @dev Will return a zero key if the key is not found (e.g., abi.encode(address(0)) for ECDSA keys).
*/
function getKeyAt(address operator, uint8 tag, uint48 timestamp) external view returns (bytes memory);
⋮----
/**
* @notice Returns the current key.
* @param operator The address of the operator.
* @param tag The tag of the key.
* @return The key.
* @dev Will return a zero key if the key is not found (e.g., abi.encode(address(0)) for ECDSA keys).
*/
function getKey(address operator, uint8 tag) external view returns (bytes memory);
⋮----
/**
* @notice Returns the operator by the key.
* @param key The key.
* @return The operator.
*/
function getOperator(bytes memory key) external view returns (address);
⋮----
/**
* @notice Returns the operators with their keys at a specific timestamp.
* @param timestamp The timestamp.
* @return The operators with their keys.
* @dev Different operators may have different numbers of keys and their tags.
*/
function getKeysAt(uint48 timestamp) external view returns (OperatorWithKeys[] memory);
⋮----
/**
* @notice Returns the current operators with their keys.
* @return The operators with their keys.
* @dev Different operators may have different numbers of keys and their tags.
*/
function getKeys() external view returns (OperatorWithKeys[] memory);
⋮----
/**
* @notice Returns the number of the operators who registered any keys.
* @return The number of the operators who registered any keys.
*/
function getKeysOperatorsLength() external view returns (uint256);
⋮----
/**
* @notice Returns the operators who registered any keys until a specific timestamp.
* @param timestamp The timestamp.
* @return The operators who registered any keys until a specific timestamp.
*/
function getKeysOperatorsAt(uint48 timestamp) external view returns (address[] memory);
⋮----
/**
* @notice Returns the operators who registered any keys.
* @return The operators who registered any keys.
*/
function getKeysOperators() external view returns (address[] memory);
⋮----
/**
* @notice Sets a key for a caller.
* @param tag The tag of the key.
* @param key The payload of the key.
* @param signature The signature to verify the key ownership.
* @param extraData The extra data of the key (e.g., the G2 key for BLS keys).
*/
function setKey(uint8 tag, bytes memory key, bytes memory signature, bytes memory extraData) external;
````
## File: src/interfaces/modules/settlement/sig-verifiers/zk/IVerifier.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IVerifier
* @notice Interface for the gnark verifier contracts.
*/
interface IVerifier {
/**
* @notice Verifies a ZK proof for the given input.
* @param proof The ZK proof.
* @param commitments The commitments.
* @param commitmentPok The commitment proof of knowledge.
* @param input The circuit public input.
* @dev Reverts if the proof is invalid.
*/
function verifyProof(
````
## File: src/interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title ISigVerifier
* @notice Interface for the signature verifier contracts.
*/
interface ISigVerifier {
/**
* @notice Returns the type of the signature verification.
* @return The type of the signature verification.
*/
function VERIFICATION_TYPE() external view returns (uint32);
⋮----
/**
* @notice Returns the result of the quorum signature verification.
* @param settlement The address of the Settlement contract.
* @param epoch The epoch from which the validator set is to use.
* @param message The message to verify.
* @param keyTag The tag of the key.
* @param quorumThreshold The quorum threshold (in absolute terms).
* @param proof The proof (depends on the verification type).
* @return The result of the quorum signature verification.
*/
function verifyQuorumSig(
````
## File: src/interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254Simple.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {ISigVerifier} from "./ISigVerifier.sol";
⋮----
/**
* @title ISigVerifierBlsBn254Simple
* @notice Interface for the SigVerifierBlsBn254Simple contract.
*/
interface ISigVerifierBlsBn254Simple is ISigVerifier {
/**
* @notice Reverts when the message length is invalid.
*/
⋮----
/**
* @notice Reverts when the non-signer index is greater than the number of validators.
*/
⋮----
/**
* @notice Reverts when the non-signers' indices are not in the correct order.
* @dev The indices must be sorted in ascending order.
*/
⋮----
/**
* @notice Reverts when the proof length is too short.
*/
⋮----
/**
* @notice Reverts when the proof offset is invalid.
*/
⋮----
/**
* @notice Reverts when the number of validators exceeds the maximum allowed for this verification mechanism.
*/
⋮----
/**
* @notice Reverts when the verification is not supported for the given key tag.
*/
⋮----
/**
* @notice Returns the marker for extra data fetching of the validator set keccak256 hash.
* @return The marker for extra data fetching of the validator set keccak256 hash.
*/
function VALIDATOR_SET_HASH_KECCAK256_HASH() external view returns (bytes32);
⋮----
/**
* @notice Returns the marker for extra data fetching of the aggregated public key G1.
* @return The marker for extra data fetching of the aggregated public key G1.
* @dev The public key is compressed to one bytes32 slot.
*/
function AGGREGATED_PUBLIC_KEY_G1_HASH() external view returns (bytes32);
⋮----
/**
* @notice Returns the maximum allowed number of validators for this verification mechanism.
* @return The maximum allowed number of validators for this verification mechanism.
* @dev The maximum exists because each non-signer's index is encoded as a 2 bytes value.
*/
function MAX_VALIDATORS() external view returns (uint256);
````
## File: src/interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254ZK.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {ISigVerifier} from "./ISigVerifier.sol";
⋮----
/**
* @title ISigVerifierBlsBn254ZK
* @notice Interface for the SigVerifierBlsBn254ZK contract.
*/
interface ISigVerifierBlsBn254ZK is ISigVerifier {
/**
* @notice Reverts when the number of verifiers and max validators is not the same or zero.
*/
⋮----
/**
* @notice Reverts when the maximum supported number of validators is zero.
*/
⋮----
/**
* @notice Reverts when the maximum supported numbers of validators is not in the correct order.
* @dev The maximum supported numbers of validators must be in ascending order.
*/
⋮----
/**
* @notice Reverts when the message length is invalid.
*/
⋮----
/**
* @notice Reverts when the proof length is invalid.
*/
⋮----
/**
* @notice Reverts when the proof offset is invalid.
*/
⋮----
/**
* @notice Reverts when the total active validators is greater than the maximum supported.
*/
⋮----
/**
* @notice Reverts when the verifier is zero address.
*/
⋮----
/**
* @notice Reverts when the verification is not supported for the given key tag.
*/
⋮----
/**
* @notice Returns the marker for extra data fetching of the total active validators.
* @return The marker for extra data fetching of the total active validators.
*/
function TOTAL_ACTIVE_VALIDATORS_HASH() external view returns (bytes32);
⋮----
/**
* @notice Returns the marker for extra data fetching of the validator set MiMC hash.
* @return The marker for extra data fetching of the validator set MiMC hash.
*/
function VALIDATOR_SET_HASH_MIMC_HASH() external view returns (bytes32);
⋮----
/**
* @notice Returns the verifier at the given index.
* @param index The index of the verifier.
* @return The verifier at the given index.
*/
function verifiers(uint256 index) external view returns (address);
⋮----
/**
* @notice Returns the maximum supported number of validators for the verifier at the given index.
* @param index The index of the verifier.
* @return The maximum supported number of validators for the verifier at the given index.
*/
function maxValidators(uint256 index) external view returns (uint256);
````
## File: src/interfaces/modules/settlement/ISettlement.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {INetworkManager} from "../../modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../modules/base/IOzEIP712.sol";
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
⋮----
/**
* @title ISettlement
* @notice Interface for the Settlement contract.
*/
interface ISettlement {
/**
* @notice Reverts when the extra data key is duplicated.
*/
⋮----
/**
* @notice Reverts when the capture timestamp is less than or equal to the capture timestamp of the latest committed header,
* or greater than or equal to the current timestamp.
*/
⋮----
/**
* @notice Reverts when the proposed during the commit epoch is less than or equal to the latest committed one.
*/
⋮----
/**
* @notice Reverts when the new quorum signature verifier is zero.
*/
⋮----
/**
* @notice Reverts when the validator set SSZ root is zero.
*/
⋮----
/**
* @notice Reverts when the version to be committed is not the same as the version inside the contract.
* @dev Can be triggered during the upgrades.
*/
⋮----
/**
* @notice Reverts when the quorum threshold is greater than the total voting power.
*/
⋮----
/**
* @notice Reverts when the validator set header is already committed for the proposed epoch.
*/
⋮----
/**
* @notice Reverts when the quorum signature verification fails.
*/
⋮----
/**
* @notice The storage of the Settlement contract.
* @param _lastCommittedHeaderEpoch The epoch of the last committed header.
* @param _sigVerifier The address of the quorum signature verifier.
* @param _valSetHeader The mapping from the epoch to the validator set header.
* @param _extraData The mapping from the epoch and the key to the extra data.
* @custom:storage-location ERC-7201 slot: erc7201:symbiotic.storage.Settlement.
*/
⋮----
/**
* @notice The parameters for the initialization of the Settlement contract.
* @param networkManagerInitParams The parameters for the initialization of the NetworkManager.
* @param ozEip712InitParams The parameters for the initialization of the OzEIP712.
* @param sigVerifier The address of the quorum signature verifier.
*/
⋮----
/**
* @notice The validator set header.
* @param version The version of the validator set header.
* @param requiredKeyTag The required key tag for the validator set header using which the next header will be committed.
* @param epoch The epoch of the validator set.
* @param captureTimestamp The capture timestamp of the validator set.
* @param quorumThreshold The quorum threshold of the validator set header which will need to be reached to commit the next header.
* @param totalVotingPower The total voting power of the validator set.
* @param validatorsSszMRoot The validator set SSZ root.
*/
⋮----
/**
* @notice The extra data.
* @param key The key to store the extra data with.
* @param value The value of the extra data.
* @dev This key-value storage is fully flexible and can be used to store any data (e.g., verification-specific aggregated data).
*/
⋮----
/**
* @notice Emitted during the Settlement initialization.
* @param sigVerifier The address of the quorum signature verifier.
*/
event InitSigVerifier(address sigVerifier);
⋮----
/**
* @notice Emitted when the quorum signature verifier is set.
* @param sigVerifier The address of the quorum signature verifier.
* @dev The new verifier will be "committed" only in the next epoch.
*/
event SetSigVerifier(address sigVerifier);
⋮----
/**
* @notice Emitted when the genesis is set.
* @param valSetHeader The validator set header.
* @param extraData The extra data.
*/
event SetGenesis(ValSetHeader valSetHeader, ExtraData[] extraData);
⋮----
/**
* @notice Emitted when the validator set header is committed.
* @param valSetHeader The validator set header.
* @param extraData The extra data.
*/
event CommitValSetHeader(ValSetHeader valSetHeader, ExtraData[] extraData);
⋮----
/**
* @notice Returns the version of the validator set.
* @return The version of the validator set.
*/
function VALIDATOR_SET_VERSION() external view returns (uint8);
⋮----
/**
* @notice Returns the quorum signature verifier at the given epoch.
* @param epoch The epoch.
* @param hint The hint for the quorum signature verifier.
* @return The quorum signature verifier at the given epoch.
*/
function getSigVerifierAt(uint48 epoch, bytes memory hint) external view returns (address);
⋮----
/**
* @notice Returns the quorum signature verifier.
* @return The quorum signature verifier.
*/
function getSigVerifier() external view returns (address);
⋮----
/**
* @notice Returns the epoch of the last committed validator set header.
* @return The epoch of the last committed validator set header.
*/
function getLastCommittedHeaderEpoch() external view returns (uint48);
⋮----
/**
* @notice Returns if the validator set header is committed at the given epoch.
* @param epoch The epoch.
* @return True if the validator set header is committed at the given epoch.
*/
function isValSetHeaderCommittedAt(uint48 epoch) external view returns (bool);
⋮----
/**
* @notice Returns the hash of the validator set header at the given epoch.
* @param epoch The epoch.
* @return The hash of the validator set header at the given epoch.
*/
function getValSetHeaderHashAt(uint48 epoch) external view returns (bytes32);
⋮----
/**
* @notice Returns the hash of the last committed validator set header.
* @return The hash of the last committed validator set header.
*/
function getValSetHeaderHash() external view returns (bytes32);
⋮----
/**
* @notice Returns the validator set header at the given epoch.
* @param epoch The epoch.
* @return The validator set header at the given epoch.
*/
function getValSetHeaderAt(uint48 epoch) external view returns (ValSetHeader memory);
⋮----
/**
* @notice Returns the last committed validator set header.
* @return The last committed validator set header.
*/
function getValSetHeader() external view returns (ValSetHeader memory);
⋮----
/**
* @notice Returns the version of the validator set header at the given epoch.
* @param epoch The epoch.
* @return The version of the validator set header at the given epoch.
*/
function getVersionFromValSetHeaderAt(uint48 epoch) external view returns (uint8);
⋮----
/**
* @notice Returns the version from the last committed validator set header.
* @return The version from the last committed validator set header.
*/
function getVersionFromValSetHeader() external view returns (uint8);
⋮----
/**
* @notice Returns the required key tag from the validator set header at the given epoch.
* @param epoch The epoch.
* @return The required key tag from the validator set header at the given epoch.
*/
function getRequiredKeyTagFromValSetHeaderAt(uint48 epoch) external view returns (uint8);
⋮----
/**
* @notice Returns the required key tag from the last committed validator set header.
* @return The required key tag from the last committed validator set header.
*/
function getRequiredKeyTagFromValSetHeader() external view returns (uint8);
⋮----
/**
* @notice Returns the capture timestamp from the validator set header at the given epoch.
* @param epoch The epoch.
* @return The capture timestamp from the validator set header at the given epoch.
*/
function getCaptureTimestampFromValSetHeaderAt(uint48 epoch) external view returns (uint48);
⋮----
/**
* @notice Returns the capture timestamp from the last committed validator set header.
* @return The capture timestamp from the last committed validator set header.
*/
function getCaptureTimestampFromValSetHeader() external view returns (uint48);
⋮----
/**
* @notice Returns the quorum threshold from the validator set header at the given epoch.
* @param epoch The epoch.
* @return The quorum threshold from the validator set header at the given epoch.
*/
function getQuorumThresholdFromValSetHeaderAt(uint48 epoch) external view returns (uint256);
⋮----
/**
* @notice Returns the quorum threshold from the last committed validator set header.
* @return The quorum threshold from the last committed validator set header.
*/
function getQuorumThresholdFromValSetHeader() external view returns (uint256);
⋮----
/**
* @notice Returns the total voting power from the validator set header at the given epoch.
* @param epoch The epoch.
* @return The total voting power from the validator set header at the given epoch.
*/
function getTotalVotingPowerFromValSetHeaderAt(uint48 epoch) external view returns (uint256);
⋮----
/**
* @notice Returns the total voting power from the last committed validator set header.
* @return The total voting power from the last committed validator set header.
*/
function getTotalVotingPowerFromValSetHeader() external view returns (uint256);
⋮----
/**
* @notice Returns the validator set SSZ root from the validator set header at the given epoch.
* @param epoch The epoch.
* @return The validator set SSZ root from the validator set header at the given epoch.
*/
function getValidatorsSszMRootFromValSetHeaderAt(uint48 epoch) external view returns (bytes32);
⋮----
/**
* @notice Returns the validator set SSZ root from the last committed validator set header.
* @return The validator set SSZ root from the last committed validator set header.
*/
function getValidatorsSszMRootFromValSetHeader() external view returns (bytes32);
⋮----
/**
* @notice Returns the extra data at the given epoch for a certain key.
* @param epoch The epoch.
* @param key The key.
* @return The extra data at the given epoch for a certain key.
*/
function getExtraDataAt(uint48 epoch, bytes32 key) external view returns (bytes32);
⋮----
/**
* @notice Returns the extra data from the last committed epoch for a certain key.
* @param key The key.
* @return The extra data from the last committed epoch for a certain key.
*/
function getExtraData(bytes32 key) external view returns (bytes32);
⋮----
/**
* @notice Returns the result of the quorum signature verification for the given message at the given epoch.
* @param message The message to verify.
* @param keyTag The key tag to use for the quorum signature verification.
* @param quorumThreshold The quorum threshold to require for the quorum signature verification.
* @param proof The proof to verify the quorum signature.
* @param epoch The epoch.
* @param hint The hint to optimize the signature verifier fetching.
* @return The result of the quorum signature verification for the given message at the given epoch.
*/
function verifyQuorumSigAt(
⋮----
/**
* @notice Returns the result of the quorum signature verification for the given message using the last committed validator set header.
* @param message The message to verify.
* @param keyTag The key tag to use for the quorum signature verification.
* @param quorumThreshold The quorum threshold to require for the quorum signature verification.
* @param proof The proof to verify the quorum signature.
* @return The result of the quorum signature verification for the given message using the last committed validator set header.
*/
function verifyQuorumSig(bytes memory message, uint8 keyTag, uint256 quorumThreshold, bytes calldata proof)
⋮----
/**
* @notice Sets the quorum signature verifier.
* @param sigVerifier The address of the quorum signature verifier.
* @dev The new verifier will be "committed" only in the next epoch.
* @dev The caller must have the needed permission.
*/
function setSigVerifier(address sigVerifier) external;
⋮----
/**
* @notice Sets the genesis validator set header and its extra data.
* @param valSetHeader The validator set header.
* @param extraData The extra data.
* @dev The caller must have the needed permission.
* Can be called multiple times.
*/
function setGenesis(ValSetHeader calldata valSetHeader, ExtraData[] calldata extraData) external;
⋮----
/**
* @notice Commits the validator set header and its extra data.
* @param header The validator set header.
* @param extraData The extra data.
* @param proof The proof to verify the quorum signature.
* @dev The caller can be anyone, the call is validated by verification of the validator set's attestation.
*/
function commitValSetHeader(ValSetHeader calldata header, ExtraData[] calldata extraData, bytes calldata proof)
````
## File: src/interfaces/modules/valset-driver/IEpochManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
⋮----
/**
* @title IEpochManager
* @notice Interface for the EpochManager contract.
*/
interface IEpochManager {
/**
* @notice Reverts when the epoch duration is zero.
*/
⋮----
/**
* @notice Reverts when the initial epoch duration timestamp is less than the current timestamp.
*/
⋮----
/**
* @notice Reverts when the timestamp is too old.
*/
⋮----
/**
* @notice The storage of the EpochManager contract.
* @param _epochDurationDataByTimestamp The epoch duration data checkpointed by timestamps.
* @param _epochDurationDataByIndex The epoch duration data checkpointed by epoch indexes.
* @custom:storage-location erc7201:symbiotic.storage.EpochManager
*/
⋮----
/**
* @notice The parameters for the initialization of the EpochManager contract.
* @param epochDuration The epoch duration.
* @param epochDurationTimestamp The initial epoch duration timestamp.
*/
⋮----
/**
* @notice Emitted during the initialization of the EpochManager contract.
* @param epochDuration The epoch duration.
* @param epochDurationTimestamp The initial epoch duration timestamp.
*/
event InitEpochDuration(uint48 epochDuration, uint48 epochDurationTimestamp);
⋮----
/**
* @notice Emitted when the epoch duration is set.
* @param epochDuration The epoch duration.
* @dev The new duration will be "committed" only in the next epoch.
*/
event SetEpochDuration(uint48 epochDuration);
⋮----
/**
* @notice Returns the current epoch.
* @return The current epoch.
*/
function getCurrentEpoch() external view returns (uint48);
⋮----
/**
* @notice Returns the current epoch duration.
* @return The current epoch duration.
*/
function getCurrentEpochDuration() external view returns (uint48);
⋮----
/**
* @notice Returns the current epoch start.
* @return The current epoch start.
*/
function getCurrentEpochStart() external view returns (uint48);
⋮----
/**
* @notice Returns the next epoch.
* @return The next epoch.
*/
function getNextEpoch() external view returns (uint48);
⋮----
/**
* @notice Returns the next epoch duration.
* @return The next epoch duration.
*/
function getNextEpochDuration() external view returns (uint48);
⋮----
/**
* @notice Returns the next epoch start.
* @return The next epoch start.
*/
function getNextEpochStart() external view returns (uint48);
⋮----
/**
* @notice Returns the epoch index at the given timestamp.
* @param timestamp The timestamp.
* @return The epoch index at the given timestamp.
*/
function getEpochIndex(uint48 timestamp) external view returns (uint48);
⋮----
/**
* @notice Returns the epoch duration of the given epoch.
* @param epoch The epoch.
* @return The epoch duration of the given epoch.
*/
function getEpochDuration(uint48 epoch) external view returns (uint48);
⋮----
/**
* @notice Returns the epoch start of the given epoch.
* @param epoch The epoch.
* @return The epoch start of the given epoch.
*/
function getEpochStart(uint48 epoch) external view returns (uint48);
⋮----
/**
* @notice Sets the epoch duration.
* @param epochDuration The epoch duration.
* @dev The new duration will be "committed" only in the next epoch.
* The caller must have the needed permission.
*/
function setEpochDuration(uint48 epochDuration) external;
````
## File: src/interfaces/modules/valset-driver/IValSetDriver.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IEpochManager} from "./IEpochManager.sol";
import {INetworkManager} from "../../modules/base/INetworkManager.sol";
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
import {PersistentSet} from "../../../libraries/structs/PersistentSet.sol";
⋮----
/**
* @title IValSetDriver
* @notice Interface for the ValSetDriver contract.
*/
interface IValSetDriver {
/**
* @notice Reverts when the cross-chain address with the same chain ID is already added.
*/
⋮----
/**
* @notice Reverts when the cross-chain address is either zero or has zero chain ID.
*/
⋮----
/**
* @notice Reverts when the maximum active validators count is zero.
*/
⋮----
/**
* @notice Reverts when the quorum threshold is greater than the maximum quorum threshold.
* @dev The maximum quorum threshold is 1e18 = 100%.
*/
⋮----
/**
* @notice Reverts when the quorum threshold with the same key tag is already added.
*/
⋮----
/**
* @notice Reverts when the subject is not added but was tried to be removed.
*/
⋮----
/**
* @notice Reverts when the number of aggregators is zero.
*/
⋮----
/**
* @notice Reverts when the number of committers is zero.
*/
⋮----
/**
* @notice The storage of the ValSetDriver contract.
* @param _isVotingPowerProviderChainAdded The mapping from the chain ID to the voting power provider chain added status.
* @param _votingPowerProviders The set of the voting power providers.
* @param _keysProvider The checkpoint of the keys provider.
* @param _isSettlementChainAdded The mapping from the chain ID to the settlement chain added status.
* @param _settlements The set of the settlements.
* @param _verificationType The checkpoint of the verification type.
* @param _maxVotingPower The checkpoint of the maximum voting power.
* @param _minInclusionVotingPower The checkpoint of the minimum inclusion voting power.
* @param _maxValidatorsCount The checkpoint of the maximum active validators count.
* @param _requiredKeyTags The checkpoint of the required key tags.
* @param _requiredHeaderKeyTag The checkpoint of the required header key tag.
* @param _isQuorumThresholdKeyTagAdded The mapping from the key tag to the quorum threshold key tag added status.
* @param _quorumThresholds The set of the quorum thresholds.
* @param _numAggregators The checkpoint of the number of aggregators.
* @param _numCommitters The checkpoint of the number of committers.
* @custom:storage-location ERC-7201 slot: erc7201:symbiotic.storage.ValSetDriver.
*/
⋮----
/**
* @notice The parameters for the initialization of the ValSetDriver contract.
* @param networkManagerInitParams The parameters for the initialization of the NetworkManager contract.
* @param epochManagerInitParams The parameters for the initialization of the EpochManager contract.
* @param numAggregators The number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification) at the genesis.
* @param numCommitters The number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain) at the genesis.
* @param votingPowerProviders The voting power providers (contracts that provide the voting powers of the operators on different chains).
* @param keysProvider The keys provider (contract that provides the keys of the operators).
* @param settlements The settlements (contracts that enable a verification of the validator set's attestations on different chains).
* @param maxVotingPower The maximum voting power for each validator.
* @param minInclusionVotingPower The minimum inclusion voting power for the operator to be included in the validator set.
* @param maxValidatorsCount The maximum active validators count in the validator set.
* @param requiredKeyTags The required key tags to include in the validator set.
* @param quorumThresholds The quorum thresholds to use for attestations' verification.
* @param requiredHeaderKeyTag The required header key tag to use to maintain the validator set through epochs.
* @param verificationType The verification type (e.g., simple on-chain verification, or zk-based one).
*/
⋮----
/**
* @notice The cross-chain address.
* @param chainId The chain ID.
* @param addr The address.
*/
⋮----
/**
* @notice The quorum threshold.
* @param keyTag The key tag.
* @param quorumThreshold The quorum threshold (percentage).
*/
⋮----
/**
* @notice The configuration.
* @param numAggregators The number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification).
* @param numCommitters The number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain).
* @param votingPowerProviders The voting power providers (contracts that provide the voting powers of the operators on different chains).
* @param keysProvider The keys provider (contract that provides the keys of the operators).
* @param settlements The settlements (contracts that enable a verification of the validator set's attestations on different chains).
* @param maxVotingPower The maximum voting power for each validator.
* @param minInclusionVotingPower The minimum inclusion voting power for the operator to be included in the validator set.
* @param maxValidatorsCount The maximum active validators count in the validator set.
* @param requiredKeyTags The required key tags to include in the validator set.
* @param quorumThresholds The quorum thresholds to use for attestations' verification.
* @param requiredHeaderKeyTag The required header key tag to use to maintain the validator set through epochs.
* @param verificationType The verification type (e.g., simple on-chain verification, or zk-based one).
*/
⋮----
/**
* @notice Emitted when the number of aggregators is set.
* @param numAggregators The number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification).
*/
event SetNumAggregators(uint208 numAggregators);
⋮----
/**
* @notice Emitted when the number of committers is set.
* @param numCommitters The number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain).
*/
event SetNumCommitters(uint208 numCommitters);
⋮----
/**
* @notice Emitted when the voting power provider is added.
* @param votingPowerProvider The voting power provider (contract that provides the voting powers of the operators on different chains).
*/
event AddVotingPowerProvider(CrossChainAddress votingPowerProvider);
⋮----
/**
* @notice Emitted when the voting power provider is removed.
* @param votingPowerProvider The voting power provider (contract that provides the voting powers of the operators on different chains).
*/
event RemoveVotingPowerProvider(CrossChainAddress votingPowerProvider);
⋮----
/**
* @notice Emitted when the keys provider is set.
* @param keysProvider The keys provider (contract that provides the keys of the operators).
*/
event SetKeysProvider(CrossChainAddress keysProvider);
⋮----
/**
* @notice Emitted when the settlement is added.
* @param settlement The settlement (contract that enable a verification of the validator set's attestations on different chains).
*/
event AddSettlement(CrossChainAddress settlement);
⋮----
/**
* @notice Emitted when the settlement is removed.
* @param settlement The settlement (contract that enable a verification of the validator set's attestations on different chains).
*/
event RemoveSettlement(CrossChainAddress settlement);
⋮----
/**
* @notice Emitted when the maximum voting power is set.
* @param maxVotingPower The maximum voting power for each validator.
*/
event SetMaxVotingPower(uint256 maxVotingPower);
⋮----
/**
* @notice Emitted when the minimum inclusion voting power is set.
* @param minInclusionVotingPower The minimum inclusion voting power for the operator to be included in the validator set.
*/
event SetMinInclusionVotingPower(uint256 minInclusionVotingPower);
⋮----
/**
* @notice Emitted when the maximum active validators count is set.
* @param maxValidatorsCount The maximum active validators count in the validator set.
*/
event SetMaxValidatorsCount(uint208 maxValidatorsCount);
⋮----
/**
* @notice Emitted when the required key tags are set.
* @param requiredKeyTags The required key tags to include in the validator set.
*/
event SetRequiredKeyTags(uint8[] requiredKeyTags);
⋮----
/**
* @notice Emitted when the quorum threshold is added.
* @param quorumThreshold The quorum threshold to use for attestations' verification.
*/
event AddQuorumThreshold(QuorumThreshold quorumThreshold);
⋮----
/**
* @notice Emitted when the required header key tag is set.
* @param requiredHeaderKeyTag The required header key tag to use to maintain the validator set through epochs.
*/
event SetRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag);
⋮----
/**
* @notice Emitted when the quorum threshold is removed.
* @param quorumThreshold The quorum threshold to use for attestations' verification.
*/
event RemoveQuorumThreshold(QuorumThreshold quorumThreshold);
⋮----
/**
* @notice Emitted when the verification type is set.
* @param verificationType The verification type (e.g., simple on-chain verification, or zk-based one).
*/
event SetVerificationType(uint32 verificationType);
⋮----
/**
* @notice Returns the maximum quorum threshold.
* @return The maximum quorum threshold.
* @dev The maximum quorum threshold is 1e18 = 100%.
*/
function MAX_QUORUM_THRESHOLD() external view returns (uint248);
⋮----
/**
* @notice Returns the configuration at the given timestamp.
* @param timestamp The timestamp.
* @return The configuration.
*/
function getConfigAt(uint48 timestamp) external view returns (Config memory);
⋮----
/**
* @notice Returns the configuration.
* @return The configuration.
*/
function getConfig() external view returns (Config memory);
⋮----
/**
* @notice Returns the number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification) at the given timestamp.
* @param timestamp The timestamp.
* @return The number of aggregators.
*/
function getNumAggregatorsAt(uint48 timestamp) external view returns (uint208);
⋮----
/**
* @notice Returns the number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification).
* @return The number of aggregators.
*/
function getNumAggregators() external view returns (uint208);
⋮----
/**
* @notice Returns the number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain) at the given timestamp.
* @param timestamp The timestamp.
* @return The number of committers.
*/
function getNumCommittersAt(uint48 timestamp) external view returns (uint208);
⋮----
/**
* @notice Returns the number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain).
* @return The number of committers.
*/
function getNumCommitters() external view returns (uint208);
⋮----
/**
* @notice Returns if the voting power provider is registered at the given timestamp.
* @param votingPowerProvider The voting power provider.
* @param timestamp The timestamp.
* @return If the voting power provider is registered.
*/
function isVotingPowerProviderRegisteredAt(CrossChainAddress memory votingPowerProvider, uint48 timestamp)
⋮----
/**
* @notice Returns if the voting power provider is registered.
* @param votingPowerProvider The voting power provider.
* @return If the voting power provider is registered.
*/
function isVotingPowerProviderRegistered(CrossChainAddress memory votingPowerProvider) external view returns (bool);
⋮----
/**
* @notice Returns the voting power providers at the given timestamp.
* @param timestamp The timestamp.
* @return The voting power providers (contracts that provide the voting powers of the operators on different chains).
*/
function getVotingPowerProvidersAt(uint48 timestamp) external view returns (CrossChainAddress[] memory);
⋮----
/**
* @notice Returns the voting power providers.
* @return The voting power providers (contracts that provide the voting powers of the operators on different chains).
*/
function getVotingPowerProviders() external view returns (CrossChainAddress[] memory);
⋮----
/**
* @notice Returns the keys provider at the given timestamp.
* @param timestamp The timestamp.
* @return The keys provider (contract that provides the keys of the operators).
*/
function getKeysProviderAt(uint48 timestamp) external view returns (CrossChainAddress memory);
⋮----
/**
* @notice Returns the keys provider.
* @return The keys provider (contract that provides the keys of the operators).
*/
function getKeysProvider() external view returns (CrossChainAddress memory);
⋮----
/**
* @notice Returns if the settlement is registered at the given timestamp.
* @param settlement The settlement.
* @param timestamp The timestamp.
* @return If the settlement is registered.
*/
function isSettlementRegisteredAt(CrossChainAddress memory settlement, uint48 timestamp)
⋮----
/**
* @notice Returns if the settlement is registered.
* @param settlement The settlement.
* @return If the settlement is registered.
*/
function isSettlementRegistered(CrossChainAddress memory settlement) external view returns (bool);
⋮----
/**
* @notice Returns the settlements at the given timestamp.
* @param timestamp The timestamp.
* @return The settlements (contracts that enable a verification of the validator set's attestations on different chains).
*/
function getSettlementsAt(uint48 timestamp) external view returns (CrossChainAddress[] memory);
⋮----
/**
* @notice Returns the settlements.
* @return The settlements (contracts that enable a verification of the validator set's attestations on different chains).
*/
function getSettlements() external view returns (CrossChainAddress[] memory);
⋮----
/**
* @notice Returns the maximum voting power at the given timestamp.
* @param timestamp The timestamp.
* @return The maximum voting power for each validator.
*/
function getMaxVotingPowerAt(uint48 timestamp) external view returns (uint256);
⋮----
/**
* @notice Returns the maximum voting power.
* @return The maximum voting power for each validator.
*/
function getMaxVotingPower() external view returns (uint256);
⋮----
/**
* @notice Returns the minimum inclusion voting power at the given timestamp.
* @param timestamp The timestamp.
* @return The minimum inclusion voting power for the operator to be included in the validator set.
*/
function getMinInclusionVotingPowerAt(uint48 timestamp) external view returns (uint256);
⋮----
/**
* @notice Returns the minimum inclusion voting power.
* @return The minimum inclusion voting power for the operator to be included in the validator set.
*/
function getMinInclusionVotingPower() external view returns (uint256);
⋮----
/**
* @notice Returns the maximum active validators count at the given timestamp.
* @param timestamp The timestamp.
* @return The maximum active validators count in the validator set.
*/
function getMaxValidatorsCountAt(uint48 timestamp) external view returns (uint208);
⋮----
/**
* @notice Returns the maximum active validators count.
* @return The maximum active validators count in the validator set.
*/
function getMaxValidatorsCount() external view returns (uint208);
⋮----
/**
* @notice Returns the required key tags at the given timestamp.
* @param timestamp The timestamp.
* @return The required key tags to include in the validator set.
*/
function getRequiredKeyTagsAt(uint48 timestamp) external view returns (uint8[] memory);
⋮----
/**
* @notice Returns the required key tags.
* @return The required key tags to include in the validator set.
*/
function getRequiredKeyTags() external view returns (uint8[] memory);
⋮----
/**
* @notice Returns if the quorum threshold is registered at the given timestamp.
* @param quorumThreshold The quorum threshold.
* @param timestamp The timestamp.
* @return If the quorum threshold is registered.
*/
function isQuorumThresholdRegisteredAt(QuorumThreshold memory quorumThreshold, uint48 timestamp)
⋮----
/**
* @notice Returns if the quorum threshold is registered.
* @param quorumThreshold The quorum threshold.
* @return If the quorum threshold is registered.
*/
function isQuorumThresholdRegistered(QuorumThreshold memory quorumThreshold) external view returns (bool);
⋮----
/**
* @notice Returns the quorum thresholds at the given timestamp.
* @param timestamp The timestamp.
* @return The quorum thresholds to use for attestations' verification.
*/
function getQuorumThresholdsAt(uint48 timestamp) external view returns (QuorumThreshold[] memory);
⋮----
/**
* @notice Returns the quorum thresholds.
* @return The quorum thresholds to use for attestations' verification.
*/
function getQuorumThresholds() external view returns (QuorumThreshold[] memory);
⋮----
/**
* @notice Returns the required header key tag at the given timestamp.
* @param timestamp The timestamp.
* @return The required header key tag to use to maintain the validator set through epochs.
*/
function getRequiredHeaderKeyTagAt(uint48 timestamp) external view returns (uint8);
⋮----
/**
* @notice Returns the required header key tag.
* @return The required header key tag to use to maintain the validator set through epochs.
*/
function getRequiredHeaderKeyTag() external view returns (uint8);
⋮----
/**
* @notice Returns the verification type at the given timestamp.
* @param timestamp The timestamp.
* @return The verification type (e.g., simple on-chain verification, or zk-based one).
*/
function getVerificationTypeAt(uint48 timestamp) external view returns (uint32);
⋮----
/**
* @notice Returns the verification type.
* @return The verification type (e.g., simple on-chain verification, or zk-based one).
*/
function getVerificationType() external view returns (uint32);
⋮----
/**
* @notice Sets the number of aggregators (those who aggregate the validators' signatures
* and produce the proof for the verification).
* @param numAggregators The number of aggregators.
* @dev The caller must have the needed permission.
*/
function setNumAggregators(uint208 numAggregators) external;
⋮----
/**
* @notice Sets the number of committers (those who commit some data (e.g., ValSetHeader)
* to on-chain).
* @param numCommitters The number of committers.
* @dev The caller must have the needed permission.
*/
function setNumCommitters(uint208 numCommitters) external;
⋮----
/**
* @notice Adds a voting power provider.
* @param votingPowerProvider The voting power provider (contract that provides the voting powers of the operators on different chains).
* @dev The caller must have the needed permission.
*/
function addVotingPowerProvider(CrossChainAddress memory votingPowerProvider) external;
⋮----
/**
* @notice Removes a voting power provider.
* @param votingPowerProvider The voting power provider (contract that provides the voting powers of the operators on different chains).
* @dev The caller must have the needed permission.
*/
function removeVotingPowerProvider(CrossChainAddress memory votingPowerProvider) external;
⋮----
/**
* @notice Sets the keys provider.
* @param keysProvider The keys provider (contract that provides the keys of the operators).
* @dev The caller must have the needed permission.
*/
function setKeysProvider(CrossChainAddress memory keysProvider) external;
⋮----
/**
* @notice Adds a settlement.
* @param settlement The settlement (contract that enable a verification of the validator set's attestations on different chains).
* @dev The caller must have the needed permission.
*/
function addSettlement(CrossChainAddress memory settlement) external;
⋮----
/**
* @notice Removes a settlement.
* @param settlement The settlement (contract that enable a verification of the validator set's attestations on different chains).
* @dev The caller must have the needed permission.
*/
function removeSettlement(CrossChainAddress memory settlement) external;
⋮----
/**
* @notice Sets the maximum voting power.
* @param maxVotingPower The maximum voting power for each validator.
* @dev The caller must have the needed permission.
*/
function setMaxVotingPower(uint256 maxVotingPower) external;
⋮----
/**
* @notice Sets the minimum inclusion voting power.
* @param minInclusionVotingPower The minimum inclusion voting power for the operator to be included in the validator set.
* @dev The caller must have the needed permission.
*/
function setMinInclusionVotingPower(uint256 minInclusionVotingPower) external;
⋮----
/**
* @notice Sets the maximum active validators count.
* @param maxValidatorsCount The maximum active validators count in the validator set.
* @dev The caller must have the needed permission.
*/
function setMaxValidatorsCount(uint208 maxValidatorsCount) external;
⋮----
/**
* @notice Sets the required key tags.
* @param requiredKeyTags The required key tags to include in the validator set.
* @dev The caller must have the needed permission.
*/
function setRequiredKeyTags(uint8[] memory requiredKeyTags) external;
⋮----
/**
* @notice Adds a quorum threshold.
* @param quorumThreshold The quorum threshold to use for attestations' verification.
* @dev The caller must have the needed permission.
*/
function addQuorumThreshold(QuorumThreshold memory quorumThreshold) external;
⋮----
/**
* @notice Removes a quorum threshold.
* @param quorumThreshold The quorum threshold to use for attestations' verification.
* @dev The caller must have the needed permission.
*/
function removeQuorumThreshold(QuorumThreshold memory quorumThreshold) external;
⋮----
/**
* @notice Sets the required header key tag.
* @param requiredHeaderKeyTag The required header key tag to use to maintain the validator set through epochs.
* @dev The caller must have the needed permission.
*/
function setRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag) external;
⋮----
/**
* @notice Sets the verification type.
* @param verificationType The verification type (e.g., simple on-chain verification, or zk-based one).
* @dev The caller must have the needed permission.
*/
function setVerificationType(uint32 verificationType) external;
````
## File: src/interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IVotingPowerCalcManager
* @notice Interface for the VotingPowerCalcManager contract.
*/
interface IVotingPowerCalcManager {
/**
* @notice Returns the voting power given a `stake` amount of `vault`'s collateral at the certain vault at the given timestamp.
* @param vault The vault.
* @param stake The stake.
* @param extraData The extra data.
* @param timestamp The timestamp.
* @return The voting power given a `stake` amount of `vault`'s collateral at the certain vault at the given timestamp.
*/
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
/**
* @notice Returns the voting power given a `stake` amount of `vault`'s collateral at the certain vault.
* @param vault The vault.
* @param stake The stake.
* @param extraData The extra data.
* @return The voting power given a `stake` amount of `vault`'s collateral at the certain vault.
*/
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData) external view returns (uint256);
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/libraries/AggregatorV3Interface.sol
````
// SPDX-License-Identifier: MIT
⋮----
// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
⋮----
function description() external view returns (string memory);
⋮----
function version() external view returns (uint256);
⋮----
function getRoundData(uint80 _roundId)
⋮----
function latestRoundData()
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/IEqualStakeVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IEqualStakeVPCalc
* @notice Interface for the EqualStakeVPCalc contract.
*/
interface IEqualStakeVPCalc {}
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/INormalizedTokenDecimalsVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title INormalizedTokenDecimalsVPCalc
* @notice Interface for the NormalizedTokenDecimalsVPCalc contract.
*/
interface INormalizedTokenDecimalsVPCalc {}
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/IPricedTokensChainlinkVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../../../../../libraries/structs/Checkpoints.sol";
⋮----
/**
* @title IPricedTokensChainlinkVPCalc
* @notice Interface for the PricedTokensChainlinkVPCalc contract.
*/
interface IPricedTokensChainlinkVPCalc {
/**
* @notice Reverts when the aggregator is zero address.
*/
⋮----
/**
* @notice The storage of the PricedTokensChainlinkVPCalc contract.
* @param _tokenHops The price conversion hops for each token.
*/
⋮----
/**
* @notice Emitted when the price conversion hops are set for a token.
* @param token The token.
* @param aggregators The price aggregators.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
*/
event SetTokenHops(address indexed token, address[2] aggregators, bool[2] inverts, uint48[2] stalenessDurations);
⋮----
/**
* @notice Returns the price conversion hops for a token at a given timestamp.
* @param token The token.
* @param timestamp The timestamp.
* @return The price conversion hops (price aggregators, invert flags, staleness durations).
*/
function getTokenHopsAt(address token, uint48 timestamp)
⋮----
/**
* @notice Returns the price conversion hops for a token.
* @param token The token.
* @return The price conversion hops (price aggregators, invert flags, staleness durations).
*/
function getTokenHops(address token) external view returns (address[2] memory, bool[2] memory, uint48[2] memory);
⋮----
/**
* @notice Returns the price for a token at a given timestamp.
* @param token The token.
* @param timestamp The timestamp.
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getTokenPriceAt(address token, uint48 timestamp) external view returns (uint256);
⋮----
/**
* @notice Returns the price for a token.
* @param token The token.
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getTokenPrice(address token) external view returns (uint256);
⋮----
/**
* @notice Sets the price conversion hops for a token.
* @param token The token.
* @param aggregators The price aggregators.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
*/
function setTokenHops(
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/IWeightedTokensVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../../../../../libraries/structs/Checkpoints.sol";
⋮----
/**
* @title IWeightedTokensVPCalc
* @notice Interface for the WeightedTokensVPCalc contract.
*/
interface IWeightedTokensVPCalc {
/**
* @notice Reverts when the weight is too large.
*/
⋮----
/**
* @notice The storage of the WeightedTokensVPCalc contract.
* @param _tokenWeight The weight for each token.
*/
⋮----
/**
* @notice Emitted when the weight for a token is set.
* @param token The token.
* @param weight The weight.
*/
event SetTokenWeight(address indexed token, uint208 weight);
⋮----
/**
* @notice Returns the weight for a token at a given timestamp.
* @param token The token.
* @param timestamp The timestamp.
* @return The weight.
* @dev Returns 1e12 if the weight wasn't explicitly set yet.
* Can return non-zero weight for unregistered tokens.
*/
function getTokenWeightAt(address token, uint48 timestamp) external view returns (uint208);
⋮----
/**
* @notice Returns the weight for a token.
* @param token The token.
* @return The weight.
* @dev Returns 1e12 if the weight wasn't explicitly set yet.
* Can return non-zero weight for unregistered tokens.
*/
function getTokenWeight(address token) external view returns (uint208);
⋮----
/**
* @notice Sets the weight for a token.
* @param token The token.
* @param weight The weight.
*/
function setTokenWeight(address token, uint208 weight) external;
````
## File: src/interfaces/modules/voting-power/common/voting-power-calc/IWeightedVaultsVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../../../../../libraries/structs/Checkpoints.sol";
⋮----
/**
* @title IWeightedVaultsVPCalc
* @notice Interface for the WeightedVaultsVPCalc contract.
*/
interface IWeightedVaultsVPCalc {
/**
* @notice Reverts when the weight is too large.
*/
⋮----
/**
* @notice The storage of the WeightedVaultsVPCalc contract.
* @param _vaultWeight The weight for each vault.
*/
⋮----
/**
* @notice Emitted when the weight for a vault is set.
* @param vault The vault.
* @param weight The weight.
*/
event SetVaultWeight(address indexed vault, uint208 weight);
⋮----
/**
* @notice Returns the weight for a vault at a given timestamp.
* @param vault The vault.
* @param timestamp The timestamp.
* @return The weight.
* @dev Returns 1e4 if the weight wasn't explicitly set yet.
* Can return non-zero weight for unregistered vaults.
*/
function getVaultWeightAt(address vault, uint48 timestamp) external view returns (uint208);
⋮----
/**
* @notice Returns the weight for a vault.
* @param vault The vault.
* @return The weight.
* @dev Returns 1e4 if the weight wasn't explicitly set yet.
* Can return non-zero weight for unregistered vaults.
*/
function getVaultWeight(address vault) external view returns (uint208);
⋮----
/**
* @notice Sets the weight for a vault.
* @param vault The vault.
* @param weight The weight.
*/
function setVaultWeight(address vault, uint208 weight) external;
````
## File: src/interfaces/modules/voting-power/extensions/IBaseRewards.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IBaseRewards
* @notice Interface for the BaseRewards contract.
*/
interface IBaseRewards {
/**
* @notice Reverts when the caller is not the rewarder.
*/
⋮----
/**
* @notice The storage of the BaseRewards contract.
* @param _rewarder The address of the rewarder.
* @custom:storage-location erc7201:symbiotic.storage.BaseRewards
*/
⋮----
/**
* @notice The parameters for the initialization of the BaseRewards contract.
* @param rewarder The address of the rewarder.
*/
⋮----
/**
* @notice Emitted when the rewarder is set.
* @param rewarder The address of the rewarder.
*/
event SetRewarder(address rewarder);
⋮----
/**
* @notice Emitted when the staker rewards are distributed.
* @param stakerRewards The address of the staker rewards.
* @param token The address of the token.
* @param amount The amount of the token.
* @param data The data (depends on the staker rewards implementation).
*/
event DistributeStakerRewards(address indexed stakerRewards, address indexed token, uint256 amount, bytes data);
⋮----
/**
* @notice Emitted when the operator rewards are distributed.
* @param operatorRewards The address of the operator rewards.
* @param token The address of the token.
* @param amount The amount of the token.
* @param root The Merkle root of the distribution.
*/
event DistributeOperatorRewards(
⋮----
/**
* @notice Returns the address of the rewarder.
* @return The address of the rewarder.
*/
function getRewarder() external view returns (address);
⋮----
/**
* @notice Sets the rewarder.
* @param rewarder The address of the rewarder.
* @dev The caller must have the needed permission.
*/
function setRewarder(address rewarder) external;
⋮----
/**
* @notice Distributes the staker rewards.
* @param stakerRewards The address of the staker rewards.
* @param token The address of the token.
* @param amount The amount of the token.
* @param data The data (depends on the staker rewards implementation).
* @dev Only the rewarder can call this function.
* The funds should be transferred to this contract separately before the call.
*/
function distributeStakerRewards(address stakerRewards, address token, uint256 amount, bytes memory data) external;
⋮----
/**
* @notice Distributes the operator rewards.
* @param operatorRewards The address of the operator rewards.
* @param token The address of the token.
* @param amount The amount of the token.
* @param root The Merkle root of the distribution.
* @dev Only the rewarder can call this function.
* The funds should be transferred to this contract separately before the call.
*/
function distributeOperatorRewards(address operatorRewards, address token, uint256 amount, bytes32 root) external;
````
## File: src/interfaces/modules/voting-power/extensions/IBaseSlashing.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IBaseSlashing
* @notice Interface for the BaseSlashing contract.
*/
interface IBaseSlashing {
/**
* @notice Reverts when the vault doesn't have a slasher.
*/
⋮----
/**
* @notice Reverts when the slashing wasn't required at the requested timestamp.
*/
⋮----
/**
* @notice Reverts when the caller is not the slasher.
*/
⋮----
/**
* @notice Reverts when the slasher is not a veto slasher.
*/
⋮----
/**
* @notice Reverts when the slasher type is unsupported.
*/
⋮----
/**
* @notice The storage of the BaseSlashing contract.
* @param _slasher The address of the slasher.
* @custom:storage-location erc7201:symbiotic.storage.BaseSlashing
*/
⋮----
/**
* @notice The parameters for the initialization of the BaseSlashing contract.
* @param slasher The address of the slasher.
*/
⋮----
/**
* @notice The hints to optimize the base slashing.
* @param slashingDataHint The hint to optimize the slashing data fetching.
* @param slashCoreHints The hints to optimize the slash core.
*/
⋮----
/**
* @notice The hints to optimize the execute slash.
* @param slashingDataHint The hint to optimize the slashing data fetching.
* @param executeSlashCoreHints The hints to optimize the execute slash core.
*/
⋮----
/**
* @notice Emitted when the slasher is set.
* @param slasher The address of the slasher.
*/
event SetSlasher(address slasher);
⋮----
/**
* @notice Emitted when the instant slash is executed.
* @param slasher The address of the slasher.
* @param operator The address of the operator.
* @param success The success of the slash.
* @param slashedAmount The amount of the slashed tokens.
*/
event InstantSlash(address indexed slasher, address indexed operator, bool indexed success, uint256 slashedAmount);
⋮----
/**
* @notice Emitted when the veto slash is executed.
* @param slasher The address of the slasher.
* @param operator The address of the operator.
* @param success The success of the slash.
* @param slashIndex The index of the slash.
*/
event VetoSlash(address indexed slasher, address indexed operator, bool indexed success, uint256 slashIndex);
⋮----
/**
* @notice Emitted when the slash is executed.
* @param slasher The address of the slasher.
* @param slashIndex The index of the slash.
* @param success The success of the slash.
* @param slashedAmount The amount of the slashed tokens.
*/
event ExecuteSlash(
⋮----
/**
* @notice Returns the address of the slasher.
* @return The address of the slasher.
*/
function getSlasher() external view returns (address);
⋮----
/**
* @notice Sets the slasher.
* @param slasher The address of the slasher.
* @dev The caller must have the needed permission.
*/
function setSlasher(address slasher) external;
⋮----
/**
* @notice Slashes the vault.
* @param timestamp The capture timestamp for the slash.
* @param vault The address of the vault.
* @param operator The address of the operator.
* @param amount The amount of the tokens to be slashed.
* @param hints The hints to optimize the vault slashing.
* @return success The success of the slash.
* @return response The response of the slash.
* @dev The function doesn't check the registration statuses.
*/
function slashVault(uint48 timestamp, address vault, address operator, uint256 amount, bytes memory hints)
⋮----
/**
* @notice Executes the slash of the vault.
* @param vault The address of the vault.
* @param slashIndex The index of the slash.
* @param hints The hints to optimize the vault slashing.
* @return success The success of the slash.
* @return slashedAmount The amount of the slashed tokens.
*/
function executeSlashVault(address vault, uint256 slashIndex, bytes memory hints)
````
## File: src/interfaces/modules/voting-power/extensions/IMultiToken.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IMultiToken
* @notice Interface for the MultiToken contract.
*/
interface IMultiToken {
/**
* @notice Registers the token.
* @param token The address of the token.
* @dev The caller must have the needed permission.
*/
function registerToken(address token) external;
⋮----
/**
* @notice Unregisters the token.
* @param token The address of the token.
* @dev The caller must have the needed permission.
*/
function unregisterToken(address token) external;
````
## File: src/interfaces/modules/voting-power/extensions/IOperatorsBlacklist.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IVotingPowerProvider} from "../IVotingPowerProvider.sol";
⋮----
/**
* @title IOperatorsBlacklist
* @notice Interface for the OperatorsBlacklist contract.
*/
interface IOperatorsBlacklist {
/**
* @notice Reverts when the operator is not blacklisted.
*/
⋮----
/**
* @notice Reverts when the operator is already blacklisted.
*/
⋮----
/**
* @notice The storage of the OperatorsBlacklist contract.
* @param _blacklisted The mapping from the operator to the blacklisted operator status.
* @custom:storage-location erc7201:symbiotic.storage.OperatorsBlacklist
*/
⋮----
/**
* @notice Emitted when the operator is blacklisted.
* @param operator The address of the operator.
*/
event BlacklistOperator(address indexed operator);
⋮----
/**
* @notice Emitted when the operator is unblacklisted.
* @param operator The address of the operator.
*/
event UnblacklistOperator(address indexed operator);
⋮----
/**
* @notice Returns the blacklist status of the operator.
* @param operator The address of the operator.
* @return The blacklist status of the operator.
*/
function isOperatorBlacklisted(address operator) external view returns (bool);
⋮----
/**
* @notice Blacklists the operator.
* @param operator The address of the operator.
* @dev The caller must have the needed permission.
* The operator will be unregistered if currently registered.
*/
function blacklistOperator(address operator) external;
⋮----
/**
* @notice Unblacklists the operator.
* @param operator The address of the operator.
* @dev The caller must have the needed permission.
*/
function unblacklistOperator(address operator) external;
````
## File: src/interfaces/modules/voting-power/extensions/IOperatorsJail.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IVotingPowerProvider} from "../IVotingPowerProvider.sol";
⋮----
/**
* @title IOperatorsJail
* @notice Interface for the OperatorsJail contract.
*/
interface IOperatorsJail {
/**
* @notice Reverts when the operator is already jailed.
*/
⋮----
/**
* @notice Reverts when the duration is invalid.
*/
⋮----
/**
* @notice Reverts when the operator is jailed.
*/
⋮----
/**
* @notice Reverts when the operator is not jailed.
*/
⋮----
/**
* @notice The storage of the OperatorsJail contract.
* @param _jailedUntil The mapping from the operator to the jailed until timestamp.
* @custom:storage-location erc7201:symbiotic.storage.OperatorsJail
*/
⋮----
/**
* @notice Emitted when the operator is jailed.
* @param operator The address of the operator.
*/
event JailOperator(address indexed operator);
⋮----
/**
* @notice Emitted when the operator is forcefully unjailed.
* @param operator The address of the operator.
*/
event UnjailOperator(address indexed operator);
⋮----
/**
* @notice Returns the jail status of the operator.
* @param operator The address of the operator.
* @return The jail status of the operator.
*/
function isOperatorJailed(address operator) external view returns (bool);
⋮----
/**
* @notice Returns the timestamp the operator is jailed until.
* @param operator The address of the operator.
* @return The timestamp the operator is jailed until.
*/
function getOperatorJailedUntil(address operator) external view returns (uint48);
⋮----
/**
* @notice Jails the operator.
* @param operator The address of the operator.
* @param duration The duration of the jail.
* @dev The caller must have the needed permission.
* The operator will be unregistered if currently registered.
* It is allowed only to extend the jail duration.
*/
function jailOperator(address operator, uint48 duration) external;
⋮----
/**
* @notice Unjails the operator.
* @param operator The address of the operator.
* @dev The caller must have the needed permission.
*/
function unjailOperator(address operator) external;
````
## File: src/interfaces/modules/voting-power/extensions/IOperatorsWhitelist.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IVotingPowerProvider} from "../IVotingPowerProvider.sol";
⋮----
/**
* @title IOperatorsWhitelist
* @notice Interface for the OperatorsWhitelist contract.
*/
interface IOperatorsWhitelist {
/**
* @notice Reverts when the whitelist status is already set.
*/
⋮----
/**
* @notice Reverts when the operator is not whitelisted.
*/
⋮----
/**
* @notice Reverts when the operator is already whitelisted.
*/
⋮----
/**
* @notice The storage of the OperatorsWhitelist contract.
* @param _whitelisted The mapping from the operator to the whitelisted operator status.
* @param _isWhitelistEnabled The status of the whitelist.
* @custom:storage-location erc7201:symbiotic.storage.OperatorsWhitelist
*/
⋮----
/**
* @notice The parameters for the initialization of the OperatorsWhitelist contract.
* @param isWhitelistEnabled The status of the whitelist.
*/
⋮----
/**
* @notice Emitted when the whitelist status is set.
* @param status The status of the whitelist.
*/
event SetWhitelistStatus(bool status);
⋮----
/**
* @notice Emitted when the operator is whitelisted.
* @param operator The address of the operator.
*/
event WhitelistOperator(address indexed operator);
⋮----
/**
* @notice Emitted when the operator is unwhitelisted.
* @param operator The address of the operator.
*/
event UnwhitelistOperator(address indexed operator);
⋮----
/**
* @notice Returns the whitelist status.
* @return The whitelist status.
*/
function isWhitelistEnabled() external view returns (bool);
⋮----
/**
* @notice Returns the whitelist status of the operator.
* @param operator The address of the operator.
* @return The whitelist status of the operator.
*/
function isOperatorWhitelisted(address operator) external view returns (bool);
⋮----
/**
* @notice Sets the whitelist status.
* @param status The status of the whitelist.
* @dev The caller must have the needed permission.
*/
function setWhitelistStatus(bool status) external;
⋮----
/**
* @notice Whitelists the operator.
* @param operator The address of the operator.
* @dev The caller must have the needed permission.
*/
function whitelistOperator(address operator) external;
⋮----
/**
* @notice Unwhitelists the operator.
* @param operator The address of the operator.
* @dev The caller must have the needed permission.
* The operator will be unregistered if currently registered and the whitelist is enabled.
*/
function unwhitelistOperator(address operator) external;
````
## File: src/interfaces/modules/voting-power/extensions/IOperatorVaults.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title IOperatorVaults
* @notice Interface for the OperatorVaults contract.
*/
interface IOperatorVaults {
/**
* @notice Registers the operator vault.
* @param operator The address of the operator.
* @param vault The address of the vault.
* @dev The caller must have the needed permission.
*/
function registerOperatorVault(address operator, address vault) external;
⋮----
/**
* @notice Unregisters the operator vault.
* @param operator The address of the operator.
* @param vault The address of the vault.
* @dev The caller must have the needed permission.
*/
function unregisterOperatorVault(address operator, address vault) external;
⋮----
/**
* @notice Unregisters the operator vault.
* @param vault The address of the vault.
* @dev The caller must be the operator of the vault.
*/
function unregisterOperatorVault(address vault) external;
````
## File: src/interfaces/modules/voting-power/extensions/IOpNetVaultAutoDeploy.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IVotingPowerProvider} from "../IVotingPowerProvider.sol";
⋮----
/**
* @title IOpNetVaultAutoDeploy
* @notice Interface for the OpNetVaultAutoDeploy contract.
*/
interface IOpNetVaultAutoDeploy {
/**
* @notice Reverts when the burner hook is enabled but the slasher is not.
*/
⋮----
/**
* @notice Reverts when the collateral is zero address.
*/
⋮----
/**
* @notice Reverts when the epoch duration is zero or less than the slashing window.
*/
⋮----
/**
* @notice Reverts when the with slasher is disabled but the slashing window is not zero.
*/
⋮----
/**
* @notice The storage of the OpNetVaultAutoDeploy contract.
* @param _isAutoDeployEnabled The status of the auto deploy.
* @param _isSetMaxNetworkLimitHookEnabled The status of the set max network limit hook.
* @param _autoDeployedVault The mapping from the operator to the auto deployed vault.
* @param _config The configuration of the auto deploy.
* @custom:storage-location erc7201:symbiotic.storage.OpNetVaultAutoDeploy
*/
⋮----
/**
* @notice The parameters for the initialization of the OpNetVaultAutoDeploy contract.
* @param isAutoDeployEnabled The status of the auto deploy.
* @param config The configuration of the auto deploy.
* @param isSetMaxNetworkLimitHookEnabled The status of the set max network limit hook.
*/
⋮----
/**
* @notice The configuration of the auto deploy.
* @param epochDuration The duration of the epoch.
* @param collateral The address of the collateral.
* @param burner The address of the burner.
* @param withSlasher The status of the with slasher.
* @param isBurnerHook The status of the burner hook.
*/
⋮----
/**
* @notice Emitted when the auto deploy status is set.
* @param status The status of the auto deploy.
*/
event SetAutoDeployStatus(bool status);
⋮----
/**
* @notice Emitted when the auto deploy config is set.
*/
event SetAutoDeployConfig(AutoDeployConfig config);
⋮----
/**
* @notice Emitted when the set max network limit hook status is set.
* @param status The status of the set max network limit hook.
*/
event SetSetMaxNetworkLimitHookStatus(bool status);
⋮----
/**
* @notice Returns the address of the vault configurator.
* @return The address of the vault configurator.
*/
function VAULT_CONFIGURATOR() external view returns (address);
⋮----
/**
* @notice Returns the status of the auto deploy.
* @return The status of the auto deploy.
*/
function isAutoDeployEnabled() external view returns (bool);
⋮----
/**
* @notice Returns the address of the auto deployed vault of the operator.
* @param operator The address of the operator.
* @return The address of the auto deployed vault of the operator.
*/
function getAutoDeployedVault(address operator) external view returns (address);
⋮----
/**
* @notice Returns the configuration of the auto deploy.
* @return The configuration of the auto deploy.
*/
function getAutoDeployConfig() external view returns (AutoDeployConfig memory);
⋮----
/**
* @notice Returns the status of the set max network limit hook.
* @return The status of the set max network limit hook.
*/
function isSetMaxNetworkLimitHookEnabled() external view returns (bool);
⋮----
/**
* @notice Sets the status of the auto deploy.
* @param status The status of the auto deploy.
* @dev The caller must have the needed permission.
*/
function setAutoDeployStatus(bool status) external;
⋮----
/**
* @notice Sets the configuration of the auto deploy.
* @param config The configuration of the auto deploy.
* @dev The caller must have the needed permission.
*/
function setAutoDeployConfig(AutoDeployConfig memory config) external;
⋮----
/**
* @notice Sets the status of the set max network limit hook.
* @param status The status of the set max network limit hook.
* @dev The caller must have the needed permission.
*/
function setSetMaxNetworkLimitHookStatus(bool status) external;
````
## File: src/interfaces/modules/voting-power/extensions/ISharedVaults.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title ISharedVaults
* @notice Interface for the SharedVaults contract.
*/
interface ISharedVaults {
/**
* @notice Registers the shared vault.
* @param sharedVault The address of the shared vault.
* @dev The caller must have the needed permission.
*/
function registerSharedVault(address sharedVault) external;
⋮----
/**
* @notice Unregisters the shared vault.
* @param sharedVault The address of the shared vault.
* @dev The caller must have the needed permission.
*/
function unregisterSharedVault(address sharedVault) external;
````
## File: src/interfaces/modules/voting-power/IVotingPowerProvider.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {INetworkManager} from "../base/INetworkManager.sol";
import {IOzEIP712} from "../base/IOzEIP712.sol";
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
import {PersistentSet} from "../../../libraries/structs/PersistentSet.sol";
⋮----
/**
* @title IVotingPowerProvider
* @notice Interface for the VotingPowerProvider contract.
*/
interface IVotingPowerProvider {
/**
* @notice Reverts when the operator is not registered in the OperatorRegistry.
*/
⋮----
/**
* @notice Reverts when the operator vault is invalid.
*/
⋮----
/**
* @notice Reverts when the shared vault is invalid.
*/
⋮----
/**
* @notice Reverts when the signature is invalid.
*/
⋮----
/**
* @notice Reverts when the token is zero address.
*/
⋮----
/**
* @notice Reverts when the vault is invalid.
*/
⋮----
/**
* @notice Reverts when the operator is already registered.
*/
⋮----
/**
* @notice Reverts when the operator is not registered.
*/
⋮----
/**
* @notice Reverts when the operator vault is already registered.
*/
⋮----
/**
* @notice Reverts when the operator vault is not registered.
*/
⋮----
/**
* @notice Reverts when the shared vault is already registered.
*/
⋮----
/**
* @notice Reverts when the shared vault is not registered.
*/
⋮----
/**
* @notice Reverts when the token is already registered.
*/
⋮----
/**
* @notice Reverts when the token is not registered.
*/
⋮----
/**
* @notice The types of the delegator.
*/
⋮----
/**
* @notice The types of the slasher.
*/
⋮----
/**
* @notice The storage of the VotingPowerProvider contract.
* @param _tokens The set of the tokens.
* @param _operators The set of the operators.
* @param _sharedVaults The set of the shared vaults.
* @param _allOperatorVaults The set of the all operator vaults.
* @param _operatorVaults The mapping from the operator to the set of the operator vaults.
* @param _slashingData The slashing data (if to require slasher, and a minimum epoch duration).
* @custom:storage-location erc7201:symbiotic.storage.VotingPowerProvider
*/
⋮----
/**
* @notice The parameters for the initialization of the VotingPowerProvider contract.
* @param networkManagerInitParams The parameters for the initialization of the NetworkManager contract.
* @param ozEip712InitParams The parameters for the initialization of the OzEIP712 contract.
* @param requireSlasher If to require slashers.
* @param minVaultEpochDuration The minimum epoch duration for the vaults.
* @param token The acceptable token (zero address if not applicable).
*/
⋮----
/**
* @notice The value of the vault.
* @param vault The address of the vault.
* @param value The value (voting power or stake).
*/
⋮----
/**
* @notice The voting power of the operator.
* @param operator The address of the operator.
* @param vaults The voting power of the operator for each vault.
*/
⋮----
/**
* @notice The extra data for the voting power of the operator.
* @param sharedVaultsExtraData The extra data for the shared vaults.
* @param operatorVaultsExtraData The extra data for the operator vaults.
*/
⋮----
/**
* @notice Emitted when the slashing data is set.
* @param requireSlasher If to require slashers.
* @param minVaultEpochDuration The minimum epoch duration for the vaults.
* @dev It doesn't force non-suitable vaults to unregister.
*/
event SetSlashingData(bool requireSlasher, uint48 minVaultEpochDuration);
⋮----
/**
* @notice Emitted when the token is registered.
*/
event RegisterToken(address indexed token);
⋮----
/**
* @notice Emitted when the token is unregistered.
* @param token The token.
*/
event UnregisterToken(address indexed token);
⋮----
/**
* @notice Emitted when the operator is registered.
* @param operator The operator.
*/
event RegisterOperator(address indexed operator);
⋮----
/**
* @notice Emitted when the operator is unregistered.
* @param operator The operator.
*/
event UnregisterOperator(address indexed operator);
⋮----
/**
* @notice Emitted when the shared vault is registered.
* @param vault The shared vault.
*/
event RegisterSharedVault(address indexed vault);
⋮----
/**
* @notice Emitted when the shared vault is unregistered.
* @param vault The shared vault.
*/
event UnregisterSharedVault(address indexed vault);
⋮----
/**
* @notice Emitted when the operator vault is registered.
* @param operator The operator.
* @param vault The operator vault.
*/
event RegisterOperatorVault(address indexed operator, address indexed vault);
⋮----
/**
* @notice Emitted when the operator vault is unregistered.
* @param operator The operator.
* @param vault The operator vault.
*/
event UnregisterOperatorVault(address indexed operator, address indexed vault);
⋮----
/**
* @notice Returns the address of the OperatorRegistry contract.
* @return The address of the OperatorRegistry contract.
*/
function OPERATOR_REGISTRY() external view returns (address);
⋮----
/**
* @notice Returns the address of the VaultFactory contract.
* @return The address of the VaultFactory contract.
*/
function VAULT_FACTORY() external view returns (address);
⋮----
/**
* @notice Returns the slashing data at a specific timestamp.
* @param timestamp The timestamp.
* @param hint The hint.
* @return requireSlasher If to require slashers.
* @return minVaultEpochDuration The minimum epoch duration for the vaults.
*/
function getSlashingDataAt(uint48 timestamp, bytes memory hint)
⋮----
/**
* @notice Returns the slashing data.
* @return requireSlasher If to require slashers.
* @return minVaultEpochDuration The minimum epoch duration for the vaults.
*/
function getSlashingData() external view returns (bool requireSlasher, uint48 minVaultEpochDuration);
⋮----
/**
* @notice Returns the status of the token registration at a specific timestamp.
* @param token The token.
* @param timestamp The timestamp.
* @return The status of the token registration.
*/
function isTokenRegisteredAt(address token, uint48 timestamp) external view returns (bool);
⋮----
/**
* @notice Returns the status of the token registration.
* @param token The token.
* @return The status of the token registration.
*/
function isTokenRegistered(address token) external view returns (bool);
⋮----
/**
* @notice Returns the tokens at a specific timestamp.
* @param timestamp The timestamp.
* @return The tokens.
*/
function getTokensAt(uint48 timestamp) external view returns (address[] memory);
⋮----
/**
* @notice Returns the tokens.
* @return The tokens.
*/
function getTokens() external view returns (address[] memory);
⋮----
/**
* @notice Returns the status of the operator registration.
* @param operator The operator.
* @return The status of the operator registration.
*/
function isOperatorRegistered(address operator) external view returns (bool);
⋮----
/**
* @notice Returns the status of the operator registration at a specific timestamp.
* @param operator The operator.
* @param timestamp The timestamp.
* @return The status of the operator registration.
*/
function isOperatorRegisteredAt(address operator, uint48 timestamp) external view returns (bool);
⋮----
/**
* @notice Returns the operators at a specific timestamp.
* @param timestamp The timestamp.
* @return The operators.
*/
function getOperatorsAt(uint48 timestamp) external view returns (address[] memory);
⋮----
/**
* @notice Returns the operators.
* @return The operators.
*/
function getOperators() external view returns (address[] memory);
⋮----
/**
* @notice Returns the status of the shared vault registration.
* @param vault The shared vault.
* @return The status of the shared vault registration.
*/
function isSharedVaultRegistered(address vault) external view returns (bool);
⋮----
/**
* @notice Returns the status of the shared vault registration at a specific timestamp.
* @param vault The shared vault.
* @param timestamp The timestamp.
* @return The status of the shared vault registration.
*/
function isSharedVaultRegisteredAt(address vault, uint48 timestamp) external view returns (bool);
⋮----
/**
* @notice Returns the shared vaults at a specific timestamp.
* @param timestamp The timestamp.
* @return The shared vaults.
*/
function getSharedVaultsAt(uint48 timestamp) external view returns (address[] memory);
⋮----
/**
* @notice Returns the shared vaults.
* @return The shared vaults.
*/
function getSharedVaults() external view returns (address[] memory);
⋮----
/**
* @notice Returns the status of the operator vault registration.
* @param vault The operator vault.
* @return The status of the operator vault registration.
*/
function isOperatorVaultRegisteredAt(address vault, uint48 timestamp) external view returns (bool);
⋮----
function isOperatorVaultRegistered(address vault) external view returns (bool);
⋮----
/**
* @notice Returns the status of the operator vault registration at a specific timestamp.
* @param operator The operator.
* @param vault The operator vault.
* @param timestamp The timestamp.
* @return The status of the operator vault registration.
*/
function isOperatorVaultRegisteredAt(address operator, address vault, uint48 timestamp) external view returns (bool);
⋮----
/**
* @notice Returns the status of the operator vault registration.
* @param operator The operator.
* @param vault The operator vault.
* @return The status of the operator vault registration.
*/
function isOperatorVaultRegistered(address operator, address vault) external view returns (bool);
⋮----
/**
* @notice Returns the operator vaults at a specific timestamp.
* @param operator The operator.
* @param timestamp The timestamp.
* @return The operator vaults.
*/
function getOperatorVaultsAt(address operator, uint48 timestamp) external view returns (address[] memory);
⋮----
/**
* @notice Returns the operator vaults.
* @param operator The operator.
* @return The operator vaults.
*/
function getOperatorVaults(address operator) external view returns (address[] memory);
⋮----
/**
* @notice Returns the vaults with stakes of the operator at a specific timestamp.
* @param operator The operator.
* @param timestamp The timestamp.
* @return The vaults with stakes of the operator.
*/
function getOperatorStakesAt(address operator, uint48 timestamp) external view returns (VaultValue[] memory);
⋮----
/**
* @notice Returns the vaults with stakes of the operator.
* @param operator The operator.
* @return The vaults with stakes of the operator.
*/
function getOperatorStakes(address operator) external view returns (VaultValue[] memory);
⋮----
/**
* @notice Returns the vaults with voting powers of the operator at a specific timestamp.
* @param operator The operator.
* @param extraData The extra data.
* @param timestamp The timestamp.
* @return The vaults with voting powers of the operator.
*/
function getOperatorVotingPowersAt(address operator, bytes memory extraData, uint48 timestamp)
⋮----
/**
* @notice Returns the vaults with voting powers of the operator.
* @param operator The operator.
* @param extraData The extra data.
* @return The vaults with voting powers of the operator.
*/
function getOperatorVotingPowers(address operator, bytes memory extraData)
⋮----
/**
* @notice Returns operators and their vaults with voting powers at a specific timestamp.
* @param extraData The extra data.
* @param timestamp The timestamp.
* @return The operators and their vaults with voting powers.
*/
function getVotingPowersAt(bytes[] memory extraData, uint48 timestamp)
⋮----
/**
* @notice Returns operators and their vaults with voting powers.
* @param extraData The extra data.
* @return The operators and their vaults with voting powers.
*/
function getVotingPowers(bytes[] memory extraData) external view returns (OperatorVotingPower[] memory);
⋮----
/**
* @notice Registers the caller as an operator.
* @dev The caller can be anyone.
*/
function registerOperator() external;
⋮----
/**
* @notice Registers the operator with a signature.
* @param operator The operator.
* @param signature The signature of the operator.
* @dev The caller can be anyone.
*/
function registerOperatorWithSignature(address operator, bytes memory signature) external;
⋮----
/**
* @notice Unregisters the operator.
* @dev The caller can be anyone.
*/
function unregisterOperator() external;
⋮----
/**
* @notice Unregisters the operator with a signature.
* @param operator The operator.
* @param signature The signature of the operator.
* @dev The caller can be anyone.
*/
function unregisterOperatorWithSignature(address operator, bytes memory signature) external;
⋮----
/**
* @notice Invalidates the old signatures of the caller.
* @dev The caller can be anyone.
* Increases the signatures' nonce by one.
*/
function invalidateOldSignatures() external;
````
## File: src/libraries/keys/KeyBlsBn254.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {BN254} from "../utils/BN254.sol";
⋮----
/**
* @title KeyBlsBn254
* @notice Library for interacting with BLS public keys on the BN254 curve, including validation, serialization, and compression.
* @dev The keys are represented as G1 points on the BN254 curve.
*/
⋮----
/**
* @notice Reverts when the key bytes are invalid.
*/
⋮----
/**
* @notice Reverts when the key is invalid.
*/
⋮----
/**
* @notice The key wrapper.
* @param value The G1 public key.
*/
⋮----
/**
* @notice Wraps a G1 public key.
* @param keyRaw The G1 public key.
* @return key The wrapped key.
* @dev Allows to wrap zero G1 point.
*/
function wrap(BN254.G1Point memory keyRaw) internal view returns (KEY_BLS_BN254 memory key) {
⋮----
/**
* @notice Unwraps a key.
* @param key The key.
* @return keyRaw The G1 public key.
*/
function unwrap(KEY_BLS_BN254 memory key) internal view returns (BN254.G1Point memory keyRaw) {
⋮----
/**
* @notice Serializes a key.
* @param key The key.
* @return keySerialized The serialized key.
* @dev Compresses G1 point to 32 bytes (255 bits).
*/
function serialize(KEY_BLS_BN254 memory key) internal view returns (bytes memory keySerialized) {
⋮----
/**
* @notice Deserializes a serialized key.
* @param keySerialized The serialized key.
* @return key The key.
*/
function deserialize(bytes memory keySerialized) internal view returns (KEY_BLS_BN254 memory key) {
⋮----
/**
* @notice Converts a key to bytes.
* @param key The key.
* @return keyBytes The bytes representation of the key.
* @dev It is a bytes representation of the underlying key itself.
*/
function toBytes(KEY_BLS_BN254 memory key) internal view returns (bytes memory keyBytes) {
⋮----
/**
* @notice Converts bytes to a key.
* @param keyBytes The bytes representation of the key.
* @return key The key.
*/
function fromBytes(bytes memory keyBytes) internal view returns (KEY_BLS_BN254 memory key) {
⋮----
/**
* @notice Returns a zero key.
* @return key The zero key.
*/
function zeroKey() internal view returns (KEY_BLS_BN254 memory key) {
⋮----
/**
* @notice Checks if two keys are equal.
* @param key1 The first key.
* @param key2 The second key.
* @return If the keys are equal.
*/
function equal(KEY_BLS_BN254 memory key1, KEY_BLS_BN254 memory key2) internal view returns (bool) {
````
## File: src/libraries/keys/KeyEcdsaSecp256k1.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title KeyEcdsaSecp256k1
* @notice Library for interacting with ECDSA public keys on the secp256k1 curve, including validation and serialization.
* @dev The keys are represented as addresses.
*/
⋮----
/**
* @notice Reverts when the key bytes are invalid.
*/
⋮----
/**
* @notice The key wrapper.
* @param value The address.
*/
⋮----
/**
* @notice Wraps an address.
* @param keyRaw The address.
* @return key The wrapped key.
* @dev Allows to wrap zero address.
*/
function wrap(address keyRaw) internal view returns (KEY_ECDSA_SECP256K1 memory key) {
⋮----
/**
* @notice Unwraps a key.
* @param key The key.
* @return keyRaw The address.
*/
function unwrap(KEY_ECDSA_SECP256K1 memory key) internal view returns (address keyRaw) {
⋮----
/**
* @notice Serializes a key.
* @param key The key.
* @return keySerialized The serialized key.
* @dev Serializes address to 32 bytes.
*/
function serialize(KEY_ECDSA_SECP256K1 memory key) internal view returns (bytes memory keySerialized) {
⋮----
/**
* @notice Deserializes a serialized key.
* @param keySerialized The serialized key.
* @return key The key.
*/
function deserialize(bytes memory keySerialized) internal view returns (KEY_ECDSA_SECP256K1 memory key) {
⋮----
/**
* @notice Converts a key to bytes.
* @param key The key.
* @return keyBytes The bytes representation of the key.
* @dev It is a bytes representation of the underlying key itself.
*/
function toBytes(KEY_ECDSA_SECP256K1 memory key) internal view returns (bytes memory keyBytes) {
⋮----
/**
* @notice Converts bytes to a key.
* @param keyBytes The bytes representation of the key.
* @return key The key.
*/
function fromBytes(bytes memory keyBytes) internal view returns (KEY_ECDSA_SECP256K1 memory key) {
⋮----
/**
* @notice Returns a zero key.
* @return key The zero key.
*/
function zeroKey() internal view returns (KEY_ECDSA_SECP256K1 memory key) {
⋮----
/**
* @notice Checks if two keys are equal.
* @param key1 The first key.
* @param key2 The second key.
* @return If the keys are equal.
*/
function equal(KEY_ECDSA_SECP256K1 memory key1, KEY_ECDSA_SECP256K1 memory key2) internal view returns (bool) {
````
## File: src/libraries/sigs/SigBlsBn254.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {BN254} from "../utils/BN254.sol";
import {KeyBlsBn254} from "../keys/KeyBlsBn254.sol";
⋮----
/**
* @title SigBlsBn254
* @notice Library for verifying BLS signatures on the BN254 curve.
*/
⋮----
/**
* @notice Reverts when the message length is invalid.
*/
⋮----
/**
* @notice Verify a BLS signature.
* @param keyBytes The encoded G1 public key.
* @param message The encoded message hash to verify.
* @param signature The encoded G1 signature.
* @param extraData The encoded G2 public key.
* @return If the signature is valid.
* @dev Burns the whole gas if pairing precompile fails.
* Returns false if the key is zero G1 point.
*/
function verify(bytes memory keyBytes, bytes memory message, bytes memory signature, bytes memory extraData)
⋮----
/**
* @notice Verify a BLS signature.
* @param keyG1 The G1 public key.
* @param messageHash The message hash to verify.
* @param signatureG1 The G1 signature.
* @param keyG2 The G2 public key.
* @return If the signature is valid.
* @dev Burns the whole gas if pairing precompile fails.
* Returns false if the key is zero G1 point.
*/
function verify(
````
## File: src/libraries/sigs/SigEcdsaSecp256k1.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyEcdsaSecp256k1} from "../keys/KeyEcdsaSecp256k1.sol";
⋮----
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
⋮----
/**
* @title SigEcdsaSecp256k1
* @notice Library for verifying ECDSA signatures on the secp256k1 curve.
*/
⋮----
/**
* @notice Reverts when the message length is invalid.
*/
⋮----
/**
* @notice Verify an ECDSA signature.
* @param keyBytes The encoded signer address.
* @param message The encoded message hash to verify.
* @param signature The encoded ECDSA signature.
* @return If the signature is valid.
* @dev Returns false if the key is zero address.
*/
function verify(
⋮----
bytes memory /* extraData */
⋮----
/**
* @notice Verify an ECDSA signature.
* @param key The signer address.
* @param message The message hash to verify.
* @param signature The ECDSA signature.
* @return If the signature is valid.
* @dev Returns false if the key is zero address.
*/
function verify(address key, bytes32 message, bytes memory signature) internal view returns (bool) {
````
## File: src/libraries/structs/Checkpoints.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints as OZCheckpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
⋮----
/**
* @title Checkpoints
* @notice Library implementing a checkpointing mechanism for values as they change at different points in time.
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
* time, and later looking up past values by key.
*/
⋮----
/**
* @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*/
function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
⋮----
/**
* @dev Returns the value in the last (most recent) checkpoint with a key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
⋮----
/**
* @dev Returns the value in the last (most recent) checkpoint with a key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookupRecent} that can be optimized by getting the hint
* (index of the checkpoint with a key lower or equal than the search key).
*/
function upperLookupRecent(Trace208 storage self, uint48 key, bytes memory hint_) internal view returns (uint208) {
⋮----
/**
* @dev Returns whether there is a checkpoint with a key lower or equal than the search key in the structure (i.e. it is not empty),
* and if so the key and value in the checkpoint, and its position in the trace.
*/
function upperLookupRecentCheckpoint(Trace208 storage self, uint48 key)
⋮----
/**
* @dev Returns whether there is a checkpoint with a key lower or equal than the search key in the structure (i.e. it is not empty),
* and if so the key and value in the checkpoint, and its position in the trace.
*
* NOTE: This is a variant of {upperLookupRecentCheckpoint} that can be optimized by getting the hint
* (index of the checkpoint with a key lower or equal than the search key).
*/
function upperLookupRecentCheckpoint(Trace208 storage self, uint48 key, bytes memory hint_)
⋮----
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace208 storage self) internal view returns (uint208) {
⋮----
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace208 storage self) internal view returns (bool, uint48, uint208) {
⋮----
/**
* @dev Returns a total number of checkpoints.
*/
function length(Trace208 storage self) internal view returns (uint256) {
⋮----
/**
* @dev Returns checkpoint at a given position.
*/
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
⋮----
/**
* @dev Pops the last (most recent) checkpoint.
*/
function pop(Trace208 storage self) internal returns (uint208 value) {
⋮----
/**
* @dev Pushes a (`key`, `value`) pair into a Trace256 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*/
function push(Trace256 storage self, uint48 key, uint256 value) internal returns (uint256, uint256) {
⋮----
function upperLookupRecent(Trace256 storage self, uint48 key) internal view returns (uint256) {
⋮----
function upperLookupRecent(Trace256 storage self, uint48 key, bytes memory hint_) internal view returns (uint256) {
⋮----
function upperLookupRecentCheckpoint(Trace256 storage self, uint48 key)
⋮----
function upperLookupRecentCheckpoint(Trace256 storage self, uint48 key, bytes memory hint_)
⋮----
function latest(Trace256 storage self) internal view returns (uint256) {
⋮----
function latestCheckpoint(Trace256 storage self) internal view returns (bool exists, uint48 _key, uint256 _value) {
⋮----
function length(Trace256 storage self) internal view returns (uint256) {
⋮----
function at(Trace256 storage self, uint32 pos) internal view returns (Checkpoint256 memory) {
⋮----
function pop(Trace256 storage self) internal returns (uint256 value) {
⋮----
function push(Trace512 storage self, uint48 key, uint256[2] memory value)
⋮----
function upperLookupRecent(Trace512 storage self, uint48 key) internal view returns (uint256[2] memory) {
⋮----
function upperLookupRecent(Trace512 storage self, uint48 key, bytes memory hint_)
⋮----
function upperLookupRecentCheckpoint(Trace512 storage self, uint48 key)
⋮----
function upperLookupRecentCheckpoint(Trace512 storage self, uint48 key, bytes memory hint_)
⋮----
function latest(Trace512 storage self) internal view returns (uint256[2] memory) {
⋮----
function latestCheckpoint(Trace512 storage self)
⋮----
function length(Trace512 storage self) internal view returns (uint256) {
⋮----
function at(Trace512 storage self, uint32 pos) internal view returns (Checkpoint512 memory) {
⋮----
function pop(Trace512 storage self) internal returns (uint256[2] memory value) {
⋮----
/**
* @dev Return the index of the last (most recent) checkpoint with a key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(OZCheckpoints.Checkpoint208[] storage self, uint48 key, uint256 low, uint256 high)
⋮----
/**
* @dev Access an element of the array without performing a bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(OZCheckpoints.Checkpoint208[] storage self, uint256 pos)
````
## File: src/libraries/structs/PersistentSet.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../structs/Checkpoints.sol";
⋮----
/**
* @title PersistentSet
* @notice Library implementing a persistent set using Checkpoints.
* @dev The library is optimized towards "write" operations, so, in general, "read" batch operations
* like `values()` and `valuesAt()` should not be used on-chain.
*/
⋮----
/**
* @notice Reverts when the key is too old.
*/
⋮----
/**
* @notice The status of an element.
* @param isAdded If the element was ever added to the set.
* @param addedAt The key (e.g., block timestamp or block number) at which the element was firstly added to the set.
* @param isRemoved The trace of keys at which the element was removed from the set.
*/
⋮----
/**
* @notice The set.
* @param _elements The elements of the set which were ever added to the set.
* @param _statuses The statuses of the elements.
* @param _length The number of elements which are currently in the set.
*/
⋮----
/**
* @notice Adds an element to the set.
* @param set The set.
* @param key The key to add element at.
* @param value The element.
* @return If the element was added to the set.
* @dev It is possible to add an element only at the same or greater key than the previous one for this value.
*/
function _add(Set storage set, uint48 key, bytes32 value) private returns (bool) {
⋮----
/**
* @notice Removes an element from the set.
* @param set The set.
* @param key The key to remove element at.
* @param value The element.
* @return If the element was removed from the set.
* @dev It is possible to remove an element only at the same or greater key than the previous one for this value.
*/
function _remove(Set storage set, uint48 key, bytes32 value) private returns (bool) {
⋮----
/**
* @notice Checks if an element is in the set at a given key.
* @param set The set.
* @param key The key to check element at.
* @param value The element.
* @param hint The hint to use for the lookup.
* @return If the element is in the set at the given key.
*/
function _containsAt(Set storage set, uint48 key, bytes32 value, bytes memory hint) private view returns (bool) {
⋮----
/**
* @notice Checks if an element is in the set at a given key.
* @param set The set.
* @param key The key to check element at.
* @param value The element.
* @return If the element is in the set at the given key.
*/
function _containsAt(Set storage set, uint48 key, bytes32 value) private view returns (bool) {
⋮----
/**
* @notice Checks if an element is in the set.
* @param set The set.
* @param value The element.
* @return If the element is in the set.
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
⋮----
/**
* @notice Returns the number of elements in the set.
* @param set The set.
* @return The number of elements in the set.
*/
function _length(Set storage set) private view returns (uint256) {
⋮----
/**
* @notice Returns the elements in the set at a given key.
* @param set The set.
* @param key The key to get elements at.
* @return values_ The elements in the set at the given key.
*/
function _valuesAt(Set storage set, uint48 key) private view returns (bytes32[] memory values_) {
⋮----
/**
* @notice Returns the elements in the set.
* @param set The set.
* @return values_ The elements in the set.
*/
function _values(Set storage set) private view returns (bytes32[] memory values_) {
⋮----
// Bytes32Set
⋮----
/**
* @notice The set of bytes32 values.
* @param _inner The set.
*/
⋮----
/**
* @notice Adds an element to the set.
* @param set The set.
* @param key The key to add element at.
* @param value The element.
* @return If the element was added to the set.
*/
function add(Bytes32Set storage set, uint48 key, bytes32 value) internal returns (bool) {
⋮----
/**
* @notice Removes an element from the set.
* @param set The set.
* @param key The key to remove element at.
* @param value The element.
* @return If the element was removed from the set.
*/
function remove(Bytes32Set storage set, uint48 key, bytes32 value) internal returns (bool) {
⋮----
function containsAt(Bytes32Set storage set, uint48 key, bytes32 value, bytes memory hint)
⋮----
function containsAt(Bytes32Set storage set, uint48 key, bytes32 value) internal view returns (bool) {
⋮----
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
⋮----
function length(Bytes32Set storage set) internal view returns (uint256) {
⋮----
/**
* @notice Returns the elements in the set at a given key.
* @param set The set.
* @param key The key to get elements at.
* @return result The elements in the set at the given key.
*/
function valuesAt(Bytes32Set storage set, uint48 key) internal view returns (bytes32[] memory result) {
⋮----
/**
* @notice Returns the elements in the set.
* @param set The set.
* @return result The elements in the set.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) {
⋮----
// AddressSet
⋮----
/**
* @notice The set of address values.
* @param _inner The set.
*/
⋮----
function add(AddressSet storage set, uint48 key, address value) internal returns (bool) {
⋮----
function remove(AddressSet storage set, uint48 key, address value) internal returns (bool) {
⋮----
function containsAt(AddressSet storage set, uint48 key, address value, bytes memory hint)
⋮----
function containsAt(AddressSet storage set, uint48 key, address value) internal view returns (bool) {
⋮----
function contains(AddressSet storage set, address value) internal view returns (bool) {
⋮----
function length(AddressSet storage set) internal view returns (uint256) {
⋮----
function valuesAt(AddressSet storage set, uint48 key) internal view returns (address[] memory result) {
⋮----
function values(AddressSet storage set) internal view returns (address[] memory result) {
````
## File: src/libraries/utils/BN254.sol
````
// SPDX-License-Identifier: MIT
// Original code: https://github.com/Layr-Labs/eigenlayer-middleware/blob/mainnet/src/libraries/BN254.sol
// Copyright (c) 2024 LayrLabs Inc.
⋮----
// modulus for the underlying field F_p of the elliptic curve
⋮----
// modulus for the underlying field F_r of the elliptic curve
⋮----
// Encoding of field elements is: X[1] * i + X[0]
⋮----
function generatorG1() internal pure returns (G1Point memory) {
⋮----
// generator of group G2
/// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
⋮----
/// @notice returns the G2 generator
/// @dev mind the ordering of the 1s and 0s!
/// this is because of the (unknown to us) convention used in the bn254 pairing precompile contract
/// "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)."
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding
function generatorG2() internal pure returns (G2Point memory) {
⋮----
// negation of the generator of group G2
⋮----
function negGeneratorG2() internal pure returns (G2Point memory) {
⋮----
/**
* @param p Some point in G1.
* @return The negation of `p`, i.e. p.plus(p.negate()) should be zero.
*/
function negate(G1Point memory p) internal pure returns (G1Point memory) {
// The prime q in the base field F_q for G1
⋮----
/**
* @return r the sum of two points of G1
*/
function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
⋮----
// solium-disable-next-line security/no-inline-assembly
⋮----
// Use "invalid" to make gas estimation work
⋮----
/**
* @notice an optimized ecMul implementation that takes O(log_2(s)) ecAdds
* @param p the point to multiply
* @param s the scalar to multiply by
* @dev this function is only safe to use if the scalar is 9 bits or less
*/
function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) {
⋮----
// if s is 1 return p
⋮----
// the accumulated product to return
⋮----
// the 2^n*p to add to the accumulated product in each iteration
⋮----
// value of most significant bit
⋮----
// index of most significant bit
⋮----
//loop until we reach the most significant bit
⋮----
// if the current bit is 1, add the 2^n*p to the accumulated product
⋮----
// double the 2^n*p for the next iteration
⋮----
// increment the index and double the value of the most significant bit
⋮----
// return the accumulated product
⋮----
/**
* @return r the product of a point on G1 and a scalar, i.e.
* p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
* points p.
*/
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
⋮----
/**
* @return The result of computing the pairing check
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
* For example,
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
*/
function pairing(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
⋮----
/**
* @notice This function is functionally the same as pairing(), however it specifies a gas limit
* the user can set, as a precompile may use the entire gas budget if it reverts.
*/
function safePairing(
⋮----
//Out is the output of the pairing precompile, either 0 or 1 based on whether the two pairings are equal.
//Success is true if the precompile actually goes through (aka all inputs are valid)
⋮----
/// @return hashedG1 the keccak256 hash of the G1 Point
/// @dev used for BLS signatures
function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) {
⋮----
/// @return the keccak256 hash of the G2 Point
⋮----
function hashG2Point(BN254.G2Point memory pk) internal pure returns (bytes32) {
⋮----
/**
* @notice adapted from https://github.com/HarryR/solcrypto/blob/master/altbn128.sol
*/
function hashToG1(bytes32 _x) internal view returns (G1Point memory) {
⋮----
// y^2 == beta
⋮----
/**
* Given X, find Y
*
* where y = sqrt(x^3 + b)
*
* Returns: (x^3 + b), y
*/
function findYFromX(uint256 x) internal view returns (uint256, uint256) {
// beta = (x^3 + b) % p
⋮----
// y^2 = x^3 + b
// this acts like: y = sqrt(beta) = beta^((p+1) / 4)
⋮----
function expMod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval) {
⋮----
input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
input[1] = 0x20; // expLen = new(big.Int).SetBytes(getData(input, 32, 32))
input[2] = 0x20; // modLen = new(big.Int).SetBytes(getData(input, 64, 32))
````
## File: src/libraries/utils/InputNormalizer.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title InputNormalizer
* @notice Library for normalizing input arrays to a given length.
*/
⋮----
/**
* @notice Reverts when the length of the input is not zero and not equal to the expected length.
*/
⋮----
/**
* @notice Normalizes an array of bytes to a given length.
* @param arr The array of bytes.
* @param length The expected length of the array.
* @return The normalized array of bytes.
*/
function normalize(bytes[] memory arr, uint256 length) internal pure returns (bytes[] memory) {
⋮----
/**
* @notice Normalizes an array of arrays of bytes to a given length.
* @param arr The array of arrays of bytes.
* @param length The expected length of the array.
* @return The normalized array of arrays of bytes.
*/
function normalize(bytes[][] memory arr, uint256 length) internal pure returns (bytes[][] memory) {
````
## File: src/libraries/utils/KeyTags.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title KeyTags
* @notice Library for working with key tags which represent the keys' types and arbitrary purpose identifiers.
*/
⋮----
/**
* @notice Reverts when the key tag is duplicated.
*/
⋮----
/**
* @notice Reverts when the key type is invalid.
*/
⋮----
/**
* @notice Reverts when the key tag is invalid.
*/
⋮----
/**
* @notice The total number of key tags.
* @dev 3 bits for type, 4 bits for tag
*/
⋮----
/**
* @notice The maximum key type.
*/
⋮----
/**
* @notice The maximum key tag.
*/
⋮----
/**
* @notice Validates a key tag.
* @param keyTag The key tag.
*/
function validateKeyTag(uint8 keyTag) internal pure {
⋮----
/**
* @notice Validates a key type.
* @param type_ The key type.
*/
function validateType(uint8 type_) internal pure {
⋮----
/**
* @notice Validates a key tag identifier.
* @param tag The key tag identifier.
*/
function validateTag(uint8 tag) internal pure {
⋮----
/**
* @notice Returns a key tag.
* @param type_ The key type.
* @param tag The key tag identifier.
* @return The key tag.
*/
function getKeyTag(uint8 type_, uint8 tag) internal pure returns (uint8) {
⋮----
/**
* @notice Returns a key type.
* @param keyTag The key tag.
* @return The key type.
*/
function getType(uint8 keyTag) internal pure returns (uint8) {
⋮----
/**
* @notice Returns a key tag identifier.
* @param keyTag The key tag.
* @return The key tag identifier.
*/
function getTag(uint8 keyTag) internal pure returns (uint8) {
⋮----
/**
* @notice Checks if a key tag is in the serialized key tags.
* @param keyTagsSerialized The serialized key tags.
* @param keyTag The key tag.
* @return If the key tag is in the serialized key tags.
*/
function contains(uint128 keyTagsSerialized, uint8 keyTag) internal pure returns (bool) {
⋮----
/**
* @notice Adds a key tag to the serialized key tags.
* @param keyTagsSerialized The serialized key tags.
* @param keyTag The key tag.
* @return The serialized key tags with the key tag added.
* @dev Doesn't revert when the key tag is already in the serialized key tags.
*/
function add(uint128 keyTagsSerialized, uint8 keyTag) internal pure returns (uint128) {
⋮----
/**
* @notice Removes a key tag from the serialized key tags.
* @param keyTagsSerialized The serialized key tags.
* @param keyTag The key tag.
* @return The serialized key tags with the key tag removed.
* @dev Doesn't revert when the key tag is not in the serialized key tags.
*/
function remove(uint128 keyTagsSerialized, uint8 keyTag) internal pure returns (uint128) {
⋮----
/**
* @notice Serializes an array of key tags.
* @param keyTags The array of key tags.
* @return keyTagsSerialized The serialized key tags.
* @dev Reverts when the key tags are duplicated.
*/
function serialize(uint8[] memory keyTags) internal pure returns (uint128 keyTagsSerialized) {
⋮----
/**
* @notice Deserializes a serialized key tags.
* @param keyTagsSerialized The serialized key tags.
* @return keyTags The array of key tags.
*/
function deserialize(uint128 keyTagsSerialized) internal pure returns (uint8[] memory keyTags) {
````
## File: src/libraries/utils/Scaler.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title Scaler
* @notice Library for scaling values between different decimals and inverting them.
*/
⋮----
/**
* @notice Scales a value given its decimals to the target decimals.
* @param value The value to scale.
* @param decimals The base decimals of the value.
* @param targetDecimals The target decimals.
* @return The scaled value.
*/
function scale(uint256 value, uint8 decimals, uint8 targetDecimals) internal pure returns (uint256) {
⋮----
/**
* @notice Inverts a value given its decimals.
* @param value The value to invert.
* @param decimals The base decimals of the value.
* @return The inverted value.
* @dev Reverts if the value is zero.
*/
function invert(uint256 value, uint8 decimals) internal pure returns (uint256) {
````
## File: src/libraries/utils/ValSetVerifier.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title ValSetVerifier
* @notice Library for verifying the validity of validator set elements.
*/
⋮----
/**
* @notice The validator's key.
* @param tag The key tag.
* @param payloadHash The hash of the key.
*/
⋮----
/**
* @notice The validator's vault.
* @param chainId The chain ID.
* @param vault The vault address.
* @param votingPower The voting power.
*/
⋮----
/**
* @notice The validator.
* @param operator The operator address.
* @param votingPower The voting power.
* @param isActive If the validator is active.
* @param keys The validator's keys.
* @param vaults The validator's vaults.
* @dev The voting power may not be equal to the sum of the voting powers inside the vaults.
*/
⋮----
/**
* @notice The validator set.
* @param validators The validators in the validator set.
*/
⋮----
/**
* @notice The Merkle proof.
* @param leaf The leaf to prove.
* @param proof The proof.
*/
⋮----
uint256 internal constant VALIDATOR_SET_TREE_HEIGHT = 0; // 1 element (ceil(log2(1)))
⋮----
uint256 internal constant VALIDATORS_LIST_TREE_HEIGHT = 20; // 1048576 elements (ceil(log2(1048576)))
⋮----
uint256 internal constant VALIDATORS_LIST_MAX_LENGTH = 1_048_576; // 1048576 elements (2 ^ VALIDATORS_LIST_TREE_HEIGHT)
⋮----
uint256 internal constant VALIDATOR_TREE_HEIGHT = 3; // 5 elements (ceil(log2(5)))
⋮----
uint256 internal constant KEY_LIST_TREE_HEIGHT = 7; // 128 elements (ceil(log2(128)))
⋮----
uint256 internal constant KEY_LIST_MAX_LENGTH = 128; // 128 elements (2 ^ KEY_LIST_TREE_HEIGHT)
⋮----
uint256 internal constant VAULT_LIST_TREE_HEIGHT = 10; // 1024 elements (ceil(log2(1024)))
⋮----
uint256 internal constant VAULT_LIST_MAX_LENGTH = 1024; // 1024 elements (2 ^ VAULT_LIST_TREE_HEIGHT)
⋮----
uint256 internal constant KEY_TREE_HEIGHT = 1; // 2 elements (ceil(log2(2)))
⋮----
uint256 internal constant VAULT_TREE_HEIGHT = 2; // 3 elements (ceil(log2(3)))
⋮----
/// @dev The precompile address for SHA-256
⋮----
uint256 internal constant VALIDATORS_LIST_LOCAL_INDEX = VALIDATOR_SET_VALIDATORS_BASE_INDEX; // to element in ValidatorSet
⋮----
VALIDATORS_LIST_LOCAL_INDEX << (1 + VALIDATORS_LIST_TREE_HEIGHT); // to first element (inclusive), "1" is for the length (for a List)
⋮----
VALIDATOR_ROOT_MIN_LOCAL_INDEX + VALIDATORS_LIST_MAX_LENGTH; // to last element (exclusive)
⋮----
VALIDATOR_SET_TREE_HEIGHT + 1 + VALIDATORS_LIST_TREE_HEIGHT; // (to element in ValidatorSet) + (length) + (to element in validators)
⋮----
uint256 internal constant VALIDATOR_OPERATOR_LOCAL_INDEX = VALIDATOR_OPERATOR_BASE_INDEX; // to element in Validator
⋮----
uint256 internal constant VALIDATOR_OPERATOR_PROOF_EXPECTED_HEIGHT = VALIDATOR_TREE_HEIGHT; // (to element in Validator)
⋮----
uint256 internal constant VALIDATOR_VOTING_POWER_LOCAL_INDEX = VALIDATOR_VOTING_POWER_BASE_INDEX; // to element in Validator
⋮----
uint256 internal constant VALIDATOR_VOTING_POWER_PROOF_EXPECTED_HEIGHT = VALIDATOR_TREE_HEIGHT; // (to element in Validator)
⋮----
uint256 internal constant VALIDATOR_IS_ACTIVE_LOCAL_INDEX = VALIDATOR_IS_ACTIVE_BASE_INDEX; // to element in Validator
⋮----
uint256 internal constant VALIDATOR_IS_ACTIVE_PROOF_EXPECTED_HEIGHT = VALIDATOR_TREE_HEIGHT; // (to element in Validator)
⋮----
uint256 internal constant KEYS_LIST_LOCAL_INDEX = VALIDATOR_KEYS_BASE_INDEX; // to element in Validator
⋮----
uint256 internal constant KEY_ROOT_MIN_LOCAL_INDEX = KEYS_LIST_LOCAL_INDEX << (1 + KEY_LIST_TREE_HEIGHT); // to first element (inclusive), "1" is for the length (for a List)
⋮----
uint256 internal constant KEY_ROOT_MAX_LOCAL_INDEX = KEY_ROOT_MIN_LOCAL_INDEX + KEY_LIST_MAX_LENGTH; // to last element (exclusive)
⋮----
uint256 internal constant KEY_ROOT_PROOF_EXPECTED_HEIGHT = VALIDATOR_TREE_HEIGHT + 1 + KEY_LIST_TREE_HEIGHT; // (to element in Validator) + (length) + (to element in keys)
⋮----
uint256 internal constant VAULTS_LIST_LOCAL_INDEX = VALIDATOR_VAULTS_BASE_INDEX; // to element in Validator
⋮----
uint256 internal constant VAULT_ROOT_MIN_LOCAL_INDEX = VAULTS_LIST_LOCAL_INDEX << (1 + VAULT_LIST_TREE_HEIGHT); // to first element (inclusive), "1" is for the length (for a List)
⋮----
uint256 internal constant VAULT_ROOT_MAX_LOCAL_INDEX = VAULT_ROOT_MIN_LOCAL_INDEX + VAULT_LIST_MAX_LENGTH; // to last element (exclusive)
⋮----
uint256 internal constant VAULT_ROOT_PROOF_EXPECTED_HEIGHT = VALIDATOR_TREE_HEIGHT + 1 + VAULT_LIST_TREE_HEIGHT; // (to element in Validator) + (length) + (to element in vaults)
⋮----
uint256 internal constant KEY_TAG_LOCAL_INDEX = KEY_TAG_BASE_INDEX; // to element in Key
⋮----
uint256 internal constant KEY_TAG_PROOF_EXPECTED_HEIGHT = KEY_TREE_HEIGHT; // (to element in Key)
⋮----
uint256 internal constant KEY_PAYLOAD_HASH_LOCAL_INDEX = KEY_PAYLOAD_HASH_BASE_INDEX; // to element in Key
⋮----
uint256 internal constant KEY_PAYLOAD_HASH_PROOF_EXPECTED_HEIGHT = KEY_TREE_HEIGHT; // (to element in Key)
⋮----
uint256 internal constant VAULT_CHAIN_ID_LOCAL_INDEX = VAULT_CHAIN_ID_BASE_INDEX; // to element in Vault
⋮----
uint256 internal constant VAULT_CHAIN_ID_PROOF_EXPECTED_HEIGHT = VAULT_TREE_HEIGHT; // (to element in Vault)
⋮----
uint256 internal constant VAULT_VAULT_LOCAL_INDEX = VAULT_VAULT_BASE_INDEX; // to element in Vault
⋮----
uint256 internal constant VAULT_VAULT_PROOF_EXPECTED_HEIGHT = VAULT_TREE_HEIGHT; // (to element in Vault)
⋮----
uint256 internal constant VAULT_VOTING_POWER_LOCAL_INDEX = VAULT_VOTING_POWER_BASE_INDEX; // to element in Vault
⋮----
uint256 internal constant VAULT_VOTING_POWER_PROOF_EXPECTED_HEIGHT = VAULT_TREE_HEIGHT; // (to element in Vault)
⋮----
/**
* @notice Verifies that the key is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @param keyRootProof The proof of the key root.
* @param keyRootLocalIndex The local index of the key root inside the validator.
* @param keyTagProof The proof of the key tag.
* @param keyPayloadHashProof The proof of the key hash.
* @return isValid If the key is in the validator set.
*/
function verifyKey(
⋮----
/**
* @notice Verifies that the vault is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @param vaultRootProof The proof of the vault root.
* @param vaultRootLocalIndex The local index of the vault root inside the validator.
* @param vaultChainIdProof The proof of the vault chain ID.
* @param vaultVaultProof The proof of the vault address.
* @param vaultVotingPowerProof The proof of the vault voting power.
* @return isValid If the vault is in the validator set.
*/
function verifyVault(
⋮----
/**
* @notice Verifies that the operator address is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @param operatorProof The proof of the operator address.
* @return isValid If the operator address is in the validator set.
*/
function verifyOperator(
⋮----
/**
* @notice Verifies that the validator's voting power is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @param votingPowerProof The proof of the voting power.
* @return isValid If the validator's voting power is in the validator set.
*/
function verifyVotingPower(
⋮----
/**
* @notice Verifies that the validator's activity status is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @param isActiveProof The proof of the validator's is active.
* @return isValid If the validator is active.
*/
function verifyIsActive(
⋮----
/**
* @notice Verifies that the validator root is in the validator set.
* @param validatorRootProof The proof of the validator root.
* @param validatorRootLocalIndex The local index of the validator root inside the validator set.
* @param validatorSetRoot The validator set root.
* @return isValid If the validator root is in the validator set.
*/
function verifyValidatorRootLocal(
⋮----
/**
* @notice Verifies that the operator address is in the validator.
* @param validatorOperatorProof The proof of the operator address.
* @param validatorRoot The validator root.
* @return isValid If the operator address is in the validator.
*/
function verifyValidatorOperatorLocal(SszProof calldata validatorOperatorProof, bytes32 validatorRoot)
⋮----
/**
* @notice Verifies that the validator's voting power is in the validator.
* @param validatorVotingPowerProof The proof of the validator's voting power.
* @param validatorRoot The validator root.
* @return isValid If the validator's voting power is in the validator.
*/
function verifyValidatorVotingPowerLocal(SszProof calldata validatorVotingPowerProof, bytes32 validatorRoot)
⋮----
/**
* @notice Verifies that the validator's activity status is in the validator.
* @param validatorIsActiveProof The proof of the validator's activity status.
* @param validatorRoot The validator root.
* @return isValid If the validator's activity status is in the validator.
*/
function verifyValidatorIsActiveLocal(SszProof calldata validatorIsActiveProof, bytes32 validatorRoot)
⋮----
/**
* @notice Verifies that the key root is in the validator.
* @param keyRootProof The proof of the key root.
* @param keyRootLocalIndex The local index of the key root inside the validator.
* @param validatorRoot The validator root.
* @return isValid If the key root is in the validator.
*/
function verifyValidatorKeyRootLocal(
⋮----
/**
* @notice Verifies that the vault root is in the validator.
* @param vaultRootProof The proof of the vault root.
* @param vaultRootLocalIndex The local index of the vault root inside the validator.
* @param validatorRoot The validator root.
* @return isValid If the vault root is in the validator.
*/
function verifyValidatorVaultRootLocal(
⋮----
/**
* @notice Verifies that the key tag is in the key.
* @param keyTagProof The proof of the key tag.
* @param keyRoot The key root.
* @return isValid If the key tag is in the key.
*/
function verifyKeyTagLocal(SszProof calldata keyTagProof, bytes32 keyRoot) internal view returns (bool) {
⋮----
/**
* @notice Verifies that the key hash is in the key.
* @param keyPayloadHashProof The proof of the key hash.
* @param keyRoot The key root.
* @return isValid If the key hash is in the key.
*/
function verifyKeyPayloadHash(SszProof calldata keyPayloadHashProof, bytes32 keyRoot) internal view returns (bool) {
⋮----
/**
* @notice Verifies that the vault's chain ID is in the vault.
* @param vaultChainIdProof The proof of the vault chain ID.
* @param vaultRoot The vault root.
* @return isValid If the vault's chain ID is in the vault.
*/
function verifyVaultChainIdLocal(SszProof calldata vaultChainIdProof, bytes32 vaultRoot)
⋮----
/**
* @notice Verifies that the vault address is in the vault.
* @param vaultVaultProof The proof of the vault address.
* @param vaultRoot The vault root.
* @return isValid If the vault address is in the vault.
*/
function verifyVaultVaultLocal(SszProof calldata vaultVaultProof, bytes32 vaultRoot) internal view returns (bool) {
⋮----
/**
* @notice Verifies that the vault's voting power is in the vault.
* @param vaultVotingPowerProof The proof of the vault voting power.
* @param vaultRoot The vault root.
* @return isValid If the vault's voting power is in the vault.
*/
function verifyVaultVotingPowerLocal(SszProof calldata vaultVotingPowerProof, bytes32 vaultRoot)
⋮----
/**
* @notice Processes an inclusion proof with a SHA256 hash.
* @param proof The inclusion proof.
* @param leaf The leaf to be proven.
* @param root The root to reconcile the proof against.
* @param localIndex The local index of the leaf.
* @param expectedHeight The height of the tree that the proof is for.
* @return valid A boolean indicating whether the derived root from the proof matches the `root` provided.
* @dev In case of an invalid proof length, we return false which is to be handled by the caller.
* In case of a failed SHA-256 call, we revert.
*/
function processInclusionProofSha256(
⋮----
/// @solidity memory-safe-assembly
⋮----
// let startOffset := add(proof.offset, 32)
// But we'll initialize directly in the loop
⋮----
// Div by 2
⋮----
// Store returndata at 0x00
⋮----
// Store returndata at 0x20
````
## File: src/modules/base/NetworkManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {INetworkManager} from "../../interfaces/modules/base/INetworkManager.sol";
⋮----
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
⋮----
import {StaticDelegateCallable} from "@symbioticfi/core/src/contracts/common/StaticDelegateCallable.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
⋮----
/// @title NetworkManager
/// @notice Contract for managing the network and subnetwork getters.
abstract contract NetworkManager is Initializable, StaticDelegateCallable, INetworkManager {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.NetworkManager")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getNetworkManagerStorage() internal pure returns (INetworkManager.NetworkManagerStorage storage $) {
⋮----
function __NetworkManager_init(NetworkManagerInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc INetworkManager
function NETWORK() public view virtual returns (address) {
⋮----
function SUBNETWORK_IDENTIFIER() public view virtual returns (uint96) {
⋮----
function SUBNETWORK() public view virtual returns (bytes32) {
````
## File: src/modules/base/OzEIP712.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IOzEIP712} from "../../interfaces/modules/base/IOzEIP712.sol";
⋮----
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
⋮----
/// @title OzEIP712
/// @notice Contract for EIP712 hashing.
abstract contract OzEIP712 is EIP712Upgradeable, IOzEIP712 {
⋮----
function __OzEIP712_init(OzEIP712InitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc IOzEIP712
function hashTypedDataV4(bytes32 structHash) public view returns (bytes32) {
⋮----
function hashTypedDataV4CrossChain(bytes32 structHash) public view virtual returns (bytes32) {
````
## File: src/modules/base/PermissionManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IPermissionManager} from "../../interfaces/modules/base/IPermissionManager.sol";
⋮----
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
⋮----
/// @title PermissionManager
/// @notice Base contract for managing permissions.
abstract contract PermissionManager is Initializable, IPermissionManager {
modifier checkPermission() {
⋮----
function _checkPermission() internal virtual;
````
## File: src/modules/common/permissions/OzAccessControl.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {PermissionManager} from "../../base/PermissionManager.sol";
⋮----
import {IOzAccessControl} from "../../../interfaces/modules/common/permissions/IOzAccessControl.sol";
⋮----
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
⋮----
/// @title OzAccessControl
/// @notice Contract for permission management based on OpenZeppelin's AccessControl.
abstract contract OzAccessControl is PermissionManager, AccessControlUpgradeable, IOzAccessControl {
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.OzAccessControl")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getOzAccessControlStorage() internal pure returns (OzAccessControlStorage storage $) {
⋮----
function __OzAccessControl_init() internal virtual onlyInitializing {
⋮----
/// @inheritdoc IOzAccessControl
function getRole(bytes4 selector) public view virtual returns (bytes32) {
⋮----
/// @inheritdoc PermissionManager
function _checkPermission() internal view virtual override {
⋮----
function _setSelectorRole(bytes4 selector, bytes32 role) internal virtual {
````
## File: src/modules/common/permissions/OzAccessManaged.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {PermissionManager} from "../../base/PermissionManager.sol";
⋮----
import {IOzAccessManaged} from "../../../interfaces/modules/common/permissions/IOzAccessManaged.sol";
⋮----
import {
AccessManagedUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
⋮----
/// @title OzAccessManaged
/// @notice Contract for permission management based on OpenZeppelin's AccessManaged.
abstract contract OzAccessManaged is PermissionManager, AccessManagedUpgradeable, IOzAccessManaged {
function __OzAccessManaged_init(OzAccessManagedInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc PermissionManager
function _checkPermission() internal virtual override {
````
## File: src/modules/common/permissions/OzOwnable.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {PermissionManager} from "../../base/PermissionManager.sol";
⋮----
import {IOzOwnable} from "../../../interfaces/modules/common/permissions/IOzOwnable.sol";
⋮----
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
⋮----
/// @title OzOwnable
/// @notice Contract for permission management based on OpenZeppelin's Ownable.
abstract contract OzOwnable is PermissionManager, OwnableUpgradeable, IOzOwnable {
function __OzOwnable_init(OzOwnableInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc PermissionManager
function _checkPermission() internal view virtual override {
````
## File: src/modules/key-registry/KeyRegistry.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {OzEIP712} from "../base/OzEIP712.sol";
⋮----
import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
import {KeyBlsBn254} from "../../libraries/keys/KeyBlsBn254.sol";
import {KeyEcdsaSecp256k1} from "../../libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyTags} from "../../libraries/utils/KeyTags.sol";
import {PersistentSet} from "../../libraries/structs/PersistentSet.sol";
import {SigBlsBn254} from "../../libraries/sigs/SigBlsBn254.sol";
import {SigEcdsaSecp256k1} from "../../libraries/sigs/SigEcdsaSecp256k1.sol";
⋮----
import {
IKeyRegistry,
KEY_TYPE_BLS_BN254,
KEY_TYPE_ECDSA_SECP256K1
} from "../../interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
⋮----
/// @title KeyRegistry
/// @notice Contract for operators' keys management.
/// @dev It supports:
/// - BLS public keys on BN254
/// - ECDSA public keys on secp256k1
contract KeyRegistry is MulticallUpgradeable, OzEIP712, IKeyRegistry {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.KeyRegistry")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getKeyRegistryStorage() internal pure returns (KeyRegistryStorage storage $) {
⋮----
function __KeyRegistry_init(KeyRegistryInitParams memory keyRegistryInitParams) public virtual onlyInitializing {
⋮----
/// @inheritdoc IKeyRegistry
function getKeyAt(address operator, uint8 tag, uint48 timestamp) public view virtual returns (bytes memory) {
⋮----
function getKey(address operator, uint8 tag) public view virtual returns (bytes memory) {
⋮----
function getOperator(bytes memory key) public view virtual returns (address) {
⋮----
function getKeysAt(address operator, uint48 timestamp) public view virtual returns (Key[] memory keys) {
⋮----
function getKeys(address operator) public view virtual returns (Key[] memory keys) {
⋮----
function getKeysAt(uint48 timestamp) public view virtual returns (OperatorWithKeys[] memory operatorsKeys) {
⋮----
function getKeys() public view virtual returns (OperatorWithKeys[] memory operatorsKeys) {
⋮----
function getKeysOperatorsLength() public view virtual returns (uint256) {
⋮----
function getKeysOperatorsAt(uint48 timestamp) public view virtual returns (address[] memory) {
⋮----
function getKeysOperators() public view virtual returns (address[] memory) {
⋮----
function _getKeyTagsAt(address operator, uint48 timestamp) internal view virtual returns (uint8[] memory) {
⋮----
function _getKeyTags(address operator) internal view virtual returns (uint8[] memory) {
⋮----
function setKey(uint8 tag, bytes memory key, bytes memory signature, bytes memory extraData) public virtual {
⋮----
function _setKey(address operator, uint8 tag, bytes memory key, bytes memory signature, bytes memory extraData)
⋮----
// Disallow usage between different operators
// Disallow usage of the same key on the same type on different tags
// Allow usage of the old key on the same type and tag
⋮----
function _setKey(address operator, uint8 tag, bytes memory key) internal virtual {
⋮----
function _setKey32(address operator, uint8 tag, bytes memory key) internal {
⋮----
function _setKey64(address operator, uint8 tag, bytes memory key) internal {
⋮----
function _verifyKey(
⋮----
function _getKey32At(address operator, uint8 tag, uint48 timestamp) internal view returns (bytes memory) {
⋮----
function _getKey32(address operator, uint8 tag) internal view returns (bytes memory) {
⋮----
function _getKey64At(address operator, uint8 tag, uint48 timestamp) internal view returns (bytes memory) {
⋮----
function _getKey64(address operator, uint8 tag) internal view returns (bytes memory) {
````
## File: src/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.sol
````
// SPDX-License-Identifier: MIT
⋮----
/**
* @title ExtraDataStorageHelper
* @notice Library for convenient and safe extra data storage slots derivation.
*/
⋮----
/**
* @notice Derives a key from a name hash.
* @param nameHash The name hash.
* @return The key.
* @dev It can be used, e.g., to store some global data like number of validators.
*/
function getKeyGlobal(bytes32 nameHash) internal pure returns (bytes32) {
⋮----
/**
* @notice Derives a key from a key tag and a name hash.
* @param keyTag The key tag.
* @param nameHash The name hash.
* @return The key.
* @dev It can be used, e.g., to store some data dependent on the key tag like quorum threshold.
*/
function getKeyGlobal(uint8 keyTag, bytes32 nameHash) internal pure returns (bytes32) {
⋮----
/**
* @notice Derives a key from a key tag, a name hash and an index.
* @param keyTag The key tag.
* @param nameHash The name hash.
* @param index The index.
* @return The key.
* @dev It can be used, e.g., to store some data dependent on the key tag, which needs more than 1 storage slot (32 bytes),
* like aggregated BLS12-381 public key.
*/
function getKeyGlobal(uint8 keyTag, bytes32 nameHash, uint256 index) internal pure returns (bytes32) {
⋮----
/**
* @notice Derives a key from a verification type and a name hash.
* @param verificationType The verification type.
* @param nameHash The name hash.
* @return The key.
* @dev It can be used, e.g., to store some data dependent on the verification type like number of validators
* with a possibility to have multiple verification types simultaneously without collisions.
*/
function getKey(uint32 verificationType, bytes32 nameHash) internal pure returns (bytes32) {
⋮----
/**
* @notice Derives a key from a verification type, a key tag and a name hash.
* @param verificationType The verification type.
* @param keyTag The key tag.
* @param nameHash The name hash.
* @return The key.
* @dev It can be used, e.g., to store some data dependent on the verification type and the key tag like quorum threshold
* with a possibility to have multiple verification types simultaneously without collisions.
*/
function getKey(uint32 verificationType, uint8 keyTag, bytes32 nameHash) internal pure returns (bytes32) {
⋮----
/**
* @notice Derives a key from a verification type, a key tag, a name hash and an index.
* @param verificationType The verification type.
* @param keyTag The key tag.
* @param nameHash The name hash.
* @param index The index.
* @return The key.
* @dev It can be used, e.g., to store some data dependent on the verification type and the key tag,
* which needs more than 1 storage slot (32 bytes), like aggregated BLS12-381 public key
* with a possibility to have multiple verification types simultaneously without collisions.
*/
function getKey(uint32 verificationType, uint8 keyTag, bytes32 nameHash, uint256 index)
````
## File: src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {BN254} from "../../../libraries/utils/BN254.sol";
import {ExtraDataStorageHelper} from "./libraries/ExtraDataStorageHelper.sol";
import {KeyBlsBn254} from "../../../libraries/keys/KeyBlsBn254.sol";
import {KeyTags} from "../../../libraries/utils/KeyTags.sol";
import {SigBlsBn254} from "../../../libraries/sigs/SigBlsBn254.sol";
⋮----
import {ISettlement} from "../../../interfaces/modules/settlement/ISettlement.sol";
import {
ISigVerifierBlsBn254Simple
} from "../../../interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254Simple.sol";
import {ISigVerifier} from "../../../interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
import {KEY_TYPE_BLS_BN254} from "../../../interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
/// @title SigVerifierBlsBn254Simple
/// @notice Contract for verifying validator's set attestations based on BLS signatures on the BN254 curve
/// by decompressing the whole validator set on-chain.
contract SigVerifierBlsBn254Simple is ISigVerifierBlsBn254Simple {
⋮----
/// @inheritdoc ISigVerifier
⋮----
/// @inheritdoc ISigVerifierBlsBn254Simple
⋮----
function verifyQuorumSig(
⋮----
// Proof Structure
// 0 : 64 - G1 aggregated signature
// 64 : 192 - G2 aggregated public key
// 192 : 224+validatorsData.length*64 - encoded data of all active validators for a given `keyTag`
// 192 : 224 - number of validators
// 224 : 224+validatorsData.length*64 - (bytes32 keySerialized,uint256 votingPower)[]
// 224+validatorsData.length*64 (nonSignersOffset) : nonSignersOffset+nonSigners.length*2 - encoded array of 2 bytes non-signer indices (from validatorsData)
// nonSignersOffset : nonSignersOffset+nonSigners.length*2 - uint16[]
⋮----
// assuming that the validator set, and, hence, total voting power, were properly committed,
// so that the sum of the non-signers' voting powers cannot be greater than the total voting power,
// and, hence, cannot overflow
````
## File: src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {BN254} from "../../../libraries/utils/BN254.sol";
import {ExtraDataStorageHelper} from "./libraries/ExtraDataStorageHelper.sol";
import {KeyTags} from "../../../libraries/utils/KeyTags.sol";
⋮----
import {ISettlement} from "../../../interfaces/modules/settlement/ISettlement.sol";
import {ISigVerifierBlsBn254ZK} from "../../../interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254ZK.sol";
import {ISigVerifier} from "../../../interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
import {IVerifier} from "../../../interfaces/modules/settlement/sig-verifiers/zk/IVerifier.sol";
import {KEY_TYPE_BLS_BN254} from "../../../interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
/// @title SigVerifierBlsBn254ZK
/// @notice Contract for verifying validator's set attestations based on BLS signatures on the BN254 curve
/// by decompressing the whole validator set using ZK.
contract SigVerifierBlsBn254ZK is ISigVerifierBlsBn254ZK {
⋮----
/// @inheritdoc ISigVerifier
⋮----
/// @inheritdoc ISigVerifierBlsBn254ZK
⋮----
function verifyQuorumSig(
⋮----
// Proof Structure
// 0 : 256 - ZK proof (uint256[8])
// 256 : 320 - commitments (uint256[2])
// 320 : 384 - commitmentPok (uint256[2])
// 384 : 416 - voting power of signers (uint256)
⋮----
function _getVerifier(uint256 totalActiveValidators) internal view returns (address) {
````
## File: src/modules/settlement/Settlement.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {NetworkManager} from "../base/NetworkManager.sol";
import {OzEIP712} from "../base/OzEIP712.sol";
import {PermissionManager} from "../base/PermissionManager.sol";
⋮----
import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
import {KeyTags} from "../../libraries/utils/KeyTags.sol";
⋮----
import {ISettlement} from "../../interfaces/modules/settlement/ISettlement.sol";
import {ISigVerifier} from "../../interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
⋮----
/// @title Settlement
/// @notice Contract for processing the validator sets through epochs and allowing verifying their attestations on-chain.
abstract contract Settlement is NetworkManager, OzEIP712, PermissionManager, ISettlement {
⋮----
/// @inheritdoc ISettlement
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.Settlement")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getSettlementStorage() internal pure returns (SettlementStorage storage $) {
⋮----
function __Settlement_init(SettlementInitParams memory settlementInitParams) internal virtual onlyInitializing {
⋮----
function getSigVerifierAt(uint48 epoch, bytes memory hint) public view virtual returns (address) {
⋮----
function getSigVerifier() public view virtual returns (address) {
⋮----
function getLastCommittedHeaderEpoch() public view virtual returns (uint48) {
⋮----
function isValSetHeaderCommittedAt(uint48 epoch) public view virtual returns (bool) {
⋮----
function getValSetHeaderHashAt(uint48 epoch) public view returns (bytes32) {
⋮----
function getValSetHeaderHash() public view returns (bytes32) {
⋮----
function getValSetHeaderAt(uint48 epoch) public view virtual returns (ValSetHeader memory) {
⋮----
function getValSetHeader() public view virtual returns (ValSetHeader memory header) {
⋮----
function getVersionFromValSetHeaderAt(uint48 epoch) public view virtual returns (uint8) {
⋮----
function getVersionFromValSetHeader() public view virtual returns (uint8) {
⋮----
function getRequiredKeyTagFromValSetHeaderAt(uint48 epoch) public view virtual returns (uint8) {
⋮----
function getRequiredKeyTagFromValSetHeader() public view virtual returns (uint8) {
⋮----
function getCaptureTimestampFromValSetHeaderAt(uint48 epoch) public view virtual returns (uint48) {
⋮----
function getCaptureTimestampFromValSetHeader() public view virtual returns (uint48) {
⋮----
function getQuorumThresholdFromValSetHeaderAt(uint48 epoch) public view virtual returns (uint256) {
⋮----
function getQuorumThresholdFromValSetHeader() public view virtual returns (uint256) {
⋮----
function getTotalVotingPowerFromValSetHeaderAt(uint48 epoch) public view virtual returns (uint256) {
⋮----
function getTotalVotingPowerFromValSetHeader() public view virtual returns (uint256) {
⋮----
function getValidatorsSszMRootFromValSetHeaderAt(uint48 epoch) public view virtual returns (bytes32) {
⋮----
function getValidatorsSszMRootFromValSetHeader() public view virtual returns (bytes32) {
⋮----
function getExtraDataAt(uint48 epoch, bytes32 key) public view virtual returns (bytes32) {
⋮----
function getExtraData(bytes32 key) public view virtual returns (bytes32) {
⋮----
function verifyQuorumSigAt(
⋮----
function verifyQuorumSig(bytes memory message, uint8 keyTag, uint256 quorumThreshold, bytes calldata proof)
⋮----
function setSigVerifier(address sigVerifier) public virtual checkPermission {
⋮----
function setGenesis(ValSetHeader calldata valSetHeader, ExtraData[] calldata extraData)
⋮----
function commitValSetHeader(ValSetHeader calldata header, ExtraData[] calldata extraData, bytes calldata proof)
⋮----
function _setValSetHeader(ValSetHeader calldata header, ExtraData[] calldata extraData) internal virtual {
⋮----
function _getCurrentValue(Checkpoints.Trace208 storage trace, uint48 currentTimepoint)
````
## File: src/modules/valset-driver/EpochManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {PermissionManager} from "../base/PermissionManager.sol";
⋮----
import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
⋮----
import {IEpochManager} from "../../interfaces/modules/valset-driver/IEpochManager.sol";
⋮----
/// @title EpochManager
/// @notice Contract for managing the epochs state machine.
abstract contract EpochManager is PermissionManager, IEpochManager {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.EpochManager")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getEpochManagerStorage() internal pure returns (EpochManagerStorage storage $) {
⋮----
function __EpochManager_init(EpochManagerInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc IEpochManager
function getCurrentEpoch() public view virtual returns (uint48) {
⋮----
function getCurrentEpochDuration() public view virtual returns (uint48 epochDuration) {
⋮----
function getCurrentEpochStart() public view virtual returns (uint48) {
⋮----
function getNextEpoch() public view virtual returns (uint48) {
⋮----
function getNextEpochDuration() public view virtual returns (uint48) {
⋮----
function getNextEpochStart() public view virtual returns (uint48) {
⋮----
function getEpochIndex(uint48 timestamp) public view virtual returns (uint48) {
⋮----
function getEpochDuration(uint48 epoch) public view virtual returns (uint48 epochDuration) {
⋮----
function getEpochStart(uint48 epoch) public view virtual returns (uint48) {
⋮----
function setEpochDuration(uint48 epochDuration) public virtual checkPermission {
⋮----
function _setEpochDuration(uint48 epochDuration) internal virtual {
⋮----
function _setEpochDuration(uint48 epochDuration, uint48 epochDurationTimestamp, uint48 epochDurationIndex)
⋮----
function _getEpochDurationDataByTimestamp(uint48 timestamp) internal view virtual returns (uint48, uint48, uint48) {
⋮----
function _getEpochDurationDataByIndex(uint48 index) internal view virtual returns (uint48, uint48, uint48) {
⋮----
function _getCurrentEpochDurationData() internal view virtual returns (uint48, uint48, uint48) {
⋮----
function _getFirstEpochDurationData() internal view virtual returns (uint48, uint48, uint48) {
⋮----
function _serializeEpochDurationData(
⋮----
function _deserializeEpochDurationData(uint208 epochDurationData)
⋮----
function _getCurrentValue(Checkpoints.Trace208 storage trace, uint48 currentTimepoint)
````
## File: src/modules/valset-driver/ValSetDriver.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {EpochManager} from "./EpochManager.sol";
import {NetworkManager} from "../base/NetworkManager.sol";
⋮----
import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
import {KeyTags} from "../../libraries/utils/KeyTags.sol";
import {PersistentSet} from "../../libraries/structs/PersistentSet.sol";
⋮----
import {IValSetDriver} from "../../interfaces/modules/valset-driver/IValSetDriver.sol";
⋮----
import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
⋮----
/// @title ValSetDriver
/// @notice Contract for providing various configs and driving data for off-chain services.
abstract contract ValSetDriver is EpochManager, NetworkManager, MulticallUpgradeable, IValSetDriver {
⋮----
/// @inheritdoc IValSetDriver
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.ValSetDriver")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getValSetDriverStorage() internal pure returns (ValSetDriverStorage storage $) {
⋮----
function __ValSetDriver_init(ValSetDriverInitParams memory valSetDriverInitParams)
⋮----
function getConfigAt(uint48 timestamp) public view virtual returns (Config memory) {
⋮----
function getConfig() public view virtual returns (Config memory) {
⋮----
function getNumAggregatorsAt(uint48 timestamp) public view virtual returns (uint208) {
⋮----
function getNumAggregators() public view virtual returns (uint208) {
⋮----
function getNumCommittersAt(uint48 timestamp) public view virtual returns (uint208) {
⋮----
function getNumCommitters() public view virtual returns (uint208) {
⋮----
function isVotingPowerProviderRegisteredAt(CrossChainAddress memory votingPowerProvider, uint48 timestamp)
⋮----
function isVotingPowerProviderRegistered(CrossChainAddress memory votingPowerProvider)
⋮----
function getVotingPowerProvidersAt(uint48 timestamp)
⋮----
function getVotingPowerProviders() public view virtual returns (CrossChainAddress[] memory votingPowerProviders) {
⋮----
function getKeysProviderAt(uint48 timestamp) public view virtual returns (CrossChainAddress memory) {
⋮----
function getKeysProvider() public view virtual returns (CrossChainAddress memory) {
⋮----
function isSettlementRegisteredAt(CrossChainAddress memory settlement, uint48 timestamp)
⋮----
function isSettlementRegistered(CrossChainAddress memory settlement) public view virtual returns (bool) {
⋮----
function getSettlementsAt(uint48 timestamp) public view virtual returns (CrossChainAddress[] memory settlements) {
⋮----
function getSettlements() public view virtual returns (CrossChainAddress[] memory settlements) {
⋮----
function getMaxVotingPowerAt(uint48 timestamp) public view virtual returns (uint256) {
⋮----
function getMaxVotingPower() public view virtual returns (uint256) {
⋮----
function getMinInclusionVotingPowerAt(uint48 timestamp) public view virtual returns (uint256) {
⋮----
function getMinInclusionVotingPower() public view virtual returns (uint256) {
⋮----
function getMaxValidatorsCountAt(uint48 timestamp) public view virtual returns (uint208) {
⋮----
function getMaxValidatorsCount() public view virtual returns (uint208) {
⋮----
function getRequiredKeyTagsAt(uint48 timestamp) public view virtual returns (uint8[] memory requiredKeyTags) {
⋮----
function getRequiredKeyTags() public view virtual returns (uint8[] memory requiredKeyTags) {
⋮----
function isQuorumThresholdRegisteredAt(QuorumThreshold memory quorumThreshold, uint48 timestamp)
⋮----
function isQuorumThresholdRegistered(QuorumThreshold memory quorumThreshold) public view virtual returns (bool) {
⋮----
function getQuorumThresholdsAt(uint48 timestamp)
⋮----
function getQuorumThresholds() public view virtual returns (QuorumThreshold[] memory quorumThresholds) {
⋮----
function getRequiredHeaderKeyTagAt(uint48 timestamp) public view virtual returns (uint8) {
⋮----
function getRequiredHeaderKeyTag() public view virtual returns (uint8) {
⋮----
function getVerificationTypeAt(uint48 timestamp) public view virtual returns (uint32) {
⋮----
function getVerificationType() public view virtual returns (uint32) {
⋮----
function setNumAggregators(uint208 numAggregators) public virtual checkPermission {
⋮----
function setNumCommitters(uint208 numCommitters) public virtual checkPermission {
⋮----
function addVotingPowerProvider(CrossChainAddress memory votingPowerProvider) public virtual checkPermission {
⋮----
function removeVotingPowerProvider(CrossChainAddress memory votingPowerProvider) public virtual checkPermission {
⋮----
function setKeysProvider(CrossChainAddress memory keysProvider) public virtual checkPermission {
⋮----
function addSettlement(CrossChainAddress memory settlement) public virtual checkPermission {
⋮----
function removeSettlement(CrossChainAddress memory settlement) public virtual checkPermission {
⋮----
function setMaxVotingPower(uint256 maxVotingPower) public virtual checkPermission {
⋮----
function setMinInclusionVotingPower(uint256 minInclusionVotingPower) public virtual checkPermission {
⋮----
function setMaxValidatorsCount(uint208 maxValidatorsCount) public virtual checkPermission {
⋮----
function setRequiredKeyTags(uint8[] memory requiredKeyTags) public virtual checkPermission {
⋮----
function addQuorumThreshold(QuorumThreshold memory quorumThreshold) public virtual checkPermission {
⋮----
function removeQuorumThreshold(QuorumThreshold memory quorumThreshold) public virtual checkPermission {
⋮----
function setRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag) public virtual checkPermission {
⋮----
function setVerificationType(uint32 verificationType) public virtual checkPermission {
⋮----
function _setNumAggregators(uint208 numAggregators) internal virtual {
⋮----
function _setNumCommitters(uint208 numCommitters) internal virtual {
⋮----
function _addVotingPowerProvider(CrossChainAddress memory votingPowerProvider) internal virtual {
⋮----
function _removeVotingPowerProvider(CrossChainAddress memory votingPowerProvider) internal virtual {
⋮----
function _setKeysProvider(CrossChainAddress memory keysProvider) internal virtual {
⋮----
function _addSettlement(CrossChainAddress memory settlement) internal virtual {
⋮----
function _removeSettlement(CrossChainAddress memory settlement) internal virtual {
⋮----
function _setMaxVotingPower(uint256 maxVotingPower) internal virtual {
⋮----
function _setMinInclusionVotingPower(uint256 minInclusionVotingPower) internal virtual {
⋮----
function _setMaxValidatorsCount(uint208 maxValidatorsCount) internal virtual {
⋮----
function _setRequiredKeyTags(uint8[] memory requiredKeyTags) internal virtual {
⋮----
function _addQuorumThreshold(QuorumThreshold memory quorumThreshold) internal virtual {
⋮----
function _removeQuorumThreshold(QuorumThreshold memory quorumThreshold) internal virtual {
⋮----
function _setRequiredHeaderKeyTag(uint8 requiredHeaderKeyTag) internal virtual {
⋮----
function _setVerificationType(uint32 verificationType) internal virtual {
⋮----
function _validateCrossChainAddress(CrossChainAddress memory crossChainAddress) internal pure virtual {
⋮----
function _serializeCrossChainAddress(CrossChainAddress memory crossChainAddress)
⋮----
function _deserializeCrossChainAddress(bytes32 compressedAddress)
⋮----
function _serializeQuorumThreshold(QuorumThreshold memory quorumThreshold) internal pure virtual returns (bytes32) {
⋮----
function _deserializeQuorumThreshold(bytes32 compressedQuorumThreshold)
````
## File: src/modules/voting-power/base/VotingPowerCalcManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IVotingPowerCalcManager} from "../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
⋮----
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
⋮----
/// @title VotingPowerCalcManager
/// @notice Base contract for voting power calculations.
abstract contract VotingPowerCalcManager is Initializable, IVotingPowerCalcManager {
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
````
## File: src/modules/voting-power/common/voting-power-calc/libraries/ChainlinkPriceFeed.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Scaler} from "../../../../../libraries/utils/Scaler.sol";
⋮----
import {
AggregatorV3Interface
} from "../../../../../interfaces/modules/voting-power/common/voting-power-calc/libraries/AggregatorV3Interface.sol";
⋮----
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
⋮----
/**
* @title ChainlinkPriceFeed
* @notice Library for fetching prices from Chainlink in a historical manner.
* @dev It supports arbitrary aggregators' decimals, an arbitrary number of aggregator hops, and a possibility to invert prices.
* It supports most of Chainlink's aggregators through the whole history except the oldest ones not supporting `getRoundData()`.
*/
⋮----
/**
* @notice Reverts when the length is zero.
*/
⋮----
/**
* @notice Reverts when the lengths are not equal.
*/
⋮----
/**
* @notice The offset for the phase in the roundId.
*/
⋮----
/**
* @notice The number of decimals to normalize the price to.
*/
⋮----
/**
* @notice The data for a round.
* @param roundId The roundId (a concatenation of the phase and the original id).
* @param answer The price.
* @param startedAt The startedAt (deprecated).
* @param updatedAt The updatedAt (the timestamp when the round was updated).
* @param answeredInRound The answeredInRound (deprecated).
*/
⋮----
/**
* @notice Returns the price at a given timestamp using one or two hops.
* @param aggregators The price aggregators.
* @param timestamp The timestamp.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getPriceAt(
⋮----
/**
* @notice Returns the price at a given timestamp using one or more hops.
* @param aggregators The price aggregators.
* @param timestamp The timestamp.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
⋮----
/**
* @notice Returns the price at a given timestamp.
* @param aggregator The price aggregator.
* @param timestamp The timestamp.
* @param invert If to invert the fetched price.
* @param stalenessDuration The staleness duration (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getPriceAt(address aggregator, uint48 timestamp, bool invert, uint48 stalenessDuration)
⋮----
/**
* @notice Returns the price data at a given timestamp.
* @param aggregator The price aggregator.
* @param timestamp The timestamp.
* @param invert If to invert the fetched price.
* @param stalenessDuration The staleness duration (if too much time passed since the last update).
* @return success If the data is available and not stale.
* @return roundData The round data.
* @dev The answer is normalized to the 18 decimals.
*/
function getPriceDataAt(address aggregator, uint48 timestamp, bool invert, uint48 stalenessDuration)
⋮----
/**
* @notice Returns the round data at a given timestamp.
* @param aggregator The price aggregator.
* @param timestamp The timestamp.
* @return success If the data is available.
* @return roundData The round data.
*/
function getRoundDataAt(address aggregator, uint48 timestamp)
⋮----
// determine the latest phaseId
⋮----
// find a phaseId which contains a needed aggregatorRoundId given the timestamp
⋮----
// find the upper bound for further binary search
⋮----
// find the biggest roundId which which is less than or equal to the timestamp
⋮----
/**
* @notice Returns the round data at a given roundId.
* @param aggregator The price aggregator.
* @param roundId The roundId.
* @return success If the data is available.
* @return roundData The round data.
*/
function getRoundData(address aggregator, uint80 roundId) public view returns (bool, RoundData memory roundData) {
⋮----
/**
* @notice Returns the latest price using one or two hops.
* @param aggregators The price aggregators.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getLatestPrice(address[2] memory aggregators, bool[2] memory inverts, uint48[2] memory stalenessDurations)
⋮----
/**
* @notice Returns the latest price using one or more hops.
* @param aggregators The price aggregators.
* @param inverts If to invert the fetched prices.
* @param stalenessDurations The staleness durations (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getLatestPrice(address[] memory aggregators, bool[] memory inverts, uint48[] memory stalenessDurations)
⋮----
/**
* @notice Returns the latest price.
* @param aggregator The price aggregator.
* @param invert If to invert the fetched price.
* @param stalenessDuration The staleness duration (if too much time passed since the last update).
* @return The price.
* @dev Returns zero if the data is stale or unavailable.
* The price is normalized to the 18 decimals.
*/
function getLatestPrice(address aggregator, bool invert, uint48 stalenessDuration) public view returns (uint256) {
⋮----
/**
* @notice Returns the latest price data.
* @param aggregator The price aggregator.
* @param invert If to invert the fetched price.
* @param stalenessDuration The staleness duration (if too much time passed since the last update).
* @return success If the data is available and not stale.
* @return roundData The round data.
* @dev The answer is normalized to the 18 decimals.
*/
function getLatestPriceData(address aggregator, bool invert, uint48 stalenessDuration)
⋮----
/**
* @notice Returns the latest round data.
* @param aggregator The price aggregator.
* @return success If the data is available.
* @return roundData The round data.
*/
function getLatestRoundData(address aggregator) public view returns (bool, RoundData memory roundData) {
⋮----
/**
* @notice Returns if the round data is stale.
* @param timestamp The timestamp.
* @param roundData The round data.
* @param stalenessDuration The staleness duration (if too much time passed since the last update).
* @return If the round data is stale.
*/
function isStale(uint48 timestamp, RoundData memory roundData, uint48 stalenessDuration)
⋮----
function serializeIds(uint16 phase, uint64 originalId) public pure returns (uint80) {
⋮----
function deserializeIds(uint80 roundId) public pure returns (uint16, uint64) {
⋮----
function toDynamicArrays(
````
## File: src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerCalcManager} from "../../base/VotingPowerCalcManager.sol";
⋮----
import {
IEqualStakeVPCalc
} from "../../../../interfaces/modules/voting-power/common/voting-power-calc/IEqualStakeVPCalc.sol";
import {IVotingPowerCalcManager} from "../../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
⋮----
/// @title EqualStakeVPCalc
/// @notice Contract for calculating the voting power, making it equal to the stake.
abstract contract EqualStakeVPCalc is VotingPowerCalcManager, IEqualStakeVPCalc {
function __EqualStakeVPCalc_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(
address, /* vault */
⋮----
bytes memory, /* extraData */
uint48 /* timestamp */
⋮----
function stakeToVotingPower(
⋮----
bytes memory /* extraData */
````
## File: src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {EqualStakeVPCalc} from "./EqualStakeVPCalc.sol";
⋮----
import {Scaler} from "../../../../libraries/utils/Scaler.sol";
⋮----
import {
INormalizedTokenDecimalsVPCalc
} from "../../../../interfaces/modules/voting-power/common/voting-power-calc/INormalizedTokenDecimalsVPCalc.sol";
import {IVotingPowerCalcManager} from "../../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
⋮----
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
⋮----
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
⋮----
/// @title NormalizedTokenDecimalsVPCalc
/// @notice Contract for calculating the voting power, normalizing the stakes in different tokens to the same decimals.
abstract contract NormalizedTokenDecimalsVPCalc is EqualStakeVPCalc, INormalizedTokenDecimalsVPCalc {
⋮----
function __NormalizedTokenDecimalsVPCalc_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
⋮----
function _getCollateral(address vault) internal view virtual returns (address) {
⋮----
function _normalizeVaultTokenDecimals(address vault, uint256 votingPower) internal view virtual returns (uint256) {
````
## File: src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {NormalizedTokenDecimalsVPCalc} from "./NormalizedTokenDecimalsVPCalc.sol";
import {PermissionManager} from "../../../base/PermissionManager.sol";
⋮----
import {ChainlinkPriceFeed} from "./libraries/ChainlinkPriceFeed.sol";
import {Checkpoints} from "../../../../libraries/structs/Checkpoints.sol";
⋮----
import {
IPricedTokensChainlinkVPCalc
} from "../../../../interfaces/modules/voting-power/common/voting-power-calc/IPricedTokensChainlinkVPCalc.sol";
import {IVotingPowerCalcManager} from "../../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
⋮----
/// @title PricedTokensChainlinkVPCalc
/// @notice Contract for calculating the voting power, pricing the tokens using Chainlink.
abstract contract PricedTokensChainlinkVPCalc is
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.PricedTokensChainlinkVPCalc")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getPricedTokensChainlinkVPCalcStorage()
⋮----
function __PricedTokensChainlinkVPCalc_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IPricedTokensChainlinkVPCalc
function getTokenHopsAt(address token, uint48 timestamp)
⋮----
function getTokenHops(address token)
⋮----
function getTokenPriceAt(address token, uint48 timestamp) public view virtual override returns (uint256) {
⋮----
function getTokenPrice(address token) public view virtual override returns (uint256) {
⋮----
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
⋮----
function setTokenHops(
⋮----
function _setTokenHops(
⋮----
function _serializeHop(address aggregator, bool invert, uint48 stalenessDuration)
⋮----
function _serializeHops(address[2] memory aggregators, bool[2] memory inverts, uint48[2] memory stalenessDurations)
⋮----
function _deserializeHop(uint256 hop)
⋮----
function _deserializeHops(uint256[2] memory hops)
````
## File: src/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {NormalizedTokenDecimalsVPCalc} from "./NormalizedTokenDecimalsVPCalc.sol";
import {PermissionManager} from "../../../base/PermissionManager.sol";
⋮----
import {Checkpoints} from "../../../../libraries/structs/Checkpoints.sol";
⋮----
import {IVotingPowerCalcManager} from "../../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
import {
IWeightedTokensVPCalc
} from "../../../../interfaces/modules/voting-power/common/voting-power-calc/IWeightedTokensVPCalc.sol";
⋮----
/// @title WeightedTokensVPCalc
/// @notice Contract for calculating the voting power, weighting the tokens.
abstract contract WeightedTokensVPCalc is NormalizedTokenDecimalsVPCalc, PermissionManager, IWeightedTokensVPCalc {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.WeightedTokensVPCalc")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getWeightedTokensVPCalcStorage() internal pure returns (WeightedTokensVPCalcStorage storage $) {
⋮----
function __WeightedTokensVPCalc_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IWeightedTokensVPCalc
function getTokenWeightAt(address token, uint48 timestamp) public view virtual returns (uint208) {
⋮----
function getTokenWeight(address token) public view virtual returns (uint208) {
⋮----
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
⋮----
function setTokenWeight(address token, uint208 weight) public virtual checkPermission {
⋮----
function _setTokenWeight(address token, uint208 weight) internal virtual {
````
## File: src/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {EqualStakeVPCalc} from "./EqualStakeVPCalc.sol";
import {PermissionManager} from "../../../base/PermissionManager.sol";
⋮----
import {Checkpoints} from "../../../../libraries/structs/Checkpoints.sol";
⋮----
import {IVotingPowerCalcManager} from "../../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
import {
IWeightedVaultsVPCalc
} from "../../../../interfaces/modules/voting-power/common/voting-power-calc/IWeightedVaultsVPCalc.sol";
⋮----
/// @title WeightedVaultsVPCalc
/// @notice Contract for calculating the voting power, weighting the vaults.
abstract contract WeightedVaultsVPCalc is EqualStakeVPCalc, PermissionManager, IWeightedVaultsVPCalc {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.WeightedVaultsVPCalc")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getWeightedVaultsVPCalcStorage() internal pure returns (WeightedVaultsVPCalcStorage storage $) {
⋮----
function __WeightedVaultsVPCalc_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IWeightedVaultsVPCalc
function getVaultWeightAt(address vault, uint48 timestamp) public view virtual returns (uint208) {
⋮----
function getVaultWeight(address vault) public view virtual returns (uint208) {
⋮----
/// @inheritdoc IVotingPowerCalcManager
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
⋮----
function setVaultWeight(address vault, uint208 weight) public virtual checkPermission {
⋮----
function _setVaultWeight(address vault, uint208 weight) internal virtual {
````
## File: src/modules/voting-power/extensions/logic/BaseRewardsLogic.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IBaseRewards} from "../../../../interfaces/modules/voting-power/extensions/IBaseRewards.sol";
import {INetworkManager} from "../../../../interfaces/modules/base/INetworkManager.sol";
⋮----
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
⋮----
import {
IDefaultOperatorRewards
} from "@symbioticfi/rewards/src/interfaces/defaultOperatorRewards/IDefaultOperatorRewards.sol";
import {IStakerRewards} from "@symbioticfi/rewards/src/interfaces/stakerRewards/IStakerRewards.sol";
⋮----
/**
* @title BaseRewardsLogic
* @notice Library with bindings for distributing rewards to stakers and operators.
*/
⋮----
/**
* @notice Distributes staker rewards.
* @param stakerRewards The address of the staker rewards contract.
* @param token The address of the token to distribute.
* @param amount The amount of the token to distribute.
* @param data The data to pass to the staker rewards contract.
* @dev The funds should be transferred to this contract separately before the call.
*/
function distributeStakerRewards(address stakerRewards, address token, uint256 amount, bytes memory data) public {
⋮----
/**
* @notice Distributes operator rewards.
* @param operatorRewards The address of the operator rewards contract.
* @param token The address of the token to distribute.
* @param amount The amount of the token to distribute.
* @param root The root of the distribution Merkle tree.
* @dev The funds should be transferred to this contract separately before the call.
*/
function distributeOperatorRewards(address operatorRewards, address token, uint256 amount, bytes32 root) public {
````
## File: src/modules/voting-power/extensions/logic/BaseSlashingLogic.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProviderLogic} from "../../logic/VotingPowerProviderLogic.sol";
⋮----
import {IBaseSlashing} from "../../../../interfaces/modules/voting-power/extensions/IBaseSlashing.sol";
import {INetworkManager} from "../../../../interfaces/modules/base/INetworkManager.sol";
import {IVotingPowerProvider} from "../../../../interfaces/modules/voting-power/IVotingPowerProvider.sol";
⋮----
import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol";
import {ISlasher as IInstantSlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
⋮----
/**
* @title BaseSlashingLogic
* @notice Library with bindings for slashing vaults.
*/
⋮----
/**
* @notice Slashes a vault.
* @param timestamp The capture timestamp.
* @param vault The address of the vault to slash.
* @param operator The address of the operator to slash.
* @param amount The amount of the tokens to slash.
* @param hints The hints to optimize gas usage.
* @dev It checks if the slashing was required at the given capture timestamp,
* and if the slashing request is not stale regarding set `minEpochDuration`.
*/
function slashVault(uint48 timestamp, address vault, address operator, uint256 amount, bytes memory hints)
⋮----
/**
* @notice Slashes a vault.
* @param timestamp The capture timestamp.
* @param slasher The address of the slasher.
* @param operator The address of the operator to slash.
* @param amount The amount of the tokens to slash.
* @param hints The hints to optimize gas usage.
* @dev It checks if the slashing was required at the given capture timestamp,
* and if the slashing request is not stale regarding set `minEpochDuration`.
*/
function slash(uint48 timestamp, address slasher, address operator, uint256 amount, bytes memory hints)
⋮----
/**
* @notice Slashes a vault.
* @param timestamp The capture timestamp.
* @param slasher The address of the slasher.
* @param operator The address of the operator to slash.
* @param amount The amount of the tokens to slash.
* @param hints The hints to optimize gas usage.
*/
function slashUnsafe(uint48 timestamp, address slasher, address operator, uint256 amount, bytes memory hints)
⋮----
/**
* @notice Executes a slash request.
* @param vault The address of the vault.
* @param slashIndex The index of the slash request.
* @param hints The hints to optimize gas usage.
* @dev It checks if the slashing request is not stale regarding set `minEpochDuration`.
*/
function executeSlashVault(address vault, uint256 slashIndex, bytes memory hints)
⋮----
/**
* @notice Executes a slash request.
* @param slasher The address of the slasher.
* @param slashIndex The index of the slash request.
* @param hints The hints to optimize gas usage.
* @dev It checks if the slashing request is not stale regarding set `minEpochDuration`.
*/
function executeSlash(address slasher, uint256 slashIndex, bytes memory hints)
⋮----
/**
* @notice Executes a slash request.
* @param slasher The address of the slasher.
* @param slashIndex The index of the slash request.
* @param hints The hints to optimize gas usage.
*/
function executeSlashUnsafe(address slasher, uint256 slashIndex, bytes memory hints)
````
## File: src/modules/voting-power/extensions/logic/OpNetVaultAutoDeployLogic.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {INetworkManager} from "../../../../interfaces/modules/base/INetworkManager.sol";
import {IOpNetVaultAutoDeploy} from "../../../../interfaces/modules/voting-power/extensions/IOpNetVaultAutoDeploy.sol";
import {IVotingPowerProvider} from "../../../../interfaces/modules/voting-power/IVotingPowerProvider.sol";
⋮----
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {
IOperatorNetworkSpecificDelegator
} from "@symbioticfi/core/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol";
import {ISlasher} from "@symbioticfi/core/src/interfaces/slasher/ISlasher.sol";
import {IVaultConfigurator} from "@symbioticfi/core/src/interfaces/IVaultConfigurator.sol";
import {IVaultTokenized} from "@symbioticfi/core/src/interfaces/vault/IVaultTokenized.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
⋮----
/**
* @title OpNetVaultAutoDeployLogic
* @notice Library for auto-deploying vaults.
*/
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.OpNetVaultAutoDeploy")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getOpNetVaultAutoDeployStorage()
⋮----
function initialize(IOpNetVaultAutoDeploy.OpNetVaultAutoDeployInitParams memory initParams) public {
⋮----
function isAutoDeployEnabled() public view returns (bool) {
⋮----
function getAutoDeployedVault(address operator) public view returns (address) {
⋮----
function getAutoDeployConfig() public view returns (IOpNetVaultAutoDeploy.AutoDeployConfig memory) {
⋮----
function isSetMaxNetworkLimitHookEnabled() public view returns (bool) {
⋮----
function setAutoDeployStatus(bool status) public {
⋮----
function setAutoDeployConfig(IOpNetVaultAutoDeploy.AutoDeployConfig memory config) public {
⋮----
function setSetMaxNetworkLimitHookStatus(bool status) public {
⋮----
function createVault(address operator) public returns (address vault, address delegator, address slasher) {
⋮----
function setAutoDeployedVault(address operator, address vault) public {
⋮----
function getVaultParams(IOpNetVaultAutoDeploy.AutoDeployConfig memory config)
⋮----
function getDelegatorParams(
IOpNetVaultAutoDeploy.AutoDeployConfig memory, /* config */
⋮----
function getSlasherParams(IOpNetVaultAutoDeploy.AutoDeployConfig memory config)
⋮----
function _validateConfig(IOpNetVaultAutoDeploy.AutoDeployConfig memory config) public view {
⋮----
// ------------------------------------ HELPER FUNCTIONS ------------------------------------
⋮----
/**
* @notice Gets the encoded base vault params.
* @param params The vault params.
* @return version The version of the vault.
* @return params The encoded base vault params.
*/
function getVaultParams(IVault.InitParams memory params) public view returns (uint64, bytes memory) {
⋮----
/**
* @notice Gets the encoded tokenized vault params.
* @param baseParams The base vault params.
* @param name The name of the tokenized vault.
* @param symbol The symbol of the tokenized vault.
* @return version The version of the vault.
* @return params The encoded tokenized vault params.
*/
function getVaultTokenizedParams(IVault.InitParams memory baseParams, string memory name, string memory symbol)
⋮----
/**
* @notice Gets the encoded operator-network-specific delegator params.
* @param operator The operator.
* @param defaultAdminRoleHolder The default admin role holder.
* @param hook The hook.
* @param hookSetRoleHolder The hook set role holder.
* @return version The version of the delegator.
* @return params The encoded operator-network-specific delegator params.
*/
function getOperatorNetworkSpecificDelegatorParams(
⋮----
/**
* @notice Gets the encoded instant slasher params.
* @param isBurnerHook If the burner needs a hook call.
* @return version The version of the slasher.
* @return params The encoded instant slasher params.
*/
function getSlasherParams(bool isBurnerHook) public view returns (uint64, bytes memory) {
⋮----
/**
* @notice Gets the encoded veto slasher params.
* @param isBurnerHook If the burner needs a hook call.
* @param vetoDuration The veto duration.
* @param resolverSetEpochsDelay The delay in epochs for a resolver to be set.
* @return version The version of the slasher.
* @return params The encoded veto slasher params.
*/
function getVetoSlasherParams(bool isBurnerHook, uint48 vetoDuration, uint256 resolverSetEpochsDelay)
⋮----
/**
* @notice Creates a vault.
* @param version The version of the vault.
* @param owner The owner of the vault.
* @param vaultParams The vault params.
* @param delegatorIndex The index of the delegator.
* @param delegatorParams The delegator params.
* @param withSlasher If the vault should have a slasher.
* @param slasherIndex The index of the slasher.
* @param slasherParams The slasher params.
* @return vault The address of the vault.
* @return delegator The address of the delegator.
* @return slasher The address of the slasher.
*/
function createVault(
````
## File: src/modules/voting-power/extensions/BaseRewards.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {BaseRewardsLogic} from "./logic/BaseRewardsLogic.sol";
⋮----
import {IBaseRewards} from "../../../interfaces/modules/voting-power/extensions/IBaseRewards.sol";
⋮----
/// @title BaseRewards
/// @notice Base contract for distributing rewards to stakers and operators.
abstract contract BaseRewards is VotingPowerProvider, IBaseRewards {
modifier onlyRewarder() {
⋮----
function _checkRewarder() internal view virtual {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.BaseRewards")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getBaseRewardsStorage() internal pure returns (IBaseRewards.BaseRewardsStorage storage $) {
⋮----
function __BaseRewards_init(BaseRewardsInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc IBaseRewards
function getRewarder() public view virtual returns (address) {
⋮----
function distributeStakerRewards(address stakerRewards, address token, uint256 amount, bytes memory data)
⋮----
function distributeOperatorRewards(address operatorRewards, address token, uint256 amount, bytes32 root)
⋮----
function setRewarder(address rewarder) public virtual checkPermission {
⋮----
function _setRewarder(address rewarder) internal virtual {
````
## File: src/modules/voting-power/extensions/BaseSlashing.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {BaseSlashingLogic} from "./logic/BaseSlashingLogic.sol";
⋮----
import {IBaseSlashing} from "../../../interfaces/modules/voting-power/extensions/IBaseSlashing.sol";
⋮----
/// @title BaseSlashing
/// @notice Base contract for slashing vaults.
abstract contract BaseSlashing is VotingPowerProvider, IBaseSlashing {
modifier onlySlasher() {
⋮----
function _checkSlasher() internal view virtual {
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.BaseSlashing")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getBaseSlashingStorage() internal pure returns (IBaseSlashing.BaseSlashingStorage storage $) {
⋮----
function __BaseSlashing_init(BaseSlashingInitParams memory initParams) internal virtual onlyInitializing {
⋮----
/// @inheritdoc IBaseSlashing
function getSlasher() public view virtual returns (address) {
⋮----
function slashVault(uint48 timestamp, address vault, address operator, uint256 amount, bytes memory hints)
⋮----
function executeSlashVault(address vault, uint256 slashIndex, bytes memory hints)
⋮----
function setSlasher(address slasher) public virtual checkPermission {
⋮----
function _setSlasher(address slasher) internal virtual {
````
## File: src/modules/voting-power/extensions/MultiToken.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {IMultiToken} from "../../../interfaces/modules/voting-power/extensions/IMultiToken.sol";
⋮----
/// @title MultiToken
/// @notice Contract for registering and unregistering multiple tokens.
abstract contract MultiToken is VotingPowerProvider, IMultiToken {
function __MultiToken_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IMultiToken
function registerToken(address token) public virtual checkPermission {
⋮----
function unregisterToken(address token) public virtual checkPermission {
````
## File: src/modules/voting-power/extensions/OperatorsBlacklist.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {IOperatorsBlacklist} from "../../../interfaces/modules/voting-power/extensions/IOperatorsBlacklist.sol";
⋮----
/// @title OperatorsBlacklist
/// @notice Contract for blacklisting operators.
abstract contract OperatorsBlacklist is VotingPowerProvider, IOperatorsBlacklist {
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.OperatorsBlacklist")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getOperatorsBlacklistStorage() internal pure returns (OperatorsBlacklistStorage storage $) {
⋮----
function __OperatorsBlacklist_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IOperatorsBlacklist
function isOperatorBlacklisted(address operator) public view virtual returns (bool) {
⋮----
function blacklistOperator(address operator) public virtual checkPermission {
⋮----
function unblacklistOperator(address operator) public virtual checkPermission {
⋮----
function _registerOperatorImpl(address operator) internal virtual override {
````
## File: src/modules/voting-power/extensions/OperatorsJail.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {IOperatorsJail} from "../../../interfaces/modules/voting-power/extensions/IOperatorsJail.sol";
⋮----
/// @title OperatorsJail
/// @notice Contract for jailing (unregistering and not allowing to register) operators for a given duration.
abstract contract OperatorsJail is VotingPowerProvider, IOperatorsJail {
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.OperatorsJail")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getOperatorsJailStorage() internal pure returns (OperatorsJailStorage storage $) {
⋮----
function __OperatorsJail_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IOperatorsJail
function isOperatorJailed(address operator) public view virtual returns (bool) {
⋮----
function getOperatorJailedUntil(address operator) public view virtual returns (uint48) {
⋮----
function jailOperator(address operator, uint48 duration) public virtual checkPermission {
⋮----
function unjailOperator(address operator) public virtual checkPermission {
⋮----
function _registerOperatorImpl(address operator) internal virtual override {
````
## File: src/modules/voting-power/extensions/OperatorsWhitelist.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {IOperatorsWhitelist} from "../../../interfaces/modules/voting-power/extensions/IOperatorsWhitelist.sol";
⋮----
/// @title OperatorsWhitelist
/// @notice Contract for whitelisting operators.
abstract contract OperatorsWhitelist is VotingPowerProvider, IOperatorsWhitelist {
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.OperatorsWhitelist")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getOperatorsWhitelistStorage() internal pure returns (OperatorsWhitelistStorage storage $) {
⋮----
function __OperatorsWhitelist_init(OperatorsWhitelistInitParams memory initParams)
⋮----
/// @inheritdoc IOperatorsWhitelist
function isWhitelistEnabled() public view virtual returns (bool) {
⋮----
function isOperatorWhitelisted(address operator) public view virtual returns (bool) {
⋮----
function setWhitelistStatus(bool status) public virtual checkPermission {
⋮----
function whitelistOperator(address operator) public virtual checkPermission {
⋮----
function unwhitelistOperator(address operator) public virtual checkPermission {
⋮----
function _registerOperatorImpl(address operator) internal virtual override {
⋮----
function _setWhitelistStatus(bool status) internal virtual {
````
## File: src/modules/voting-power/extensions/OperatorVaults.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {IOperatorVaults} from "../../../interfaces/modules/voting-power/extensions/IOperatorVaults.sol";
⋮----
/// @title OperatorVaults
/// @notice Contract for registering and unregistering operator vaults.
abstract contract OperatorVaults is VotingPowerProvider, IOperatorVaults {
function __OperatorVaults_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc IOperatorVaults
function registerOperatorVault(address operator, address vault) public virtual checkPermission {
⋮----
function unregisterOperatorVault(address operator, address vault) public virtual checkPermission {
⋮----
function unregisterOperatorVault(address vault) public virtual {
````
## File: src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {OpNetVaultAutoDeployLogic} from "./logic/OpNetVaultAutoDeployLogic.sol";
⋮----
import {IOpNetVaultAutoDeploy} from "../../../interfaces/modules/voting-power/extensions/IOpNetVaultAutoDeploy.sol";
⋮----
import {ISetMaxNetworkLimitHook} from "@symbioticfi/network/src/interfaces/ISetMaxNetworkLimitHook.sol";
⋮----
/// @title OpNetVaultAutoDeploy
/// @notice Contract for auto-deploying vaults for operators on their registration.
abstract contract OpNetVaultAutoDeploy is VotingPowerProvider, IOpNetVaultAutoDeploy {
/// @inheritdoc IOpNetVaultAutoDeploy
⋮----
/// @dev Must be called after __VotingPowerProvider_init().
function __OpNetVaultAutoDeploy_init(OpNetVaultAutoDeployInitParams memory initParams)
⋮----
function isAutoDeployEnabled() public view virtual returns (bool) {
⋮----
function getAutoDeployedVault(address operator) public view virtual returns (address) {
⋮----
function getAutoDeployConfig() public view virtual returns (AutoDeployConfig memory) {
⋮----
function isSetMaxNetworkLimitHookEnabled() public view virtual returns (bool) {
⋮----
function setAutoDeployStatus(bool status) public virtual checkPermission {
⋮----
function setAutoDeployConfig(AutoDeployConfig memory config) public virtual checkPermission {
⋮----
function setSetMaxNetworkLimitHookStatus(bool status) public virtual checkPermission {
⋮----
function _registerOperatorImpl(address operator) internal virtual override {
⋮----
function _unregisterOperatorVaultImpl(address operator, address vault) internal virtual override {
````
## File: src/modules/voting-power/extensions/SharedVaults.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {VotingPowerProvider} from "../VotingPowerProvider.sol";
⋮----
import {ISharedVaults} from "../../../interfaces/modules/voting-power/extensions/ISharedVaults.sol";
⋮----
/// @title SharedVaults
/// @notice Contract for registering and unregistering shared vaults.
abstract contract SharedVaults is VotingPowerProvider, ISharedVaults {
function __SharedVaults_init() internal virtual onlyInitializing {}
⋮----
/// @inheritdoc ISharedVaults
function registerSharedVault(address sharedVault) public virtual checkPermission {
⋮----
function unregisterSharedVault(address sharedVault) public virtual checkPermission {
````
## File: src/modules/voting-power/logic/VotingPowerProviderLogic.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Checkpoints} from "../../../libraries/structs/Checkpoints.sol";
import {InputNormalizer} from "../../../libraries/utils/InputNormalizer.sol";
import {PersistentSet} from "../../../libraries/structs/PersistentSet.sol";
⋮----
import {INetworkManager} from "../../../interfaces/modules/base/INetworkManager.sol";
import {IVotingPowerCalcManager} from "../../../interfaces/modules/voting-power/base/IVotingPowerCalcManager.sol";
import {IVotingPowerProvider} from "../../../interfaces/modules/voting-power/IVotingPowerProvider.sol";
⋮----
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
import {IEntity} from "@symbioticfi/core/src/interfaces/common/IEntity.sol";
import {
IOperatorNetworkSpecificDelegator
} from "@symbioticfi/core/src/interfaces/delegator/IOperatorNetworkSpecificDelegator.sol";
import {IOperatorSpecificDelegator} from "@symbioticfi/core/src/interfaces/delegator/IOperatorSpecificDelegator.sol";
import {IRegistry} from "@symbioticfi/core/src/interfaces/common/IRegistry.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IVetoSlasher} from "@symbioticfi/core/src/interfaces/slasher/IVetoSlasher.sol";
⋮----
/**
* @title VotingPowerProviderLogic
* @notice Library-logic of the voting power provider contract.
*/
⋮----
// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.VotingPowerProvider")) - 1)) & ~bytes32(uint256(0xff))
⋮----
function _getVotingPowerProviderStorage()
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory initParams) public {
⋮----
function getSlashingDataAt(uint48 timestamp, bytes memory hint) public view returns (bool, uint48) {
⋮----
function getSlashingData() public view returns (bool, uint48) {
⋮----
function isTokenRegisteredAt(address token, uint48 timestamp) public view returns (bool) {
⋮----
function isTokenRegistered(address token) public view returns (bool) {
⋮----
function getTokensAt(uint48 timestamp) public view returns (address[] memory) {
⋮----
function getTokens() public view returns (address[] memory) {
⋮----
function getTokensLength() public view returns (uint256) {
⋮----
function isOperatorRegisteredAt(address operator, uint48 timestamp) public view returns (bool) {
⋮----
function isOperatorRegistered(address operator) public view returns (bool) {
⋮----
function getOperatorsAt(uint48 timestamp) public view returns (address[] memory) {
⋮----
function getOperators() public view returns (address[] memory) {
⋮----
function getOperatorsLength() public view returns (uint256) {
⋮----
function isSharedVaultRegisteredAt(address vault, uint48 timestamp) public view returns (bool) {
⋮----
function isSharedVaultRegistered(address vault) public view returns (bool) {
⋮----
function getSharedVaultsAt(uint48 timestamp) public view returns (address[] memory) {
⋮----
function getSharedVaults() public view returns (address[] memory) {
⋮----
function getSharedVaultsLength() public view returns (uint256) {
⋮----
function isOperatorVaultRegisteredAt(address vault, uint48 timestamp) public view returns (bool) {
⋮----
function isOperatorVaultRegistered(address vault) public view returns (bool) {
⋮----
function isOperatorVaultRegisteredAt(address operator, address vault, uint48 timestamp) public view returns (bool) {
⋮----
function isOperatorVaultRegistered(address operator, address vault) public view returns (bool) {
⋮----
function getOperatorVaultsAt(address operator, uint48 timestamp) public view returns (address[] memory) {
⋮----
function getOperatorVaults(address operator) public view returns (address[] memory) {
⋮----
function getOperatorVaultsLength(address operator) public view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) public view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) public view returns (uint256) {
⋮----
function getOperatorStakesAt(address operator, uint48 timestamp)
⋮----
function getOperatorStakes(address operator)
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function getOperatorVotingPowersAt(address operator, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPowers(address operator, bytes memory extraData)
⋮----
function getVotingPowersAt(bytes[] memory extraData, uint48 timestamp)
⋮----
function getVotingPowers(bytes[] memory extraData)
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) public {
⋮----
function registerToken(address token) public {
⋮----
function unregisterToken(address token) public {
⋮----
function registerOperator(address operator) public {
⋮----
function unregisterOperator(address operator) public {
⋮----
function registerSharedVault(address vault) public {
⋮----
function registerOperatorVault(address operator, address vault) public {
⋮----
function unregisterSharedVault(address vault) public {
⋮----
function unregisterOperatorVault(address operator, address vault) public {
⋮----
function serializeSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) public pure returns (uint208) {
⋮----
function deserializeSlashingData(uint208 slashingData) public pure returns (bool, uint48) {
⋮----
function _validateOperator(address operator) public view returns (bool) {
⋮----
function _validateVault(address vault) public view returns (bool) {
⋮----
function _validateSharedVault(address vault) public view returns (bool) {
⋮----
function _validateOperatorVault(address operator, address vault) public view returns (bool) {
⋮----
function _validateVaultSlashing(address vault) public view returns (bool) {
````
## File: src/modules/voting-power/VotingPowerProvider.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {NetworkManager} from "../base/NetworkManager.sol";
import {OzEIP712} from "../base/OzEIP712.sol";
import {PermissionManager} from "../base/PermissionManager.sol";
import {VotingPowerCalcManager} from "./base/VotingPowerCalcManager.sol";
⋮----
import {VotingPowerProviderLogic} from "./logic/VotingPowerProviderLogic.sol";
⋮----
import {IVotingPowerProvider} from "../../interfaces/modules/voting-power/IVotingPowerProvider.sol";
⋮----
import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
import {NoncesUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
⋮----
/// @title VotingPowerProvider
/// @notice Contract for managing tokens, operators, vaults, and their voting powers.
abstract contract VotingPowerProvider is
⋮----
/// @inheritdoc IVotingPowerProvider
⋮----
function __VotingPowerProvider_init(VotingPowerProviderInitParams memory votingPowerProviderInitParams)
⋮----
function getSlashingDataAt(uint48 timestamp, bytes memory hint) public view virtual returns (bool, uint48) {
⋮----
function getSlashingData() public view virtual returns (bool, uint48) {
⋮----
function isTokenRegisteredAt(address token, uint48 timestamp) public view virtual returns (bool) {
⋮----
function isTokenRegistered(address token) public view virtual returns (bool) {
⋮----
function getTokensAt(uint48 timestamp) public view virtual returns (address[] memory) {
⋮----
function getTokens() public view virtual returns (address[] memory) {
⋮----
function isOperatorRegisteredAt(address operator, uint48 timestamp) public view virtual returns (bool) {
⋮----
function isOperatorRegistered(address operator) public view virtual returns (bool) {
⋮----
function getOperatorsAt(uint48 timestamp) public view virtual returns (address[] memory) {
⋮----
function getOperators() public view virtual returns (address[] memory) {
⋮----
function isSharedVaultRegisteredAt(address vault, uint48 timestamp) public view virtual returns (bool) {
⋮----
function isSharedVaultRegistered(address vault) public view virtual returns (bool) {
⋮----
function getSharedVaultsAt(uint48 timestamp) public view virtual returns (address[] memory) {
⋮----
function getSharedVaults() public view virtual returns (address[] memory) {
⋮----
function isOperatorVaultRegisteredAt(address vault, uint48 timestamp) public view virtual returns (bool) {
⋮----
function isOperatorVaultRegistered(address vault) public view virtual returns (bool) {
⋮----
function isOperatorVaultRegisteredAt(address operator, address vault, uint48 timestamp)
⋮----
function isOperatorVaultRegistered(address operator, address vault) public view virtual returns (bool) {
⋮----
function getOperatorVaultsAt(address operator, uint48 timestamp) public view virtual returns (address[] memory) {
⋮----
function getOperatorVaults(address operator) public view virtual returns (address[] memory) {
⋮----
function getOperatorStakesAt(address operator, uint48 timestamp) public view virtual returns (VaultValue[] memory) {
⋮----
function getOperatorStakes(address operator) public view virtual returns (VaultValue[] memory) {
⋮----
function getOperatorVotingPowersAt(address operator, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPowers(address operator, bytes memory extraData)
⋮----
function getVotingPowersAt(bytes[] memory extraData, uint48 timestamp)
⋮----
function getVotingPowers(bytes[] memory extraData) public view virtual returns (OperatorVotingPower[] memory) {
⋮----
/// @dev Returns the length of the tokens.
function _getTokensLength() internal view virtual returns (uint256) {
⋮----
/// @dev Returns the length of the operators.
function _getOperatorsLength() internal view virtual returns (uint256) {
⋮----
/// @dev Returns the length of the shared vaults.
function _getSharedVaultsLength() internal view virtual returns (uint256) {
⋮----
/// @dev Returns the length of the operator vaults.
function _getOperatorVaultsLength(address operator) internal view virtual returns (uint256) {
⋮----
/// @dev Returns the stake of the operator at a specific timestamp.
function _getOperatorStakeAt(address operator, address vault, uint48 timestamp)
⋮----
/// @dev Returns the stake of the operator.
function _getOperatorStake(address operator, address vault) internal view virtual returns (uint256) {
⋮----
/// @dev Returns the voting power of the operator at a specific timestamp.
function _getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
/// @dev Returns the voting power of the operator.
function _getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator() public virtual {
⋮----
function registerOperatorWithSignature(address operator, bytes memory signature) public virtual {
⋮----
function unregisterOperator() public virtual {
⋮----
function unregisterOperatorWithSignature(address operator, bytes memory signature) public virtual {
⋮----
function invalidateOldSignatures() public virtual {
⋮----
function _setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) internal virtual {
⋮----
function _registerToken(address token) internal virtual {
⋮----
function _unregisterToken(address token) internal virtual {
⋮----
function _registerOperator(address operator) internal virtual {
⋮----
function _unregisterOperator(address operator) internal virtual {
⋮----
function _registerSharedVault(address vault) internal virtual {
⋮----
function _registerOperatorVault(address operator, address vault) internal virtual {
⋮----
function _unregisterSharedVault(address vault) internal virtual {
⋮----
function _unregisterOperatorVault(address operator, address vault) internal virtual {
⋮----
function _registerOperatorImpl(address operator) internal virtual {
⋮----
function _unregisterOperatorImpl(address operator) internal virtual {
⋮----
function _registerOperatorVaultImpl(address operator, address vault) internal virtual {
⋮----
function _unregisterOperatorVaultImpl(address operator, address vault) internal virtual {
⋮----
function _verifyEIP712(address operator, bytes32 structHash, bytes memory signature) internal view {
````
## File: test/data/zk/Verifier_10.sol
````
// SPDX-License-Identifier: MIT
⋮----
/// @title Groth16 verifier template.
/// @author Remco Bloemen
/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed
/// (256 bytes) and compressed (128 bytes) format. A view function is provided
/// to compress proofs.
/// @notice See for further explanation.
contract Verifier {
/// Some of the provided public input values are larger than the field modulus.
/// @dev Public input elements are not automatically reduced, as this is can be
/// a dangerous source of bugs.
⋮----
/// The proof is invalid.
/// @dev This can mean that provided Groth16 proof points are not on their
/// curves, that pairing equation fails, or that the proof is not for the
/// provided public input.
⋮----
/// The commitment is invalid
/// @dev This can mean that provided commitment points and/or proof of knowledge are not on their
/// curves, that pairing equation fails, or that the commitment and/or proof of knowledge is not for the
/// commitment key.
⋮----
// Addresses of precompiles
⋮----
// Base field Fp order P and scalar field Fr order R.
// For BN254 these are computed as follows:
// t = 4965661367192848881
// P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1
// R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1
⋮----
// Extension field Fp2 = Fp[i] / (i² + 1)
// Note: This is the complex extension field of Fp with i² = -1.
// Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i.
// Note: The order of Fp2 elements is *opposite* that of the pairing contract, which
// expects Fp2 elements in order (a₁, a₀). This is also the order in which
// Fp2 elements are encoded in the public interface as this became convention.
⋮----
// Constants in Fp
⋮----
// Exponents for inversions and square roots mod P
uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2
uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4;
⋮----
// Groth16 alpha point in G1
⋮----
// Groth16 beta point in G2 in powers of i
⋮----
// Groth16 gamma point in G2 in powers of i
⋮----
// Groth16 delta point in G2 in powers of i
⋮----
// Pedersen G point in G2 in powers of i
⋮----
// Pedersen GSigmaNeg point in G2 in powers of i
⋮----
// Constant and public input points
⋮----
/// Negation in Fp.
/// @notice Returns a number x such that a + x = 0 in Fp.
/// @notice The input does not need to be reduced.
/// @param a the base
/// @return x the result
function negate(uint256 a) internal pure returns (uint256 x) {
⋮----
x = (P - (a % P)) % P; // Modulo is cheaper than branching
⋮----
/// Exponentiation in Fp.
/// @notice Returns a number x such that a ^ e = x in Fp.
⋮----
/// @param e the exponent
⋮----
function exp(uint256 a, uint256 e) internal view returns (uint256 x) {
⋮----
// Exponentiation failed.
// Should not happen.
⋮----
/// Invertsion in Fp.
/// @notice Returns a number x such that a * x = 1 in Fp.
⋮----
/// @notice Reverts with ProofInvalid() if the inverse does not exist
/// @param a the input
/// @return x the solution
function invert_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Inverse does not exist.
// Can only happen during G2 point decompression.
⋮----
/// Square root in Fp.
/// @notice Returns a number x such that x * x = a in Fp.
/// @notice Will revert with InvalidProof() if the input is not a square
/// or not reduced.
/// @param a the square
⋮----
function sqrt_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Square root does not exist or a is not reduced.
// Happens when G1 point is not on curve.
⋮----
/// Square test in Fp.
/// @notice Returns whether a number x exists such that x * x = a in Fp.
⋮----
function isSquare_Fp(uint256 a) internal view returns (bool) {
⋮----
/// Square root in Fp2.
/// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is
/// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i.
/// @notice Will revert with InvalidProof() if
/// * the input is not a square,
/// * the hint is incorrect, or
/// * the input coefficients are not reduced.
/// @param a0 The real part of the input.
/// @param a1 The imaginary part of the input.
/// @param hint A hint which of two possible signs to pick in the equation.
/// @return x0 The real part of the square root.
/// @return x1 The imaginary part of the square root.
function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) {
// If this square root reverts there is no solution in Fp2.
⋮----
// Check result to make sure we found a root.
// Note: this also fails if a0 or a1 is not reduced.
⋮----
/// Compress a G1 point.
/// @notice Reverts with InvalidProof if the coordinates are not reduced
/// or if the point is not on the curve.
/// @notice The point at infinity is encoded as (0,0) and compressed to 0.
/// @param x The X coordinate in Fp.
/// @param y The Y coordinate in Fp.
/// @return c The compresed point (x with one signal bit).
function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) {
⋮----
// G1 point not in field.
⋮----
// Point at infinity
⋮----
// Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid.
⋮----
// G1 point not on curve.
⋮----
/// Decompress a G1 point.
/// @notice Reverts with InvalidProof if the input does not represent a valid point.
⋮----
/// @param c The compresed point (x with one signal bit).
/// @return x The X coordinate in Fp.
/// @return y The Y coordinate in Fp.
function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) {
// Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square.
// so we can use it to represent the point at infinity.
⋮----
// Point at infinity as encoded in EIP196 and EIP197.
⋮----
// G1 x coordinate not in field.
⋮----
// Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore
// y can not be zero.
// Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve.
⋮----
/// Compress a G2 point.
/// @notice Reverts with InvalidProof if the coefficients are not reduced
⋮----
/// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1)
/// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i).
/// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0).
/// @param x0 The real part of the X coordinate.
/// @param x1 The imaginary poart of the X coordinate.
/// @param y0 The real part of the Y coordinate.
/// @param y1 The imaginary part of the Y coordinate.
/// @return c0 The first half of the compresed point (x0 with two signal bits).
/// @return c1 The second half of the compressed point (x1 unmodified).
function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1)
⋮----
// G2 point not in field.
⋮----
// Compute y^2
// Note: shadowing variables and scoping to avoid stack-to-deep.
⋮----
// Determine hint bit
// If this sqrt fails the x coordinate is not on the curve.
⋮----
// Recover y
⋮----
/// Decompress a G2 point.
⋮----
/// @param c0 The first half of the compresed point (x0 with two signal bits).
/// @param c1 The second half of the compressed point (x1 unmodified).
/// @return x0 The real part of the X coordinate.
/// @return x1 The imaginary poart of the X coordinate.
/// @return y0 The real part of the Y coordinate.
/// @return y1 The imaginary part of the Y coordinate.
function decompress_g2(uint256 c0, uint256 c1)
⋮----
// Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square.
⋮----
// Point at infinity as encoded in EIP197.
⋮----
// G2 x0 or x1 coefficient not in field.
⋮----
// Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve.
// Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero.
// But y0 or y1 may still independently be zero.
⋮----
/// Compute the public input linear combination.
/// @notice Reverts with PublicInputNotInField if the input is not in the field.
/// @notice Computes the multi-scalar-multiplication of the public input
/// elements and the verification key including the constant term.
/// @param input The public inputs. These are elements of the scalar field Fr.
/// @param publicCommitments public inputs generated from pedersen commitments.
/// @param commitments The Pedersen commitments from the proof.
/// @return x The X coordinate of the resulting G1 point.
/// @return y The Y coordinate of the resulting G1 point.
function publicInputMSM(
⋮----
// Note: The ECMUL precompile does not reject unreduced values, so we check this.
// Note: Unrolling this loop does not cost much extra in code-size, the bulk of the
// code-size is in the PUB_ constants.
// ECMUL has input (x, y, scalar) and output (x', y').
// ECADD has input (x1, y1, x2, y2) and output (x', y').
// We reduce commitments(if any) with constants as the first point argument to ECADD.
// We call them such that ecmul output is already in the second point
// argument to ECADD so we can have a tight loop.
⋮----
// Either Public input not in field, or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
⋮----
/// Compress a proof.
/// @notice Will revert with InvalidProof if the curve points are invalid,
/// but does not verify the proof itself.
/// @param proof The uncompressed Groth16 proof. Elements are in the same order as for
/// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197.
/// @param commitments Pedersen commitments from the proof.
/// @param commitmentPok proof of knowledge for the Pedersen commitments.
/// @return compressed The compressed proof. Elements are in the same order as for
/// verifyCompressedProof. I.e. points (A, B, C) in compressed format.
/// @return compressedCommitments compressed Pedersen commitments from the proof.
/// @return compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
function compressProof(
⋮----
/// Verify a Groth16 proof with compressed points.
/// @notice Reverts with InvalidProof if the proof is invalid or
/// with PublicInputNotInField the public input is not reduced.
/// @notice There is no return value. If the function does not revert, the
/// proof was successfully verified.
/// @param compressedProof the points (A, B, C) in compressed format
/// matching the output of compressProof.
/// @param compressedCommitments compressed Pedersen commitments from the proof.
/// @param compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
/// @param input the public input field elements in the scalar field Fr.
/// Elements must be reduced.
function verifyCompressedProof(
⋮----
// Commitments
⋮----
// Verify pedersen commitments
⋮----
// Verify the pairing
// Note: The precompile expects the F2 coefficients in big-endian order.
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
// e(A, B)
⋮----
// e(C, -δ)
⋮----
// e(α, -β)
⋮----
// e(L_pub, -γ)
⋮----
// Check pairing equation.
⋮----
// Either proof or verification key invalid.
⋮----
/// Verify an uncompressed Groth16 proof.
⋮----
/// @param proof the points (A, B, C) in EIP-197 format matching the output
/// of compressProof.
/// @param commitments the Pedersen commitments from the proof.
/// @param commitmentPok the proof of knowledge for the Pedersen commitments.
⋮----
function verifyProof(
⋮----
// HashToField
⋮----
calldatacopy(f, commitments, 0x40) // Copy Commitments
⋮----
let f := mload(0x40) // Free memory pointer.
⋮----
// Copy points (A, B, C) to memory. They are already in correct encoding.
// This is pairing e(A, B) and G1 of e(C, -δ).
⋮----
// Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory.
// OPT: This could be better done using a single codecopy, but
// Solidity (unlike standalone Yul) doesn't provide a way to
// to do this.
⋮----
// Also check returned value (both are either 1 or 0).
````
## File: test/data/zk/Verifier_100.sol
````
// SPDX-License-Identifier: MIT
⋮----
/// @title Groth16 verifier template.
/// @author Remco Bloemen
/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed
/// (256 bytes) and compressed (128 bytes) format. A view function is provided
/// to compress proofs.
/// @notice See for further explanation.
contract Verifier {
/// Some of the provided public input values are larger than the field modulus.
/// @dev Public input elements are not automatically reduced, as this is can be
/// a dangerous source of bugs.
⋮----
/// The proof is invalid.
/// @dev This can mean that provided Groth16 proof points are not on their
/// curves, that pairing equation fails, or that the proof is not for the
/// provided public input.
⋮----
/// The commitment is invalid
/// @dev This can mean that provided commitment points and/or proof of knowledge are not on their
/// curves, that pairing equation fails, or that the commitment and/or proof of knowledge is not for the
/// commitment key.
⋮----
// Addresses of precompiles
⋮----
// Base field Fp order P and scalar field Fr order R.
// For BN254 these are computed as follows:
// t = 4965661367192848881
// P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1
// R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1
⋮----
// Extension field Fp2 = Fp[i] / (i² + 1)
// Note: This is the complex extension field of Fp with i² = -1.
// Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i.
// Note: The order of Fp2 elements is *opposite* that of the pairing contract, which
// expects Fp2 elements in order (a₁, a₀). This is also the order in which
// Fp2 elements are encoded in the public interface as this became convention.
⋮----
// Constants in Fp
⋮----
// Exponents for inversions and square roots mod P
uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2
uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4;
⋮----
// Groth16 alpha point in G1
⋮----
// Groth16 beta point in G2 in powers of i
⋮----
// Groth16 gamma point in G2 in powers of i
⋮----
// Groth16 delta point in G2 in powers of i
⋮----
// Pedersen G point in G2 in powers of i
⋮----
// Pedersen GSigmaNeg point in G2 in powers of i
⋮----
// Constant and public input points
⋮----
/// Negation in Fp.
/// @notice Returns a number x such that a + x = 0 in Fp.
/// @notice The input does not need to be reduced.
/// @param a the base
/// @return x the result
function negate(uint256 a) internal pure returns (uint256 x) {
⋮----
x = (P - (a % P)) % P; // Modulo is cheaper than branching
⋮----
/// Exponentiation in Fp.
/// @notice Returns a number x such that a ^ e = x in Fp.
⋮----
/// @param e the exponent
⋮----
function exp(uint256 a, uint256 e) internal view returns (uint256 x) {
⋮----
// Exponentiation failed.
// Should not happen.
⋮----
/// Invertsion in Fp.
/// @notice Returns a number x such that a * x = 1 in Fp.
⋮----
/// @notice Reverts with ProofInvalid() if the inverse does not exist
/// @param a the input
/// @return x the solution
function invert_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Inverse does not exist.
// Can only happen during G2 point decompression.
⋮----
/// Square root in Fp.
/// @notice Returns a number x such that x * x = a in Fp.
/// @notice Will revert with InvalidProof() if the input is not a square
/// or not reduced.
/// @param a the square
⋮----
function sqrt_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Square root does not exist or a is not reduced.
// Happens when G1 point is not on curve.
⋮----
/// Square test in Fp.
/// @notice Returns whether a number x exists such that x * x = a in Fp.
⋮----
function isSquare_Fp(uint256 a) internal view returns (bool) {
⋮----
/// Square root in Fp2.
/// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is
/// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i.
/// @notice Will revert with InvalidProof() if
/// * the input is not a square,
/// * the hint is incorrect, or
/// * the input coefficients are not reduced.
/// @param a0 The real part of the input.
/// @param a1 The imaginary part of the input.
/// @param hint A hint which of two possible signs to pick in the equation.
/// @return x0 The real part of the square root.
/// @return x1 The imaginary part of the square root.
function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) {
// If this square root reverts there is no solution in Fp2.
⋮----
// Check result to make sure we found a root.
// Note: this also fails if a0 or a1 is not reduced.
⋮----
/// Compress a G1 point.
/// @notice Reverts with InvalidProof if the coordinates are not reduced
/// or if the point is not on the curve.
/// @notice The point at infinity is encoded as (0,0) and compressed to 0.
/// @param x The X coordinate in Fp.
/// @param y The Y coordinate in Fp.
/// @return c The compresed point (x with one signal bit).
function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) {
⋮----
// G1 point not in field.
⋮----
// Point at infinity
⋮----
// Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid.
⋮----
// G1 point not on curve.
⋮----
/// Decompress a G1 point.
/// @notice Reverts with InvalidProof if the input does not represent a valid point.
⋮----
/// @param c The compresed point (x with one signal bit).
/// @return x The X coordinate in Fp.
/// @return y The Y coordinate in Fp.
function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) {
// Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square.
// so we can use it to represent the point at infinity.
⋮----
// Point at infinity as encoded in EIP196 and EIP197.
⋮----
// G1 x coordinate not in field.
⋮----
// Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore
// y can not be zero.
// Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve.
⋮----
/// Compress a G2 point.
/// @notice Reverts with InvalidProof if the coefficients are not reduced
⋮----
/// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1)
/// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i).
/// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0).
/// @param x0 The real part of the X coordinate.
/// @param x1 The imaginary poart of the X coordinate.
/// @param y0 The real part of the Y coordinate.
/// @param y1 The imaginary part of the Y coordinate.
/// @return c0 The first half of the compresed point (x0 with two signal bits).
/// @return c1 The second half of the compressed point (x1 unmodified).
function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1)
⋮----
// G2 point not in field.
⋮----
// Compute y^2
// Note: shadowing variables and scoping to avoid stack-to-deep.
⋮----
// Determine hint bit
// If this sqrt fails the x coordinate is not on the curve.
⋮----
// Recover y
⋮----
/// Decompress a G2 point.
⋮----
/// @param c0 The first half of the compresed point (x0 with two signal bits).
/// @param c1 The second half of the compressed point (x1 unmodified).
/// @return x0 The real part of the X coordinate.
/// @return x1 The imaginary poart of the X coordinate.
/// @return y0 The real part of the Y coordinate.
/// @return y1 The imaginary part of the Y coordinate.
function decompress_g2(uint256 c0, uint256 c1)
⋮----
// Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square.
⋮----
// Point at infinity as encoded in EIP197.
⋮----
// G2 x0 or x1 coefficient not in field.
⋮----
// Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve.
// Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero.
// But y0 or y1 may still independently be zero.
⋮----
/// Compute the public input linear combination.
/// @notice Reverts with PublicInputNotInField if the input is not in the field.
/// @notice Computes the multi-scalar-multiplication of the public input
/// elements and the verification key including the constant term.
/// @param input The public inputs. These are elements of the scalar field Fr.
/// @param publicCommitments public inputs generated from pedersen commitments.
/// @param commitments The Pedersen commitments from the proof.
/// @return x The X coordinate of the resulting G1 point.
/// @return y The Y coordinate of the resulting G1 point.
function publicInputMSM(
⋮----
// Note: The ECMUL precompile does not reject unreduced values, so we check this.
// Note: Unrolling this loop does not cost much extra in code-size, the bulk of the
// code-size is in the PUB_ constants.
// ECMUL has input (x, y, scalar) and output (x', y').
// ECADD has input (x1, y1, x2, y2) and output (x', y').
// We reduce commitments(if any) with constants as the first point argument to ECADD.
// We call them such that ecmul output is already in the second point
// argument to ECADD so we can have a tight loop.
⋮----
// Either Public input not in field, or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
⋮----
/// Compress a proof.
/// @notice Will revert with InvalidProof if the curve points are invalid,
/// but does not verify the proof itself.
/// @param proof The uncompressed Groth16 proof. Elements are in the same order as for
/// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197.
/// @param commitments Pedersen commitments from the proof.
/// @param commitmentPok proof of knowledge for the Pedersen commitments.
/// @return compressed The compressed proof. Elements are in the same order as for
/// verifyCompressedProof. I.e. points (A, B, C) in compressed format.
/// @return compressedCommitments compressed Pedersen commitments from the proof.
/// @return compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
function compressProof(
⋮----
/// Verify a Groth16 proof with compressed points.
/// @notice Reverts with InvalidProof if the proof is invalid or
/// with PublicInputNotInField the public input is not reduced.
/// @notice There is no return value. If the function does not revert, the
/// proof was successfully verified.
/// @param compressedProof the points (A, B, C) in compressed format
/// matching the output of compressProof.
/// @param compressedCommitments compressed Pedersen commitments from the proof.
/// @param compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
/// @param input the public input field elements in the scalar field Fr.
/// Elements must be reduced.
function verifyCompressedProof(
⋮----
// Commitments
⋮----
// Verify pedersen commitments
⋮----
// Verify the pairing
// Note: The precompile expects the F2 coefficients in big-endian order.
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
// e(A, B)
⋮----
// e(C, -δ)
⋮----
// e(α, -β)
⋮----
// e(L_pub, -γ)
⋮----
// Check pairing equation.
⋮----
// Either proof or verification key invalid.
⋮----
/// Verify an uncompressed Groth16 proof.
⋮----
/// @param proof the points (A, B, C) in EIP-197 format matching the output
/// of compressProof.
/// @param commitments the Pedersen commitments from the proof.
/// @param commitmentPok the proof of knowledge for the Pedersen commitments.
⋮----
function verifyProof(
⋮----
// HashToField
⋮----
calldatacopy(f, commitments, 0x40) // Copy Commitments
⋮----
let f := mload(0x40) // Free memory pointer.
⋮----
// Copy points (A, B, C) to memory. They are already in correct encoding.
// This is pairing e(A, B) and G1 of e(C, -δ).
⋮----
// Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory.
// OPT: This could be better done using a single codecopy, but
// Solidity (unlike standalone Yul) doesn't provide a way to
// to do this.
⋮----
// Also check returned value (both are either 1 or 0).
````
## File: test/data/zk/Verifier_1000.sol
````
// SPDX-License-Identifier: MIT
⋮----
/// @title Groth16 verifier template.
/// @author Remco Bloemen
/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed
/// (256 bytes) and compressed (128 bytes) format. A view function is provided
/// to compress proofs.
/// @notice See for further explanation.
contract Verifier {
/// Some of the provided public input values are larger than the field modulus.
/// @dev Public input elements are not automatically reduced, as this is can be
/// a dangerous source of bugs.
⋮----
/// The proof is invalid.
/// @dev This can mean that provided Groth16 proof points are not on their
/// curves, that pairing equation fails, or that the proof is not for the
/// provided public input.
⋮----
/// The commitment is invalid
/// @dev This can mean that provided commitment points and/or proof of knowledge are not on their
/// curves, that pairing equation fails, or that the commitment and/or proof of knowledge is not for the
/// commitment key.
⋮----
// Addresses of precompiles
⋮----
// Base field Fp order P and scalar field Fr order R.
// For BN254 these are computed as follows:
// t = 4965661367192848881
// P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1
// R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1
⋮----
// Extension field Fp2 = Fp[i] / (i² + 1)
// Note: This is the complex extension field of Fp with i² = -1.
// Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i.
// Note: The order of Fp2 elements is *opposite* that of the pairing contract, which
// expects Fp2 elements in order (a₁, a₀). This is also the order in which
// Fp2 elements are encoded in the public interface as this became convention.
⋮----
// Constants in Fp
⋮----
// Exponents for inversions and square roots mod P
uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2
uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4;
⋮----
// Groth16 alpha point in G1
⋮----
// Groth16 beta point in G2 in powers of i
⋮----
// Groth16 gamma point in G2 in powers of i
⋮----
// Groth16 delta point in G2 in powers of i
⋮----
// Pedersen G point in G2 in powers of i
⋮----
// Pedersen GSigmaNeg point in G2 in powers of i
⋮----
// Constant and public input points
⋮----
/// Negation in Fp.
/// @notice Returns a number x such that a + x = 0 in Fp.
/// @notice The input does not need to be reduced.
/// @param a the base
/// @return x the result
function negate(uint256 a) internal pure returns (uint256 x) {
⋮----
x = (P - (a % P)) % P; // Modulo is cheaper than branching
⋮----
/// Exponentiation in Fp.
/// @notice Returns a number x such that a ^ e = x in Fp.
⋮----
/// @param e the exponent
⋮----
function exp(uint256 a, uint256 e) internal view returns (uint256 x) {
⋮----
// Exponentiation failed.
// Should not happen.
⋮----
/// Invertsion in Fp.
/// @notice Returns a number x such that a * x = 1 in Fp.
⋮----
/// @notice Reverts with ProofInvalid() if the inverse does not exist
/// @param a the input
/// @return x the solution
function invert_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Inverse does not exist.
// Can only happen during G2 point decompression.
⋮----
/// Square root in Fp.
/// @notice Returns a number x such that x * x = a in Fp.
/// @notice Will revert with InvalidProof() if the input is not a square
/// or not reduced.
/// @param a the square
⋮----
function sqrt_Fp(uint256 a) internal view returns (uint256 x) {
⋮----
// Square root does not exist or a is not reduced.
// Happens when G1 point is not on curve.
⋮----
/// Square test in Fp.
/// @notice Returns whether a number x exists such that x * x = a in Fp.
⋮----
function isSquare_Fp(uint256 a) internal view returns (bool) {
⋮----
/// Square root in Fp2.
/// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is
/// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i.
/// @notice Will revert with InvalidProof() if
/// * the input is not a square,
/// * the hint is incorrect, or
/// * the input coefficients are not reduced.
/// @param a0 The real part of the input.
/// @param a1 The imaginary part of the input.
/// @param hint A hint which of two possible signs to pick in the equation.
/// @return x0 The real part of the square root.
/// @return x1 The imaginary part of the square root.
function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) {
// If this square root reverts there is no solution in Fp2.
⋮----
// Check result to make sure we found a root.
// Note: this also fails if a0 or a1 is not reduced.
⋮----
/// Compress a G1 point.
/// @notice Reverts with InvalidProof if the coordinates are not reduced
/// or if the point is not on the curve.
/// @notice The point at infinity is encoded as (0,0) and compressed to 0.
/// @param x The X coordinate in Fp.
/// @param y The Y coordinate in Fp.
/// @return c The compresed point (x with one signal bit).
function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) {
⋮----
// G1 point not in field.
⋮----
// Point at infinity
⋮----
// Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid.
⋮----
// G1 point not on curve.
⋮----
/// Decompress a G1 point.
/// @notice Reverts with InvalidProof if the input does not represent a valid point.
⋮----
/// @param c The compresed point (x with one signal bit).
/// @return x The X coordinate in Fp.
/// @return y The Y coordinate in Fp.
function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) {
// Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square.
// so we can use it to represent the point at infinity.
⋮----
// Point at infinity as encoded in EIP196 and EIP197.
⋮----
// G1 x coordinate not in field.
⋮----
// Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore
// y can not be zero.
// Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve.
⋮----
/// Compress a G2 point.
/// @notice Reverts with InvalidProof if the coefficients are not reduced
⋮----
/// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1)
/// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i).
/// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0).
/// @param x0 The real part of the X coordinate.
/// @param x1 The imaginary poart of the X coordinate.
/// @param y0 The real part of the Y coordinate.
/// @param y1 The imaginary part of the Y coordinate.
/// @return c0 The first half of the compresed point (x0 with two signal bits).
/// @return c1 The second half of the compressed point (x1 unmodified).
function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1)
⋮----
// G2 point not in field.
⋮----
// Compute y^2
// Note: shadowing variables and scoping to avoid stack-to-deep.
⋮----
// Determine hint bit
// If this sqrt fails the x coordinate is not on the curve.
⋮----
// Recover y
⋮----
/// Decompress a G2 point.
⋮----
/// @param c0 The first half of the compresed point (x0 with two signal bits).
/// @param c1 The second half of the compressed point (x1 unmodified).
/// @return x0 The real part of the X coordinate.
/// @return x1 The imaginary poart of the X coordinate.
/// @return y0 The real part of the Y coordinate.
/// @return y1 The imaginary part of the Y coordinate.
function decompress_g2(uint256 c0, uint256 c1)
⋮----
// Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square.
⋮----
// Point at infinity as encoded in EIP197.
⋮----
// G2 x0 or x1 coefficient not in field.
⋮----
// Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve.
// Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero.
// But y0 or y1 may still independently be zero.
⋮----
/// Compute the public input linear combination.
/// @notice Reverts with PublicInputNotInField if the input is not in the field.
/// @notice Computes the multi-scalar-multiplication of the public input
/// elements and the verification key including the constant term.
/// @param input The public inputs. These are elements of the scalar field Fr.
/// @param publicCommitments public inputs generated from pedersen commitments.
/// @param commitments The Pedersen commitments from the proof.
/// @return x The X coordinate of the resulting G1 point.
/// @return y The Y coordinate of the resulting G1 point.
function publicInputMSM(
⋮----
// Note: The ECMUL precompile does not reject unreduced values, so we check this.
// Note: Unrolling this loop does not cost much extra in code-size, the bulk of the
// code-size is in the PUB_ constants.
// ECMUL has input (x, y, scalar) and output (x', y').
// ECADD has input (x1, y1, x2, y2) and output (x', y').
// We reduce commitments(if any) with constants as the first point argument to ECADD.
// We call them such that ecmul output is already in the second point
// argument to ECADD so we can have a tight loop.
⋮----
// Either Public input not in field, or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
⋮----
/// Compress a proof.
/// @notice Will revert with InvalidProof if the curve points are invalid,
/// but does not verify the proof itself.
/// @param proof The uncompressed Groth16 proof. Elements are in the same order as for
/// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197.
/// @param commitments Pedersen commitments from the proof.
/// @param commitmentPok proof of knowledge for the Pedersen commitments.
/// @return compressed The compressed proof. Elements are in the same order as for
/// verifyCompressedProof. I.e. points (A, B, C) in compressed format.
/// @return compressedCommitments compressed Pedersen commitments from the proof.
/// @return compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
function compressProof(
⋮----
/// Verify a Groth16 proof with compressed points.
/// @notice Reverts with InvalidProof if the proof is invalid or
/// with PublicInputNotInField the public input is not reduced.
/// @notice There is no return value. If the function does not revert, the
/// proof was successfully verified.
/// @param compressedProof the points (A, B, C) in compressed format
/// matching the output of compressProof.
/// @param compressedCommitments compressed Pedersen commitments from the proof.
/// @param compressedCommitmentPok compressed proof of knowledge for the Pedersen commitments.
/// @param input the public input field elements in the scalar field Fr.
/// Elements must be reduced.
function verifyCompressedProof(
⋮----
// Commitments
⋮----
// Verify pedersen commitments
⋮----
// Verify the pairing
// Note: The precompile expects the F2 coefficients in big-endian order.
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
// e(A, B)
⋮----
// e(C, -δ)
⋮----
// e(α, -β)
⋮----
// e(L_pub, -γ)
⋮----
// Check pairing equation.
⋮----
// Either proof or verification key invalid.
⋮----
/// Verify an uncompressed Groth16 proof.
⋮----
/// @param proof the points (A, B, C) in EIP-197 format matching the output
/// of compressProof.
/// @param commitments the Pedersen commitments from the proof.
/// @param commitmentPok the proof of knowledge for the Pedersen commitments.
⋮----
function verifyProof(
⋮----
// HashToField
⋮----
calldatacopy(f, commitments, 0x40) // Copy Commitments
⋮----
let f := mload(0x40) // Free memory pointer.
⋮----
// Copy points (A, B, C) to memory. They are already in correct encoding.
// This is pairing e(A, B) and G1 of e(C, -δ).
⋮----
// Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory.
// OPT: This could be better done using a single codecopy, but
// Solidity (unlike standalone Yul) doesn't provide a way to
// to do this.
⋮----
// Also check returned value (both are either 1 or 0).
````
## File: test/data/genesis_header.json
````json
{
"header": {
"version": 1,
"validatorsSszMRoot": "0xa1d1e9127339816cd3cc49c40d1b188a4c5056b0cff77137bcf992b070b935d9",
"epoch": 0,
"requiredKeyTag": 15,
"captureTimestamp": 1746024875,
"quorumThreshold": 20000000000001,
"totalVotingPower": 30000000000000
},
"extraData": [
{
"key": "0x7f6185ad9469ee6a9c05e14b4e03be396fc9beb5e6626c77957d25b5b62d83ab",
"value": "0x0000000000000000000000000000000000000000000000000000000000000014"
},
{
"key": "0xd07277185a3cf0575b363bbe652653f46b583ea129748f095887313569ff44b4",
"value": "0x221e349ac65d42e4884601fd0ddba2b964bb5055bd96f431458652333ede252a"
}
]
}
````
## File: test/examples/MyVotingPowerProvider.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {IOzOwnable} from "../../src/interfaces/modules/common/permissions/IOzOwnable.sol";
⋮----
import {BN254} from "../../src/libraries/utils/BN254.sol";
import "../InitSetup.sol";
⋮----
contract MyVotingPowerProviderTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_RegisterOperatorValid() public {
⋮----
function test_RegisterOperator_RevertIfNotEntity() public {
⋮----
function test_RegisterOperator_RevertIfAlreadyRegistered() public {
⋮----
function test_UnregisterOperator() public {
⋮----
function test_UnregisterOperator_RevertIfNotRegistered() public {
⋮----
function test_IsOperatorRegisteredAt_withTime() public {
⋮----
function testGetOperatorsAt_withTime() public {
⋮----
function test_SlashingData() public {
⋮----
function test_RegisterOperatorVault() public {
⋮----
function test_RegisterOperatorVault_RevertIfOperatorNotRegistered() public {
⋮----
function test_SlashVault_InstantSlasher() public {}
⋮----
function test_SlashVault_VetoSlasherFlow() public {}
⋮----
function test_SlashVault_RevertIfNoSlasher() public {}
⋮----
function test_DistributeRewards() public {}
⋮----
function test_CheckStakes() public {
⋮----
function test_RegisterOperator() public {
⋮----
function test_RegisterOperatorVaultExternal() public {
⋮----
function test_registerOperatorWithSignature() public {
⋮----
function test_registerOperatorWithSignature_RevertIfInvalidSig() public {
⋮----
function test_IncreaseNonce() public {
⋮----
function test_unregisterOperatorWithSignature() public {
````
## File: test/helpers/blsTestGenerator.py
````python
# used for helped aggregation
def get_public_key_G1(secret_key: int) -> Tuple[FQ, FQ, FQ]
⋮----
def get_public_key(secret_key: int) -> Tuple[FQ2, FQ2, FQ2]
⋮----
def sign(message: Tuple[FQ, FQ, FQ], secret_key: int)
⋮----
def aggregate_signatures(signatures: list[Tuple[FQ, FQ, FQ]]) -> Tuple[FQ, FQ, FQ]
⋮----
res = signatures[0]
⋮----
res = add(res, signature)
⋮----
def aggregate_public_keys(pubkeys: list[Tuple[FQ2, FQ2, FQ2]]) -> Tuple[FQ2, FQ2, FQ2]
⋮----
res = pubkeys[0]
⋮----
res = add(res, pubkey)
⋮----
def aggregate_public_keys_G1(pubkeys: list[Tuple[FQ, FQ, FQ]]) -> Tuple[FQ, FQ, FQ]
⋮----
def hash_to_point(data: bytes)
⋮----
x = int.from_bytes(data, byteorder='big') % field_modulus
⋮----
# Check if y^2 == beta
⋮----
x = (x + 1) % field_modulus
⋮----
def find_y_from_x(x: int) -> Tuple[int, int]
⋮----
"""
Given x coordinate, find y coordinate on BN254 curve
Returns (beta, y) where:
beta = x^3 + 3 (mod p)
y = sqrt(beta) if it exists
"""
# Calculate beta = x^3 + 3 mod p
beta = (pow(x, 3, field_modulus) + 3) % field_modulus
⋮----
# Calculate y = beta^((p+1)/4) mod p
# Using same exponent as in BN254.sol: 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52
y = pow(beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, field_modulus)
⋮----
def sqrt(x_square: int) -> Tuple[int, bool]
⋮----
# Calculate y = x^((p+1)/4) mod p
# This is equivalent to finding square root modulo p
# where p ≡ 3 (mod 4)
exp = (field_modulus + 1) // 4
y = pow(x_square, exp, field_modulus)
⋮----
# Verify y is actually a square root
⋮----
def parse_solc_G1(solc_G1: Tuple[int, int])
⋮----
def format_G1(g1_element: Tuple[FQ, FQ, FQ]) -> Tuple[FQ, FQ]
⋮----
def format_G2(g2_element: Tuple[FQ2, FQ2, FQ2]) -> Tuple[FQ2, FQ2]
⋮----
def verify(message: bytes, signature: Tuple[FQ, FQ, FQ], public_key: Tuple[FQ2, FQ2, FQ2]) -> bool
⋮----
# Map message to curve point
h = hash_to_point(message)
⋮----
# Check e(signature, G2) = e(h, public_key)
# Note: signature and h are in G1, while G2 and public_key are in G2
pairing1 = pairing(G2, signature)
pairing2 = pairing(public_key, h)
⋮----
def generate_operator_address() -> str
⋮----
# Generate random private key
private_key = os.urandom(32)
acc = Account.create(private_key)
# Pad address to 32 bytes
⋮----
secret_key = 69
⋮----
public_key = get_public_key(secret_key)
public_key_g1 = get_public_key_G1(secret_key)
⋮----
formatted_pubkey = format_G2(public_key)
formatted_pubkey_g1 = format_G1(public_key_g1)
⋮----
# Create message hash as done in the contract
operator = generate_operator_address()
message = eth_abi.encode(
⋮----
message_hash = keccak(message)
⋮----
data = message_hash
⋮----
message = hash_to_point(data)
# Generate signature
signature = sign(message, secret_key)
formatted_sig = format_G1(signature)
⋮----
# Format values for test output
⋮----
# Verify the signature
is_valid = verify(data, signature, public_key)
⋮----
# Test vectors
test_vectors = {
````
## File: test/helpers/BN254G2.sol
````
/**
* @title Elliptic curve operations on twist points for alt_bn128
* @author Mustafa Al-Bassam (mus@musalbas.com)
* @dev Homepage: https://github.com/musalbas/solidity-BN256G2
*/
⋮----
// WARNING: this code is used ONLY for testing purposes, DO NOT USE IN PRODUCTION
⋮----
/**
* @notice Add two twist points
* @param pt1xx Coefficient 1 of x on point 1
* @param pt1xy Coefficient 2 of x on point 1
* @param pt1yx Coefficient 1 of y on point 1
* @param pt1yy Coefficient 2 of y on point 1
* @param pt2xx Coefficient 1 of x on point 2
* @param pt2xy Coefficient 2 of x on point 2
* @param pt2yx Coefficient 1 of y on point 2
* @param pt2yy Coefficient 2 of y on point 2
* @return (pt3xx, pt3xy, pt3yx, pt3yy)
*/
function ECTwistAdd(
⋮----
/**
* @notice Multiply a twist point by a scalar
* @param s Scalar to multiply by
* @param pt1xx Coefficient 1 of x
* @param pt1xy Coefficient 2 of x
* @param pt1yx Coefficient 1 of y
* @param pt1yy Coefficient 2 of y
* @return (pt2xx, pt2xy, pt2yx, pt2yy)
*/
function ECTwistMul(uint256 s, uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy)
⋮----
/**
* @notice Get the field modulus
* @return The field modulus
*/
function GetFieldModulus() internal pure returns (uint256) {
⋮----
function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) {
⋮----
function _FQ2Mul(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256, uint256) {
⋮----
function _FQ2Muc(uint256 xx, uint256 xy, uint256 c) internal pure returns (uint256, uint256) {
⋮----
function _FQ2Add(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256, uint256) {
⋮----
function _FQ2Sub(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256 rx, uint256 ry) {
⋮----
function _FQ2Div(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal view returns (uint256, uint256) {
⋮----
function _FQ2Inv(uint256 x, uint256 y) internal view returns (uint256, uint256) {
⋮----
function _isOnCurve(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (bool) {
⋮----
function _modInv(uint256 a, uint256 n) internal view returns (uint256 result) {
⋮----
function _fromJacobian(uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy, uint256 pt1zx, uint256 pt1zy)
⋮----
function _ECTwistAddJacobian(_ECTwistAddJacobianArgs memory $) internal pure returns (uint256[6] memory pt3) {
⋮----
($.pt2yx, $.pt2yy) = _FQ2Mul($.pt2yx, $.pt2yy, $.pt1zx, $.pt1zy); // U1 = y2 * z1
(pt3[PTYX], pt3[PTYY]) = _FQ2Mul($.pt1yx, $.pt1yy, $.pt2zx, $.pt2zy); // U2 = y1 * z2
($.pt2xx, $.pt2xy) = _FQ2Mul($.pt2xx, $.pt2xy, $.pt1zx, $.pt1zy); // V1 = x2 * z1
(pt3[PTZX], pt3[PTZY]) = _FQ2Mul($.pt1xx, $.pt1xy, $.pt2zx, $.pt2zy); // V2 = x1 * z2
⋮----
($.pt2zx, $.pt2zy) = _FQ2Mul($.pt1zx, $.pt1zy, $.pt2zx, $.pt2zy); // W = z1 * z2
($.pt1xx, $.pt1xy) = _FQ2Sub($.pt2yx, $.pt2yy, pt3[PTYX], pt3[PTYY]); // U = U1 - U2
($.pt1yx, $.pt1yy) = _FQ2Sub($.pt2xx, $.pt2xy, pt3[PTZX], pt3[PTZY]); // V = V1 - V2
($.pt1zx, $.pt1zy) = _FQ2Mul($.pt1yx, $.pt1yy, $.pt1yx, $.pt1yy); // V_squared = V * V
($.pt2yx, $.pt2yy) = _FQ2Mul($.pt1zx, $.pt1zy, pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2
($.pt1zx, $.pt1zy) = _FQ2Mul($.pt1zx, $.pt1zy, $.pt1yx, $.pt1yy); // V_cubed = V * V_squared
(pt3[PTZX], pt3[PTZY]) = _FQ2Mul($.pt1zx, $.pt1zy, $.pt2zx, $.pt2zy); // newz = V_cubed * W
($.pt2xx, $.pt2xy) = _FQ2Mul($.pt1xx, $.pt1xy, $.pt1xx, $.pt1xy); // U * U
($.pt2xx, $.pt2xy) = _FQ2Mul($.pt2xx, $.pt2xy, $.pt2zx, $.pt2zy); // U * U * W
($.pt2xx, $.pt2xy) = _FQ2Sub($.pt2xx, $.pt2xy, $.pt1zx, $.pt1zy); // U * U * W - V_cubed
($.pt2zx, $.pt2zy) = _FQ2Muc($.pt2yx, $.pt2yy, 2); // 2 * V_squared_times_V2
($.pt2xx, $.pt2xy) = _FQ2Sub($.pt2xx, $.pt2xy, $.pt2zx, $.pt2zy); // A = U * U * W - V_cubed - 2 * V_squared_times_V2
(pt3[PTXX], pt3[PTXY]) = _FQ2Mul($.pt1yx, $.pt1yy, $.pt2xx, $.pt2xy); // newx = V * A
($.pt1yx, $.pt1yy) = _FQ2Sub($.pt2yx, $.pt2yy, $.pt2xx, $.pt2xy); // V_squared_times_V2 - A
($.pt1yx, $.pt1yy) = _FQ2Mul($.pt1xx, $.pt1xy, $.pt1yx, $.pt1yy); // U * (V_squared_times_V2 - A)
($.pt1xx, $.pt1xy) = _FQ2Mul($.pt1zx, $.pt1zy, pt3[PTYX], pt3[PTYY]); // V_cubed * U2
(pt3[PTYX], pt3[PTYY]) = _FQ2Sub($.pt1yx, $.pt1yy, $.pt1xx, $.pt1xy); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2
⋮----
function _ECTwistDoubleJacobian(
⋮----
(pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 3); // 3 * x
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x
(pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z
(pt2yx, pt2yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y
(pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S
(pt1xx, pt1xy) = _FQ2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W
(pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 8); // 8 * B
(pt1xx, pt1xy) = _FQ2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B
(pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S
(pt2yx, pt2yy) = _FQ2Muc(pt2yx, pt2yy, 4); // 4 * B
(pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H
(pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H)
(pt2xx, pt2xy) = _FQ2Muc(pt1yx, pt1yy, 8); // 8 * y
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared
(pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared
(pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 2); // 2 * H
(pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S
(pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared
(pt2zx, pt2zy) = _FQ2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared
⋮----
function _ECTwistMulJacobian(
````
## File: test/helpers/ed25519TestData.json
````json
{
"operator": "0xFFa6DD45436695c0185c9E1721638bc951b6853d",
"key": "0xf5240b978fc69dc2fdc62775572794e8cd0fd8ac4c0510336fb07232e8086692",
"signature": "0x78dd2320878fc2fb9f818d56442926eab183f7b94acfb5eaf5d7a24a018f4c200582b0b0cfc195991e1b827187abd35eb099dda6cd6f3458eb53d086db82c808",
"invalidKey": "0xc3e65061bd3c7857f68ab167faa3da83d964d2ec9d2447d367a7cdb4a3256d24",
"invalidSignature": "0x4b829ff953a071273aca67046a71a7f2c0d74ab8dcb3636cfeaf6c4a8f3c9ba5a6de5754c5189fc0e38e3df225657043fbfc0786f4b676ffab319bd92af20307"
}
````
## File: test/helpers/ed25519TestGenerator.js
````javascript
// Generate random operator address
function generateOperatorAddress() {
const wallet = ethers.Wallet.createRandom();
⋮----
// Generate Ed25519 keypair and signature
function generateTestData(operatorAddress) {
// Generate keypair
const privateKey = ed25519.utils.randomPrivateKey();
const publicKey = ed25519.getPublicKey(privateKey);
⋮----
// Create message hash as done in the contract
let message = keccak256(Buffer.concat([Buffer.from(operatorAddress.replace("0x", ""), "hex"), publicKey]));
⋮----
// Sign the message
const signature = "0x" + bytesToHex(ed25519.sign(message, privateKey));
⋮----
// Verify the signature
const isValid = ed25519.verify(
hexToBytes(signature.slice(2)), // Remove 0x prefix
⋮----
throw new Error("Generated signature failed verification");
⋮----
// Return ABI encoded data
const abiCoder = new ethers.AbiCoder();
const key = abiCoder.encode(["bytes32"], ["0x" + bytesToHex(publicKey)]);
⋮----
// Generate invalid test data with mismatched key and signature
function generateInvalidTestData(operatorAddress) {
// Generate two different keypairs
const privateKey1 = ed25519.utils.randomPrivateKey();
const publicKey1 = ed25519.getPublicKey(privateKey1);
const privateKey2 = ed25519.utils.randomPrivateKey();
const publicKey2 = ed25519.getPublicKey(privateKey2);
⋮----
// Create message hash with publicKey1
let message = keccak256(Buffer.concat([Buffer.from(operatorAddress.replace("0x", ""), "hex"), publicKey1]));
⋮----
// Sign with privateKey2 (mismatch)
const signature = "0x" + bytesToHex(ed25519.sign(message, privateKey2));
⋮----
// ABI encode publicKey1
⋮----
const key = abiCoder.encode(["bytes32"], ["0x" + bytesToHex(publicKey1)]);
⋮----
// Generate both valid and invalid test data
const operatorAddress = generateOperatorAddress();
const validTestData = generateTestData(operatorAddress);
const invalidTestData = generateInvalidTestData(operatorAddress);
⋮----
// Write data to file
fs.writeFileSync(
⋮----
JSON.stringify(
````
## File: test/libraries/keys/KeyBlsBn254.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import {KeyBlsBn254} from "../../../src/libraries/keys/KeyBlsBn254.sol";
import {BN254} from "../../../src/libraries/utils/BN254.sol";
⋮----
import {KeyBlsBn254Mock} from "../../mocks/KeyBlsBn254Mock.sol";
⋮----
contract KeyBlsBn254Test is Test {
⋮----
function setUp() public {
⋮----
function test_WrapUnwrapIdentity() public {
⋮----
function test_WrapUnwrapNonZero() public {
⋮----
function test_SerializeDeserializeIdentity() public {
⋮----
function test_SerializeDeserializeNonZero() public {
⋮----
function test_SerializeDeserializeNonZeroNegate() public {
⋮----
function test_ToBytesFromBytesIdentity() public {
⋮----
function test_ToBytesFromBytesNonZero() public {
⋮----
function test_FuzzWrapUnwrap(uint256 xIn) public {
⋮----
function test_FuzzSerializeDeserialize(uint256 xIn) public {
⋮----
function test_FuzzSerializeDeserializeNonZeroNegate(uint256 xIn) public {
⋮----
function test_FuzzToBytesFromBytes(uint256 xIn) public {
⋮----
function test_SerializeRevertsInvalidKey() public {
⋮----
function test_DeserializeEmptyBytesIsIdentity() public {
⋮----
function test_DeserializeRevertsInvalidLength() public {
⋮----
function test_FromBytesRevertsInvalidLength() public {
⋮----
function test_FromBytesRevertsInvalidBytes() public {
⋮----
function test_WrapRevertsInvalidKey(uint256 X) public {
⋮----
function test_ZeroKey() public {
⋮----
function test_Equal() public {
⋮----
function test_EqualFalse() public {
⋮----
function test_OutOfBounds() public {
````
## File: test/libraries/keys/KeyEcdsaSecp256k1.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import {KeyEcdsaSecp256k1} from "../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
⋮----
import {KeyEcdsaSecp256k1Mock} from "../../mocks/KeyEcdsaSecp256k1Mock.sol";
⋮----
contract KeyEcdsaSecp256k1Test is Test {
⋮----
function setUp() public {
⋮----
function test_WrapUnwrap() public {
⋮----
function test_SerializeDeserialize() public {
⋮----
function test_ToBytesFromBytes() public {
⋮----
function test_FuzzWrapUnwrap(address rawKey) public {
⋮----
function test_FuzzSerializeDeserialize(address rawKey) public {
⋮----
function test_FuzzToBytesFromBytes(address rawKey) public {
⋮----
function test_FromBytesRevertsIfNot20Bytes() public {
⋮----
function test_DeserializeRevertsIfNot20Bytes() public {
⋮----
function test_FromBytesRevertsInvalidBytes() public {
⋮----
function test_ZeroKey() public {
⋮----
function test_Equal() public {
⋮----
function test_EqualFalse() public {
````
## File: test/libraries/sigs/SigBlsBn254.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import {SigBlsBn254} from "../../../src/libraries/sigs/SigBlsBn254.sol";
import {KeyBlsBn254} from "../../../src/libraries/keys/KeyBlsBn254.sol";
import {BN254} from "../../../src/libraries/utils/BN254.sol";
import {BN254G2} from "../../helpers/BN254G2.sol";
⋮----
contract SigBlsBn254Test is Test {
⋮----
function getG2Key(uint256 privateKey) public view returns (BN254.G2Point memory) {
⋮----
function test_BLSRegisterOperator() public {
⋮----
function test_BLSRegisterOperatorInvalid() public {
⋮----
function test_ZeroKey() public {
⋮----
function verify(bytes memory keyBytes, bytes memory message, bytes memory signature, bytes memory extraData)
⋮----
function test_InvalidMessageLength() public {
````
## File: test/libraries/sigs/SigEcdsaSecp256k1.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import {SigEcdsaSecp256k1} from "../../../src/libraries/sigs/SigEcdsaSecp256k1.sol";
import {KeyEcdsaSecp256k1} from "../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
⋮----
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
⋮----
contract SigEcdsaSecp256k1Test is Test {
⋮----
function test_CorrectSignature() public {
⋮----
function test_IncorrectSignature() public {
⋮----
function test_FuzzVerification(uint256 privKey, bytes memory msgData) public {
⋮----
function test_ZeroKey() public {
⋮----
function verify(bytes memory keyBytes, bytes memory message, bytes memory signature, bytes memory extraData)
⋮----
function test_InvalidMessageLength() public {
````
## File: test/libraries/structs/Checkpoints.t.sol
````
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/Checkpoints.t.js.
⋮----
import {Test} from "forge-std/Test.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {Checkpoints} from "../../../src/libraries/structs/Checkpoints.sol";
⋮----
contract CheckpointsTrace208Test is Test {
⋮----
// Maximum gap between keys used during the fuzzing tests: the `_prepareKeys` function with make sure that
// key#n+1 is in the [key#n, key#n + _KEY_MAX_GAP] range.
⋮----
// helpers
function _boundUint48(uint48 x, uint48 min, uint48 max) internal pure returns (uint48) {
⋮----
function _prepareKeys(uint48[] memory keys, uint48 maxSpread) internal pure {
⋮----
function _prepareKeysUnrepeated(uint48[] memory keys, uint48 maxSpread) internal pure {
⋮----
function _assertLatestCheckpoint(bool exist, uint48 key, uint208 value) internal {
⋮----
// tests
function testPush(uint48[] memory keys, uint208[] memory values, uint48 pastKey) public {
⋮----
// initial state
⋮----
// push
⋮----
// check length & latest
⋮----
// used to test reverts
function push(uint48 key, uint208 value) external {
⋮----
function testLookup(uint48[] memory keys, uint208[] memory values, uint48 lookup) public {
⋮----
// track expected result of lookups
⋮----
// find the first key that is not smaller than the lookup key
⋮----
function testUpperLookupRecentWithHint(
⋮----
// Build checkpoints
⋮----
// Test upperLookupRecentCheckpoint without hint
function testUpperLookupRecentCheckpoint(uint48[] memory keys, uint208[] memory values, uint48 lookup) public {
⋮----
// Expected values
⋮----
// Test function
⋮----
// Test upperLookupRecentCheckpoint with hint
function testUpperLookupRecentCheckpointWithHint(
⋮----
// Test latest
function testLatest(uint48[] memory keys, uint208[] memory values) public {
⋮----
// Test latestCheckpoint
function testLatestCheckpoint(uint48[] memory keys, uint208[] memory values) public {
⋮----
// Test length
function testLength(uint48[] memory keys, uint208[] memory values) public {
⋮----
// Test at
function testAt(uint48[] memory keys, uint208[] memory values, uint32 index) public {
⋮----
function pop() external {
⋮----
// Test pop
function testPop(uint48[] memory keys, uint208[] memory values) public {
⋮----
contract CheckpointsTrace256Test is Test {
⋮----
function _assertLatestCheckpoint(bool exist, uint48 key, uint256 value) internal {
⋮----
function testPush(uint48[] memory keys, uint256[] memory values, uint48 pastKey) public {
⋮----
function push(uint48 key, uint256 value) external {
⋮----
function testLookup(uint48[] memory keys, uint256[] memory values, uint48 lookup) public {
⋮----
function testUpperLookupRecentCheckpoint(uint48[] memory keys, uint256[] memory values, uint48 lookup) public {
⋮----
function testLatest(uint48[] memory keys, uint256[] memory values) public {
⋮----
function testLatestCheckpoint(uint48[] memory keys, uint256[] memory values) public {
⋮----
function testLength(uint48[] memory keys, uint256[] memory values) public {
⋮----
function testAt(uint48[] memory keys, uint256[] memory values, uint32 index) public {
⋮----
function testPop(uint48[] memory keys, uint256[] memory values) public {
⋮----
contract CheckpointsTrace512Test is Test {
⋮----
function _assertEqPair(uint256[2] memory a, uint256[2] memory b) internal {
⋮----
function _assertLatestCheckpointPair(bool exist, uint48 key, uint256[2] memory value) internal {
⋮----
function push(uint48 key, uint256[2] memory value) external {
⋮----
function _safe48(uint256 val) internal pure returns (uint48) {
⋮----
function _getCheckpointAt(uint32 i) internal view returns (uint48, uint256[2] memory) {
````
## File: test/libraries/structs/PersistentSet.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {PersistentSet} from "../../../src/libraries/structs/PersistentSet.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
⋮----
contract PersistentSetTest is Test {
⋮----
function setUp() public {}
⋮----
function test_AddressSetAddRemoveAndContains() public {
⋮----
function test_AddressSetLengthAndValuesAt() public {
⋮----
function test_AddressSetAllValues() public {
⋮----
function test_Bytes32SetAddRemoveAndContains() public {
⋮----
function test_Bytes32SetValuesAt() public {
⋮----
function test_Bytes32SetAllValues() public {
⋮----
function test_LargeAddressSetExceed256Elements() public {
⋮----
function remove(uint48 key, address value) public {
⋮----
function test_RevertPersistentSet_InvalidKey() public {
````
## File: test/libraries/utils/InputNormalizer.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {InputNormalizer} from "../../../src/libraries/utils/InputNormalizer.sol";
⋮----
contract InputNormalizerTest is Test {
function normalizeSingleDim(bytes[] memory arr, uint256 length) public pure returns (bytes[] memory) {
⋮----
function normalizeDoubleDim(bytes[][] memory arr, uint256 length) public pure returns (bytes[][] memory) {
⋮----
function test_normalizeSingleDimEmpty() public {
⋮----
function test_normalizeSingleDimExact() public {
⋮----
function test_normalizeSingleDimMismatchRevert() public {
⋮----
function test_normalizeDoubleDimEmpty() public {
⋮----
function test_normalizeDoubleDimExact() public {
⋮----
function test_normalizeDoubleDimMismatchRevert() public {
````
## File: test/libraries/utils/KeyTag.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {KeyTags} from "../../../src/libraries/utils/KeyTags.sol";
⋮----
contract KeyTagTest is Test {
⋮----
function setUp() public {}
⋮----
function test_GetKeyTagValid() public {
⋮----
function test_GetKeyTagInvalidType() public {
⋮----
function getKeyTag(uint8 type_, uint8 identifier) public pure returns (uint8) {
⋮----
function test_GetKeyTagInvalidIdentifier() public {
⋮----
function test_GetType() public {
⋮----
function test_GetTag() public {
⋮----
function test_GetTypeRevertWhenTooLarge() public {
⋮----
function getType(uint8 keyTag) public pure returns (uint8) {
⋮----
function test_GetTagRevertWhenTooLarge() public {
⋮----
function getTag(uint8 keyTag) public pure returns (uint8) {
⋮----
function test_ContainsAddRemove() public {
⋮----
function test_AddMultiple() public {
⋮----
function test_SerializeUniqueKeyTags() public {
⋮----
function serialize(uint8[] memory tags) public pure returns (uint128) {
⋮----
function test_SerializeRevertOnDuplicate() public {
⋮----
function test_DeserializeBitmask() public {
````
## File: test/libraries/utils/ValSetVerifier.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {ValSetVerifier} from "../../../src/libraries/utils/ValSetVerifier.sol";
import {ValSetVerifierMock} from "../../mocks/ValSetVerifierMock.sol";
⋮----
contract ValSetVerifierContract {
function verifyOperator(
⋮----
function verifyVotingPower(
⋮----
function verifyIsActive(
⋮----
function verifyKey(
⋮----
function verifyValidatorKeyRootLocal(
⋮----
function verifyVault(
⋮----
function verifyValidatorVaultRootLocal(
⋮----
contract ValSetVerifierDataTest is Test {
⋮----
function setUp() public {
⋮----
function test_VerifyOperator() public {
⋮----
function test_VerifyVotingPower() public {
⋮----
function test_VerifyIsActive() public {
⋮----
function test_VerifyKey() public {
⋮----
function test_VerifyVault() public {
⋮----
ValSetVerifier.SszProof({leaf: bytes32(uint256(0x697a) << (256 - 2 * 8)), proof: vaultChainIdArr}); // 0x7a69 = 31337
````
## File: test/mocks/KeyBlsBn254Mock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {BN254} from "../../src/libraries/utils/BN254.sol";
import {KeyBlsBn254} from "../../src/libraries/keys/KeyBlsBn254.sol";
⋮----
contract KeyBlsBn254Mock {
function wrap(BN254.G1Point memory keyRaw) public view returns (KeyBlsBn254.KEY_BLS_BN254 memory key) {
⋮----
function unwrap(KeyBlsBn254.KEY_BLS_BN254 memory key) public view returns (BN254.G1Point memory keyRaw) {
⋮----
function serialize(KeyBlsBn254.KEY_BLS_BN254 memory key) public view returns (bytes memory keySerialized) {
⋮----
function deserialize(bytes memory keySerialized) public view returns (KeyBlsBn254.KEY_BLS_BN254 memory key) {
⋮----
function toBytes(KeyBlsBn254.KEY_BLS_BN254 memory key) public view returns (bytes memory keyBytes) {
⋮----
function fromBytes(bytes memory keyBytes) public view returns (KeyBlsBn254.KEY_BLS_BN254 memory key) {
⋮----
function zeroKey() public view returns (KeyBlsBn254.KEY_BLS_BN254 memory key) {
⋮----
function equal(KeyBlsBn254.KEY_BLS_BN254 memory key1, KeyBlsBn254.KEY_BLS_BN254 memory key2)
````
## File: test/mocks/KeyEcdsaSecp256k1Mock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyEcdsaSecp256k1} from "../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
⋮----
contract KeyEcdsaSecp256k1Mock {
function wrap(address keyRaw) public view returns (KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key) {
⋮----
function unwrap(KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key) public view returns (address keyRaw) {
⋮----
function serialize(KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key)
⋮----
function deserialize(bytes memory keySerialized)
⋮----
function toBytes(KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key) public view returns (bytes memory keyBytes) {
⋮----
function fromBytes(bytes memory keyBytes) public view returns (KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key) {
⋮----
function zeroKey() public view returns (KeyEcdsaSecp256k1.KEY_ECDSA_SECP256K1 memory key) {
⋮----
function equal(
````
## File: test/mocks/KeyRegistryWithKey64.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyRegistry} from "../../src/modules/key-registry/KeyRegistry.sol";
⋮----
import {IKeyRegistry} from "../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
⋮----
import {OzEIP712} from "../../src/modules/base/OzEIP712.sol";
⋮----
import {Checkpoints} from "../../src/libraries/structs/Checkpoints.sol";
import {InputNormalizer} from "../../src/libraries/utils/InputNormalizer.sol";
import {PersistentSet} from "../../src/libraries/structs/PersistentSet.sol";
⋮----
import {KeyTags} from "../../src/libraries/utils/KeyTags.sol";
import {KeyBlsBn254} from "../../src/libraries/keys/KeyBlsBn254.sol";
import {KeyEcdsaSecp256k1} from "../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
⋮----
import {SigBlsBn254} from "../../src/libraries/sigs/SigBlsBn254.sol";
import {SigEcdsaSecp256k1} from "../../src/libraries/sigs/SigEcdsaSecp256k1.sol";
⋮----
contract KeyRegistryWithKey64 is KeyRegistry {
⋮----
function getKeyAt(address operator, uint8 tag, uint48 timestamp) public view override returns (bytes memory) {
⋮----
function getKey(address operator, uint8 tag) public view override returns (bytes memory) {
⋮----
function _setKey(address operator, uint8 tag, bytes memory key) internal override {
⋮----
function _verifyKey(
````
## File: test/mocks/NoPermissionManager.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {PermissionManager} from "../../src/modules/base/PermissionManager.sol";
⋮----
abstract contract NoPermissionManager is PermissionManager {
function __NoPermissionManager_init() internal virtual onlyInitializing {}
function _checkPermission() internal pure virtual override {}
````
## File: test/mocks/RewarderMock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IBaseRewards} from "../../src/interfaces/modules/voting-power/extensions/IBaseRewards.sol";
⋮----
contract RewarderMock {
function distributeStakerRewards(
⋮----
function distributeOperatorRewards(
````
## File: test/mocks/SigVerifierFalseMock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {ISigVerifier} from "../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
⋮----
contract SigVerifierFalseMock is ISigVerifier {
/**
* @inheritdoc ISigVerifier
*/
⋮----
function verifyQuorumSig(
address, /* settlement */
uint48, /* epoch */
bytes memory, /* message */
uint8, /* keyTag */
uint256, /* quorumThreshold */
bytes calldata /* proof */
````
## File: test/mocks/SigVerifierMock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {ISigVerifier} from "../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
⋮----
contract SigVerifierMock is ISigVerifier {
/**
* @inheritdoc ISigVerifier
*/
⋮----
function verifyQuorumSig(
address, /* settlement */
uint48, /* epoch */
bytes memory, /* message */
uint8, /* keyTag */
uint256, /* quorumThreshold */
bytes calldata /* proof */
````
## File: test/mocks/SlasherMock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {IBaseSlashing} from "../../src/interfaces/modules/voting-power/extensions/IBaseSlashing.sol";
⋮----
contract SlasherMock {
function slashVault(
⋮----
function executeSlashVault(address middleware, address vault, uint256 slashIndex, bytes memory hints)
````
## File: test/mocks/ValSetVerifierMock.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {ValSetVerifier} from "../../src/libraries/utils/ValSetVerifier.sol";
⋮----
contract ValSetVerifierMock {
function verifyOperator(
⋮----
function verifyValidatorRootLocal(
⋮----
function verifyValidatorOperatorLocal(ValSetVerifier.SszProof calldata operatorRootProof, bytes32 validatorSetRoot)
⋮----
function verifyValidatorVaultRootLocal(
⋮----
function verifyVaultVotingPowerLocal(ValSetVerifier.SszProof calldata vaultVotingPowerProof, bytes32 vaultRoot)
````
## File: test/mocks/VotingPowerProviderFull.sol
````
// SPDX-License-Identifier: MIT
⋮----
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 {OperatorsBlacklist} from "../../src/modules/voting-power/extensions/OperatorsBlacklist.sol";
import {OperatorsWhitelist} from "../../src/modules/voting-power/extensions/OperatorsWhitelist.sol";
import {NetworkManager} from "../../src/modules/base/NetworkManager.sol";
import {OpNetVaultAutoDeploy} from "../../src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol";
import {OperatorVaults} from "../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {BaseSlashing} from "../../src/modules/voting-power/extensions/BaseSlashing.sol";
import {
PricedTokensChainlinkVPCalc
} from "../../src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.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 VotingPowerProviderFull is
⋮----
function initialize(
⋮----
function _registerOperatorImpl(address operator)
⋮----
function _unregisterOperatorVaultImpl(address operator, address vault)
⋮----
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
````
## File: test/mocks/VotingPowerProviderSemiFull.sol
````
// SPDX-License-Identifier: MIT
⋮----
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 {SharedVaults} from "../../src/modules/voting-power/extensions/SharedVaults.sol";
import {MultiToken} from "../../src/modules/voting-power/extensions/MultiToken.sol";
import {OperatorsBlacklist} from "../../src/modules/voting-power/extensions/OperatorsBlacklist.sol";
import {OperatorsWhitelist} from "../../src/modules/voting-power/extensions/OperatorsWhitelist.sol";
import {NetworkManager} from "../../src/modules/base/NetworkManager.sol";
import {OpNetVaultAutoDeploy} from "../../src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol";
import {OperatorVaults} from "../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {BaseSlashing} from "../../src/modules/voting-power/extensions/BaseSlashing.sol";
import {BaseRewards} from "../../src/modules/voting-power/extensions/BaseRewards.sol";
⋮----
contract VotingPowerProviderSemiFull is
⋮----
function initialize(
⋮----
function _registerOperatorImpl(address operator)
````
## File: test/mocks/VotingPowerProviderSharedVaults.sol
````
// SPDX-License-Identifier: MIT
⋮----
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 {SharedVaults} from "../../src/modules/voting-power/extensions/SharedVaults.sol";
⋮----
contract VotingPowerProviderSharedVaults is VotingPowerProvider, OzOwnable, EqualStakeVPCalc, SharedVaults {
⋮----
function initialize(
````
## File: test/modules/base/NetworkManager.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {NetworkManager} from "../../../src/modules/base/NetworkManager.sol";
import {INetworkManager} from "../../../src/interfaces/modules/base/INetworkManager.sol";
⋮----
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
⋮----
contract TestNetworkManager is NetworkManager {
function initialize(address net, uint96 subID) external initializer {
⋮----
contract NetworkManagerTest is Test {
⋮----
function setUp() public {
⋮----
function test_InitializeAndCheckGetters() public {
⋮----
function test_ReinitializeReverts() public {
⋮----
function test_DefaultsBeforeInit() public {
⋮----
function test_Location() public {
⋮----
function test_RevertNetworkManager_InvalidNetwork() public {
````
## File: test/modules/base/OzEIP712.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {OzEIP712} from "../../../src/modules/base/OzEIP712.sol";
import {IOzEIP712} from "../../../src/interfaces/modules/base/IOzEIP712.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
⋮----
contract TestOzEIP712 is OzEIP712 {
function initialize(string memory _name, string memory _version) external initializer {
⋮----
contract OzEIP712Test is Test {
⋮----
function setUp() public {
⋮----
function test_InitializeSetsDomain() public {
⋮----
function test_Location() public {
⋮----
function test_HashTypedDataV4() public {
⋮----
function test_SignatureRecovery() public {
⋮----
function test_ReInitialize() public {
````
## File: test/modules/base/PermissionManager.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {PermissionManager} from "../../../src/modules/base/PermissionManager.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
⋮----
contract TestPermissionManager is PermissionManager {
⋮----
function initialize(address _owner) external initializer {
⋮----
function _checkPermission() internal view override {
⋮----
function protectedAction() external checkPermission {}
⋮----
contract PermissionManagerTest is Test {
⋮----
function setUp() public {
⋮----
function test_ProtectedAction_SucceedsForOwner() public {
⋮----
function test_ProtectedAction_RevertIfNotOwner() public {
````
## File: test/modules/base/VotingPowerCalcManager.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {VotingPowerCalcManager} from "../../../src/modules/voting-power/base/VotingPowerCalcManager.sol";
⋮----
contract TestVotingPowerCalcManager is VotingPowerCalcManager {
⋮----
function initialize() external initializer {
⋮----
function stakeToVotingPowerAt(address vault, uint256 stake, bytes memory extraData, uint48 timestamp)
⋮----
function stakeToVotingPower(address vault, uint256 stake, bytes memory extraData)
⋮----
contract VotingPowerCalcManagerTest is Test {
⋮----
function setUp() public {
⋮----
function testReInitializeReverts() public {
⋮----
function testStakeToVotingPowerAt() public {
⋮----
// We'll pass in some dummy values for the other arguments.
⋮----
function testStakeToVotingPower() public {
⋮----
function testWithExtraData() public {
````
## File: test/modules/common/permissions/NoPermissionManager.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
⋮----
contract TestNoPermissionManager is NoPermissionManager {
function initialize() external initializer {}
⋮----
function actionRequiringNoPermission() external checkPermission {}
⋮----
contract NoPermissionManagerTest is Test {
⋮----
function setUp() public {
⋮----
function test_NoPermissionCheck() public {
````
## File: test/modules/common/permissions/OzAccessControl.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {OzAccessControl} from "../../../../src/modules/common/permissions/OzAccessControl.sol";
import {IOzAccessControl} from "../../../../src/interfaces/modules/common/permissions/IOzAccessControl.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
⋮----
contract TestOzAccessControl is OzAccessControl {
⋮----
function initialize() external initializer {
⋮----
function protectedFunction() external checkPermission {}
⋮----
function setSelectorRole(bytes4 selector, bytes32 role) external {
⋮----
contract OzAccessControlTest is Test {
⋮----
function setUp() public {
⋮----
function test_Location() public {
⋮----
function test_ProtectedFunction_DefaultAdminCanCall() public {
⋮----
function testProtectedFunction_RevertIfCallerDoesNotHaveRole() public {
⋮----
function testChangeRoleForProtectedFunction() public {
⋮----
function testGetRoleForFunctionSelector() public {
⋮----
function testSetNoRoleForSelector() public {
````
## File: test/modules/common/permissions/OzAccessManaged.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {OzAccessManaged} from "../../../../src/modules/common/permissions/OzAccessManaged.sol";
⋮----
import {IAuthority} from "@openzeppelin/contracts/access/manager/IAuthority.sol";
⋮----
contract MockAuthority is IAuthority {
⋮----
function canCall(address caller, address target, bytes4 selector) external view returns (bool) {
⋮----
contract TestOzAccessManaged is OzAccessManaged {
function protectedAction() external checkPermission {}
⋮----
function initialize(address authority) external initializer {
⋮----
contract OzAccessManagedTest is Test {
⋮----
function setUp() public {
⋮----
function testProtectedAction_SucceedsForAdmin() public {
⋮----
function testProtectedAction_RevertsForNonAdmin() public {
⋮----
function testCannotChangeAuthority() public {
````
## File: test/modules/common/permissions/OzOwnable.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {OzOwnable} from "../../../../src/modules/common/permissions/OzOwnable.sol";
⋮----
contract TestOzOwnable is OzOwnable {
function initialize(address owner_) external initializer {
⋮----
function protectedAction() external checkPermission {}
⋮----
contract OzOwnableTest is Test {
⋮----
function setUp() public {
⋮----
function testProtectedAction_SucceedsForOwner() public {
⋮----
function testProtectedAction_RevertsForNonOwner() public {
⋮----
function testReinitializeReverts() public {
⋮----
function testTransferOwnership() public {
⋮----
testOwnable.protectedAction(); // should succeed
````
## File: test/modules/key-registry/KeyRegistry.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {KeyRegistry} from "../../../src/modules/key-registry/KeyRegistry.sol";
import {IKeyRegistry} from "../../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
import {KeyBlsBn254} from "../../../src/libraries/keys/KeyBlsBn254.sol";
import {KeyEcdsaSecp256k1} from "../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {BN254} from "../../../src/libraries/utils/BN254.sol";
import {BN254G2} from "../../helpers/BN254G2.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {
KEY_TYPE_BLS_BN254,
KEY_TYPE_ECDSA_SECP256K1
} from "../../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
import {IOzEIP712} from "../../../src/interfaces/modules/base/IOzEIP712.sol";
import {KeyTags} from "../../../src/libraries/utils/KeyTags.sol";
⋮----
import {KeyRegistryWithKey64, KEY_TYPE_KEY64} from "../../mocks/KeyRegistryWithKey64.sol";
⋮----
contract TestKeyRegistry is KeyRegistryWithKey64 {
function initialize(string memory name_, string memory version_) external initializer {
⋮----
function getKeyTagsAt(address operator, uint48 timestamp) public view virtual returns (uint8[] memory) {
⋮----
function getKeyTags(address operator) public view virtual returns (uint8[] memory) {
⋮----
contract KeyRegistryTest is Test {
⋮----
function getG2Key(uint256 privateKey) internal view returns (BN254.G2Point memory) {
⋮----
function setUp() public {
⋮----
function test_SetECDSAKey() public {
⋮----
function test_SetECDSAKey_RevertOnInvalidSignature() public {
⋮----
function test_SetBLSKey() public {
⋮----
function test_SetKey_AlreadyUsedKeyDifferentOperator() public {
⋮----
function test_SetKey_SameOperatorSameTag_Overwrite() public {
⋮----
function test_SetKey_SameOperatorDifferentTags() public {
⋮----
function test_SetKey_RevertOnInvalidKeyType() public {
⋮----
function test_GetOperator_UnknownKey() public {
⋮----
function test_GetKeysOperators_MultipleOperators() public {
⋮----
function test_GetKeysAt_TimeCheckpoints() public {
⋮----
function _registerSimpleECDSA(address operator, uint256 pk, uint8 tagIdentifier) internal {
⋮----
function test_SetKey64() public {
⋮----
function test_Location() public {
````
## File: test/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test} from "forge-std/Test.sol";
import {ExtraDataStorageHelper} from "src/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.sol";
⋮----
contract ExtraDataStorageHelperTest is Test {
function _randomNameHash(string memory seed) internal pure returns (bytes32) {
⋮----
function test_BaseKey() public {
⋮----
function test_TaggedKey() public {
⋮----
function test_IndexedKey() public {
⋮----
// Check first few indices
⋮----
function testFuzz_Uniqueness(
⋮----
function test_SimpleKey() public {
⋮----
function test_TagOnlyKey() public {
⋮----
function test_IndexedTagOnlyKey() public {
````
## File: test/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyTags} from "../../../../src/libraries/utils/KeyTags.sol";
import {KeyEcdsaSecp256k1} from "../../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyBlsBn254, BN254} from "../../../../src/libraries/keys/KeyBlsBn254.sol";
import {SigBlsBn254} from "../../../../src/libraries/sigs/SigBlsBn254.sol";
import {
KEY_TYPE_BLS_BN254,
KEY_TYPE_ECDSA_SECP256K1
} from "../../../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
import {
ExtraDataStorageHelper
} from "../../../../src/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.sol";
⋮----
import {BN254G2} from "../../../helpers/BN254G2.sol";
⋮----
import {ISettlement} from "../../../../src/interfaces/modules/settlement/ISettlement.sol";
import {IOzOwnable} from "../../../../src/interfaces/modules/common/permissions/IOzOwnable.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IEpochManager} from "../../../../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {IOperatorsWhitelist} from "../../../../src/interfaces/modules/voting-power/extensions/IOperatorsWhitelist.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {
ISigVerifierBlsBn254Simple
} from "../../../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254Simple.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
⋮----
import {MasterSetupTest} from "../../../MasterSetup.sol";
⋮----
import {console2} from "forge-std/console2.sol";
⋮----
import {
SigVerifierBlsBn254Simple
} from "../../../../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol";
import "../../../InitSetup.sol";
⋮----
import {ISigVerifier} from "../../../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
⋮----
import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
⋮----
import {VotingPowerProviderSemiFull} from "../../../mocks/VotingPowerProviderSemiFull.sol";
import {MyKeyRegistry} from "../../../../examples/MyKeyRegistry.sol";
import {MySettlement} from "../../../../examples/MySettlement.sol";
import {MyValSetDriver} from "../../../../examples/MyValSetDriver.sol";
⋮----
import {IKeyRegistry} from "../../../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
import {IValSetDriver} from "../../../../src/interfaces/modules/valset-driver/IValSetDriver.sol";
⋮----
contract SigVerifierBlsBn254SimpleTest is MasterSetupTest {
⋮----
function setUp() public override {
⋮----
function test_verifyQuorumSig1() public {
⋮----
function test_verifyQuorumSig2() public {
⋮----
function test_verifyQuorumSig3() public {
⋮----
function test_RevertUnsupportedKeyTag() public {
⋮----
function test_RevertInvalidMessageLength() public {
⋮----
function test_RevertInvalidProofOffset() public {
⋮----
function test_RevertInvalidProofLength() public {
⋮----
function test_ZeroValidators() public {
⋮----
function test_RevertTooManyValidators() public {
⋮----
function test_RevertInvalidNonSignerIndex() public {
⋮----
function test_RevertInvalidNonSignersOrder() public {
⋮----
function test_FalseValidatorSet() public {
⋮----
function test_Revert_InvalidNonSignersOrder() public {
⋮----
function test_FalseQuorumThreshold() public {
⋮----
function loadGenesisSimple()
⋮----
function getValidatorsData() public returns (ValidatorData[] memory validatorsData, uint256[] memory privateKeys) {
````
## File: test/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {KeyTags} from "../../../../src/libraries/utils/KeyTags.sol";
import {KeyEcdsaSecp256k1} from "../../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyBlsBn254, BN254} from "../../../../src/libraries/keys/KeyBlsBn254.sol";
import {SigBlsBn254} from "../../../../src/libraries/sigs/SigBlsBn254.sol";
import {
KEY_TYPE_BLS_BN254,
KEY_TYPE_ECDSA_SECP256K1
} from "../../../../src/interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
import {BN254G2} from "../../../helpers/BN254G2.sol";
⋮----
import {ISettlement} from "../../../../src/interfaces/modules/settlement/ISettlement.sol";
⋮----
import "../../../MasterGenesisSetup.sol";
⋮----
import {console2} from "forge-std/console2.sol";
import {stdStorage, StdStorage} from "forge-std/Test.sol";
⋮----
import {SigVerifierBlsBn254ZK} from "../../../../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol";
⋮----
import {ISigVerifier} from "../../../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {
ISigVerifierBlsBn254ZK
} from "../../../../src/interfaces/modules/settlement/sig-verifiers/ISigVerifierBlsBn254ZK.sol";
⋮----
import {
ExtraDataStorageHelper
} from "../../../../src/modules/settlement/sig-verifiers/libraries/ExtraDataStorageHelper.sol";
⋮----
import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
⋮----
contract SigVerifierBlsBn254ZKTest is MasterGenesisSetupTest {
⋮----
function setUp() public override {
⋮----
function test_Create() public {
⋮----
function test_RevertInvalidLength() public {
⋮----
function test_Revert_InvalidMaxValidators() public {
⋮----
function test_Revert_InvalidVerifier() public {
⋮----
function test_Revert_InvalidMaxValidatorsOrder() public {
⋮----
function test_Revert_UnsupportedKeyTag() public {
⋮----
function test_Revert_InvalidMessageLength() public {
⋮----
function test_Revert_InvalidProofLength() public {
⋮----
function test_FalseQuorumThreshold() public {
⋮----
function test_verifyQuorumSig() public {
⋮----
function test_verifyQuorumSig_FalseZkProof() public {
⋮----
function test_ZeroValidators() public {
⋮----
function test_RevertInvalidTotalActiveValidators() public {
````
## File: test/modules/settlement/Settlement.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test} from "forge-std/Test.sol";
⋮----
import {KeyTags} from "../../../src/libraries/utils/KeyTags.sol";
import {KeyEcdsaSecp256k1} from "../../../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyBlsBn254, BN254} from "../../../src/libraries/keys/KeyBlsBn254.sol";
import {SigBlsBn254} from "../../../src/libraries/sigs/SigBlsBn254.sol";
⋮----
import {BN254G2} from "../../helpers/BN254G2.sol";
⋮----
import {ISettlement} from "../../../src/interfaces/modules/settlement/ISettlement.sol";
⋮----
import {MasterGenesisSetupTest} from "../../MasterGenesisSetup.sol";
⋮----
import {console2} from "forge-std/console2.sol";
⋮----
import {SigVerifierBlsBn254ZK} from "../../../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol";
⋮----
import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Settlement} from "../../../src/modules/settlement/Settlement.sol";
⋮----
import {IOzEIP712} from "../../../src/interfaces/modules/base/IOzEIP712.sol";
import {INetworkManager} from "../../../src/interfaces/modules/base/INetworkManager.sol";
import {SigVerifierMock} from "../../mocks/SigVerifierMock.sol";
import {SigVerifierBlsBn254Simple} from "../../../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol";
import {SigVerifierFalseMock} from "../../mocks/SigVerifierFalseMock.sol";
⋮----
contract SettlementTest is MasterGenesisSetupTest {
⋮----
function setUp() public override {
⋮----
// function test_commitValSetHeader() public {
// (ISettlement.ValSetHeader memory valSetHeader, ISettlement.ExtraData[] memory extraData) = loadGenesis();
⋮----
// valSetHeader.epoch = 1;
// valSetHeader.captureTimestamp = uint48(vm.getBlockTimestamp()) - 1;
⋮----
// bytes32 messageHash = masterSetupParams.master.hashTypedDataV4CrossChain(
// keccak256(
// abi.encode(
// VALSET_HEADER_COMMIT_TYPEHASH,
// masterSetupParams.master.SUBNETWORK(),
// 0,
// keccak256(abi.encode(valSetHeader)),
// keccak256(abi.encode(extraData))
// )
// )
// );
⋮----
// console2.log("messageHash");
// console2.logBytes32(messageHash);
⋮----
// BN254.G1Point memory aggKeyG1;
// BN254.G2Point memory aggKeyG2;
// BN254.G1Point memory aggSigG1;
⋮----
// for (uint256 i; i < vars.operators.length; ++i) {
// BN254.G1Point memory keyG1 = BN254.generatorG1().scalar_mul(vars.operators[i].privateKey);
⋮----
// BN254.G2Point memory keyG2 = getG2Key(vars.operators[i].privateKey);
// BN254.G1Point memory messageG1 = BN254.hashToG1(messageHash);
// BN254.G1Point memory sigG1 = messageG1.scalar_mul(vars.operators[i].privateKey);
// aggSigG1 = aggSigG1.plus(sigG1);
// aggKeyG1 = aggKeyG1.plus(keyG1);
⋮----
// if (aggKeyG2.X[0] == 0 && aggKeyG2.X[1] == 0 && aggKeyG2.Y[0] == 0 && aggKeyG2.Y[1] == 0) {
// aggKeyG2 = keyG2;
// } else {
// (uint256 x1, uint256 x2, uint256 y1, uint256 y2) = BN254G2.ECTwistAdd(
// aggKeyG2.X[1],
// aggKeyG2.X[0],
// aggKeyG2.Y[1],
// aggKeyG2.Y[0],
// keyG2.X[1],
// keyG2.X[0],
// keyG2.Y[1],
// keyG2.Y[0]
// );
// aggKeyG2 = BN254.G2Point([x2, x1], [y2, y1]);
// }
// }
⋮----
// bytes memory zkProof =
// hex"0c9d92bd8aac8588329e85aade26354a7b9206e170f0df0ee891c3927e5a58522adf6d35c9649dbf628cfe567bc31647d52cf5ae023c88984cecbf01fb477d492761b1f57ca217b83d1851f3e9276e3a758fe92b0f7022d9610ed51e1d7da1521458461ac568a806eb566e1f177baba0bee7c49bbb225347da8d236def25eb3829f4a51eecc66d28b5c973a943d752aa383cbab591b59406da361cbeac1dfcc22afdfa764b84685fabc31a3e5367ca30c2eaa3480ec44a9f847f952da34df4ca0ec698607fb631abd2939ea85d57c69e097b8cdba0734b21154479dc7c39d2a11d2dec162d71b5fad118e59a9dd6917335f251384a3cb16ed48af9f3dbed8266000000011199b925c505c27fe05e9f75e2a0965aea4b6cdb945a4a481c6bc06bd080da701cd2629a69c1946bcd2695c369de10999ce9ec4f0c51d1f8d265460b4f2646d923e00d2fa0a29d4760394d8da2af4f7545377705157c75b86a20044f792a50b30068fdfeaa3eb3be8444c454fdf3629d902034c84714a652394c35da7fa2fb6f";
⋮----
// bytes memory proof_ = Bytes.slice(zkProof, 0, 256);
// bytes memory commitments = Bytes.slice(zkProof, 260, 324);
// bytes memory commitmentPok = Bytes.slice(zkProof, 324, 388);
⋮----
// IVotingPowerProvider.OperatorVotingPower[] memory votingPowers =
// masterSetupParams.votingPowerProvider.getVotingPowers(new bytes[](0));
// uint256 signersVotingPower = 0;
// for (uint256 i; i < votingPowers.length; ++i) {
// for (uint256 j; j < votingPowers[i].vaults.length; ++j) {
// signersVotingPower += votingPowers[i].vaults[j].value;
⋮----
// bytes memory fullProof = abi.encodePacked(proof_, commitments, commitmentPok, signersVotingPower);
⋮----
// masterSetupParams.master.commitValSetHeader(valSetHeader, extraData, fullProof, new bytes(0));
// }
⋮----
contract TestSettlement is Settlement {
⋮----
function initialize(SettlementInitParams memory settlementInitParams, address _owner) external initializer {
⋮----
// PermissionManager requirement:
function _checkPermission() internal view override {
⋮----
contract SettlementRawTest is Test {
⋮----
function setUp() public {
⋮----
function testVersion() public {
⋮----
function testInitParams() public {
⋮----
function testSetGenesis_Permission() public {
⋮----
function testSetGenesis_Revert_ValSetHeaderAlreadySubmitted() public {
⋮----
function testCommitValSetHeader_Basic() public {
⋮----
// address sigVerifier = address(new SigVerifierBlsBn254Simple());
// vm.prank(owner);
// testSettle.setSigVerifier(sigVerifier);
⋮----
function test_setSigVerifier() public {
⋮----
function test_setSigVerifier_Revert_InvalidSigVerifier() public {
⋮----
function test_commitValSetHeader_VerificationFailed() public {
````
## File: test/modules/valset-driver/EpochManager.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
import {NoPermissionManager} from "../../mocks/NoPermissionManager.sol";
import {EpochManager} from "../../../src/modules/valset-driver/EpochManager.sol";
import {IEpochManager} from "../../../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {Checkpoints} from "../../../src/libraries/structs/Checkpoints.sol";
⋮----
contract TestEpochManager is EpochManager, NoPermissionManager {
⋮----
function initialize(EpochManagerInitParams memory initParams) external initializer {
⋮----
function getEpochDurationDataByTimestamp(uint48 timestamp) public view returns (uint48, uint48, uint48) {
⋮----
function getEpochDurationDataByIndex(uint48 index) public view returns (uint48, uint48, uint48) {
⋮----
function getCurrentEpochDurationData() public view returns (uint48, uint48, uint48) {
⋮----
function setEpochDuration(uint48 epochDuration, uint48 epochDurationTimestamp, uint48 epochDurationIndex) public {
⋮----
function serializeEpochDurationData(uint48 epochDuration, uint48 epochDurationTimestamp, uint48 epochDurationIndex)
⋮----
function deserializeEpochDurationData(uint208 epochDurationData) public pure returns (uint48, uint48, uint48) {
⋮----
function getCurrentValuePublic(uint48 currentTimepoint) public view returns (uint208) {
⋮----
function pushTestCheckpoint(uint48 key, uint208 value) public {
⋮----
contract EpochManagerTest is Test {
⋮----
function setUp() public {
⋮----
function test_Initialize_SetsEpochDuration() public {
⋮----
function test_Initialize_SetsEpochDuration_WithZeroTimestamp() public {
⋮----
function test_Initialize_RevertOnZeroEpochDuration() public {
⋮----
function test_Initialize_RevertOnPastTimestamp() public {
⋮----
function test_AdvanceTimeAndCheckEpoch() public {
⋮----
function test_SetEpochDuration_RevertIfIndexLessThanCurrent() public {
⋮----
function test_SetEpochDuration_RevertOnZeroDuration() public {
⋮----
function test_GetEpochIndex() public {
⋮----
function test_GetEpochIndex_RevertIfTooOldTimestamp() public {
⋮----
function test_GetEpochDurationAndStart() public {
⋮----
function test_SerializeDeserializeEpochDurationData() public {
⋮----
function test_GetEpochDurationDataByTimestamp() public {
⋮----
function test_GetEpochDurationDataByIndex() public {
⋮----
function test_GetCurrentEpochDurationData() public {
⋮----
function test_DirectSetEpochDuration() public {
⋮----
function test_GetCurrentValue_NoCheckpoint() public {
⋮----
function test_GetCurrentValue_SingleCheckpoint() public {
⋮----
function test_GetCurrentValue_MultipleCheckpoints() public {
⋮----
// getCurrentValuePublic is unreliable for cases when there are more than 1 checkpoint in the future
````
## File: test/modules/valset-driver/ValSetDriver.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {ValSetDriver} from "../../../src/modules/valset-driver/ValSetDriver.sol";
import {IValSetDriver} from "../../../src/interfaces/modules/valset-driver/IValSetDriver.sol";
⋮----
import {INetworkManager} from "../../../src/interfaces/modules/base/INetworkManager.sol";
import {IEpochManager} from "../../../src/interfaces/modules/valset-driver/IEpochManager.sol";
⋮----
contract TestValSetDriver is ValSetDriver {
⋮----
function initialize(IValSetDriver.ValSetDriverInitParams memory initParams, address _owner) external initializer {
⋮----
function _checkPermission() internal view override {
⋮----
contract ValSetDriverTest is Test {
⋮----
function cca(address _addr, uint64 _chainId) internal pure returns (IValSetDriver.CrossChainAddress memory) {
⋮----
function qth(uint8 _keyTag, uint248 _quorumThreshold) internal pure returns (IValSetDriver.QuorumThreshold memory) {
⋮----
function setUp() public {
⋮----
function test_InitialConfig() public {
⋮----
function test_PermissionChecks() public {
⋮----
function test_AddRemoveVotingPowerProvider() public {
⋮----
function test_SetKeysProvider() public {
⋮----
function test_AddRemoveSettlement() public {
⋮----
function test_AddRemoveQuorumThreshold() public {
⋮----
function test_SetVerificationType() public {
⋮----
function test_TimeBasedQueries() public {
⋮----
function test_SetNumAggregators() public {
⋮----
function test_SetNumCommitters() public {
⋮----
function test_Location() public {
⋮----
function test_UpdateAllConfigs() public {
⋮----
function test_TimeBasedConfig() public {
⋮----
function test_GetValSetConfig() public {
````
## File: test/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {
NormalizedTokenDecimalsVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol";
import {OperatorVaults} from "../../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import {BN254} from "../../../../../src/libraries/utils/BN254.sol";
import "../../../../InitSetup.sol";
⋮----
contract MockToken is ERC20 {
⋮----
_mint(msg.sender, type(uint128).max); // plenty for tests
⋮----
function decimals() public view override returns (uint8) {
⋮----
contract TestVotingPowerProvider is VotingPowerProvider, NormalizedTokenDecimalsVPCalc, NoPermissionManager {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function getTokensLength() external view returns (uint256) {
⋮----
function getOperatorsLength() external view returns (uint256) {
⋮----
function getSharedVaultsLength() external view returns (uint256) {
⋮----
function getOperatorVaultsLength(address operator) external view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) external view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) external view returns (uint256) {
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator(address operator) external {
⋮----
function unregisterOperator(address operator) external {
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) external {
⋮----
function registerToken(address token) external {
⋮----
function unregisterToken(address token) external {
⋮----
function registerSharedVault(address vault) external {
⋮----
function unregisterSharedVault(address vault) external {
⋮----
function registerOperatorVault(address operator, address vault) external {
⋮----
function unregisterOperatorVault(address operator, address vault) external {
⋮----
function validateVault(address vault) external view returns (bool) {
⋮----
function validateSharedVault(address vault) external view returns (bool) {
⋮----
function validateOperatorVault(address operator, address vault) external view returns (bool) {
⋮----
function validateVaultSlashing(address vault) external view returns (bool) {
⋮----
contract NormalizedTokenDecimalsVPCalcTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_CheckStakes_18() public {
⋮----
function test_CheckStakes_24() public {
⋮----
function test_CheckStakes_8() public {
````
## File: test/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {IVotingPowerProvider} from "../../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../../src/interfaces/modules/base/IOzEIP712.sol";
⋮----
import {
PricedTokensChainlinkVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.sol";
import {NoPermissionManager} from "../../../../../test/mocks/NoPermissionManager.sol";
import {
IPricedTokensChainlinkVPCalc
} from "../../../../../src/interfaces/modules/voting-power/common/voting-power-calc/IPricedTokensChainlinkVPCalc.sol";
import {
ChainlinkPriceFeed
} from "../../../../../src/modules/voting-power/common/voting-power-calc/libraries/ChainlinkPriceFeed.sol";
⋮----
import {
AggregatorV3Interface
} from "../../../../../src/interfaces/modules/voting-power/common/voting-power-calc/libraries/AggregatorV3Interface.sol";
⋮----
import "../../../../InitSetup.sol";
⋮----
contract TestVotingPowerProvider is VotingPowerProvider, PricedTokensChainlinkVPCalc, NoPermissionManager {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function getTokensLength() external view returns (uint256) {
⋮----
function getOperatorsLength() external view returns (uint256) {
⋮----
function getSharedVaultsLength() external view returns (uint256) {
⋮----
function getOperatorVaultsLength(address operator) external view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) external view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) external view returns (uint256) {
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator(address operator) external {
⋮----
function unregisterOperator(address operator) external {
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) external {
⋮----
function registerToken(address token) external {
⋮----
function unregisterToken(address token) external {
⋮----
function registerSharedVault(address vault) external {
⋮----
function unregisterSharedVault(address vault) external {
⋮----
function registerOperatorVault(address operator, address vault) external {
⋮----
function unregisterOperatorVault(address operator, address vault) external {
⋮----
function validateVault(address vault) external view returns (bool) {
⋮----
function validateSharedVault(address vault) external view returns (bool) {
⋮----
function validateOperatorVault(address operator, address vault) external view returns (bool) {
⋮----
function validateVaultSlashing(address vault) external view returns (bool) {
⋮----
contract PricedTokensChainlinkVPCalcTest is InitSetupTest {
⋮----
function setUp() public override {}
⋮----
function test_ChainlinkCalcTracksRealPrice() public {
⋮----
function test_ChainlinkCalcTracksRealPriceWithInvert() public {
⋮----
function test_ChainlinkCalcTracksRealPriceStale() public {
⋮----
function test_ChainlinkCalcTracksRealPriceHistorical() public {
⋮----
function test_ChainlinkCalcTracksRealPriceHistoricalZero() public {
````
## File: test/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {
NormalizedTokenDecimalsVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol";
import {
WeightedTokensVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.sol";
import {OperatorVaults} from "../../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import {
IWeightedTokensVPCalc
} from "../../../../../src/interfaces/modules/voting-power/common/voting-power-calc/IWeightedTokensVPCalc.sol";
⋮----
import {BN254} from "../../../../../src/libraries/utils/BN254.sol";
import "../../../../InitSetup.sol";
⋮----
contract MockToken is ERC20 {
⋮----
_mint(msg.sender, type(uint128).max); // plenty for tests
⋮----
function decimals() public view override returns (uint8) {
⋮----
contract TestVotingPowerProvider is VotingPowerProvider, WeightedTokensVPCalc, NoPermissionManager {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function getTokensLength() external view returns (uint256) {
⋮----
function getOperatorsLength() external view returns (uint256) {
⋮----
function getSharedVaultsLength() external view returns (uint256) {
⋮----
function getOperatorVaultsLength(address operator) external view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) external view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) external view returns (uint256) {
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator(address operator) external {
⋮----
function unregisterOperator(address operator) external {
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) external {
⋮----
function registerToken(address token) external {
⋮----
function unregisterToken(address token) external {
⋮----
function registerSharedVault(address vault) external {
⋮----
function unregisterSharedVault(address vault) external {
⋮----
function registerOperatorVault(address operator, address vault) external {
⋮----
function unregisterOperatorVault(address operator, address vault) external {
⋮----
function validateVault(address vault) external view returns (bool) {
⋮----
function validateSharedVault(address vault) external view returns (bool) {
⋮----
function validateOperatorVault(address operator, address vault) external view returns (bool) {
⋮----
function validateVaultSlashing(address vault) external view returns (bool) {
⋮----
contract WeightedTokensVPCalcTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_CheckStakesTokenWeight() public {
⋮----
function test_SetTokenWeight_RevertIfTooLarge() public {
⋮----
function test_StakeToVotingPowerAt_UsesHistoricalTokenWeightAndNormalization() public {
⋮----
// Make a deposit at t0
⋮----
// Default weight is 1e12 at t0
⋮----
// Change weight at t1 and ensure historical query at t0 still uses default weight
⋮----
// Another change at t2 should reflect new weight while t1 stays at previous
````
## File: test/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {
NormalizedTokenDecimalsVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol";
import {
WeightedVaultsVPCalc
} from "../../../../../src/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.sol";
import {OperatorVaults} from "../../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import {
IWeightedVaultsVPCalc
} from "../../../../../src/interfaces/modules/voting-power/common/voting-power-calc/IWeightedVaultsVPCalc.sol";
⋮----
import {BN254} from "../../../../../src/libraries/utils/BN254.sol";
import "../../../../InitSetup.sol";
⋮----
contract MockToken is ERC20 {
⋮----
_mint(msg.sender, type(uint128).max); // plenty for tests
⋮----
function decimals() public view override returns (uint8) {
⋮----
contract TestVotingPowerProvider is VotingPowerProvider, WeightedVaultsVPCalc, NoPermissionManager {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function getTokensLength() external view returns (uint256) {
⋮----
function getOperatorsLength() external view returns (uint256) {
⋮----
function getSharedVaultsLength() external view returns (uint256) {
⋮----
function getOperatorVaultsLength(address operator) external view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) external view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) external view returns (uint256) {
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator(address operator) external {
⋮----
function unregisterOperator(address operator) external {
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) external {
⋮----
function registerToken(address token) external {
⋮----
function unregisterToken(address token) external {
⋮----
function registerSharedVault(address vault) external {
⋮----
function unregisterSharedVault(address vault) external {
⋮----
function registerOperatorVault(address operator, address vault) external {
⋮----
function unregisterOperatorVault(address operator, address vault) external {
⋮----
function validateVault(address vault) external view returns (bool) {
⋮----
function validateSharedVault(address vault) external view returns (bool) {
⋮----
function validateOperatorVault(address operator, address vault) external view returns (bool) {
⋮----
function validateVaultSlashing(address vault) external view returns (bool) {
⋮----
contract WeightedVaultsVPCalcTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_CheckStakesVaultWeight() public {
⋮----
function test_SetVaultWeight_RevertIfTooLarge() public {
⋮----
function test_GetVaultWeightAt_UsesHistoricalVaultWeight() public {
⋮----
// At t0, vault weight should be default (1e4)
⋮----
// Change vault weight at t1
⋮----
// Historical query at t0 should still return default weight
⋮----
// Current query at t1 should return new weight
⋮----
// Another change at t2
⋮----
// Historical queries should return appropriate weights
⋮----
function test_StakeToVotingPowerAt_UsesHistoricalVaultWeight() public {
⋮----
// Make a deposit at t0
⋮----
// Default vault weight is 1e4 at t0
⋮----
// Change vault weight at t1 and ensure historical query at t0 still uses default weight
⋮----
// Another change at t2 should reflect new weight while t1 stays at previous
````
## File: test/modules/voting-power/extensions/BaseRewards.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import {BN254} from "../../../../src/libraries/utils/BN254.sol";
import "../../../MasterSetup.sol";
⋮----
import {RewarderMock} from "../../../../test/mocks/RewarderMock.sol";
⋮----
import {SymbioticRewardsBindings} from "@symbioticfi/rewards/test/integration/SymbioticRewardsBindings.sol";
import "@symbioticfi/rewards/test/integration/SymbioticRewardsImports.sol";
⋮----
contract BaseRewardsTest is MasterSetupTest, SymbioticRewardsBindings {
⋮----
function setUp() public override {
⋮----
function test_StakerRewards() public {
⋮----
function test_OperatorRewards() public {
⋮----
function _initRewards_SymbioticRewards() internal virtual {
⋮----
function test_Location() public {
⋮----
function _getDefaultStakerRewards_SymbioticRewards(address vault, uint256 adminFee, address admin)
⋮----
function _getDefaultOperatorRewards_SymbioticRewards() internal virtual returns (address) {
````
## File: test/modules/voting-power/extensions/BaseSlashing.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {IEntity} from "lib/core/src/interfaces/common/IEntity.sol";
import {IVault} from "lib/core/src/interfaces/vault/IVault.sol";
⋮----
import {BN254} from "../../../../src/libraries/utils/BN254.sol";
import "../../../MasterSetup.sol";
⋮----
import {SlasherMock} from "../../../../test/mocks/SlasherMock.sol";
⋮----
contract BaseSlashingTest is MasterSetupTest {
function setUp() public override {
⋮----
function test_SlashVault() public {
⋮----
function test_SlashVault_WithHints() public {
⋮----
function test_SlashVaultUnsafe() public {
⋮----
function test_SlashVault_VetoSlasher() public {
⋮----
function test_ExecuteSlashVaul_NotVetoSlasher() public {
⋮----
function test_ExecuteSlashVault_NoSlasher() public {
⋮----
function test_RevertWhen_SlashVault_NoSlashing() public {
⋮----
uint48(1), // set timestamp that has no slasher data
⋮----
function test_RevertWhen_SlashVault_UnknownSlasherType() public {
⋮----
// mock the slasher type to be unknown
⋮----
function test_SlashVault_EpochDurationPassed() public {
⋮----
// increase timestamp to pass the minVaultEpochDuration
⋮----
function test_Location() public {
````
## File: test/modules/voting-power/extensions/EqualStakeVPCalc.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
contract EqualStakeVPCalcTest is Test {
function setUp() public {}
⋮----
function test_create() public {}
````
## File: test/modules/voting-power/extensions/MultiToken.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IMultiToken} from "../../../../src/interfaces/modules/voting-power/extensions/IMultiToken.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import "../../../InitSetup.sol";
⋮----
contract TestMultiToken is NoPermissionManager, EqualStakeVPCalc, MultiToken {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
contract MultiTokenTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
function test_RegisterToken_OnlyOwnerCanCall() public {
⋮----
function test_RegisterUnregisterToken_VaultManagerSide() public {
````
## File: test/modules/voting-power/extensions/OperatorsBlacklist.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {OperatorsBlacklist} from "../../../../src/modules/voting-power/extensions/OperatorsBlacklist.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
⋮----
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOperatorsBlacklist} from "../../../../src/interfaces/modules/voting-power/extensions/IOperatorsBlacklist.sol";
import {InitSetupTest} from "../../../InitSetup.sol";
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
contract TestOperatorsBlacklist is
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function _registerOperatorImpl(address operator) internal override(OperatorsBlacklist, VotingPowerProvider) {
⋮----
contract OperatorsBlacklistTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// blacklistOps.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_BasicEnvironment() public {
⋮----
function test_BlacklistOperator() public {
⋮----
function test_BlacklistOperator_RevertIfAlreadyBlacklisted() public {
⋮----
function test_UnblacklistOperator() public {
⋮----
function test_UnblacklistOperator_RevertIfNotBlacklisted() public {
⋮----
function test_Location() public {
````
## File: test/modules/voting-power/extensions/OperatorsJail.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {OperatorsJail} from "../../../../src/modules/voting-power/extensions/OperatorsJail.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
⋮----
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOperatorsJail} from "../../../../src/interfaces/modules/voting-power/extensions/IOperatorsJail.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
⋮----
import {InitSetupTest} from "../../../InitSetup.sol";
⋮----
contract TestOperatorsJail is OperatorsJail, NoPermissionManager, EqualStakeVPCalc, MultiToken, OperatorVaults {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function _registerOperatorImpl(address operator) internal override(OperatorsJail, VotingPowerProvider) {
⋮----
contract OperatorsJailTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
function test_BasicEnvironment() public {
⋮----
function test_JailOperator() public {
⋮----
function test_JailOperator_RevertIfAlreadyJailed() public {
⋮----
function test_UnjailOperator() public {
⋮----
function test_UnjailOperator_RevertIfNotJailed() public {
⋮----
function test_Location() public {
````
## File: test/modules/voting-power/extensions/OperatorsWhitelist.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {IOperatorsWhitelist} from "../../../../src/interfaces/modules/voting-power/extensions/IOperatorsWhitelist.sol";
import "../../../InitSetup.sol";
⋮----
import {OperatorsWhitelist} from "../../../../src/modules/voting-power/extensions/OperatorsWhitelist.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
contract TestOperatorsWhitelist is
⋮----
function initialize(
⋮----
function _registerOperatorImpl(address operator) internal override(OperatorsWhitelist, VotingPowerProvider) {
⋮----
contract OperatorsWhitelistTest is Test, InitSetupTest {
⋮----
function setUp() public override {
⋮----
// whitelistOps.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_WhitelistEnabledByDefault() public {
⋮----
function test_RegisterOperator_RevertIfNotWhitelisted() public {
⋮----
function test_WhitelistOperatorAndRegister() public {
⋮----
function test_WhitelistOperator_RevertIfAlreadyWhitelisted() public {
⋮----
function test_UnwhitelistOperator_RegisteredOperatorGetsUnregistered() public {
⋮----
function test_UnwhitelistOperator_RevertIfNotWhitelisted() public {
⋮----
function test_DisableWhitelistAndRegister() public {
⋮----
function test_SetWhitelistStatus_RevertIfAlreadySet() public {
⋮----
function test_SetWhitelistStatus_RevertIfNotWhitelisted() public {
⋮----
function test_DisableWhitelistAndRegisterOperatorVault() public {
⋮----
function test_Location() public {
````
## File: test/modules/voting-power/extensions/OperatorVaults.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {IOperatorVaults} from "../../../../src/interfaces/modules/voting-power/extensions/IOperatorVaults.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {OzOwnable} from "../../../../src/modules/common/permissions/OzOwnable.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
⋮----
import "../../../InitSetup.sol";
⋮----
contract TestOperatorVaults is OperatorVaults, OzOwnable, EqualStakeVPCalc {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function registerToken(address token) public {
⋮----
contract OperatorVaultsTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
function test_RegisterOperatorVault_OnlyOwnerCanCall() public {
````
## File: test/modules/voting-power/extensions/OpNetVaultAutoDeploy.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {OpNetVaultAutoDeploy} from "../../../../src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {MultiToken} from "../../../../src/modules/voting-power/extensions/MultiToken.sol";
import {OperatorVaults} from "../../../../src/modules/voting-power/extensions/OperatorVaults.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {
IOpNetVaultAutoDeploy
} from "../../../../src/interfaces/modules/voting-power/extensions/IOpNetVaultAutoDeploy.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {InitSetupTest} from "../../../InitSetup.sol";
import {IVault} from "@symbioticfi/core/src/interfaces/vault/IVault.sol";
import {IBaseSlasher} from "@symbioticfi/core/src/interfaces/slasher/IBaseSlasher.sol";
import {INetworkMiddlewareService} from "@symbioticfi/core/src/interfaces/service/INetworkMiddlewareService.sol";
import {IBaseDelegator} from "@symbioticfi/core/src/interfaces/delegator/IBaseDelegator.sol";
⋮----
import {Network} from "@symbioticfi/network/src/Network.sol";
import {INetwork} from "@symbioticfi/network/src/interfaces/INetwork.sol";
⋮----
contract TestOpNetVaultAutoDeploy is
⋮----
function initialize(
⋮----
function _registerOperatorImpl(address operator) internal override(OpNetVaultAutoDeploy, VotingPowerProvider) {
⋮----
function _unregisterOperatorVaultImpl(address operator, address vault)
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) public {
⋮----
contract OpNetVaultAutoDeployTest is Test, InitSetupTest {
⋮----
function setUp() public override {
⋮----
function test_BasicFlags() public {
⋮----
function test_SetAutoDeployStatus() public {
⋮----
function test_SetAutoDeployConfig_InvalidCollateral() public {
⋮----
function test_SetAutoDeployConfig_InvalidEpochDurationZero() public {
⋮----
function test_SetAutoDeployConfig_InvalidEpochDurationLessThanMinVaultEpochDuration() public {
⋮----
function test_SetAutoDeployConfig_InvalidWithSlasher() public {
⋮----
function test_SetAutoDeployConfig_InvalidBurnerHook() public {
⋮----
function test_SetAutoDeployConfig_InvalidBurnerParamsWithSlasher() public {
⋮----
function test_AutoDeployOnRegister() public {
⋮----
function test_AutoDeployOnRegister_WithoutSlasher() public {
⋮----
function test_AutoDeployOnRegister_SetMaxNetworkLimitHook() public {
⋮----
function test_Location() public {
````
## File: test/modules/voting-power/extensions/SharedVaults.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {SharedVaults} from "../../../../src/modules/voting-power/extensions/SharedVaults.sol";
import {ISharedVaults} from "../../../../src/interfaces/modules/voting-power/extensions/ISharedVaults.sol";
import {INetworkManager} from "../../../../src/interfaces/modules/base/INetworkManager.sol";
import {NoPermissionManager} from "../../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {IVotingPowerProvider} from "../../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IOzEIP712} from "../../../../src/interfaces/modules/base/IOzEIP712.sol";
import {VotingPowerProvider} from "../../../../src/modules/voting-power/VotingPowerProvider.sol";
⋮----
import "../../../InitSetup.sol";
⋮----
contract TestSharedVaults is SharedVaults, NoPermissionManager, EqualStakeVPCalc {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function registerToken(address token) public {
⋮----
contract SharedVaultsTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
function test_RegisterSharedVault_OnlyOwnerCanCall() public {
// sharedVaults.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_RegisterUnregisterSharedVault_VaultManagerSide() public {
````
## File: test/modules/voting-power/VotingPowerProvider.t.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "forge-std/Test.sol";
⋮----
import {VotingPowerProvider} from "../../../src/modules/voting-power/VotingPowerProvider.sol";
import {VotingPowerProviderLogic} from "../../../src/modules/voting-power/logic/VotingPowerProviderLogic.sol";
import {MultiToken} from "../../../src/modules/voting-power/extensions/MultiToken.sol";
import {IVotingPowerProvider} from "../../../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {INetworkManager} from "../../../src/interfaces/modules/base/INetworkManager.sol";
import {IOzEIP712} from "../../../src/interfaces/modules/base/IOzEIP712.sol";
import {NoPermissionManager} from "../../../test/mocks/NoPermissionManager.sol";
import {EqualStakeVPCalc} from "../../../src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol";
import {OperatorVaults} from "../../../src/modules/voting-power/extensions/OperatorVaults.sol";
⋮----
import {BN254} from "../../../src/libraries/utils/BN254.sol";
import "../../InitSetup.sol";
⋮----
contract TestVotingPowerProvider is VotingPowerProvider, EqualStakeVPCalc, NoPermissionManager {
⋮----
function initialize(IVotingPowerProvider.VotingPowerProviderInitParams memory votingPowerProviderInit)
⋮----
function getTokensLength() external view returns (uint256) {
⋮----
function getOperatorsLength() external view returns (uint256) {
⋮----
function getSharedVaultsLength() external view returns (uint256) {
⋮----
function getOperatorVaultsLength(address operator) external view returns (uint256) {
⋮----
function getOperatorStakeAt(address operator, address vault, uint48 timestamp) external view returns (uint256) {
⋮----
function getOperatorStake(address operator, address vault) external view returns (uint256) {
⋮----
function getOperatorVotingPowerAt(address operator, address vault, bytes memory extraData, uint48 timestamp)
⋮----
function getOperatorVotingPower(address operator, address vault, bytes memory extraData)
⋮----
function registerOperator(address operator) external {
⋮----
function unregisterOperator(address operator) external {
⋮----
function setSlashingData(bool requireSlasher, uint48 minVaultEpochDuration) external {
⋮----
function registerToken(address token) external {
⋮----
function unregisterToken(address token) external {
⋮----
function registerSharedVault(address vault) external {
⋮----
function unregisterSharedVault(address vault) external {
⋮----
function registerOperatorVault(address operator, address vault) external {
⋮----
function unregisterOperatorVault(address operator, address vault) external {
⋮----
function validateVault(address vault) external view returns (bool) {
⋮----
function validateSharedVault(address vault) external view returns (bool) {
⋮----
function validateOperatorVault(address operator, address vault) external view returns (bool) {
⋮----
function validateVaultEpochDuration(address vault) external view returns (bool) {
⋮----
contract VotingPowerProviderTest is InitSetupTest {
⋮----
function setUp() public override {
⋮----
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[0]);
⋮----
function test_RegisterOperatorValid() public {
⋮----
function test_RegisterOperator_RevertIfNotEntity() public {
⋮----
function test_RegisterOperator_RevertIfAlreadyRegistered() public {
⋮----
function test_UnregisterOperator() public {
⋮----
function test_UnregisterOperator_RevertIfNotRegistered() public {
⋮----
function test_IsOperatorRegisteredAt_withTime() public {
⋮----
function testGetOperatorsAt_withTime() public {
⋮----
function test_SlashingData() public {
⋮----
function test_RegisterToken() public {
⋮----
function test_RegisterToken_RevertOnZeroAddress() public {
⋮----
function test_UnregisterToken() public {
⋮----
function test_RegisterSharedVault() public {
⋮----
function test_RegisterSharedVault_RevertIfInvalidVault() public {
⋮----
function test_RegisterSharedVault_RevertIfTokenNotRegistered() public {
⋮----
function test_RegisterOperatorVault() public {
⋮----
function test_RegisterOperatorVault_RevertIfOperatorNotRegistered() public {
⋮----
function test_SlashVault_InstantSlasher() public {}
⋮----
function test_SlashVault_VetoSlasherFlow() public {}
⋮----
function test_SlashVault_RevertIfNoSlasher() public {}
⋮----
function test_DistributeRewards() public {}
⋮----
function test_ValidateVault() public {
⋮----
function test_ValidateVaultSlashingFailsIfLessThanMinVaultEpochDuration() public {
⋮----
function test_Location() public {
⋮----
function test_CheckStakes() public {
⋮----
// for (uint256 i; i < initSetupParams.masterChain.tokens.length; ++i) {
// vm.startPrank(vars.deployer.addr);
// votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[i]);
// vm.stopPrank();
// }
⋮----
function test_RegisterOperator() public {
⋮----
function test_RegisterOperatorVaultExternal() public {
⋮----
function test_registerOperatorWithSignature() public {
⋮----
function test_registerOperatorWithSignature_RevertIfInvalidSig() public {
⋮----
function test_IncreaseNonce() public {
⋮----
function test_unregisterOperatorWithSignature() public {
````
## File: test/InitSetup.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import "@symbioticfi/core/test/integration/SymbioticCoreInit.sol";
⋮----
import {Token} from "@symbioticfi/core/test/mocks/Token.sol";
⋮----
import {KeyTags} from "../src/libraries/utils/KeyTags.sol";
import {MyKeyRegistry} from "../examples/MyKeyRegistry.sol";
import {MyVotingPowerProvider} from "../examples/MyVotingPowerProvider.sol";
import {VotingPowerProviderSemiFull} from "../test/mocks/VotingPowerProviderSemiFull.sol";
import {MySettlement} from "../examples/MySettlement.sol";
import {Network} from "@symbioticfi/network/src/Network.sol";
import {MyValSetDriver} from "../examples/MyValSetDriver.sol";
import {KeyEcdsaSecp256k1} from "../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyBlsBn254, BN254} from "../src/libraries/keys/KeyBlsBn254.sol";
import {KEY_TYPE_BLS_BN254, KEY_TYPE_ECDSA_SECP256K1} from "../src/interfaces/modules/key-registry/IKeyRegistry.sol";
import {BN254G2} from "../test/helpers/BN254G2.sol";
import {IOzEIP712} from "../src/interfaces/modules/base/IOzEIP712.sol";
import {IKeyRegistry} from "../src/interfaces/modules/key-registry/IKeyRegistry.sol";
⋮----
contract InitSetupTest is SymbioticCoreInit {
⋮----
function setUp() public virtual override {
⋮----
function getOperator(uint256 index) public returns (Vm.Wallet memory operator) {
// deterministic operator private key
⋮----
function getStaker(uint256 index) public returns (Vm.Wallet memory staker) {
⋮----
function getNetwork() public returns (Vm.Wallet memory network) {
⋮----
function getDeployer() public returns (Vm.Wallet memory deployer) {
⋮----
function getG2Key(uint256 privateKey) public view returns (BN254.G2Point memory) {
````
## File: test/MasterGenesisSetup.sol
````
// SPDX-License-Identifier: MIT
⋮----
import "./MasterSetup.sol";
⋮----
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
⋮----
contract MasterGenesisSetupTest is MasterSetupTest {
⋮----
function setUp() public virtual override {
⋮----
function loadGenesis()
````
## File: test/MasterSetup.sol
````
// SPDX-License-Identifier: MIT
⋮----
import {Test, console2} from "forge-std/Test.sol";
⋮----
import {ISettlement} from "../src/interfaces/modules/settlement/ISettlement.sol";
import {IOzOwnable} from "../src/interfaces/modules/common/permissions/IOzOwnable.sol";
import {INetworkManager} from "../src/interfaces/modules/base/INetworkManager.sol";
import {IEpochManager} from "../src/interfaces/modules/valset-driver/IEpochManager.sol";
import {IOzEIP712} from "../src/interfaces/modules/base/IOzEIP712.sol";
import {IValSetDriver} from "../src/interfaces/modules/valset-driver/IValSetDriver.sol";
import {IOperatorsWhitelist} from "../src/interfaces/modules/voting-power/extensions/IOperatorsWhitelist.sol";
import {IVotingPowerProvider} from "../src/interfaces/modules/voting-power/IVotingPowerProvider.sol";
import {IBaseSlashing} from "../src/interfaces/modules/voting-power/extensions/IBaseSlashing.sol";
import {IBaseRewards} from "../src/interfaces/modules/voting-power/extensions/IBaseRewards.sol";
⋮----
import {KeyTags} from "../src/libraries/utils/KeyTags.sol";
⋮----
import {SigVerifierMock} from "./mocks/SigVerifierMock.sol";
⋮----
import {KeyEcdsaSecp256k1} from "../src/libraries/keys/KeyEcdsaSecp256k1.sol";
import {KeyBlsBn254, BN254} from "../src/libraries/keys/KeyBlsBn254.sol";
⋮----
import {BN254G2} from "./helpers/BN254G2.sol";
import "./InitSetup.sol";
⋮----
import {SigVerifierBlsBn254ZK} from "../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254ZK.sol";
import {SigVerifierBlsBn254Simple} from "../src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol";
import {Verifier as Verifier_10} from "./data/zk/Verifier_10.sol";
import {Verifier as Verifier_100} from "./data/zk/Verifier_100.sol";
import {Verifier as Verifier_1000} from "./data/zk/Verifier_1000.sol";
⋮----
contract MasterSetupTest is InitSetupTest {
⋮----
function setUp() public virtual override {
⋮----
// for (uint256 i; i < initSetupParams.masterChain.tokens.length; ++i) {
// vm.startPrank(vars.deployer.addr);
// masterSetupParams.votingPowerProvider.registerToken(initSetupParams.masterChain.tokens[i]);
// vm.stopPrank();
// }
````
## File: .env.example
````
ETH_RPC_URL=
````
## File: .gitignore
````
# Ignore node_modules and dependencies
node_modules
*.log
yarn-error.log
# Ignore build outputs
dist
out
**/__pycache__
# Ignore environment files
.env
# Ignore version control files
docs/autogen/.git
docs/autogen/.gitignore
# Ignore editor and OS-specific files
*.swp
*.DS_Store
Thumbs.db
# Ignore IDE-specific files
.idea/
.vscode/
cache/
out/
broadcast/
deployments/
script/logs.txt
lcov.info
/target
/coverage
/report
.password
````
## File: .gitmodules
````
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/crypto-lib"]
path = lib/crypto-lib
url = https://github.com/get-smooth/crypto-lib
[submodule "lib/rewards"]
path = lib/rewards
url = https://github.com/symbioticfi/rewards
[submodule "lib/chainlink-evm"]
path = lib/chainlink-evm
url = https://github.com/smartcontractkit/chainlink-evm
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "lib/network"]
path = lib/network
url = https://github.com/symbioticfi/network
[submodule "lib/core"]
path = lib/core
url = https://github.com/symbioticfi/core
````
## File: .nvmrc
````
20
````
## File: .pre-commit-config.yaml
````yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: mixed-line-ending
args: ["--fix=lf"]
exclude: "^(docs/autogen|snapshots/)"
- id: trailing-whitespace
exclude: "^(docs/autogen|snapshots/)"
- id: end-of-file-fixer
exclude: "^(docs/autogen|snapshots/)"
- id: check-merge-conflict
- id: check-json
exclude: "^(docs/autogen|snapshots/)"
- id: check-yaml
- repo: local
hooks:
- id: sort-imports
name: Sort imports
description: Normalize and sort import statements in Solidity files
language: system
entry: python3 script/utils/sort_imports.py
files: "^(src|examples)/.*\\.sol$"
pass_filenames: true
- id: sort-errors
name: Sort solidity errors
description: Alphabetize error declarations in Solidity files
language: system
entry: python3 script/utils/sort_errors.py
files: "^(src|examples)/.*\\.sol$"
pass_filenames: true
- id: format
name: Format solidity code
description: Format solidity code with `forge fmt`
language: system
entry: forge fmt
files: '\.sol$'
exclude: "^lib/"
pass_filenames: true
- id: doc
name: Generate documentation
description: Generate docs with `forge doc`
language: system
entry: bash -lc 'forge build; rm -rf docs/autogen; forge doc -b -o docs/autogen'
pass_filenames: false
- id: forge-snapshots
name: Update forge snapshots
language: system
entry: bash -lc 'mkdir -p snapshots; forge build; forge build --sizes | tee snapshots/sizes.txt >/dev/null; forge test --isolate --gas-report | tee snapshots/gas.txt >/dev/null'
pass_filenames: false
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
name: Format non-solidity files with prettier
exclude: "^(docs/autogen|snapshots/)"
````
## File: .prettierignore
````
foundry.toml
out
lib/
cache/
docs/autogenerated
*.sol
deployments/
snapshots/
````
## File: .prettierrc
````
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": true,
"trailingComma": "all",
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 120,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.json",
"options": {
"tabWidth": 4
}
}
]
}
````
## File: codecov.yml
````yaml
codecov:
require_ci_to_pass: true
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
# basic
target: auto
threshold: 0%
base: auto
# advanced
if_no_uploads: error
if_not_found: success
if_ci_failed: error
only_pulls: false
patch:
default:
# basic
target: auto
threshold: 0%
base: auto
# advanced
if_no_uploads: error
if_not_found: success
if_ci_failed: error
only_pulls: false
parsers:
gcov:
branch_detection:
conditional: true
loop: true
method: false
macro: false
comment:
layout: "reach,diff,flags,files,footer"
behavior: default
require_changes: false
require_base: false
require_head: true
ignore:
- "script"
- "test"
- "src/test"
- "src/libraries/utils/BN254.sol"
````
## File: CONTRIBUTING.md
````markdown
# Contributing
- [Install](#install)
- [Pre-commit Hooks](#pre-commit-hooks)
- [Requirements for merge](#requirements-for-merge)
- [Branching](#branching)
- [Main](#main)
- [Audit](#audit)
- [Code Practices](#code-practices)
- [Code Style](#code-style)
- [Solidity Versioning](#solidity-versioning)
- [Interfaces](#interfaces)
- [NatSpec \& Comments](#natspec--comments)
- [Testing](#testing)
- [Best Practices](#best-practices)
- [IR Compilation](#ir-compilation)
- [Gas Metering](#gas-metering)
- [Deployment](#deployment)
- [Bytecode Hash](#bytecode-hash)
- [Dependency Management](#dependency-management)
- [Releases](#releases)
## Install
Follow these steps to set up your local environment for development:
- [Install foundry](https://book.getfoundry.sh/getting-started/installation)
- Install dependencies: `forge install`
- [Install pre-commit](https://pre-commit.com/#installation)
- Install pre commit hooks: `pre-commit install`
## Pre-commit Hooks
Follow the [installation steps](#install) to enable pre-commit hooks. To ensure consistency in our formatting `pre-commit` is used to check whether code was formatted properly and the documentation is up to date. Whenever a commit does not meet the checks implemented by pre-commit, the commit will fail and the pre-commit checks will modify the files to make the commits pass. Include these changes in your commit for the next commit attempt to succeed. On pull requests the CI checks whether all pre-commit hooks were run correctly.
This repo includes the following pre-commit hooks that are defined in the `.pre-commit-config.yaml`:
- `mixed-line-ending`: This hook ensures that all files have the same line endings (LF).
- `trailing-whitespace`: Strips trailing spaces from lines so that diffs remain clean and editors don't introduce noise.
- `end-of-file-fixer`: Ensures every file ends with a single newline and removes extra blank lines at the end of files.
- `check-merge-conflict`: Fails when Git merge conflict markers are present to avoid committing unresolved conflicts.
- `check-json`: Validates JSON files and fails fast on malformed syntax.
- `check-yaml`: Parses YAML files to verify they are syntactically valid.
- `sort-imports`: Normalises and sorts imports according to the rules mentioned in the [Code Style](#code-style) below.
- `sort-errors`: Sorts errors according to the rules mentioned in the [Code Style](#code-style) below.
- `format`: This hook uses `forge fmt` to format all Solidity files.
- `doc`: This hook uses `forge doc` to generate the Solidity documentation. Commit the generated files whenever the documentation changes.
- `prettier`: All remaining files are formatted using prettier.
## Requirements for merge
In order for a PR to be merged, it must pass the following requirements:
- All commits within the PR must be signed
- CI must pass (tests, linting, etc.)
- New features must be merged with associated tests
- Bug fixes must have a corresponding test that fails without the fix
- The PR must be approved by at least one maintainer
## Branching
This section outlines the branching strategy of this repo.
### Main
The main branch is supposed to reflect the deployed state on all networks, if not indicated otherwise inside the README. Only audited code should be merged into main. Сommits from dev branches should be merged into the main branch using a regular merge strategy. The commit messages should follow [the Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/).
### Audit
Before an audit, the code should be frozen on a branch dedicated to the audit with the naming convention `audit/`. Each fix in response to an audit finding should be developed as a separate commit. The commit message should look similar to `fix: - `.
## Code Practices
### Code Style
The repo follows the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). In addition to that, this repo also borrows the following rules from [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/GUIDELINES.md#solidity-conventions):
- Internal or private state variables or functions should have an underscore prefix.
```solidity
contract TestContract {
uint256 private _privateVar;
uint256 internal _internalVar;
function _testInternal() internal { ... }
function _testPrivate() private { ... }
}
```
- Naming collisions should be avoided using a single trailing underscore.
```solidity
contract TestContract {
uint256 public foo;
constructor(uint256 foo_) {
foo = foo_;
}
}
```
- Interface names should have a capital I prefix.
```solidity
interface IERC777 {
```
- Contracts not intended to be used standalone should be marked abstract, so they are required to be inherited by other contracts.
```solidity
abstract contract AccessControl is ..., {
```
- Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen or is permissible. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.
Also, such exceptions/additions exist:
- Functions should be grouped according to their visibility and ordered:
1. constructor
2. external
3. public
4. internal
5. private
6. receive function (if exists)
7. fallback function (if exists)
- Each contract should be virtually divided into sections by using such separators:
1. /\* CONSTANTS \*/
2. /\* IMMUTABLES \*/
3. /\* STATE VARIABLES \*/
4. /\* MODIFIERS \*/
5. /\* CONSTRUCTOR \*/
6. /\* EXTERNAL FUNCTIONS \*/
7. /\* PUBLIC FUNCTIONS \*/
8. /\* INTERNAL FUNCTIONS \*/
9. /\* PRIVATE FUNCTIONS \*/
10. /\* RECEIVE FUNCTION \*/
11. /\* FALLBACK FUNCTION \*/
- Each interface should be virtually divided into sections by using such separators:
1. /\* ERRORS \*/
2. /\* STRUCTS \*/
3. /\* EVENTS \*/
4. /\* FUNCTIONS \*/
- Do not use external and private visibilities in most cases.
- Events should generally be emitted immediately after the state change that they
represent, and should be named the same as the function's name. Some exceptions may be made for gas
efficiency if the result doesn't affect the observable ordering of events.
```solidity
function _burn(address who, uint256 value) internal {
super._burn(who, value);
emit Burn(who, value);
}
```
- Custom errors should be used whenever possible. The naming should be concise and easy to read.
- Imports should be divided into separate groups and ordered alphabetically ascending inside each group:
1. contracts
2. libraries
3. interfaces
4. external files separately
```solidity
import {NetworkManager} from "../base/NetworkManager.sol";
import {OzEIP712} from "../base/OzEIP712.sol";
import {PermissionManager} from "../base/PermissionManager.sol";
import {Checkpoints} from "../../libraries/structs/Checkpoints.sol";
import {KeyTags} from "../../libraries/utils/KeyTags.sol";
import {ISettlement} from "../interfaces/modules/settlement/ISettlement.sol";
import {ISigVerifier} from "../interfaces/modules/settlement/sig-verifiers/ISigVerifier.sol";
import {StaticDelegateCallable} from "@symbioticfi/core/src/contracts/common/StaticDelegateCallable.sol";
import {Subnetwork} from "@symbioticfi/core/src/contracts/libraries/Subnetwork.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
```
- In case of comparison with `msg.sender` or `tx.origin`, these keywords should be on the right side of the inequality.
```solidity
modifier onlyOwner() internal {
if (owner != msg.sender) {
revert NotOwner();
}
}
```
- Errors should be ordered alphabetically ascending.
```solidity
error InsufficientFunds();
error NoAccess();
error NotOwner();
```
### Solidity Versioning
Contracts that are meant to be deployed should have an explicit version set in the `pragma` statement.
```solidity
pragma solidity 0.8.X;
```
Abstract contracts, libraries and interfaces should use the caret (`^`) range operator to specify the version range to ensure better compatibility.
```solidity
pragma solidity ^0.X.0;
```
Libraries and abstract contracts using functionality introduced in newer versions of Solidity can use caret range operators with higher path versions (e.g., `^0.8.24` when using transient storage opcodes). For interfaces, it should be considered to use the greater than or equal to (`>=`) range operator to ensure better compatibility with future versions of Solidity.
### Interfaces
Every contract MUST implement its corresponding interface that includes all externally callable functions, errors and events.
### NatSpec & Comments
Interfaces should be the entry point for all contracts. When exploring a contract within the repository, the interface MUST contain all relevant information to understand the functionality of the contract in the form of NatSpec comments. This includes all externally callable functions, structs, errors and events. The NatSpec documentation MUST be added to the functions, structs, errors and events within the interface. This allows a reader to understand the functionality of a function before moving on to the implementation. The implementing functions MUST point to the NatSpec documentation in the interface using `@inheritdoc`. Internal and private functions shouldn't have NatSpec documentation except for `@dev` comments, whenever more context is needed. Additional comments within a function should only be used to give more context to more complex operations; otherwise, the code should be kept readable and self-explanatory. NatSpec comments in contracts should use a triple slash (`///`) to bring less noise to the implementation, while libraries and interfaces should use `/* */` wrappers.
The comments should respect the following rules:
- For read functions: `@notice Returns <...>`
- For write functions: `@notice `
- For structs: `@notice `
- For errors: `@notice Raised when <...>`
- For events: `@notice Emitted when <...>`
Each contract/library/interface should have a title comment that should follow such a structure:
1. `@title ` (e.g., `Vault`)
2. `@notice Contract/Library/Interface for <...>.` - also, other variations are possible, e.g.:
- `@notice Interface for the Vault contract.`
- `@notice Base contract for <...>.`
- `@notice Library-logic for <...>.`
3. `@dev <...>` (optional)
## Testing
The following testing practices should be followed when writing unit tests for new code. All functions, lines and branches should be tested to result in 100% testing coverage. Fuzz parameters and conditions whenever possible. Extremes should be tested in dedicated edge case and corner case tests. Invariants should be tested in dedicated invariant tests.
Differential testing should be used to compare assembly implementations with implementations in Solidity or testing alternative implementations against existing Solidity or non-Solidity code using ffi.
New features must be merged with associated tests. Bug fixes should have a corresponding test that fails without the bug fix.
### Best Practices
Best practices and naming conventions should be followed as outlined in the [Foundry Book](https://getfoundry.sh/forge/tests/overview).
### IR Compilation
All contracts and tests should be compilable without IR whenever possible.
### Gas Metering
Gas for function calls should be metered using the built-in `vm.snapshotGasLastCall` function in forge. To meter across multiple calls `vm.startSnapshotGas` and `vm.stopSnapshotGas` can be used. Tests that measure gas should be annotated with `/// forge-config: default.isolate = true` and not be fuzzed to ensure that the gas snapshot is accurate and consistent for CI verification. All external functions should have a gas snapshot test, and diverging paths within a function should have appropriate gas snapshot tests.
For more information on gas metering, see the [Forge cheatcodes reference](https://getfoundry.sh/reference/cheatcodes/gas-snapshots/#snapshotgas-cheatcodes).
### Bytecode Hash
Bytecode hash should be set to `none` in the `foundry.toml` file to ensure that the bytecode is consistent.
## Dependency Management
The preferred way to manage dependencies is using [`forge install`](https://book.getfoundry.sh/forge/dependencies). This ensures that your project uses the correct versions and structure for all external libraries. Also, `npm` and `soldeer` packages should be published to increase coverage of different use-cases.
## Releases
Every deployment and change made to contracts after deployment should be accompanied by a tag and release on GitHub.
````
## File: foundry.lock
````
{
"lib/chainlink-evm": {
"rev": "448d48945910a0e1fcab5abff555c0f8f3d87070"
},
"lib/core": {
"tag": {
"name": "v1.0.3",
"rev": "74c0c6fbd5531a6065cdafdab07840b04a0d2039"
}
},
"lib/crypto-lib": {
"rev": "f2c00ecced1df96fe81894d19a6b8ec754beedb9"
},
"lib/forge-std": {
"tag": {
"name": "v1.11.0",
"rev": "8e40513d678f392f398620b3ef2b418648b33e89"
}
},
"lib/network": {
"rev": "8ee834279cb4fb45adfcb5fee4a405f06b3134ca"
},
"lib/openzeppelin-contracts": {
"tag": {
"name": "v5.2.0",
"rev": "acd4ff74de833399287ed6b31b4debf6b2b35527"
}
},
"lib/openzeppelin-contracts-upgradeable": {
"tag": {
"name": "v5.2.0",
"rev": "3d5fa5c24c411112bab47bec25cfa9ad0af0e6e8"
}
},
"lib/rewards": {
"rev": "b5a1f5b46f33f31938fc0116086b3a75e748c8b1"
}
}
````
## File: foundry.toml
````toml
[profile.default]
evm_version = "prague"
solc = "0.8.28"
optimizer = true
optimizer_runs = 200
via_ir = false
bytecode_hash = "none"
src = "src"
out = "out"
libs = ["lib"]
fs_permissions = [{ access = "read-write", path = "./"}]
gas_reports = ["*"]
gas_limit = "18446744073709551615"
dynamic_test_linking = true
ignored_warnings_from = ["test/","script/"]
ffi = true
[rpc_endpoints]
mainnet = "${ETH_RPC_URL}"
hoodi = "${ETH_RPC_URL_HOODI}"
holesky = "${ETH_RPC_URL_HOLESKY}"
sepolia = "${ETH_RPC_URL_SEPOLIA}"
[fmt]
bracket_spacing = false
int_types = "long"
line_length = 120
multiline_func_header = "attributes_first"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
single_line_statement_blocks = "preserve"
sort_imports = false
contract_new_lines = false
override_spacing = false
hex_underscore = "preserve"
wrap_comments = false
[lint]
lint_on_build = false
exclude_lints = ["asm-keccak256","mixed-case-function","mixed-case-variable","pascal-case-struct","screaming-snake-case-const"]
ignore = ["test/**/*.sol","script/**/*.sol","src/interfaces/**/*.sol"]
additional_compiler_profiles = [
{ name = "test", via_ir = false, optimizer = false },
{ name = "via-ir-1", via_ir = true, optimizer = true, optimizer_runs = 1 }
]
compilation_restrictions = [
{ paths = "test/**", via_ir = false, optimizer = false },
{ paths = "{test/mocks/VotingPowerProviderFull.sol}", via_ir = true, optimizer = true, optimizer_runs = 1 }
]
[profile.default.fuzz]
runs = 1000
max_test_rejects = 262144
[profile.pr.fuzz]
runs = 10000
max_test_rejects = 262144
[profile.ci.fuzz]
runs = 100000
max_test_rejects = 262144
[profile.debug]
via_ir = false
optimizer_runs = 200
fuzz.runs = 100
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
````
## File: LICENSE
````
MIT License
Copyright (c) 2024 Symbiotic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
````
## File: package.json
````json
{
"name": "@symbioticfi/relay-contracts",
"version": "1.0.0-rc.2",
"description": "Symbiotic Relay smart contracts allowing construction of validator set using various mechanics, verification and management of operators' keys of various types, aggregated signatures verification, and validator set's running.",
"homepage": "https://symbiotic.fi/relay",
"bugs": "https://github.com/symbioticfi/relay-contracts/issues",
"license": "MIT",
"author": "Symbiotic Team",
"files": [
"examples/**/*",
"src/**/*",
"script/**/*",
"test/mocks/**/*"
],
"repository": {
"type": "git",
"url": "https://github.com/symbioticfi/relay-contracts.git"
},
"keywords": [
"solidity",
"ethereum",
"smart",
"contracts",
"security"
],
"dependencies": {
"@noble/curves": "^1.3.0",
"dotenv": "^16.5.0",
"ethereum-cryptography": "^2.1.3",
"ethers": "^6.11.1",
"@openzeppelin/contracts": "5.2.0",
"@openzeppelin/contracts-upgradeable": "5.2.0",
"@symbioticfi/core": "1.0.3",
"@symbioticfi/rewards": "2.0.0"
},
"engines": {
"node": ">=18.0.0"
}
}
````
## File: README.md
````markdown
> [!WARNING]
> The SDK is a work in progress and is currently under audits. Breaking changes may occur in SDK updates as well as backward compatibility is not guaranteed. Use with caution.
# Symbiotic Relay Smart Contracts
[](https://deepwiki.com/symbioticfi/relay-contracts)
[](https://codecov.io/github/symbioticfi/relay-contracts)
## Overview
Symbiotic Relay is a peer-to-peer side-network designed to collect and aggregate signatures from validators, maintain validator sets on the settlement contract.
To achieve that, Symbiotic provides a set of predefined smart contracts, in general, representing the following modules:
- [VotingPowerProvider](./src/modules/voting-power/) - provides the basic data regarding operators, vaults and their voting power, it allows constructing various onboarding schemes such as:
- [OperatorsWhitelist](./src/modules/voting-power/extensions/OperatorsWhitelist.sol) - only whitelisted operators can register
- [OperatorsBlacklist](./src/modules/voting-power/extensions/OperatorsBlacklist.sol) - blacklisted operators are unregistered and are forbidden to return back
- [OperatorsJail](./src/modules/voting-power/extensions/OperatorsJail.sol) - operators can be jailed for some amount of time and register back after that
- [SharedVaults](./src/modules/voting-power/extensions/SharedVaults.sol) - shared (with other networks) vaults (like the ones with NetworkRestakeDelegator) can be added
- [OperatorVaults](./src/modules/voting-power/extensions/OperatorVaults.sol) - vaults that are attached to a single operator can be added
- [MultiToken](./src/modules/voting-power/extensions/MultiToken.sol) - possible to add new supported tokens on the go
- [OpNetVaultAutoDeploy](./src/modules/voting-power/extensions/OpNetVaultAutoDeploy.sol) - enable auto-creation of the configured by you vault on each operator registration
- [VotingPowerCalculators](./src/modules/voting-power/common/voting-power-calc/) - there are several stake-to-votingPower conversion mechanisms you can use separately or combine:
- [EqualStakeVPCalc](./src/modules/voting-power/common/voting-power-calc/EqualStakeVPCalc.sol) - voting power is equal to stake
- [NormalizedTokenDecimalsVPCalc](./src/modules/voting-power/common/voting-power-calc/NormalizedTokenDecimalsVPCalc.sol) - all tokens' decimals are normalized to 18
- [PricedTokensChainlinkVPCalc](./src/modules/voting-power/common/voting-power-calc/PricedTokensChainlinkVPCalc.sol) - voting power is calculated using Chainlink price feeds
- [WeightedTokensVPCalc](./src/modules/voting-power/common/voting-power-calc/WeightedTokensVPCalc.sol) - voting power is affected by configured weights for tokens
- [WeightedVaultsVPCalc](./src/modules/voting-power/common/voting-power-calc/WeightedVaultsVPCalc.sol) - voting power is affected by configured weights for vaults
- Also, there are ready bindings for [slashing](./src/modules/voting-power/extensions/BaseSlashing.sol) and [rewards](./src/modules/voting-power/extensions/BaseRewards.sol)
- [KeyRegistry](./src/modules/key-registry/) - verifies and manages operators' keys; currently, these key types are supported:
- [BlsBn254](./src/libraries/keys/KeyBlsBn254.sol) ([signature verification](./src/libraries/sigs/SigBlsBn254.sol))
- [EcdsaSecp256k1](./src/libraries/keys/KeyEcdsaSecp256k1.sol) ([signature verification](./src/libraries/sigs/SigEcdsaSecp256k1.sol))
- [ValSetDriver](./src/modules/valset-driver/) - is used by the off-chain part of the Symbiotic Relay for validator set deriving and maintenance
- [Settlement](./src/modules/settlement/) - requires a compressed validator set (header) to be committed each epoch, but allows verifying signatures made by the validator set; currently, it supports the following verification mechanics:
- [SimpleVerifier](./src/modules/settlement/sig-verifiers/SigVerifierBlsBn254Simple.sol) - requires the whole validator set to be inputted on the verification, but in a compressed and efficient way, so that it is the best choice to use up to around 125 validators
- [ZKVerifier](./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
## Examples
Can be found [here](./examples/).
## Usage
### Dependencies
- Git ([installation](https://git-scm.com/downloads))
- Foundry ([installation](https://getfoundry.sh/introduction/installation/))
### Prerequisites
**Clone the repository**
```
git clone --recurse-submodules https://github.com/symbioticfi/relay-contracts.git
```
### Deploy Your Relay
The deployment tooling can be found at [`script/`](./script/) folder. It consists of [`RelayDeploy.sol`](./script/RelayDeploy.sol) Foundry script template [`relay-deploy.sh`](./script/relay-deploy.sh) bash script (the Relay smart contracts use external libraries for their implementations, so that it's not currently possible to use solely Foundry script for multi-chain deployment).
- [`RelayDeploy.sol`](./script/RelayDeploy.sol) - abstract base that wires common Symbiotic core helpers and exposes the four deployment hooks: KeyRegistry, VotingPowerProvider, Settlement, and ValVetDriver
- [`relay-deploy.sh`](./script/relay-deploy.sh) - orchestrates per-contract multi-chain deployments (uses Python inside to parse `toml` file)
The script deploys Relay modules under [OZ's TransparentUpgradeableProxy](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) using [CreateX](https://github.com/pcaversaccio/createx) (it provides better control for production deployments and more simplified approaches for development).
#### Dependencies
- Python ([installation](https://www.python.org/downloads/))
#### Deployment
1. Implement your `MyRelayDeploy.sol` ([see example](./script/examples/MyRelayDeploy.sol)) - this Foundry script should include the deployment configuration of your Relay modules
- you need to implement all virtual functions of `RelayDeploy.sol`
- in constructor, need to input the path of the `toml` file
- you are provided with additional helpers such as `getCore()`, `getKeyRegistry()`, `getVotingPowerProvider()`, etc. (see full list in [`RelayDeploy.sol`](./script/RelayDeploy.sol))
2. Implement your `my-relay-deploy.toml` ([see example](./script/examples/my-relay-deploy.toml)) - this configuration file should include RPC URLs that will be needed for the deployment, and which modules should be deployed on which chains
- **do not replace [1234567890] placeholder with endpoint_url = ""**
- the contracts are deployed in such order:
1. KeyRegistry
2. VotingPowerProvider
3. Settlement
4. ValSetDriver
3. Execute the deployment script, e.g.:
```bash
./script/relay-deploy.sh ./script/examples/MyRelayDeploy.sol ./script/examples/my-relay-deploy.toml --broadcast --ledger
```
_Basic form is `./script/relay-deploy.sh `_
At the end, your `toml` file will contain the addresses of the deployed Relay modules.
### Build, Test, and Format
```
forge build
forge test
forge fmt
```
**Configure environment**
Create `.env` based on the template:
```
ETH_RPC_URL=
ETHERSCAN_API_KEY=
```
## Security
Security audits can be found [here](./audits).
````
## File: remappings.txt
````
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@symbioticfi/core/=lib/core/
@symbioticfi/network/=lib/network
@crypto-lib/=lib/crypto-lib/src/
@symbioticfi/rewards/=lib/rewards/
````
---
## Relay (+ Go client)
This file is a merged representation of the entire codebase, combined into a single document by Repomix.
The content has been processed where content has been compressed (code blocks are separated by ⋮---- delimiter).
# File Summary
## Purpose
This file contains a packed representation of the entire repository's contents.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
## File Format
The content is organized as follows:
1. This summary section
2. Repository information
3. Directory structure
4. Repository files (if enabled)
5. Multiple file entries, each consisting of:
a. A header with the file path (## File: path/to/file)
b. The full contents of the file in a code block
## Usage Guidelines
- This file should be treated as read-only. Any changes should be made to the
original repository files, not this packed version.
- When processing this file, use the file path to distinguish
between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
the same level of security as you would the original repository.
## Notes
- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Content has been compressed - code blocks are separated by ⋮---- delimiter
- Files are sorted by Git change count (files with more changes are at the bottom)
# Directory Structure
```
.github/
workflows/
build.yaml
nightly.yaml
release.yaml
tests.yaml
dependabot.yml
api/
client/
examples/
main.go
README.md
v1/
client.go
types.go
LICENSE
proto/
v1/
api.proto
cmd/
relay/
root/
app.go
config.go
root.go
main.go
utils/
cmd-helpers/
helpers.go
keys/
add.go
cmd.go
print.go
remove.go
update.go
network/
cmd.go
genesis.go
info.go
printers.go
operator/
cmd.go
info.go
invalidate_old_signatures.go
register_key.go
register_operator.go
register_with_signature.go
unregister_operator.go
unregister_with_signature.go
root/
root.go
main.go
docs/
api/
v1/
api.swagger.json
doc.md
index.html
cli/
relay/
relay_sidecar.md
utils/
utils_keys_add.md
utils_keys_list.md
utils_keys_remove.md
utils_keys_update.md
utils_keys.md
utils_network_generate-genesis.md
utils_network_info.md
utils_network.md
utils_operator_info.md
utils_operator_invalidate-old-signatures.md
utils_operator_register-key.md
utils_operator_register-operator-with-signature.md
utils_operator_register-operator.md
utils_operator_register-signature.md
utils_operator_unregister-operator-with-signature.md
utils_operator_unregister-operator.md
utils_operator_unregister-signature.md
utils_operator.md
utils_version.md
utils.md
e2e/
scripts/
deploy.sh
generate_network.sh
genesis-generator.sh
sidecar-start.sh
tests/
api_test.go
epoch_test.go
genesis_test.go
http_gateway_test.go
metadata_test.go
setup_test.go
sidecar.yaml
sign_test.go
sync_test.go
types_test.go
README.md
setup.sh
hack/
codegen/
generate-client-types.go
docgen/
generate-cli-docs.go
internal/
client/
p2p/
proto/
v1/
message_grpc.pb.go
message.pb.go
message.proto
broadcast_signature_aggregated_message.go
broadcast_signature_generated_message.go
discovery_integration_test.go
discovery_test.go
discovery.go
p2p_broadcast_test.go
p2p_grpc_handler.go
p2p_grpc_send_want_aggregation_proofs_request_test.go
p2p_grpc_send_want_aggregation_proofs_request.go
p2p_grpc_send_want_signatures_request_test.go
p2p_grpc_send_want_signatures_request.go
p2p_grpc_test.go
p2p_handle_message_test.go
p2p_handle_message_unit_test.go
p2p_handle_message.go
p2p_test.go
p2p.go
repository/
badger/
proto/
v1/
badger.pb.go
badger.proto
badger_repository_add_proof.go
badger_repository_add_signature.go
badger_repository_aggregation_proof_pending_test.go
badger_repository_aggregation_proof_test.go
badger_repository_aggregation_proof.go
badger_repository_network_config_test.go
badger_repository_network_config.go
badger_repository_proof_commits_test.go
badger_repository_proof_commits.go
badger_repository_proto_test.go
badger_repository_signature_map_test.go
badger_repository_signature_map.go
badger_repository_signature_request_test.go
badger_repository_signature_request.go
badger_repository_signature_test.go
badger_repository_signature.go
badger_repository_test.go
badger_repository_transaction_test.go
badger_repository_transaction.go
badger_repository_validator_set_test.go
badger_repository_validator_set.go
badger_repository.go
cached_repository_test.go
cached_repository.go
cache/
generic_cache.go
entity/
entity_aggregation_proof_sync_test.go
entity_error.go
entity_signature_map_test.go
entity_signature_map.go
entity_signature_request.go
entity_signature_sync.go
p2p_entity.go
gen/
api/
v1/
api_grpc.pb.go
api.pb.go
api.pb.gw.go
usecase/
aggregation-policy/
low-cost/
low_cost_policy.go
low-latency/
low_latency_policy.go
types/
types.go
aggregation_policies.go
aggregator-app/
mocks/
aggregator_app.go
aggregator_app_test.go
aggregator_app.go
api-server/
mocks/
app_mock.go
app.go
get_aggregation_proof_v1_test.go
get_aggregation_proof_v1.go
get_aggregation_proofs_by_epoch_v1_test.go
get_aggregation_proofs_by_epoch_v1.go
get_aggregation_status_v1_test.go
get_aggregation_status_v1.go
get_current_epoch_v1_test.go
get_current_epoch_v1.go
get_last_all_committed_v1_test.go
get_last_all_committed_v1.go
get_last_committed_v1_test.go
get_last_committed_v1.go
get_local_validator_v1_test.go
get_local_validator_v1.go
get_signature_request_ids_by_epoch_v1_test.go
get_signature_request_ids_by_epoch_v1.go
get_signature_request_v1_test.go
get_signature_request_v1.go
get_signature_requests_by_epoch_v1_test.go
get_signature_requests_by_epoch_v1.go
get_signature_v1.go
get_signatures_by_epoch_v1_test.go
get_signatures_by_epoch_v1.go
get_signatures_v1_test.go
get_validator_by_address_v1_test.go
get_validator_by_address_v1.go
get_validator_by_key_v1_test.go
get_validator_by_key_v1.go
get_validator_set_header_v1_test.go
get_validator_set_header_v1.go
get_validator_set_v1_test.go
get_validator_set_v1.go
get_validatorset_metadata_v1_test.go
get_validatorset_metadata_v1.go
helpers_test.go
http_test.go
http.go
interceptors_test.go
interceptors.go
listen_proofs_v1_test.go
listen_proofs_v1.go
listen_signature_v1.go
listen_signatures_v1_test.go
listen_validator_set_v1_test.go
listen_validator_set_v1.go
sign_message_v1_test.go
sign_message_v1.go
broadcaster/
doc.go
hub_test.go
hub.go
entity-processor/
mocks/
entity_processor.go
entity_processor_test.go
entity_processor.go
key-provider/
cache_key_provider.go
env_provider.go
key_provider.go
key_store_provider_test.go
key_store_provider.go
simple_key_provider.go
metrics/
metrics_app.go
metrics_grpc.go
metrics.go
signature-listener/
mocks/
signature_listener_uc.go
signature_listener_uc_test.go
signature_listener_uc.go
signer-app/
mocks/
signer_app.go
signer_app_handle_signature_aggregated_message.go
signer_app_test.go
signer_app.go
sync-provider/
sync_provider_build_want_aggregation_proofs_request.go
sync_provider_build_want_signatures_map.go
sync_provider_handle_want_aggregation_proofs_request.go
sync_provider_handle_want_signatures.go
sync_provider_process_received_aggregation_proofs.go
sync_provider_process_received_signatures.go
sync_provider_test.go
sync_provider.go
sync-runner/
sync_runner.go
valset-listener/
valset_generator_handle_agg_proof.go
valset_listener_uc.go
valset-status-tracker/
status_tracker.go
pkg/
log/
context_handler.go
log_test.go
log.go
prettylog.go
proof/
circuit.go
helpers_test.go
helpers.go
proof_test.go
proof.go
server/
interceptors.go
metrics_server.go
signals/
signal_test.go
signal.go
symbiotic/
client/
evm/
abi/
IKeyRegistry.abi.json
ISettlement.abi.json
IValSetDriver.abi.json
IVotingPowerProvider.abi.json
gen/
keyRegistry.go
multicall3.go
operatorRegistry.go
settlement.go
valsetDriver.go
votingPowerProvider.go
mocks/
eth.go
eth_commit_valset_test.go
eth_commit_valset.go
eth_operator_test.go
eth_operator.go
eth_set_genesis_test.go
eth_set_genesis.go
eth_test.go
eth_verify_quorum_sig_test.go
eth_verify_quorum_sig.go
eth.go
multicall_test.go
multicall.go
entity/
entity_test.go
entity.go
evm_entity.go
key_tag_entity_test.go
key_tag_entity.go
key.go
usecase/
aggregator/
aggregator-types/
aggregator.go
blsBn254Simple/
aggregator_test.go
aggregator.go
blsBn254ZK/
aggregator_test.go
aggregator.go
helpers/
helpers_test.go
helpers.go
aggregators_test.go
aggregators.go
crypto/
bls12381Bn254/
key_test.go
key.go
blsBn254/
key_test.go
key.go
ecdsaSecp256k1/
key_test.go
key.go
keys.go
ssz/
ssz.go
types.go
valset-deriver/
mocks/
deriver.go
valset_deriver_test.go
valset_deriver.go
symbiotic.go
.dockerignore
.env.example
.gitignore
.gitmodules
.golangci.yml
buf.badger.gen.yaml
buf.gen.yaml
buf.lock
buf.p2p.gen.yaml
buf.yaml
CONTRIBUTING.md
DEVELOPMENT.md
Dockerfile
example.config.yaml
go.mod
Makefile
README.md
```
# Files
## File: .github/workflows/build.yaml
````yaml
---
name: Build
on:
workflow_call:
inputs:
version:
type: string
description: The version to build, if not provided go version srting is used
required: false
default: ""
jobs:
build:
name: Build
runs-on:
group: relay
timeout-minutes: 15
steps:
- name: Checkout source code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # pin@v4.3.0
with:
fetch-depth: 0
- name: Setup Private Git Repo Access
run: |
git config --global url.https://x-oauth-basic:${{ secrets.GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
echo "GOPRIVATE=github.com/symbioticfi/relay" >> $GITHUB_ENV
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # pin@v5.5.0
with:
go-version: 1.25.3
- name: Get version
id: get_version
run: |
if [ -n "${{ inputs.version }}" ]; then
VERSION_INFO=${{ inputs.version }}
echo "Version Info: $VERSION_INFO"
echo "TAG=$VERSION_INFO" >> $GITHUB_ENV
else
echo "No version input provided, will auto calculate"
fi
- name: Build relay utils linux amd64
run: make build-relay-utils OS=linux ARCH=amd64
- name: Upload artifact relay_utils_linux_amd64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_utils_linux_amd64
path: relay_utils_linux_amd64
- name: Build relay utils linux arm64
run: make build-relay-utils OS=linux ARCH=arm64
- name: Upload artifact relay_utils_linux_arm64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_utils_linux_arm64
path: relay_utils_linux_arm64
- name: Build relay utils darwin arm64
run: make build-relay-utils OS=darwin ARCH=arm64
- name: Upload artifact relay_utils_darwin_arm64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_utils_darwin_arm64
path: relay_utils_darwin_arm64
- name: Build relay sidecar linux amd64
run: make build-relay-sidecar OS=linux ARCH=amd64
- name: Upload artifact relay_sidecar_linux_amd64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_sidecar_linux_amd64
path: relay_sidecar_linux_amd64
- name: Build relay sidecar linux arm64
run: make build-relay-sidecar OS=linux ARCH=arm64
- name: Upload artifact relay_sidecar_linux_arm64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_sidecar_linux_arm64
path: relay_sidecar_linux_arm64
- name: Build relay sidecar darwin arm64
run: make build-relay-sidecar OS=darwin ARCH=arm64
- name: Upload artifact relay_sidecar_darwin_arm64
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # pin@v4.6.2
with:
name: relay_sidecar_darwin_arm64
path: relay_sidecar_darwin_arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
with:
driver-opts: network=host
- name: Login to Docker Hub
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Cache Docker layers
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build & Push Images
run: make image
id: push-image
timeout-minutes: 30
env:
PUSH_IMAGE: true
IMAGE_REPO: symbioticfi/relay
PUSH_LATEST: true # push latest for all builds nuightly or stable release
- name: Echo image built
run: echo "Image built - [${{ steps.push-image.outputs.image }}]"
````
## File: .github/workflows/nightly.yaml
````yaml
---
name: Nightly Build
on:
schedule:
# Run at 03:00 UTC every day (avoiding peak 00:00 congestion)
- cron: "0 3 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
tests:
name: Tests
uses: ./.github/workflows/tests.yaml
secrets: inherit
build:
needs:
- tests
name: Build
uses: ./.github/workflows/build.yaml
secrets: inherit
nightly-release:
name: Nightly Release
needs:
- tests
- build
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout source code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # pin@v4.3.0
with:
fetch-depth: 0
- name: Generate nightly tag
id: nightly_tag
run: |
DATE=$(date +%Y%m%d)
echo "tag=nightly-$DATE" >> "$GITHUB_OUTPUT"
echo "Generated nightly tag: nightly-$DATE"
- name: Generate changelog
id: changelog
run: |
# Get the last nightly tag or use a fallback
LAST_TAG=$(git tag --list "nightly-*" --sort=-version:refname | head -1)
if [ -z "$LAST_TAG" ]; then
echo "No previous nightly tag found, using last 10 commits"
git log -10 --pretty=format:"- %s (%an)" > CHANGELOG.md
else
echo "Generating changelog between $LAST_TAG and current commit"
git log $LAST_TAG..HEAD --pretty=format:"- %s (%an)" > CHANGELOG.md
fi
cat CHANGELOG.md
- name: Download relay utils artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # pin@v5.0.0
with:
pattern: relay_utils_*
merge-multiple: true
- name: Download relay sidecar artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # pin@v5.0.0
with:
pattern: relay_sidecar_*
merge-multiple: true
- name: Create nightly release
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # pin@v2.2.2
with:
tag_name: ${{ steps.nightly_tag.outputs.tag }}
draft: false
prerelease: true
body_path: CHANGELOG.md
files: |
relay_utils_linux_amd64
relay_utils_linux_arm64
relay_utils_darwin_arm64
relay_sidecar_linux_amd64
relay_sidecar_linux_arm64
relay_sidecar_darwin_arm64
````
## File: .github/workflows/release.yaml
````yaml
---
name: Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
jobs:
tests:
name: Tests
uses: ./.github/workflows/tests.yaml
secrets: inherit
build:
needs:
- tests
name: Build
uses: ./.github/workflows/build.yaml
with:
version: ${{ github.ref_name }}
secrets: inherit
release:
name: Release
needs:
- tests
- build
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout source code
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # pin@v4.3.0
with:
fetch-depth: 0
- name: Get previous tag
id: get_previous_tag
run: |
echo "tag=$(git describe --tags --abbrev=0 HEAD^)" >> "$GITHUB_OUTPUT"
- name: Generate changelog
id: changelog
run: |
echo "Generating changelog between ${{ steps.get_previous_tag.outputs.tag }} and ${{ github.ref_name }}"
git log ${{ steps.get_previous_tag.outputs.tag }}..${{ github.ref_name }} --pretty=format:"- %s (%an)" > CHANGELOG.md
cat CHANGELOG.md
- name: Download relay utils artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # pin@v5.0.0
with:
pattern: relay_utils_*
merge-multiple: true
- name: Download relay sidecar artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # pin@v5.0.0
with:
pattern: relay_sidecar_*
merge-multiple: true
- name: Release
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # pin@v2.2.2
with:
draft: true
body_path: CHANGELOG.md
files: |
relay_utils_linux_amd64
relay_utils_linux_arm64
relay_utils_darwin_arm64
relay_sidecar_linux_amd64
relay_sidecar_linux_arm64
relay_sidecar_darwin_arm64
````
## File: .github/workflows/tests.yaml
````yaml
---
name: "CI Pipeline"
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [dev, main]
workflow_call:
env:
GO_VERSION: "1.25.3"
NODE_VERSION: "22"
FOUNDRY_VERSION: "v1.3.1"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
code-quality:
name: "Code Quality & Linting"
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: "Checkout Repository"
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: "Configure Private Repository Access"
run: |
git config --global url.https://x-oauth-basic:${{ secrets.GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
echo "GOPRIVATE=github.com/symbioticfi/relay" >> $GITHUB_ENV
- name: "Setup Go Environment"
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: "go.sum"
- name: "Generate Code"
run: make generate
- name: "Run Code Linting"
run: make lint
- name: "Verify Code Generation"
id: verify-codegen
run: |
if ! git diff --exit-code; then
echo "❌ Code generation produced changes. Please run 'make generate' and commit the changes."
echo "changes=true" >> $GITHUB_OUTPUT
git diff
exit 1
else
echo "✅ Code generation verification passed."
echo "changes=false" >> $GITHUB_OUTPUT
fi
unit-tests:
name: "Unit Tests"
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: [code-quality]
steps:
- name: "Checkout Repository"
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: "Configure Private Repository Access"
run: |
git config --global url.https://x-oauth-basic:${{ secrets.GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
echo "GOPRIVATE=github.com/symbioticfi/relay" >> $GITHUB_ENV
- name: "Setup Go Environment"
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: "go.sum"
- name: "Execute Unit Tests"
run: make unit-test
- name: "Extract Test Coverage"
id: coverage
run: |
if [[ -f coverage.txt ]]; then
TOTAL_LINE=$(grep '^total:' coverage.txt | tail -1)
COVERAGE=$(echo "$TOTAL_LINE" | grep -Eo '[0-9]+\.[0-9]+%')
COVERAGE_VALUE="${COVERAGE:-Not available}"
echo "coverage=${COVERAGE_VALUE}" >> $GITHUB_OUTPUT
echo "COVERAGE=${COVERAGE_VALUE}" >> $GITHUB_ENV
echo "Test Coverage: ${COVERAGE_VALUE}"
else
echo "coverage=Not available" >> $GITHUB_OUTPUT
echo "COVERAGE=Not available" >> $GITHUB_ENV
echo "⚠️ Coverage file not found"
fi
- name: "Post Coverage Report to PR"
if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'
uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2
with:
message: |
## 🧪 Test Coverage Report
**Coverage:** `${{ steps.coverage.outputs.coverage }}`
e2e-tests:
name: "E2E Tests - ${{ matrix.config.name }}"
runs-on: ${{ matrix.config.verification_type == 0 && 'relay-16' || 'ubuntu-24.04' }}
timeout-minutes: 30
needs: [unit-tests]
strategy:
matrix:
config:
- name: "Simple Setup"
operators: 4
commiters: 1
aggregators: 1
verification_type: 1
- name: "Multi Committer and Aggregator"
operators: 10
commiters: 2
aggregators: 3
verification_type: 1
- name: "ZK Aggregator Test"
operators: 10
commiters: 3
aggregators: 3
verification_type: 0
epoch_time: 120
env:
# E2E Test Configuration
OPERATORS: ${{ matrix.config.operators }}
COMMITERS: ${{ matrix.config.commiters }}
AGGREGATORS: ${{ matrix.config.aggregators }}
VERIFICATION_TYPE: ${{ matrix.config.verification_type }}
EPOCH_TIME: ${{ matrix.config.epoch_time || 60 }}
BLOCK_TIME: 1
FINALITY_BLOCKS: 2
GENERATE_SIDECARS: false
steps:
- name: "Checkout Repository"
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: "Configure Private Repository Access"
run: |
git config --global url.https://x-oauth-basic:${{ secrets.GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
echo "GOPRIVATE=github.com/symbioticfi/relay" >> $GITHUB_ENV
- name: "Setup Go Environment"
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: "go.sum"
- name: "Setup Node.js Environment"
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: "Setup Foundry Toolchain"
uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
with:
version: ${{ env.FOUNDRY_VERSION }}
- name: "Setup Docker Buildx"
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: "Install Go Dependencies"
run: go mod download
- name: "Initialize E2E Test Environment"
run: |
echo "Configuring E2E test environment..."
echo " - Operators: ${{ env.OPERATORS }}"
echo " - Commiters: ${{ env.COMMITERS }}"
echo " - Aggregators: ${{ env.AGGREGATORS }}"
echo " - Verification Type: ${{ env.VERIFICATION_TYPE }}"
echo " - Epoch Time: ${{ env.EPOCH_TIME }}s"
echo " - Block Time: ${{ env.BLOCK_TIME }}s"
echo " - Finality Blocks: ${{ env.FINALITY_BLOCKS }}"
cd e2e
chmod +x setup.sh
./setup.sh
cd ../
chmod -R 777 e2e/
- name: "Start Test Network"
run: |
cd e2e/temp-network
echo "Starting Docker Compose network..."
docker compose up -d
echo "Waiting for services to initialize..."
sleep 30
echo "✅ Network startup completed"
- name: "Execute E2E Tests"
run: |
echo "Running End-to-End tests..."
make e2e-test
- name: "Collect Diagnostic Information"
if: failure()
run: |
cd e2e
echo "❌ Test failure detected - collecting diagnostic information..."
# Create organized logs directory structure
mkdir -p logs/{containers,system,summary}
echo "Gathering container information..."
# Get active containers (excluding anvil containers which are noisy)
CONTAINER_IDS=$(docker ps -a --format "table {{.ID}}\t{{.Names}}" | grep -v -E "(anvil|buildx_buildkit|CONTAINER)" | awk '{print $1}' | tr '\n' ' ')
if [ -n "$CONTAINER_IDS" ]; then
echo "Found active containers: $(echo $CONTAINER_IDS | wc -w)"
# Container status overview
{
echo "=== Container Status Overview ==="
echo "Generated at: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo "Workflow: ${{ github.workflow }}"
echo "Run ID: ${{ github.run_id }}"
echo ""
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -v -E "(anvil|buildx_buildkit)"
} > logs/containers/status-overview.log
# Individual container logs
for container_id in $CONTAINER_IDS; do
if [ -n "$container_id" ]; then
CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $container_id 2>/dev/null | sed 's/^\/*//' || echo "container-$container_id")
echo "Collecting logs for: $CONTAINER_NAME"
{
echo "=== Container: $CONTAINER_NAME ($container_id) ==="
echo "Generated at: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo "Last 500 lines of logs:"
echo ""
docker logs --tail=500 $container_id 2>&1
} > logs/containers/$CONTAINER_NAME.log
fi
done
else
echo "⚠️ No active containers found (excluding anvil)" > logs/containers/status-overview.log
fi
echo "Gathering system information..."
{
echo "=== System Diagnostics ==="
echo "Generated at: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo ""
echo "=== Disk Usage ==="
df -h
echo ""
echo "=== Memory Usage ==="
free -h
echo ""
echo "=== All Docker Containers ==="
docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "=== Docker Images ==="
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}"
} > logs/system/diagnostics.log
echo "Creating test summary..."
{
echo "=== E2E Test Failure Summary ==="
echo "Timestamp: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo "Workflow: ${{ github.workflow }}"
echo "Run ID: ${{ github.run_id }}"
echo "Run Number: ${{ github.run_number }}"
echo "Repository: ${{ github.repository }}"
echo "Branch: ${{ github.ref_name }}"
echo ""
echo "=== Test Configuration ==="
echo " - Operators: ${{ env.OPERATORS }}"
echo " - Commiters: ${{ env.COMMITERS }}"
echo " - Aggregators: ${{ env.AGGREGATORS }}"
echo " - Verification Type: ${{ env.VERIFICATION_TYPE }}"
echo " - Epoch Time: ${{ env.EPOCH_TIME }}s"
echo " - Block Time: ${{ env.BLOCK_TIME }}s"
echo " - Finality Blocks: ${{ env.FINALITY_BLOCKS }}"
echo ""
echo "=== Available Log Files ==="
echo "containers/status-overview.log - Container status summary"
echo "containers/[name].log - Individual container logs (last 500 lines)"
echo "system/diagnostics.log - System resource usage and Docker info"
echo "summary/failure-report.log - This summary file"
echo ""
echo "=== Next Steps ==="
echo "1. Review container logs for error messages"
echo "2. Check system diagnostics for resource constraints"
echo "3. Verify test configuration parameters"
echo "4. Consider adjusting timeout values if needed"
} > logs/summary/failure-report.log
echo "✅ Diagnostic collection completed"
echo "Log file summary:"
find logs -type f -name "*.log" -exec echo " - {}" \; | sort
- name: "Upload Diagnostic Artifacts"
if: failure()
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: "e2e-diagnostics-${{ matrix.config.name }}-${{ github.run_number }}-${{ github.run_attempt }}"
path: e2e/logs/
retention-days: 7
if-no-files-found: warn
````
## File: .github/dependabot.yml
````yaml
version: 2
updates:
# Enable version updates for docker
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
# Enable version updates for go
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
# Enable version updates for github-actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
target-branch: "dev"
````
## File: api/client/examples/main.go
````go
// Basic usage example for the Symbiotic Relay Go client.
//
// This example demonstrates how to:
// 1. Connect to a Symbiotic Relay server
// 2. Get the current epoch
// 3. Sign a message
// 4. Retrieve aggregation proofs
// 5. Get validator set information
// 6. Get individual signatures
// 7. Get signature request IDs by epoch
// 8. Get signature requests by epoch
// 9. Get a signature request by request ID
// 10. Stream signatures in real-time
// 11. Stream aggregation proofs in real-time
// 12. Stream validator set changes in real-time
⋮----
package main
⋮----
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/go-errors/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
client "github.com/symbioticfi/relay/api/client/v1"
)
⋮----
"context"
"fmt"
"log"
"os"
"time"
⋮----
"github.com/go-errors/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
⋮----
client "github.com/symbioticfi/relay/api/client/v1"
⋮----
// RelayClient wraps the Symbiotic client with helpful methods
type RelayClient struct {
client *client.SymbioticClient
conn *grpc.ClientConn
}
⋮----
// NewRelayClient creates a new client connected to the specified server URL
func NewRelayClient(serverURL string) (*RelayClient, error)
⋮----
// Create gRPC connection
⋮----
// Create the symbiotic client
⋮----
// Close closes the gRPC connection
func (rc *RelayClient) Close() error
⋮----
// GetCurrentEpoch gets the current epoch information
func (rc *RelayClient) GetCurrentEpoch(ctx context.Context) (*client.GetCurrentEpochResponse, error)
⋮----
// GetLastAllCommitted gets the last all committed epochs for all chains
func (rc *RelayClient) GetLastAllCommitted(ctx context.Context) (*client.GetLastAllCommittedResponse, error)
⋮----
// SignMessage signs a message using the specified key tag
func (rc *RelayClient) SignMessage(ctx context.Context, keyTag uint32, message []byte, requiredEpoch *uint64) (*client.SignMessageResponse, error)
⋮----
// GetAggregationProof gets aggregation proof for a specific request
func (rc *RelayClient) GetAggregationProof(ctx context.Context, requestID string) (*client.GetAggregationProofResponse, error)
⋮----
// GetSignatures gets individual signatures for a request
func (rc *RelayClient) GetSignatures(ctx context.Context, requestID string) (*client.GetSignaturesResponse, error)
⋮----
// GetSignatureRequestIDsByEpoch gets all signature request IDs for a given epoch
func (rc *RelayClient) GetSignatureRequestIDsByEpoch(ctx context.Context, epoch uint64) (*client.GetSignatureRequestIDsByEpochResponse, error)
⋮----
// GetSignatureRequestsByEpoch gets all signature requests for a given epoch
func (rc *RelayClient) GetSignatureRequestsByEpoch(ctx context.Context, epoch uint64) (*client.GetSignatureRequestsByEpochResponse, error)
⋮----
// GetSignatureRequest gets a signature request by its request ID
func (rc *RelayClient) GetSignatureRequest(ctx context.Context, requestID string) (*client.GetSignatureRequestResponse, error)
⋮----
// GetValidatorSet gets validator set information
func (rc *RelayClient) GetValidatorSet(ctx context.Context, epoch *uint64) (*client.GetValidatorSetResponse, error)
⋮----
// ListenSignatures streams signatures in real-time
func (rc *RelayClient) ListenSignatures(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenSignaturesResponse], error)
⋮----
// ListenProofs streams aggregation proofs in real-time
func (rc *RelayClient) ListenProofs(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenProofsResponse], error)
⋮----
// ListenValidatorSet streams validator set changes in real-time
func (rc *RelayClient) ListenValidatorSet(ctx context.Context, startEpoch *uint64) (grpc.ServerStreamingClient[client.ListenValidatorSetResponse], error)
⋮----
func main()
⋮----
// Initialize client
⋮----
// Create context with timeout
⋮----
// Example 1: Get current epoch
⋮----
// Example 2: Get suggested epoch
⋮----
// Example 3: Get validator set
⋮----
// Display some validator details
⋮----
// Example 4: Sign a message
⋮----
// Example 5: Get aggregation proof (this might fail if signing is not complete)
⋮----
// Example 6: Get individual signatures
⋮----
// Example 7: Get signature request IDs by epoch
⋮----
// Display first few request IDs
⋮----
// Example 8: Get signature requests by epoch
⋮----
// Display first few signature requests
⋮----
// Example 9: Get a signature request by request ID
⋮----
// Example 10: Listen to signatures stream
⋮----
// Create a new context with a shorter timeout for streaming example
⋮----
// Start listening from a specific epoch (optional)
var startEpoch *uint64
⋮----
epoch := epochResponse.GetEpoch() - 1 // Start from previous epoch to get some historical data
⋮----
// Example 11: Listen to aggregation proofs stream
⋮----
// Example 12: Listen to validator set changes stream
````
## File: api/client/examples/README.md
````markdown
# Symbiotic Relay Client Examples
This directory contains example code demonstrating how to use the [Symbiotic Relay Go client library](../v1/) to interact with a Symbiotic Relay server.
## Basic Usage Example
The example shows how to:
1. Connect to a Symbiotic Relay server
2. Get current epoch information
3. Sign messages
4. Retrieve aggregation proofs and signatures
5. Get validator set information
6. Use streaming responses for real-time updates
## Prerequisites
Before running the examples, ensure you have:
- **[Go 1.25 or later](https://golang.org/doc/install)** installed
- **Access to a running Symbiotic Relay Network**
- **Network connectivity** to the relay server
- **Valid key configurations** on the relay server (for signing operations)
## Running the Example
```bash
cd api/client/examples
go run main.go
```
By default, the example will try to connect to `localhost:8080`. You can specify a different server URL by setting the `RELAY_SERVER_URL` environment variable:
```bash
RELAY_SERVER_URL=my-relay-server:8081 go run main.go
```
NOTE: for the signature/proof generation to work you need to run the script for all active relay servers to get the majority consensus to generate proof.
## Integration with Your Application
To integrate this client into your own application:
1. **Import the client package**:
```go
import client "github.com/symbioticfi/relay/api/client/v1"
```
2. **Create a connection**:
```go
conn, err := grpc.Dial(serverURL, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return err
}
client := client.NewSymbioticClient(conn)
```
3. **Use the client methods** as demonstrated in the [example](main.go)
4. **Handle errors appropriately** for your use case
5. **Ensure proper connection cleanup** with `defer conn.Close()`
## More Examples
For a more comprehensive example of using the client library in a real-world application, see:
- **[Symbiotic Super Sum Example](https://github.com/symbioticfi/symbiotic-super-sum/tree/main/off-chain)**
## API Reference
For complete API documentation, refer to:
- **API Documentation**: [`docs/api/v1/doc.md`](../../../docs/api/v1/doc.md)
- **Protocol Buffer definitions**: [`api/proto/v1/api.proto`](../../proto/v1/api.proto)
- **Generated Go types**: [`api/client/v1/types.go`](../v1/types.go)
- **Client interface**: [`api/client/v1/client.go`](../v1/client.go)
## License
This client library and example code are licensed under the MIT License. See the [LICENSE](../LICENSE) file for details.
````
## File: api/client/v1/client.go
````go
package v1
⋮----
import (
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"google.golang.org/grpc"
)
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
"google.golang.org/grpc"
⋮----
// SymbioticClient wraps the generated gRPC client
type SymbioticClient struct {
apiv1.SymbioticAPIServiceClient
}
⋮----
// NewSymbioticClient creates a new client instance for symbiotic relay
func NewSymbioticClient(conn grpc.ClientConnInterface) *SymbioticClient
````
## File: api/client/v1/types.go
````go
// Code generated by generate-client-types. DO NOT EDIT.
package v1
⋮----
import (
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
)
⋮----
apiv1 "github.com/symbioticfi/relay/internal/gen/api/v1"
⋮----
// Exported types for client usage
⋮----
// Enums
⋮----
// Enum constants
const (
// ErrorCode values
ErrorCode_ERROR_CODE_UNSPECIFIED = apiv1.ErrorCode_ERROR_CODE_UNSPECIFIED
ErrorCode_ERROR_CODE_NO_DATA = apiv1.ErrorCode_ERROR_CODE_NO_DATA
ErrorCode_ERROR_CODE_INTERNAL = apiv1.ErrorCode_ERROR_CODE_INTERNAL
ErrorCode_ERROR_CODE_NOT_AGGREGATOR = apiv1.ErrorCode_ERROR_CODE_NOT_AGGREGATOR
// SigningStatus values
SigningStatus_SIGNING_STATUS_UNSPECIFIED = apiv1.SigningStatus_SIGNING_STATUS_UNSPECIFIED
SigningStatus_SIGNING_STATUS_PENDING = apiv1.SigningStatus_SIGNING_STATUS_PENDING
SigningStatus_SIGNING_STATUS_COMPLETED = apiv1.SigningStatus_SIGNING_STATUS_COMPLETED
SigningStatus_SIGNING_STATUS_FAILED = apiv1.SigningStatus_SIGNING_STATUS_FAILED
SigningStatus_SIGNING_STATUS_TIMEOUT = apiv1.SigningStatus_SIGNING_STATUS_TIMEOUT
// ValidatorSetStatus values
ValidatorSetStatus_VALIDATOR_SET_STATUS_UNSPECIFIED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_UNSPECIFIED
ValidatorSetStatus_VALIDATOR_SET_STATUS_DERIVED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_DERIVED
ValidatorSetStatus_VALIDATOR_SET_STATUS_AGGREGATED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_AGGREGATED
ValidatorSetStatus_VALIDATOR_SET_STATUS_COMMITTED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_COMMITTED
ValidatorSetStatus_VALIDATOR_SET_STATUS_MISSED = apiv1.ValidatorSetStatus_VALIDATOR_SET_STATUS_MISSED
)
⋮----
// ErrorCode values
⋮----
// SigningStatus values
⋮----
// ValidatorSetStatus values
⋮----
// Request types
⋮----
// Response types
⋮----
// Data types
````
## File: api/client/LICENSE
````
MIT License
Copyright (c) 2025 Symbiotic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
````
## File: api/proto/v1/api.proto
````protobuf
syntax = "proto3";
package api.proto.v1;
import "google/protobuf/timestamp.proto";
import "google/api/annotations.proto";
option go_package = "github.com/symbioticfi/relay/api/proto/v1";
// SymbioticAPI provides access to the Symbiotic relay functions
service SymbioticAPIService {
// Sign a message
rpc SignMessage(SignMessageRequest) returns (SignMessageResponse) {
option (google.api.http) = {
post: "/v1/sign"
body: "*"
};
}
// Get aggregation proof
rpc GetAggregationProof(GetAggregationProofRequest) returns (GetAggregationProofResponse) {
option (google.api.http) = {
get: "/v1/aggregation/proof/{request_id}"
};
}
// Get aggregation proofs by epoch
rpc GetAggregationProofsByEpoch(GetAggregationProofsByEpochRequest) returns (GetAggregationProofsByEpochResponse) {
option (google.api.http) = {
get: "/v1/aggregation/proofs/epoch/{epoch}"
};
}
// Get current epoch
rpc GetCurrentEpoch(GetCurrentEpochRequest) returns (GetCurrentEpochResponse) {
option (google.api.http) = {
get: "/v1/epoch/current"
};
}
// Get signature by request id
rpc GetSignatures(GetSignaturesRequest) returns (GetSignaturesResponse) {
option (google.api.http) = {
get: "/v1/signatures/{request_id}"
};
}
// Get signature by epoch
rpc GetSignaturesByEpoch(GetSignaturesByEpochRequest) returns (GetSignaturesByEpochResponse) {
option (google.api.http) = {
get: "/v1/signatures/epoch/{epoch}"
};
}
// Get all signature request IDs by epoch
rpc GetSignatureRequestIDsByEpoch(GetSignatureRequestIDsByEpochRequest) returns (GetSignatureRequestIDsByEpochResponse) {
option (google.api.http) = {
get: "/v1/signature-request-ids/epoch/{epoch}"
};
}
// Get all signature requests by epoch
rpc GetSignatureRequestsByEpoch(GetSignatureRequestsByEpochRequest) returns (GetSignatureRequestsByEpochResponse) {
option (google.api.http) = {
get: "/v1/signature-requests/epoch/{epoch}"
};
}
// Get signature request by request id
rpc GetSignatureRequest(GetSignatureRequestRequest) returns (GetSignatureRequestResponse) {
option (google.api.http) = {
get: "/v1/signature-request/{request_id}"
};
}
// Get aggregation status, can be sent only to aggregator nodes
rpc GetAggregationStatus(GetAggregationStatusRequest) returns (GetAggregationStatusResponse) {
option (google.api.http) = {
get: "/v1/aggregation/status/{request_id}"
};
}
// Get current validator set
rpc GetValidatorSet(GetValidatorSetRequest) returns (GetValidatorSetResponse) {
option (google.api.http) = {
get: "/v1/validator-set"
};
}
// Get validator by address
rpc GetValidatorByAddress(GetValidatorByAddressRequest) returns (GetValidatorByAddressResponse) {
option (google.api.http) = {
get: "/v1/validator/address/{address}"
};
}
// Get validator by key
rpc GetValidatorByKey(GetValidatorByKeyRequest) returns (GetValidatorByKeyResponse) {
option (google.api.http) = {
get: "/v1/validator/key/{key_tag}/{on_chain_key}"
};
}
// Get local validator
rpc GetLocalValidator(GetLocalValidatorRequest) returns (GetLocalValidatorResponse) {
option (google.api.http) = {
get: "/v1/validator/local"
};
}
// Get validator set header
rpc GetValidatorSetHeader(GetValidatorSetHeaderRequest) returns (GetValidatorSetHeaderResponse) {
option (google.api.http) = {
get: "/v1/validator-set/header"
};
}
// Get last committed epoch for a specific settlement chain
rpc GetLastCommitted(GetLastCommittedRequest) returns (GetLastCommittedResponse) {
option (google.api.http) = {
get: "/v1/committed/chain/{settlement_chain_id}"
};
}
// Get last committed epochs for all settlement chains
rpc GetLastAllCommitted(GetLastAllCommittedRequest) returns (GetLastAllCommittedResponse) {
option (google.api.http) = {
get: "/v1/committed/all"
};
}
// Get validator set metadata like extra data and request id to fetch aggregation and signature requests
rpc GetValidatorSetMetadata(GetValidatorSetMetadataRequest) returns (GetValidatorSetMetadataResponse) {
option (google.api.http) = {
get: "/v1/validator-set/metadata"
};
}
// Stream signatures in real-time. If start_epoch is provided, sends historical data first
rpc ListenSignatures(ListenSignaturesRequest) returns (stream ListenSignaturesResponse) {
option (google.api.http) = {
get: "/v1/stream/signatures"
};
}
// Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first
rpc ListenProofs(ListenProofsRequest) returns (stream ListenProofsResponse) {
option (google.api.http) = {
get: "/v1/stream/proofs"
};
}
// Stream validator set changes in real-time. If start_epoch is provided, sends historical data first
rpc ListenValidatorSet(ListenValidatorSetRequest) returns (stream ListenValidatorSetResponse) {
option (google.api.http) = {
get: "/v1/stream/validator-set"
};
}
}
// Request message for signing a message
message SignMessageRequest {
// Key tag identifier (0-127)
uint32 key_tag = 1;
// Message to be signed
bytes message = 2;
// Required epoch (optional, if not provided latest committed epoch will be used)
optional uint64 required_epoch = 3;
}
// Response message for sign message request
message SignMessageResponse {
// Hash of the signature request
string request_id = 1;
// Epoch number
uint64 epoch = 2;
}
// Request message for listening to signatures stream
message ListenSignaturesRequest {
// Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates
// If not provided, only signatures generated after stream creation will be sent
optional uint64 start_epoch = 1;
}
// Response message for signatures stream
message ListenSignaturesResponse {
// Id of the signature request
string request_id = 1;
// Epoch number
uint64 epoch = 2;
// Signature data
Signature signature = 3;
}
// Request message for listening to aggregation proofs stream
message ListenProofsRequest {
// Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates
// If not provided, only proofs generated after stream creation will be sent
optional uint64 start_epoch = 1;
}
// Response message for aggregation proofs stream
message ListenProofsResponse {
// Id of the request
string request_id = 1;
// Epoch number
uint64 epoch = 2;
// Final aggregation proof
AggregationProof aggregation_proof = 3;
}
// Request message for listening to validator set changes stream
message ListenValidatorSetRequest {
// Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates
// If not provided, only validator sets generated after stream creation will be sent
optional uint64 start_epoch = 1;
}
// Response message for validator set changes stream
message ListenValidatorSetResponse {
// The validator set
ValidatorSet validator_set = 1;
}
// Request message for getting aggregation proof
message GetAggregationProofRequest {
string request_id = 1;
}
// Request message for getting aggregation proof
message GetAggregationProofsByEpochRequest {
// Epoch number
uint64 epoch = 1;
}
// Request message for getting current epoch
message GetCurrentEpochRequest {}
// Request message for getting signatures
message GetSignaturesRequest {
string request_id = 1;
}
// Request message for getting signatures by epoch
message GetSignaturesByEpochRequest {
// Epoch number
uint64 epoch = 1;
}
// Response message for getting signatures
message GetSignaturesResponse {
// List of signatures
repeated Signature signatures = 1;
}
// Response message for getting signatures by epoch
message GetSignaturesByEpochResponse {
// List of signatures
repeated Signature signatures = 1;
}
// Request message for getting all signature request IDs by epoch
message GetSignatureRequestIDsByEpochRequest {
// Epoch number
uint64 epoch = 1;
}
// Response message for getting all signature request IDs by epoch
message GetSignatureRequestIDsByEpochResponse {
// List of all signature request IDs for the epoch
repeated string request_ids = 1;
}
// Request message for getting all signature requests by epoch
message GetSignatureRequestsByEpochRequest {
// Epoch number
uint64 epoch = 1;
}
// Response message for getting all signature requests by epoch
message GetSignatureRequestsByEpochResponse {
// List of all signature requests for the epoch
repeated SignatureRequest signature_requests = 1;
}
// Request message for getting signature request
message GetSignatureRequestRequest {
string request_id = 1;
}
// Request message for getting aggregation status
message GetAggregationStatusRequest {
string request_id = 1;
}
// Request message for getting validator set
message GetValidatorSetRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
}
// Request message for getting validator by address
message GetValidatorByAddressRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
// Validator address (required)
string address = 2;
}
// Request message for getting validator by key
message GetValidatorByKeyRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
// Validator key tag (required)
uint32 key_tag = 2;
// Validator on chain (public) key (required)
bytes on_chain_key = 3;
}
// Request message for getting local validator
message GetLocalValidatorRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
}
// Request message for getting validator set header
message GetValidatorSetHeaderRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
}
// Request message for getting validator set metadata
message GetValidatorSetMetadataRequest {
// Epoch number (optional, if not provided current epoch will be used)
optional uint64 epoch = 1;
}
// Response message for getting current epoch
message GetCurrentEpochResponse {
// Epoch number
uint64 epoch = 1;
// Epoch start time
google.protobuf.Timestamp start_time = 2;
}
// SignatureRequest represents a signature request
message SignatureRequest {
// Request ID
string request_id = 1;
// Key tag identifier (0-127)
uint32 key_tag = 2;
// Message to be signed
bytes message = 3;
// Required epoch
uint64 required_epoch = 4;
}
// Response message for getting signature request
message GetSignatureRequestResponse {
SignatureRequest signature_request = 1;
}
// Response message for getting aggregation proof
message GetAggregationProofResponse {
AggregationProof aggregation_proof = 1;
}
// Response message for getting aggregation proof
message GetAggregationProofsByEpochResponse {
repeated AggregationProof aggregation_proofs = 1;
}
// Response message for getting aggregation proof
message AggregationProof {
// Message hash
bytes message_hash = 2;
// Proof data
bytes proof = 3;
// Request ID
string request_id = 4;
}
// Response message for getting aggregation status
message GetAggregationStatusResponse {
// Current voting power of the aggregator (big integer as string)
string current_voting_power = 1;
// List of operator addresses that signed the request
repeated string signer_operators = 2;
}
// Digital signature
message Signature {
// Signature data
bytes signature = 1;
// Message hash
bytes message_hash = 2;
// Public key
bytes public_key = 3;
// Request ID
string request_id = 4;
}
// Response message for getting validator set
message GetValidatorSetResponse {
// The validator set
ValidatorSet validator_set = 1;
}
// Response message for getting validator by address
message GetValidatorByAddressResponse {
// The validator
Validator validator = 1;
}
// Response message for getting validator by key
message GetValidatorByKeyResponse {
// The validator
Validator validator = 1;
}
// Response message for getting local validator
message GetLocalValidatorResponse {
// The validator
Validator validator = 1;
}
message ExtraData {
bytes key = 1;
bytes value = 2;
}
// Response message for getting validator set header
message GetValidatorSetMetadataResponse {
repeated ExtraData extra_data = 1;
bytes commitment_data = 2;
string request_id = 3;
}
// Response message for getting validator set header
message GetValidatorSetHeaderResponse {
// Version of the validator set
uint32 version = 1;
// Key tag required to commit next validator set
uint32 required_key_tag = 2;
// Validator set epoch
uint64 epoch = 3;
// Epoch capture timestamp
google.protobuf.Timestamp capture_timestamp = 4;
// Quorum threshold (big integer as string)
string quorum_threshold = 5;
// Total voting power (big integer as string)
string total_voting_power = 6;
// Validators SSZ Merkle root (hex string)
string validators_ssz_mroot = 7;
}
// Validator set status enumeration
enum ValidatorSetStatus {
// Default/unknown status
VALIDATOR_SET_STATUS_UNSPECIFIED = 0;
// Derived status
VALIDATOR_SET_STATUS_DERIVED = 1;
// Aggregated status
VALIDATOR_SET_STATUS_AGGREGATED = 2;
// Committed status
VALIDATOR_SET_STATUS_COMMITTED = 3;
// Missed status
VALIDATOR_SET_STATUS_MISSED = 4;
}
// Validator information
message Validator {
// Operator address (hex string)
string operator = 1;
// Voting power of the validator (big integer as string)
string voting_power = 2;
// Indicates if the validator is active
bool is_active = 3;
// List of cryptographic keys
repeated Key keys = 4;
// List of validator vaults
repeated ValidatorVault vaults = 5;
}
// Cryptographic key
message Key {
// Key tag identifier (0-127)
uint32 tag = 1;
// Key payload
bytes payload = 2;
}
// Validator vault information
message ValidatorVault {
// Chain identifier
uint64 chain_id = 1;
// Vault address
string vault = 2;
// Voting power for this vault (big integer as string)
string voting_power = 3;
}
// Signing process status enumeration
enum SigningStatus {
// Default/unknown status
SIGNING_STATUS_UNSPECIFIED = 0;
// Request has been created and is waiting for signatures
SIGNING_STATUS_PENDING = 1;
// Signing process completed successfully with proof
SIGNING_STATUS_COMPLETED = 2;
// Signing process failed
SIGNING_STATUS_FAILED = 3;
// Signing request timed out
SIGNING_STATUS_TIMEOUT = 4;
}
// Error code enumeration
enum ErrorCode {
// Default/unknown error
ERROR_CODE_UNSPECIFIED = 0;
// No data found
ERROR_CODE_NO_DATA = 1;
// Internal server error
ERROR_CODE_INTERNAL = 2;
// Not an aggregator node
ERROR_CODE_NOT_AGGREGATOR = 3;
}
// Request message for getting last committed epoch for a specific settlement chain
message GetLastCommittedRequest {
// Settlement chain ID
uint64 settlement_chain_id = 1;
}
// Response message for getting last committed epoch
message GetLastCommittedResponse {
// Settlement chain ID
uint64 settlement_chain_id = 1;
ChainEpochInfo epoch_info = 2;
}
// Request message for getting last committed epochs for all chains
message GetLastAllCommittedRequest {
// No parameters needed
}
// Response message for getting all last committed epochs
message GetLastAllCommittedResponse {
// List of settlement chains with their last committed epochs
map epoch_infos = 1;
// Suggested epoch info for signatures, it is the minimum commited epoch among all chains
ChainEpochInfo suggested_epoch_info = 2;
}
// Settlement chain with its last committed epoch
message ChainEpochInfo {
// Last committed epoch for this chain
uint64 last_committed_epoch = 1;
// Epoch start time
google.protobuf.Timestamp start_time = 2;
}
message ValidatorSet {
// Version of the validator set
uint32 version = 1;
// Key tag required to commit next validator set
uint32 required_key_tag = 2;
// Validator set epoch
uint64 epoch = 3;
// Epoch capture timestamp
google.protobuf.Timestamp capture_timestamp = 4;
// Quorum threshold (big integer as string)
string quorum_threshold = 5;
// Status of validator set header
ValidatorSetStatus status = 6;
// List of validators
repeated Validator validators = 7;
}
````
## File: cmd/relay/root/app.go
````go
package root
⋮----
import (
"context"
"log/slog"
"net/http"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/go-errors/errors"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
"golang.org/x/sync/errgroup"
"github.com/symbioticfi/relay/internal/client/p2p"
"github.com/symbioticfi/relay/internal/client/repository/badger"
"github.com/symbioticfi/relay/internal/entity"
aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
aggregatorApp "github.com/symbioticfi/relay/internal/usecase/aggregator-app"
api_server "github.com/symbioticfi/relay/internal/usecase/api-server"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
signatureListener "github.com/symbioticfi/relay/internal/usecase/signature-listener"
signerApp "github.com/symbioticfi/relay/internal/usecase/signer-app"
sync_provider "github.com/symbioticfi/relay/internal/usecase/sync-provider"
sync_runner "github.com/symbioticfi/relay/internal/usecase/sync-runner"
valsetListener "github.com/symbioticfi/relay/internal/usecase/valset-listener"
valsetStatusTracker "github.com/symbioticfi/relay/internal/usecase/valset-status-tracker"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/proof"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
)
⋮----
"context"
"log/slog"
"net/http"
"time"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/go-errors/errors"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
"golang.org/x/sync/errgroup"
⋮----
"github.com/symbioticfi/relay/internal/client/p2p"
"github.com/symbioticfi/relay/internal/client/repository/badger"
"github.com/symbioticfi/relay/internal/entity"
aggregationPolicy "github.com/symbioticfi/relay/internal/usecase/aggregation-policy"
aggregatorApp "github.com/symbioticfi/relay/internal/usecase/aggregator-app"
api_server "github.com/symbioticfi/relay/internal/usecase/api-server"
entity_processor "github.com/symbioticfi/relay/internal/usecase/entity-processor"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
signatureListener "github.com/symbioticfi/relay/internal/usecase/signature-listener"
signerApp "github.com/symbioticfi/relay/internal/usecase/signer-app"
sync_provider "github.com/symbioticfi/relay/internal/usecase/sync-provider"
sync_runner "github.com/symbioticfi/relay/internal/usecase/sync-runner"
valsetListener "github.com/symbioticfi/relay/internal/usecase/valset-listener"
valsetStatusTracker "github.com/symbioticfi/relay/internal/usecase/valset-status-tracker"
"github.com/symbioticfi/relay/pkg/log"
"github.com/symbioticfi/relay/pkg/proof"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
func runApp(ctx context.Context) error
⋮----
var keyProvider *keyprovider.CacheKeyProvider
⋮----
var err error
⋮----
var prover *proof.ZkProver
⋮----
// Load all missing epochs before starting services
⋮----
// also start monitoring for new epochs immediately so that we don't miss any epochs while starting other services
⋮----
var aggApp *aggregatorApp.AggregatorApp
⋮----
func initP2PService(ctx context.Context, cfg config, keyProvider keyprovider.KeyProvider, provider *sync_provider.Syncer, mtr *metrics.Metrics) (*p2p.Service, *p2p.DiscoveryService, error)
⋮----
// pad to make 20 byte to 32 bytes
⋮----
// TODO: include p2p key in valset
⋮----
libp2p.PrivateNetwork(swarmPSK), // Use a private network with the provided swarm key
libp2p.Identity(p2pIdentityPK), // Use the provided identity private key to sign messages that will be sent over the P2P gossip sub
````
## File: cmd/relay/root/config.go
````go
package root
⋮----
import (
"context"
"fmt"
"io/fs"
"reflect"
"strconv"
"strings"
"time"
"github.com/spf13/pflag"
"github.com/symbioticfi/relay/pkg/signals"
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
⋮----
"context"
"fmt"
"io/fs"
"reflect"
"strconv"
"strings"
"time"
⋮----
"github.com/spf13/pflag"
⋮----
"github.com/symbioticfi/relay/pkg/signals"
⋮----
"github.com/go-errors/errors"
"github.com/go-playground/validator/v10"
"github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/spf13/viper"
⋮----
// The config can be populated from command-line flags, environment variables, and a config.yaml file.
// Priority order (highest to lowest):
// 1. Command-line flags
// 2. Environment variables (prefixed with SYMB_ and dashes replaced by underscores)
// 3. config.yaml file (specified by --config or default "config.yaml")
type config struct {
StorageDir string `mapstructure:"storage-dir"`
CircuitsDir string `mapstructure:"circuits-dir"`
MaxUnsigners uint64 `mapstructure:"aggregation-policy-max-unsigners"`
Log LogConfig `mapstructure:"log" validate:"required"`
API APIConfig `mapstructure:"api" validate:"required"`
Metrics MetricsConfig `mapstructure:"metrics"`
Driver CMDCrossChainAddress `mapstructure:"driver" validate:"required"`
SecretKeys CMDSecretKeySlice `mapstructure:"secret-keys"`
KeyStore KeyStore `mapstructure:"keystore"`
SignalCfg signals.Config `mapstructure:"signal"`
Cache CacheConfig `mapstructure:"cache"`
Sync SyncConfig `mapstructure:"sync"`
KeyCache KeyCache `mapstructure:"key-cache"`
P2P P2PConfig `mapstructure:"p2p" validate:"required"`
Evm EvmConfig `mapstructure:"evm" validate:"required"`
ForceRole ForceRole `mapstructure:"force-role"`
Retention RetentionConfig `mapstructure:"retention"`
}
⋮----
type LogConfig struct {
Level string `mapstructure:"level" validate:"oneof=debug info warn error"`
Mode string `mapstructure:"mode" validate:"oneof=json text pretty"`
}
⋮----
type APIConfig struct {
ListenAddress string `mapstructure:"listen" validate:"required"`
MaxAllowedStreams uint64 `mapstructure:"max-allowed-streams" validate:"required"`
VerboseLogging bool `mapstructure:"verbose-logging"`
HTTPGateway bool `mapstructure:"http-gateway"`
}
⋮----
type MetricsConfig struct {
ListenAddress string `mapstructure:"listen"`
PprofEnabled bool `mapstructure:"pprof"`
}
⋮----
type CMDCrossChainAddress struct {
ChainID uint64 `mapstructure:"chain-id" validate:"required"`
Address string `mapstructure:"address" validate:"required"`
}
⋮----
type CMDSecretKeySlice []CMDSecretKey
⋮----
func (s *CMDSecretKeySlice) String() string
⋮----
func (s *CMDSecretKeySlice) Set(str string) error
⋮----
func (s *CMDSecretKeySlice) Type() string
⋮----
type CMDSecretKey struct {
Namespace string `validate:"required"`
KeyType uint8 `validate:"required"`
KeyId int `validate:"required"`
Secret string `validate:"required"`
}
⋮----
func (c *CMDSecretKey) FromStr(str string) (*CMDSecretKey, error)
⋮----
type KeyStore struct {
Path string `json:"path"`
Password string `json:"password"`
}
type CacheConfig struct {
NetworkConfigCacheSize int `mapstructure:"network-config-size"`
ValidatorSetCacheSize int `mapstructure:"validator-set-size"`
}
⋮----
type SyncConfig struct {
Enabled bool `mapstructure:"enabled"`
Period time.Duration `mapstructure:"period"`
Timeout time.Duration `mapstructure:"timeout"`
EpochsToSync uint64 `mapstructure:"epochs"`
}
⋮----
type KeyCache struct {
// max size of the cache
Size int `mapstructure:"size"`
Enabled bool `mapstructure:"enabled"`
}
⋮----
// max size of the cache
⋮----
type P2PConfig struct {
ListenAddress string `mapstructure:"listen" validate:"required"`
Bootnodes []string `mapstructure:"bootnodes"`
DHTMode string `mapstructure:"dht-mode" validate:"oneof=auto server client disabled"`
MDnsEnabled bool `mapstructure:"mdns"`
}
⋮----
type EvmConfig struct {
Chains []string `mapstructure:"chains" validate:"required"`
MaxCalls int `mapstructure:"max-calls"`
}
⋮----
type ForceRole struct {
Aggregator bool `mapstructure:"aggregator"`
Committer bool `mapstructure:"committer"`
}
⋮----
type RetentionConfig struct {
ValSetEpochs uint64 `mapstructure:"valset-epochs"`
}
⋮----
func (c config) Validate() error
⋮----
// Validate that sync.epochs doesn't exceed retention.valset-epochs
⋮----
var (
configFile string
)
⋮----
func addRootFlags(cmd *cobra.Command)
⋮----
func DecodeFlagToStruct(fromType reflect.Type, toType reflect.Type, from interface
⋮----
// if not string return as is
⋮----
// Handle time.Duration specifically
⋮----
// if fromType implements pflag.Value then we can parse it from string
⋮----
func initConfig(cmd *cobra.Command, _ []string) error
⋮----
var cfg config
⋮----
// pflags allows to implement custom types by implementing pflag.Value (we can define how to parse struct from string)
// but[1] viper converts back struct defined flags to string automatically using String() method :(
// but[2] fortunately viper allows to pass decoder that we can use to convert string back to struct :D
⋮----
type contextKeyStruct struct{}
⋮----
func ctxWithCfg(ctx context.Context, cfg config) context.Context
func cfgFromCtx(ctx context.Context) config
````
## File: cmd/relay/root/root.go
````go
package root
⋮----
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"github.com/spf13/cobra"
)
⋮----
"context"
"log/slog"
"os"
"os/signal"
"syscall"
⋮----
"github.com/spf13/cobra"
⋮----
var Version = "local"
var BuildTime = "unknown"
⋮----
func NewRootCommand() *cobra.Command
⋮----
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "relay_sidecar",
Short: "Relay sidecar for signature aggregation",
Long: "A P2P service for collecting and aggregating signatures for Ethereum contracts.",
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRunE: initConfig,
RunE: func(cmd *cobra.Command, args []string) error {
return runApp(signalContext(cmd.Context()))
},
}
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
````
## File: cmd/relay/main.go
````go
package main
⋮----
import (
"context"
"log/slog"
"os"
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/cmd/relay/root"
)
⋮----
"context"
"log/slog"
"os"
⋮----
"github.com/go-errors/errors"
"github.com/symbioticfi/relay/cmd/relay/root"
⋮----
func main()
````
## File: cmd/utils/cmd-helpers/helpers.go
````go
package cmdhelpers
⋮----
import (
"fmt"
"math/big"
"sort"
"strconv"
"strings"
"syscall"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"golang.org/x/term"
)
⋮----
"fmt"
"math/big"
"sort"
"strconv"
"strings"
"syscall"
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"golang.org/x/term"
⋮----
type SecretKeyMapFlag struct {
Secrets map[uint64]string
}
⋮----
func (s *SecretKeyMapFlag) String() string
⋮----
sort.Strings(parts) // Optional: consistent output order
⋮----
func (s *SecretKeyMapFlag) Set(val string) error
⋮----
func (s *SecretKeyMapFlag) Type() string
⋮----
func GetPassword() (string, error)
⋮----
func PrintTreeValidator(leveledList pterm.LeveledList, validator symbiotic.Validator, totalVotingPower *big.Int) pterm.LeveledList
⋮----
func GetPct(value *big.Int, total *big.Int) float64
````
## File: cmd/utils/keys/add.go
````go
package keys
⋮----
import (
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
)
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var addKeyCmd = &cobra.Command{
Use: "add",
Short: "Add key",
RunE: func(cmd *cobra.Command, args []string) error {
if addFlags.PrivateKey == "" && !addFlags.Generate {
return errors.New("add --generate if private key omitted")
}
if addFlags.EvmNs {
if addFlags.ChainID < 0 {
return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
}
return addKeyWithNamespace(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(addFlags.ChainID), addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
} else if addFlags.RelayNs {
if addFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
return errors.New("key tag is required for relay namespace")
}
kt := symbiotic.KeyTag(addFlags.KeyTag)
if kt.Type() == symbiotic.KeyTypeInvalid {
return errors.New("invalid key tag, type not supported")
}
keyId := kt & 0x0F
return addKeyWithNamespace(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
} else if addFlags.P2PNs {
return addKeyWithNamespace(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, addFlags.Generate, addFlags.Force, addFlags.PrivateKey)
}
return errors.New("either --evm or --relay or --p2p must be specified")
},
}
⋮----
func addKeyWithNamespace(ns string, keyType symbiotic.KeyType, id int, generate bool, force bool, privateKey string) error
⋮----
var err error
````
## File: cmd/utils/keys/cmd.go
````go
package keys
⋮----
import (
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/spf13/cobra"
)
⋮----
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/spf13/cobra"
⋮----
func NewKeysCmd() *cobra.Command
⋮----
var keysCmd = &cobra.Command{
Use: "keys",
Short: "Keys tool",
}
⋮----
type GlobalFlags struct {
Path string
Password string
}
⋮----
type AddFlags struct {
EvmNs bool
RelayNs bool
P2PNs bool
KeyTag uint8
ChainID int16
PrivateKey string
Generate bool
Force bool
}
⋮----
type RemoveFlags struct {
EvmNs bool
RelayNs bool
P2PNs bool
KeyTag uint8
ChainID int16
}
⋮----
type UpdateFlags struct {
EvmNs bool
RelayNs bool
P2PNs bool
KeyTag uint8
ChainID int16
PrivateKey string
Force bool
}
⋮----
var globalFlags GlobalFlags
var addFlags AddFlags
⋮----
var removeFlags RemoveFlags
var updateFlags UpdateFlags
⋮----
func initFlags()
````
## File: cmd/utils/keys/print.go
````go
package keys
⋮----
import (
"strconv"
"github.com/pterm/pterm"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/entity"
"github.com/spf13/cobra"
)
⋮----
"strconv"
⋮----
"github.com/pterm/pterm"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/spf13/cobra"
⋮----
var printKeysCmd = &cobra.Command{
Use: "list",
Short: "Print all keys",
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if globalFlags.Password == "" {
globalFlags.Password, err = cmdhelpers.GetPassword()
if err != nil {
return err
}
}
keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
if err != nil {
return err
}
aliases := keyStore.GetAliases()
tableData := pterm.TableData{{"#", "Alias", "Key Tag (Symb Keys)", "Public Key"}}
for i, alias := range aliases {
ns, kType, id, err := keyprovider.AliasToKeyTypeId(alias)
if err != nil {
return err
}
pk, err := keyStore.GetPrivateKeyByNamespaceTypeId(ns, kType, id)
if err != nil {
return err
}
prettyPk, err := pk.PublicKey().OnChain().MarshalText()
if err != nil {
return err
}
tag := "-"
// for other namespace no guarantees can be made about the key id size
if ns == keyprovider.SYMBIOTIC_KEY_NAMESPACE {
kTag, err := entity.KeyTagFromTypeAndId(kType, uint8(id))
if err != nil {
return err
}
tag = kTag.String()
}
tableData = append(tableData, []string{
strconv.Itoa(i + 1),
alias,
tag,
string(prettyPk),
})
}
return pterm.DefaultTable.WithHasHeader().WithData(tableData).Render()
},
}
⋮----
var err error
⋮----
// for other namespace no guarantees can be made about the key id size
````
## File: cmd/utils/keys/remove.go
````go
package keys
⋮----
import (
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
)
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var removeKeyCmd = &cobra.Command{
Use: "remove",
Short: "Remove key",
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if globalFlags.Password == "" {
globalFlags.Password, err = cmdhelpers.GetPassword()
if err != nil {
return err
}
}
keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
if err != nil {
return err
}
if removeFlags.EvmNs {
if removeFlags.ChainID < 0 {
return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
}
return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(removeFlags.ChainID), globalFlags.Password)
} else if removeFlags.RelayNs {
if removeFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
return errors.New("key tag is required for relay namespace")
}
kt := symbiotic.KeyTag(removeFlags.KeyTag)
if kt.Type() == symbiotic.KeyTypeInvalid {
return errors.New("invalid key tag, type not supported")
}
keyId := kt & 0x0F
return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), globalFlags.Password)
} else if removeFlags.P2PNs {
return keyStore.DeleteKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, globalFlags.Password)
}
return errors.New("either --evm or --relay or --p2p must be specified")
},
}
⋮----
var err error
````
## File: cmd/utils/keys/update.go
````go
package keys
⋮----
import (
"github.com/ethereum/go-ethereum/common"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
)
⋮----
"github.com/ethereum/go-ethereum/common"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/go-errors/errors"
"github.com/spf13/cobra"
⋮----
var updateKeyCmd = &cobra.Command{
Use: "update",
Short: "Update key",
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if globalFlags.Password == "" {
globalFlags.Password, err = cmdhelpers.GetPassword()
if err != nil {
return err
}
}
keyStore, err := keyprovider.NewKeystoreProvider(globalFlags.Path, globalFlags.Password)
if err != nil {
return err
}
if updateFlags.PrivateKey == "" {
return errors.New("private key is required for update")
}
privKeyBytes := common.FromHex(updateFlags.PrivateKey)
if updateFlags.EvmNs {
if updateFlags.ChainID < 0 {
return errors.New("chain ID is required for evm namespace, use --chain-id=0 for default key for all chains")
}
exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(updateFlags.ChainID))
if err != nil {
return err
}
if !exists {
return errors.New("key doesn't exist")
}
key, err := crypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, privKeyBytes)
if err != nil {
return err
}
return keyStore.AddKeyByNamespaceTypeId(keyprovider.EVM_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, int(updateFlags.ChainID), key, globalFlags.Password, true)
} else if updateFlags.RelayNs {
if updateFlags.KeyTag == uint8(symbiotic.KeyTypeInvalid) {
return errors.New("key tag is required for relay namespace")
}
kt := symbiotic.KeyTag(updateFlags.KeyTag)
if kt.Type() == symbiotic.KeyTypeInvalid {
return errors.New("invalid key tag, type not supported")
}
keyId := kt & 0x0F
exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId))
if err != nil {
return err
}
if !exists {
return errors.New("key doesn't exist")
}
key, err := crypto.NewPrivateKey(kt.Type(), privKeyBytes)
if err != nil {
return err
}
return keyStore.AddKeyByNamespaceTypeId(keyprovider.SYMBIOTIC_KEY_NAMESPACE, kt.Type(), int(keyId), key, globalFlags.Password, true)
} else if updateFlags.P2PNs {
exists, err := keyStore.HasKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID)
if err != nil {
return err
}
if !exists {
return errors.New("key doesn't exist")
}
key, err := crypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, privKeyBytes)
if err != nil {
return err
}
return keyStore.AddKeyByNamespaceTypeId(keyprovider.P2P_KEY_NAMESPACE, symbiotic.KeyTypeEcdsaSecp256k1, keyprovider.P2P_HOST_IDENTITY_KEY_ID, key, globalFlags.Password, true)
}
return errors.New("either --evm or --relay or --p2p must be specified")
},
}
⋮----
var err error
````
## File: cmd/utils/network/cmd.go
````go
package network
⋮----
import (
"context"
"os"
"os/signal"
"syscall"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"context"
"os"
"os/signal"
"syscall"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
func NewNetworkCmd() *cobra.Command
⋮----
var networkCmd = &cobra.Command{
Use: "network",
Short: "Network tool",
}
⋮----
type GlobalFlags struct {
Chains []string
DriverAddress string
DriverChainId uint64
Epoch uint64
}
⋮----
type InfoFlags struct {
Validators bool
ValidatorsFull bool
Addresses bool
Settlement bool
}
⋮----
type GenesisFlags struct {
Json bool
Commit bool
Epoch int64
Output string
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
var globalFlags GlobalFlags
var infoFlags InfoFlags
var genesisFlags GenesisFlags
⋮----
func initFlags()
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
````
## File: cmd/utils/network/genesis.go
````go
package network
⋮----
import (
"os"
"strconv"
"time"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"os"
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/symbioticfi/relay/symbiotic/usecase/aggregator"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var genesisCmd = &cobra.Command{
Use: "generate-genesis",
Short: "Generate genesis validator set header",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
})
if err != nil {
return err
}
if genesisFlags.Commit {
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
for _, chainId := range evmClient.GetChains() {
secret, ok := genesisFlags.Secrets.Secrets[chainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter private key for chain with ID: " + strconv.Itoa(int(chainId)))
}
pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
if err != nil {
return err
}
err = kp.AddKeyByNamespaceTypeId(
keyprovider.EVM_KEY_NAMESPACE,
symbiotic.KeyTypeEcdsaSecp256k1,
int(chainId),
pk,
)
if err != nil {
return err
}
}
}
spinner := getSpinner("Fetching on-chain network config...")
deriver, err := valsetDeriver.NewDeriver(evmClient)
if err != nil {
return errors.Errorf("failed to create deriver: %v", err)
}
currentOnchainEpoch := symbiotic.Epoch(0)
if genesisFlags.Epoch >= 0 {
currentOnchainEpoch = symbiotic.Epoch(genesisFlags.Epoch)
} else {
currentOnchainEpoch, err = evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
spinner.Success()
spinner = getSpinner("Fetching on-chain validators data...")
newValset, err := deriver.GetValidatorSet(ctx, currentOnchainEpoch, networkConfig)
if err != nil {
return errors.Errorf("failed to get validator set extra for epoch %d: %w", currentOnchainEpoch, err)
}
spinner.Success()
spinner = getSpinner("Building header and extra data...")
// header generation is clear now
header, err := newValset.GetHeader()
if err != nil {
return errors.Errorf("failed to generate validator set header: %w", err)
}
aggregator, err := aggregator.NewAggregator(networkConfig.VerificationType, nil)
if err != nil {
return errors.Errorf("failed to create aggregator: %w", err)
}
// extra data generation is also clear but still in deriver
extraData, err := aggregator.GenerateExtraData(newValset, networkConfig.RequiredKeyTags)
if err != nil {
return errors.Errorf("failed to generate extra data: %w", err)
}
spinner.Success()
jsonData := printHeaderWithExtraDataToJSON(header, extraData)
if !genesisFlags.Json {
panels := pterm.Panels{
{
{Data: pterm.DefaultBox.WithTitle("Validator Set Header").Sprint(
printHeaderTable(header),
)},
},
{
{Data: pterm.DefaultBox.WithTitle("Extra Data").Sprint(
printExtraDataTable(extraData),
)},
},
}
pterm.DefaultPanel.WithPanels(panels).Render()
} else {
pterm.Println(jsonData)
}
if genesisFlags.Output != "" {
err = os.WriteFile(genesisFlags.Output, []byte(jsonData), 0600)
if err != nil {
return errors.Errorf("failed to write output file: %w", err)
}
pterm.Success.Println("Genesis data written to " + genesisFlags.Output)
}
if genesisFlags.Commit {
for _, settlement := range networkConfig.Settlements {
spinner = getSpinner("Setting genesis on " + settlement.Address.String())
txResult, err := evmClient.SetGenesis(
ctx,
settlement,
header,
extraData)
if err != nil {
spinner.Fail("Transaction failed: ", err)
return errors.Errorf("failed to set genesis for network %d: %w", settlement.ChainId, err)
}
spinner.Success("Transaction hash: ", txResult.TxHash.String())
}
}
return nil
},
}
⋮----
// header generation is clear now
⋮----
// extra data generation is also clear but still in deriver
⋮----
func getSpinner(text string) *pterm.SpinnerPrinter
````
## File: cmd/utils/network/info.go
````go
package network
⋮----
import (
"time"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/samber/lo"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)
⋮----
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/samber/lo"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
⋮----
var infoCmd = &cobra.Command{
Use: "info",
Short: "Print network information",
RunE: func(cmd *cobra.Command, args []string) error {
var err error
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
if err != nil {
return errors.Errorf("Failed to get evm client: %v", err)
}
deriver, err := valsetDeriver.NewDeriver(evmClient)
if err != nil {
return errors.Errorf("Failed to create deriver: %v", err)
}
epoch := symbiotic.Epoch(globalFlags.Epoch)
if globalFlags.Epoch == 0 {
epoch, err = evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("Failed to get current epoch: %w", err)
}
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, epoch)
if err != nil {
return errors.Errorf("Failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, epoch)
if err != nil {
return errors.Errorf("Failed to get config: %w", err)
}
epochDuration, err := evmClient.GetEpochDuration(ctx, epoch)
if err != nil {
return errors.Errorf("Failed to get epoch duration: %w", err)
}
valset, err := deriver.GetValidatorSet(ctx, epoch, networkConfig)
if err != nil {
return errors.Errorf("Failed to get validator set: %w", err)
}
// row with info and config
panels := pterm.Panels{
{
{Data: pterm.DefaultBox.WithTitle("Network info").Sprint(
printNetworkInfo(epoch, captureTimestamp, &networkConfig, &valset),
)},
{Data: pterm.DefaultBox.WithTitle("Network config").Sprint(
printNetworkConfig(epochDuration, &networkConfig),
)},
},
}
// row with addresses [optional]
if infoFlags.Addresses {
panels = append(panels, []pterm.Panel{
{Data: pterm.DefaultBox.WithTitle("Addresses").Sprint(
printAddresses(symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
}, &networkConfig),
)},
})
}
// row with settlements info
if infoFlags.Settlement {
settlementData := make([]settlementReplicaData, len(networkConfig.Settlements))
eg, egCtx := errgroup.WithContext(ctx)
eg.SetLimit(5)
for i, settlement := range networkConfig.Settlements {
eg.Go(func() error {
isCommitted, err := evmClient.IsValsetHeaderCommittedAt(egCtx, settlement, epoch)
if err != nil {
return errors.Errorf("Failed to get latest epoch: %w", err)
}
settlementData[i].IsCommitted = isCommitted
if isCommitted {
headerHash, err := evmClient.GetHeaderHashAt(egCtx, settlement, epoch)
if err != nil {
return errors.Errorf("Failed to get header hash: %w", err)
}
settlementData[i].HeaderHash = headerHash
}
lastCommittedHeaderEpoch, err := evmClient.GetLastCommittedHeaderEpoch(ctx, settlement)
if err != nil {
return errors.Errorf("Failed to get last committed header epoch: %w", err)
}
settlementData[i].LastCommittedHeaderEpoch = uint64(lastCommittedHeaderEpoch)
allEpochsFromZero := lo.RepeatBy(int(epoch+1), func(i int) symbiotic.Epoch {
return symbiotic.Epoch(i)
})
commitmentResults, err := evmClient.IsValsetHeaderCommittedAtEpochs(egCtx, settlement, allEpochsFromZero)
if err != nil {
return errors.Errorf("Failed to check epoch commitments: %w", err)
}
settlementData[i].MissedEpochs = uint64(lo.CountBy(commitmentResults, func(committed bool) bool { return !committed }))
return nil
})
}
if err := eg.Wait(); err != nil {
return err
}
header, err := valset.GetHeader()
if err != nil {
return errors.Errorf("Failed to get header: %w", err)
}
panels = append(panels, []pterm.Panel{
{Data: pterm.DefaultBox.WithTitle("Settlement").Sprint(
printSettlementData(header, networkConfig, settlementData),
)},
})
}
// row with validators [optional]
if infoFlags.ValidatorsFull {
panels = append(panels, []pterm.Panel{
{Data: pterm.DefaultBox.WithTitle("Validators").Sprint(
printValidatorsTree(&valset),
)},
})
} else if infoFlags.Validators {
panels = append(panels, []pterm.Panel{
{Data: pterm.DefaultBox.WithTitle("Validators").Sprint(
printValidatorsTable(&valset),
)},
})
}
pterm.DefaultPanel.WithPanels(panels).Render()
return nil
},
}
⋮----
var err error
⋮----
// row with info and config
⋮----
// row with addresses [optional]
⋮----
// row with settlements info
⋮----
// row with validators [optional]
````
## File: cmd/utils/network/printers.go
````go
package network
⋮----
import (
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"time"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/ethereum/go-ethereum/common"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/samber/lo"
)
⋮----
"encoding/json"
"fmt"
"math/big"
"strconv"
"strings"
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/samber/lo"
⋮----
type settlementReplicaData struct {
IsCommitted bool
HeaderHash common.Hash
MissedEpochs uint64
LastCommittedHeaderEpoch uint64
}
⋮----
func printAddresses(driver symbiotic.CrossChainAddress, networkConfig *symbiotic.NetworkConfig) string
⋮----
func printNetworkConfig(epochDuration uint64, networkConfig *symbiotic.NetworkConfig) string
⋮----
func printNetworkInfo(epoch symbiotic.Epoch, epochStart symbiotic.Timestamp, networkConfig *symbiotic.NetworkConfig, valset *symbiotic.ValidatorSet) string
⋮----
func printValidatorsTree(valset *symbiotic.ValidatorSet) string
⋮----
// Render the tree structure using the default tree printer.
⋮----
func printValidatorsTable(valset *symbiotic.ValidatorSet) string
⋮----
func printHeaderTable(header symbiotic.ValidatorSetHeader) string
⋮----
func printExtraDataTable(extraData symbiotic.ExtraDataList) string
⋮----
func printHeaderWithExtraDataToJSON(validatorSetHeader symbiotic.ValidatorSetHeader, extraDataList symbiotic.ExtraDataList) string
⋮----
type jsonHeader struct {
Version uint8 `json:"version"`
ValidatorsSszMRoot string `json:"validatorsSszMRoot"` // hex string
Epoch uint64 `json:"epoch"`
RequiredKeyTag uint8 `json:"requiredKeyTag"`
CaptureTimestamp uint64 `json:"captureTimestamp"`
QuorumThreshold *big.Int `json:"quorumThreshold"`
TotalVotingPower *big.Int `json:"totalVotingPower"`
}
⋮----
ValidatorsSszMRoot string `json:"validatorsSszMRoot"` // hex string
⋮----
type jsonExtraData struct {
Key string `json:"key"` // hex string
Value string `json:"value"` // hex string
}
⋮----
Key string `json:"key"` // hex string
Value string `json:"value"` // hex string
⋮----
type jsonValidatorSetHeaderWithExtraData struct {
Header jsonHeader `json:"header"`
ExtraDataList []jsonExtraData `json:"extraData"`
}
⋮----
func printSettlementData(
valsetHeader symbiotic.ValidatorSetHeader,
networkConfig symbiotic.NetworkConfig,
settlementData []settlementReplicaData,
) string
````
## File: cmd/utils/operator/cmd.go
````go
package operator
⋮----
import (
"context"
"os"
"os/signal"
"syscall"
"github.com/go-errors/errors"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"context"
"os"
"os/signal"
"syscall"
⋮----
"github.com/go-errors/errors"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
func NewOperatorCmd() *cobra.Command
⋮----
var operatorCmd = &cobra.Command{
Use: "operator",
Short: "Operator tool",
}
⋮----
type GlobalFlags struct {
Chains []string
DriverAddress string
DriverChainId uint64
VotingProviderChainId uint64
}
⋮----
type InfoFlags struct {
Epoch uint64
Full bool
Path string
Password string
KeyTag uint8
}
⋮----
type RegisterKeyFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
Path string
Password string
KeyTag uint8
}
⋮----
type InvalidateOldSignaturesFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type RegisterOperatorWithSignatureFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type UnregisterOperatorWithSignatureFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type RegisterOperatorFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
type UnregisterOperatorFlags struct {
Secrets cmdhelpers.SecretKeyMapFlag
}
⋮----
var globalFlags GlobalFlags
var infoFlags InfoFlags
var registerKeyFlags RegisterKeyFlags
var invalidateOldSignaturesFlags InvalidateOldSignaturesFlags
var registerOperatorWithSignatureFlags RegisterOperatorWithSignatureFlags
var unregisterOperatorWithSignatureFlags UnregisterOperatorWithSignatureFlags
var registerOperatorFlags RegisterOperatorFlags
var unregisterOperatorFlags UnregisterOperatorFlags
⋮----
func initFlags()
⋮----
// signalContext returns a context that is canceled if either SIGTERM or SIGINT signal is received.
func signalContext(ctx context.Context) context.Context
⋮----
// findVotingPowerProviderByChainId finds a voting power provider by chain id from the list
func findVotingPowerProviderByChainId(providers []symbiotic.CrossChainAddress, chainId uint64) (symbiotic.CrossChainAddress, error)
````
## File: cmd/utils/operator/info.go
````go
package operator
⋮----
import (
"time"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/spf13/cobra"
)
⋮----
"time"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
valsetDeriver "github.com/symbioticfi/relay/symbiotic/usecase/valset-deriver"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/spf13/cobra"
⋮----
var infoCmd = &cobra.Command{
Use: "info",
Short: "Print operator information",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
if infoFlags.Password == "" {
infoFlags.Password, err = cmdhelpers.GetPassword()
if err != nil {
return errors.Errorf("failed to get password: %w", err)
}
}
if infoFlags.Epoch == 0 {
epoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
infoFlags.Epoch = uint64(epoch)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, symbiotic.Epoch(infoFlags.Epoch))
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, symbiotic.Epoch(infoFlags.Epoch))
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
epoch, err := evmClient.GetLastCommittedHeaderEpoch(ctx, networkConfig.Settlements[0])
if err != nil {
return errors.Errorf("failed to get valset header: %w", err)
}
deriver, err := valsetDeriver.NewDeriver(evmClient)
if err != nil {
return errors.Errorf("failed to create valset deriver: %w", err)
}
valset, err := deriver.GetValidatorSet(ctx, epoch, networkConfig)
if err != nil {
return errors.Errorf("failed to get validator set: %w", err)
}
keyStore, err := keyprovider.NewKeystoreProvider(infoFlags.Path, infoFlags.Password)
if err != nil {
return err
}
kt := symbiotic.KeyTag(infoFlags.KeyTag)
pk, err := keyStore.GetPrivateKey(kt)
if err != nil {
return err
}
validator, found := valset.FindValidatorByKey(kt, pk.PublicKey().OnChain())
if !found {
return errors.Errorf("validator not found for key: %d %s", kt, common.Bytes2Hex(pk.PublicKey().Raw()))
}
leveledList := pterm.LeveledList{}
leveledList = cmdhelpers.PrintTreeValidator(leveledList, validator, valset.GetTotalActiveVotingPower().Int)
text, _ := pterm.DefaultTree.WithRoot(putils.TreeFromLeveledList(leveledList)).Srender()
panels := pterm.Panels{{{Data: pterm.DefaultBox.WithTitle("Operator info").Sprint(text)}}}
pterm.DefaultPanel.WithPanels(panels).Render()
return nil
},
}
````
## File: cmd/utils/operator/invalidate_old_signatures.go
````go
package operator
⋮----
import (
"strconv"
"time"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var invalidateOldSignaturesCmd = &cobra.Command{
Use: "invalidate-old-signatures",
Short: "Invalidate old signatures for operator",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
currentOnChainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnChainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnChainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
if len(networkConfig.VotingPowerProviders) == 0 {
return errors.New("no voting power providers found in network config")
}
votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
if err != nil {
return err
}
// Load the operator key for the voting power provider's chain
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := invalidateOldSignaturesFlags.Secrets.Secrets[votingPowerProvider.ChainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
}
pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
if err != nil {
return err
}
err = kp.AddKeyByNamespaceTypeId(
keyprovider.EVM_KEY_NAMESPACE,
symbiotic.KeyTypeEcdsaSecp256k1,
int(votingPowerProvider.ChainId),
pk,
)
if err != nil {
return err
}
txResult, err := evmClient.InvalidateOldSignatures(ctx, votingPowerProvider)
if err != nil {
return errors.Errorf("failed to invalidate old signatures: %w", err)
}
pterm.Success.Println("Old signatures invalidated! TxHash:", txResult.TxHash.String())
return nil
},
}
⋮----
// Load the operator key for the voting power provider's chain
````
## File: cmd/utils/operator/register_key.go
````go
package operator
⋮----
import (
"log/slog"
"strconv"
"time"
"github.com/ethereum/go-ethereum/common/math"
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381Bn254"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"log/slog"
"strconv"
"time"
⋮----
"github.com/ethereum/go-ethereum/common/math"
⋮----
cmdhelpers "github.com/symbioticfi/relay/cmd/utils/cmd-helpers"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/bls12381Bn254"
"github.com/symbioticfi/relay/symbiotic/usecase/crypto/blsBn254"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var registerKeyCmd = &cobra.Command{
Use: "register-key",
Short: "Register operator key in key registry",
RunE: func(cmd *cobra.Command, args []string) error {
var err error
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
// TODO multiple chains key registration support
if len(evmClient.GetChains()) != 1 {
return errors.New("only single chain is supported")
}
chainId := evmClient.GetChains()[0]
// duplicate from genesis
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := registerKeyFlags.Secrets.Secrets[chainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter private key for chain with ID: " + strconv.Itoa(int(chainId)))
}
pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
if err != nil {
return err
}
err = kp.AddKeyByNamespaceTypeId(
keyprovider.EVM_KEY_NAMESPACE,
symbiotic.KeyTypeEcdsaSecp256k1,
int(chainId),
pk,
)
if err != nil {
return err
}
if registerKeyFlags.Password == "" {
registerKeyFlags.Password, err = cmdhelpers.GetPassword()
if err != nil {
return err
}
}
keyStore, err := keyprovider.NewKeystoreProvider(registerKeyFlags.Path, registerKeyFlags.Password)
if err != nil {
return err
}
kt := symbiotic.KeyTag(registerKeyFlags.KeyTag)
pk, err = keyStore.GetPrivateKey(kt)
if err != nil {
return errors.Errorf("failed to get private key for keyTag %v from keystore: %w", kt, err)
}
currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
eip712Domain, err := evmClient.GetEip712Domain(ctx, networkConfig.KeysProvider)
if err != nil {
return errors.Errorf("failed to get eip712 domain: %w", err)
}
ecdsaPk, err := crypto.HexToECDSA(secret)
if err != nil {
return err
}
operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)
key := pk.PublicKey().OnChain()
commitmentData, err := keyCommitmentData(eip712Domain, operator, key)
if err != nil {
return errors.Errorf("failed to get commitment data: %w", err)
}
signature, _, err := pk.Sign(commitmentData)
if err != nil {
return errors.Errorf("failed to sign commitment data: %w", err)
}
// For ECDSA signatures, we need to adjust the recovery ID
// Go's crypto.Sign() returns V as 0 or 1, but Ethereum expects 27 or 28
if kt.Type() == symbiotic.KeyTypeEcdsaSecp256k1 && len(signature) == 65 {
// Convert recovery ID from 0/1 to 27/28 for Ethereum
signature[64] += 27
}
var extraData []byte
switch kt.Type() {
case symbiotic.KeyTypeBlsBn254:
blsKey, err := blsBn254.FromRaw(pk.PublicKey().Raw())
if err != nil {
return errors.Errorf("failed to parse BLS public key: %w", err)
}
rawByte := blsKey.G2().RawBytes()
extraData = rawByte[:]
case symbiotic.KeyTypeBls12381Bn254:
blsKey, err := bls12381Bn254.FromRaw(pk.PublicKey().Raw())
if err != nil {
return errors.Errorf("failed to parse BLS public key: %w", err)
}
rawByte := blsKey.G2().RawBytes()
extraData = rawByte[:]
case symbiotic.KeyTypeEcdsaSecp256k1:
// no extra data needed for ECDSA keys
case symbiotic.KeyTypeInvalid:
return errors.New("invalid key type")
}
// Use the adjusted signature for registration
txResult, err := evmClient.RegisterKey(ctx, networkConfig.KeysProvider, kt, key, signature, extraData)
if err != nil {
return errors.Errorf("failed to register operator: %w", err)
}
slog.InfoContext(ctx, "Operator Key registered!", "txHash", txResult.TxHash.String(), "key-tag", kt)
return nil
},
}
⋮----
var err error
⋮----
// TODO multiple chains key registration support
⋮----
// duplicate from genesis
⋮----
// For ECDSA signatures, we need to adjust the recovery ID
// Go's crypto.Sign() returns V as 0 or 1, but Ethereum expects 27 or 28
⋮----
// Convert recovery ID from 0/1 to 27/28 for Ethereum
⋮----
var extraData []byte
⋮----
// no extra data needed for ECDSA keys
⋮----
// Use the adjusted signature for registration
⋮----
func keyCommitmentData(eip712Domain symbiotic.Eip712Domain, operator common.Address, keyBytes []byte) ([]byte, error)
````
## File: cmd/utils/operator/register_operator.go
````go
package operator
⋮----
import (
"strconv"
"time"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var registerOperatorCmd = &cobra.Command{
Use: "register-operator",
Short: "Register operator on-chain via VotingPowerProvider",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
if len(networkConfig.VotingPowerProviders) == 0 {
return errors.New("no voting power providers found in network config")
}
votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
if err != nil {
return err
}
// Load the operator key for the voting power provider's chain
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := registerOperatorFlags.Secrets.Secrets[votingPowerProvider.ChainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
}
pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
if err != nil {
return err
}
err = kp.AddKeyByNamespaceTypeId(
keyprovider.EVM_KEY_NAMESPACE,
symbiotic.KeyTypeEcdsaSecp256k1,
int(votingPowerProvider.ChainId),
pk,
)
if err != nil {
return err
}
txResult, err := evmClient.RegisterOperatorVotingPowerProvider(ctx, votingPowerProvider)
if err != nil {
return errors.Errorf("failed to register operator: %w", err)
}
pterm.Success.Println("Operator registered! TxHash:", txResult.TxHash.String())
return nil
},
}
⋮----
// Load the operator key for the voting power provider's chain
````
## File: cmd/utils/operator/register_with_signature.go
````go
package operator
⋮----
import (
"strconv"
"time"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var registerOperatorWithSignatureCmd = &cobra.Command{
Use: "register-operator-with-signature",
Short: "Generate EIP-712 signature for operator registration",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := registerOperatorWithSignatureFlags.Secrets.Secrets[globalFlags.DriverChainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(globalFlags.DriverChainId)))
}
ecdsaPk, err := crypto.HexToECDSA(secret)
if err != nil {
return errors.Errorf("failed to parse private key: %w", err)
}
operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)
currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
// Find VotingPowerProvider by chain ID
if len(networkConfig.VotingPowerProviders) == 0 {
return errors.New("no voting power providers found in network config")
}
votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
if err != nil {
return err
}
eip712Domain, err := evmClient.GetVotingPowerProviderEip712Domain(ctx, votingPowerProvider)
if err != nil {
return errors.Errorf("failed to get eip712 domain: %w", err)
}
nonce, err := evmClient.GetOperatorNonce(ctx, votingPowerProvider, operator)
if err != nil {
return errors.Errorf("failed to get operator nonce: %w", err)
}
// Build EIP-712 typed data for RegisterOperator
typedData := apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
{Name: "verifyingContract", Type: "address"},
},
"RegisterOperator": []apitypes.Type{
{Name: "operator", Type: "address"},
{Name: "nonce", Type: "uint256"},
},
},
PrimaryType: "RegisterOperator",
Domain: apitypes.TypedDataDomain{
Name: eip712Domain.Name,
Version: eip712Domain.Version,
ChainId: (*math.HexOrDecimal256)(eip712Domain.ChainId),
VerifyingContract: eip712Domain.VerifyingContract.Hex(),
},
Message: apitypes.TypedDataMessage{
"operator": operator.Hex(),
"nonce": (*math.HexOrDecimal256)(nonce),
},
}
typedDataHash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return errors.Errorf("failed to hash typed data: %w", err)
}
signature, err := crypto.Sign(typedDataHash, ecdsaPk)
if err != nil {
return errors.Errorf("failed to sign: %w", err)
}
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
if len(signature) == 65 {
signature[64] += 27
}
pterm.Success.Printf("0x%x\n", signature)
return nil
},
}
⋮----
// Find VotingPowerProvider by chain ID
⋮----
// Build EIP-712 typed data for RegisterOperator
⋮----
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
````
## File: cmd/utils/operator/unregister_operator.go
````go
package operator
⋮----
import (
"strconv"
"time"
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
keyprovider "github.com/symbioticfi/relay/internal/usecase/key-provider"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
symbioticCrypto "github.com/symbioticfi/relay/symbiotic/usecase/crypto"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var unregisterOperatorCmd = &cobra.Command{
Use: "unregister-operator",
Short: "Unregister operator on-chain via VotingPowerProvider",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
kp, err := keyprovider.NewSimpleKeystoreProvider()
if err != nil {
return err
}
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
KeyProvider: kp,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
if len(networkConfig.VotingPowerProviders) == 0 {
return errors.New("no voting power providers found in network config")
}
votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
if err != nil {
return err
}
// Load the operator key for the voting power provider's chain
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := unregisterOperatorFlags.Secrets.Secrets[votingPowerProvider.ChainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(votingPowerProvider.ChainId)))
}
pk, err := symbioticCrypto.NewPrivateKey(symbiotic.KeyTypeEcdsaSecp256k1, common.FromHex(secret))
if err != nil {
return err
}
err = kp.AddKeyByNamespaceTypeId(
keyprovider.EVM_KEY_NAMESPACE,
symbiotic.KeyTypeEcdsaSecp256k1,
int(votingPowerProvider.ChainId),
pk,
)
if err != nil {
return err
}
txResult, err := evmClient.UnregisterOperatorVotingPowerProvider(ctx, votingPowerProvider)
if err != nil {
return errors.Errorf("failed to unregister operator: %w", err)
}
pterm.Success.Println("Operator unregistered! TxHash:", txResult.TxHash.String())
return nil
},
}
⋮----
// Load the operator key for the voting power provider's chain
````
## File: cmd/utils/operator/unregister_with_signature.go
````go
package operator
⋮----
import (
"strconv"
"time"
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"strconv"
"time"
⋮----
"github.com/symbioticfi/relay/internal/usecase/metrics"
"github.com/symbioticfi/relay/symbiotic/client/evm"
symbiotic "github.com/symbioticfi/relay/symbiotic/entity"
⋮----
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/go-errors/errors"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
var unregisterOperatorWithSignatureCmd = &cobra.Command{
Use: "unregister-operator-with-signature",
Short: "Generate EIP-712 signature for operator unregistration",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := signalContext(cmd.Context())
evmClient, err := evm.NewEvmClient(ctx, evm.Config{
ChainURLs: globalFlags.Chains,
DriverAddress: symbiotic.CrossChainAddress{
ChainId: globalFlags.DriverChainId,
Address: common.HexToAddress(globalFlags.DriverAddress),
},
RequestTimeout: 5 * time.Second,
Metrics: metrics.New(metrics.Config{}),
})
if err != nil {
return err
}
privateKeyInput := pterm.DefaultInteractiveTextInput.WithMask("*")
secret, ok := unregisterOperatorWithSignatureFlags.Secrets.Secrets[globalFlags.DriverChainId]
if !ok {
secret, _ = privateKeyInput.Show("Enter operator private key for chain with ID: " + strconv.Itoa(int(globalFlags.DriverChainId)))
}
ecdsaPk, err := crypto.HexToECDSA(secret)
if err != nil {
return errors.Errorf("failed to parse private key: %w", err)
}
operator := crypto.PubkeyToAddress(ecdsaPk.PublicKey)
currentOnchainEpoch, err := evmClient.GetCurrentEpoch(ctx)
if err != nil {
return errors.Errorf("failed to get current epoch: %w", err)
}
captureTimestamp, err := evmClient.GetEpochStart(ctx, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get capture timestamp: %w", err)
}
networkConfig, err := evmClient.GetConfig(ctx, captureTimestamp, currentOnchainEpoch)
if err != nil {
return errors.Errorf("failed to get config: %w", err)
}
// Find VotingPowerProvider by chain ID
if len(networkConfig.VotingPowerProviders) == 0 {
return errors.New("no voting power providers found in network config")
}
votingPowerProvider, err := findVotingPowerProviderByChainId(networkConfig.VotingPowerProviders, globalFlags.VotingProviderChainId)
if err != nil {
return err
}
eip712Domain, err := evmClient.GetVotingPowerProviderEip712Domain(ctx, votingPowerProvider)
if err != nil {
return errors.Errorf("failed to get eip712 domain: %w", err)
}
nonce, err := evmClient.GetOperatorNonce(ctx, votingPowerProvider, operator)
if err != nil {
return errors.Errorf("failed to get operator nonce: %w", err)
}
// Build EIP-712 typed data for UnregisterOperator
typedData := apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
{Name: "verifyingContract", Type: "address"},
},
"UnregisterOperator": []apitypes.Type{
{Name: "operator", Type: "address"},
{Name: "nonce", Type: "uint256"},
},
},
PrimaryType: "UnregisterOperator",
Domain: apitypes.TypedDataDomain{
Name: eip712Domain.Name,
Version: eip712Domain.Version,
ChainId: (*math.HexOrDecimal256)(eip712Domain.ChainId),
VerifyingContract: eip712Domain.VerifyingContract.Hex(),
},
Message: apitypes.TypedDataMessage{
"operator": operator.Hex(),
"nonce": (*math.HexOrDecimal256)(nonce),
},
}
typedDataHash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return errors.Errorf("failed to hash typed data: %w", err)
}
signature, err := crypto.Sign(typedDataHash, ecdsaPk)
if err != nil {
return errors.Errorf("failed to sign: %w", err)
}
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
if len(signature) == 65 {
signature[64] += 27
}
pterm.Success.Printf("0x%x\n", signature)
return nil
},
}
⋮----
// Find VotingPowerProvider by chain ID
⋮----
// Build EIP-712 typed data for UnregisterOperator
⋮----
// Ethereum expects recovery ID to be 27 or 28, not 0 or 1
````
## File: cmd/utils/root/root.go
````go
package root
⋮----
import (
"runtime"
"github.com/symbioticfi/relay/cmd/utils/keys"
"github.com/symbioticfi/relay/cmd/utils/network"
"github.com/symbioticfi/relay/cmd/utils/operator"
"github.com/symbioticfi/relay/pkg/log"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)
⋮----
"runtime"
⋮----
"github.com/symbioticfi/relay/cmd/utils/keys"
"github.com/symbioticfi/relay/cmd/utils/network"
"github.com/symbioticfi/relay/cmd/utils/operator"
"github.com/symbioticfi/relay/pkg/log"
⋮----
"github.com/pterm/pterm"
"github.com/spf13/cobra"
⋮----
type config struct {
logLevel string
logMode string
}
⋮----
var Version = "local"
var BuildTime = "unknown"
⋮----
var cfg config
⋮----
func NewRootCommand() *cobra.Command
⋮----
var rootCmd = &cobra.Command{
Use: "utils",
Short: "Utils tool",
PreRun: func(cmd *cobra.Command, args []string) {
log.Init(cfg.logLevel, cfg.logMode)
},
}
⋮----
var versionCommand = &cobra.Command{
Use: "version",
Short: "Print the version of the utils tool",
Run: func(cmd *cobra.Command, args []string) {
pterm.Info.Println("Utils tool version:", Version)
pterm.Info.Println("Go version:", runtime.Version())
pterm.Info.Println("OS/Arch:", runtime.GOOS+"/"+runtime.GOARCH)
pterm.Info.Println("Build time:", BuildTime)
},
}
````
## File: cmd/utils/main.go
````go
package main
⋮----
import (
"os"
"github.com/pterm/pterm"
"github.com/symbioticfi/relay/cmd/utils/root"
)
⋮----
"os"
⋮----
"github.com/pterm/pterm"
"github.com/symbioticfi/relay/cmd/utils/root"
⋮----
func main()
````
## File: docs/api/v1/api.swagger.json
````json
{
"swagger": "2.0",
"info": {
"title": "v1/api.proto",
"version": "version not set"
},
"tags": [
{
"name": "SymbioticAPIService"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v1/aggregation/proof/{requestId}": {
"get": {
"summary": "Get aggregation proof",
"operationId": "SymbioticAPIService_GetAggregationProof",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetAggregationProofResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "requestId",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/aggregation/proofs/epoch/{epoch}": {
"get": {
"summary": "Get aggregation proofs by epoch",
"operationId": "SymbioticAPIService_GetAggregationProofsByEpoch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetAggregationProofsByEpochResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number",
"in": "path",
"required": true,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/aggregation/status/{requestId}": {
"get": {
"summary": "Get aggregation status, can be sent only to aggregator nodes",
"operationId": "SymbioticAPIService_GetAggregationStatus",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetAggregationStatusResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "requestId",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/committed/all": {
"get": {
"summary": "Get last committed epochs for all settlement chains",
"operationId": "SymbioticAPIService_GetLastAllCommitted",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetLastAllCommittedResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/committed/chain/{settlementChainId}": {
"get": {
"summary": "Get last committed epoch for a specific settlement chain",
"operationId": "SymbioticAPIService_GetLastCommitted",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetLastCommittedResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "settlementChainId",
"description": "Settlement chain ID",
"in": "path",
"required": true,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/epoch/current": {
"get": {
"summary": "Get current epoch",
"operationId": "SymbioticAPIService_GetCurrentEpoch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetCurrentEpochResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/sign": {
"post": {
"summary": "Sign a message",
"operationId": "SymbioticAPIService_SignMessage",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/SignMessageResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/SignMessageRequest"
}
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/signature-request-ids/epoch/{epoch}": {
"get": {
"summary": "Get all signature request IDs by epoch",
"operationId": "SymbioticAPIService_GetSignatureRequestIDsByEpoch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetSignatureRequestIDsByEpochResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number",
"in": "path",
"required": true,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/signature-request/{requestId}": {
"get": {
"summary": "Get signature request by request id",
"operationId": "SymbioticAPIService_GetSignatureRequest",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetSignatureRequestResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "requestId",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/signature-requests/epoch/{epoch}": {
"get": {
"summary": "Get all signature requests by epoch",
"operationId": "SymbioticAPIService_GetSignatureRequestsByEpoch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetSignatureRequestsByEpochResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number",
"in": "path",
"required": true,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/signatures/epoch/{epoch}": {
"get": {
"summary": "Get signature by epoch",
"operationId": "SymbioticAPIService_GetSignaturesByEpoch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetSignaturesByEpochResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number",
"in": "path",
"required": true,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/signatures/{requestId}": {
"get": {
"summary": "Get signature by request id",
"operationId": "SymbioticAPIService_GetSignatures",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetSignaturesResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "requestId",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/stream/proofs": {
"get": {
"summary": "Stream aggregation proofs in real-time. If start_epoch is provided, sends historical data first",
"operationId": "SymbioticAPIService_ListenProofs",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/ListenProofsResponse"
},
"error": {
"$ref": "#/definitions/Status"
}
},
"title": "Stream result of ListenProofsResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "startEpoch",
"description": "Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates\nIf not provided, only proofs generated after stream creation will be sent",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/stream/signatures": {
"get": {
"summary": "Stream signatures in real-time. If start_epoch is provided, sends historical data first",
"operationId": "SymbioticAPIService_ListenSignatures",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/ListenSignaturesResponse"
},
"error": {
"$ref": "#/definitions/Status"
}
},
"title": "Stream result of ListenSignaturesResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "startEpoch",
"description": "Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates\nIf not provided, only signatures generated after stream creation will be sent",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/stream/validator-set": {
"get": {
"summary": "Stream validator set changes in real-time. If start_epoch is provided, sends historical data first",
"operationId": "SymbioticAPIService_ListenValidatorSet",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/ListenValidatorSetResponse"
},
"error": {
"$ref": "#/definitions/Status"
}
},
"title": "Stream result of ListenValidatorSetResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "startEpoch",
"description": "Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates\nIf not provided, only validator sets generated after stream creation will be sent",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator-set": {
"get": {
"summary": "Get current validator set",
"operationId": "SymbioticAPIService_GetValidatorSet",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetValidatorSetResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator-set/header": {
"get": {
"summary": "Get validator set header",
"operationId": "SymbioticAPIService_GetValidatorSetHeader",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetValidatorSetHeaderResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator-set/metadata": {
"get": {
"summary": "Get validator set metadata like extra data and request id to fetch aggregation and signature requests",
"operationId": "SymbioticAPIService_GetValidatorSetMetadata",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetValidatorSetMetadataResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator/address/{address}": {
"get": {
"summary": "Get validator by address",
"operationId": "SymbioticAPIService_GetValidatorByAddress",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetValidatorByAddressResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "address",
"description": "Validator address (required)",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator/key/{keyTag}/{onChainKey}": {
"get": {
"summary": "Get validator by key",
"operationId": "SymbioticAPIService_GetValidatorByKey",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetValidatorByKeyResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "keyTag",
"description": "Validator key tag (required)",
"in": "path",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "onChainKey",
"description": "Validator on chain (public) key (required)",
"in": "path",
"required": true,
"type": "string",
"format": "byte"
},
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
},
"/v1/validator/local": {
"get": {
"summary": "Get local validator",
"operationId": "SymbioticAPIService_GetLocalValidator",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/GetLocalValidatorResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/Status"
}
}
},
"parameters": [
{
"name": "epoch",
"description": "Epoch number (optional, if not provided current epoch will be used)",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"SymbioticAPIService"
]
}
}
},
"definitions": {
"AggregationProof": {
"type": "object",
"properties": {
"messageHash": {
"type": "string",
"format": "byte",
"title": "Message hash"
},
"proof": {
"type": "string",
"format": "byte",
"title": "Proof data"
},
"requestId": {
"type": "string",
"title": "Request ID"
}
},
"title": "Response message for getting aggregation proof"
},
"Any": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"ChainEpochInfo": {
"type": "object",
"properties": {
"lastCommittedEpoch": {
"type": "string",
"format": "uint64",
"title": "Last committed epoch for this chain"
},
"startTime": {
"type": "string",
"format": "date-time",
"title": "Epoch start time"
}
},
"title": "Settlement chain with its last committed epoch"
},
"ExtraData": {
"type": "object",
"properties": {
"key": {
"type": "string",
"format": "byte"
},
"value": {
"type": "string",
"format": "byte"
}
}
},
"GetAggregationProofResponse": {
"type": "object",
"properties": {
"aggregationProof": {
"$ref": "#/definitions/AggregationProof"
}
},
"title": "Response message for getting aggregation proof"
},
"GetAggregationProofsByEpochResponse": {
"type": "object",
"properties": {
"aggregationProofs": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/AggregationProof"
}
}
},
"title": "Response message for getting aggregation proof"
},
"GetAggregationStatusResponse": {
"type": "object",
"properties": {
"currentVotingPower": {
"type": "string",
"title": "Current voting power of the aggregator (big integer as string)"
},
"signerOperators": {
"type": "array",
"items": {
"type": "string"
},
"title": "List of operator addresses that signed the request"
}
},
"title": "Response message for getting aggregation status"
},
"GetCurrentEpochResponse": {
"type": "object",
"properties": {
"epoch": {
"type": "string",
"format": "uint64",
"title": "Epoch number"
},
"startTime": {
"type": "string",
"format": "date-time",
"title": "Epoch start time"
}
},
"title": "Response message for getting current epoch"
},
"GetLastAllCommittedResponse": {
"type": "object",
"properties": {
"epochInfos": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ChainEpochInfo"
},
"title": "List of settlement chains with their last committed epochs"
},
"suggestedEpochInfo": {
"$ref": "#/definitions/ChainEpochInfo",
"title": "Suggested epoch info for signatures, it is the minimum commited epoch among all chains"
}
},
"title": "Response message for getting all last committed epochs"
},
"GetLastCommittedResponse": {
"type": "object",
"properties": {
"settlementChainId": {
"type": "string",
"format": "uint64",
"title": "Settlement chain ID"
},
"epochInfo": {
"$ref": "#/definitions/ChainEpochInfo"
}
},
"title": "Response message for getting last committed epoch"
},
"GetLocalValidatorResponse": {
"type": "object",
"properties": {
"validator": {
"$ref": "#/definitions/Validator",
"title": "The validator"
}
},
"title": "Response message for getting local validator"
},
"GetSignatureRequestIDsByEpochResponse": {
"type": "object",
"properties": {
"requestIds": {
"type": "array",
"items": {
"type": "string"
},
"title": "List of all signature request IDs for the epoch"
}
},
"title": "Response message for getting all signature request IDs by epoch"
},
"GetSignatureRequestResponse": {
"type": "object",
"properties": {
"signatureRequest": {
"$ref": "#/definitions/SignatureRequest"
}
},
"title": "Response message for getting signature request"
},
"GetSignatureRequestsByEpochResponse": {
"type": "object",
"properties": {
"signatureRequests": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/SignatureRequest"
},
"title": "List of all signature requests for the epoch"
}
},
"title": "Response message for getting all signature requests by epoch"
},
"GetSignaturesByEpochResponse": {
"type": "object",
"properties": {
"signatures": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/Signature"
},
"title": "List of signatures"
}
},
"title": "Response message for getting signatures by epoch"
},
"GetSignaturesResponse": {
"type": "object",
"properties": {
"signatures": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/Signature"
},
"title": "List of signatures"
}
},
"title": "Response message for getting signatures"
},
"GetValidatorByAddressResponse": {
"type": "object",
"properties": {
"validator": {
"$ref": "#/definitions/Validator",
"title": "The validator"
}
},
"title": "Response message for getting validator by address"
},
"GetValidatorByKeyResponse": {
"type": "object",
"properties": {
"validator": {
"$ref": "#/definitions/Validator",
"title": "The validator"
}
},
"title": "Response message for getting validator by key"
},
"GetValidatorSetHeaderResponse": {
"type": "object",
"properties": {
"version": {
"type": "integer",
"format": "int64",
"title": "Version of the validator set"
},
"requiredKeyTag": {
"type": "integer",
"format": "int64",
"title": "Key tag required to commit next validator set"
},
"epoch": {
"type": "string",
"format": "uint64",
"title": "Validator set epoch"
},
"captureTimestamp": {
"type": "string",
"format": "date-time",
"title": "Epoch capture timestamp"
},
"quorumThreshold": {
"type": "string",
"title": "Quorum threshold (big integer as string)"
},
"totalVotingPower": {
"type": "string",
"title": "Total voting power (big integer as string)"
},
"validatorsSszMroot": {
"type": "string",
"title": "Validators SSZ Merkle root (hex string)"
}
},
"title": "Response message for getting validator set header"
},
"GetValidatorSetMetadataResponse": {
"type": "object",
"properties": {
"extraData": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/ExtraData"
}
},
"commitmentData": {
"type": "string",
"format": "byte"
},
"requestId": {
"type": "string"
}
},
"title": "Response message for getting validator set header"
},
"GetValidatorSetResponse": {
"type": "object",
"properties": {
"validatorSet": {
"$ref": "#/definitions/ValidatorSet",
"title": "The validator set"
}
},
"title": "Response message for getting validator set"
},
"Key": {
"type": "object",
"properties": {
"tag": {
"type": "integer",
"format": "int64",
"title": "Key tag identifier (0-127)"
},
"payload": {
"type": "string",
"format": "byte",
"title": "Key payload"
}
},
"title": "Cryptographic key"
},
"ListenProofsResponse": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"title": "Id of the request"
},
"epoch": {
"type": "string",
"format": "uint64",
"title": "Epoch number"
},
"aggregationProof": {
"$ref": "#/definitions/AggregationProof",
"title": "Final aggregation proof"
}
},
"title": "Response message for aggregation proofs stream"
},
"ListenSignaturesResponse": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"title": "Id of the signature request"
},
"epoch": {
"type": "string",
"format": "uint64",
"title": "Epoch number"
},
"signature": {
"$ref": "#/definitions/Signature",
"title": "Signature data"
}
},
"title": "Response message for signatures stream"
},
"ListenValidatorSetResponse": {
"type": "object",
"properties": {
"validatorSet": {
"$ref": "#/definitions/ValidatorSet",
"title": "The validator set"
}
},
"title": "Response message for validator set changes stream"
},
"SignMessageRequest": {
"type": "object",
"properties": {
"keyTag": {
"type": "integer",
"format": "int64",
"title": "Key tag identifier (0-127)"
},
"message": {
"type": "string",
"format": "byte",
"title": "Message to be signed"
},
"requiredEpoch": {
"type": "string",
"format": "uint64",
"title": "Required epoch (optional, if not provided latest committed epoch will be used)"
}
},
"title": "Request message for signing a message"
},
"SignMessageResponse": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"title": "Hash of the signature request"
},
"epoch": {
"type": "string",
"format": "uint64",
"title": "Epoch number"
}
},
"title": "Response message for sign message request"
},
"Signature": {
"type": "object",
"properties": {
"signature": {
"type": "string",
"format": "byte",
"title": "Signature data"
},
"messageHash": {
"type": "string",
"format": "byte",
"title": "Message hash"
},
"publicKey": {
"type": "string",
"format": "byte",
"title": "Public key"
},
"requestId": {
"type": "string",
"title": "Request ID"
}
},
"title": "Digital signature"
},
"SignatureRequest": {
"type": "object",
"properties": {
"requestId": {
"type": "string",
"title": "Request ID"
},
"keyTag": {
"type": "integer",
"format": "int64",
"title": "Key tag identifier (0-127)"
},
"message": {
"type": "string",
"format": "byte",
"title": "Message to be signed"
},
"requiredEpoch": {
"type": "string",
"format": "uint64",
"title": "Required epoch"
}
},
"title": "SignatureRequest represents a signature request"
},
"Status": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/Any"
}
}
}
},
"Validator": {
"type": "object",
"properties": {
"operator": {
"type": "string",
"title": "Operator address (hex string)"
},
"votingPower": {
"type": "string",
"title": "Voting power of the validator (big integer as string)"
},
"isActive": {
"type": "boolean",
"title": "Indicates if the validator is active"
},
"keys": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/Key"
},
"title": "List of cryptographic keys"
},
"vaults": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/ValidatorVault"
},
"title": "List of validator vaults"
}
},
"title": "Validator information"
},
"ValidatorSet": {
"type": "object",
"properties": {
"version": {
"type": "integer",
"format": "int64",
"title": "Version of the validator set"
},
"requiredKeyTag": {
"type": "integer",
"format": "int64",
"title": "Key tag required to commit next validator set"
},
"epoch": {
"type": "string",
"format": "uint64",
"title": "Validator set epoch"
},
"captureTimestamp": {
"type": "string",
"format": "date-time",
"title": "Epoch capture timestamp"
},
"quorumThreshold": {
"type": "string",
"title": "Quorum threshold (big integer as string)"
},
"status": {
"$ref": "#/definitions/ValidatorSetStatus",
"title": "Status of validator set header"
},
"validators": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/Validator"
},
"title": "List of validators"
}
}
},
"ValidatorSetStatus": {
"type": "string",
"enum": [
"VALIDATOR_SET_STATUS_UNSPECIFIED",
"VALIDATOR_SET_STATUS_DERIVED",
"VALIDATOR_SET_STATUS_AGGREGATED",
"VALIDATOR_SET_STATUS_COMMITTED",
"VALIDATOR_SET_STATUS_MISSED"
],
"default": "VALIDATOR_SET_STATUS_UNSPECIFIED",
"description": "- VALIDATOR_SET_STATUS_UNSPECIFIED: Default/unknown status\n - VALIDATOR_SET_STATUS_DERIVED: Derived status\n - VALIDATOR_SET_STATUS_AGGREGATED: Aggregated status\n - VALIDATOR_SET_STATUS_COMMITTED: Committed status\n - VALIDATOR_SET_STATUS_MISSED: Missed status",
"title": "Validator set status enumeration"
},
"ValidatorVault": {
"type": "object",
"properties": {
"chainId": {
"type": "string",
"format": "uint64",
"title": "Chain identifier"
},
"vault": {
"type": "string",
"title": "Vault address"
},
"votingPower": {
"type": "string",
"title": "Voting power for this vault (big integer as string)"
}
},
"title": "Validator vault information"
}
}
}
````
## File: docs/api/v1/doc.md
````markdown
# Protocol Documentation
## Table of Contents
- [v1/api.proto](#v1_api-proto)
- [AggregationProof](#api-proto-v1-AggregationProof)
- [ChainEpochInfo](#api-proto-v1-ChainEpochInfo)
- [ExtraData](#api-proto-v1-ExtraData)
- [GetAggregationProofRequest](#api-proto-v1-GetAggregationProofRequest)
- [GetAggregationProofResponse](#api-proto-v1-GetAggregationProofResponse)
- [GetAggregationProofsByEpochRequest](#api-proto-v1-GetAggregationProofsByEpochRequest)
- [GetAggregationProofsByEpochResponse](#api-proto-v1-GetAggregationProofsByEpochResponse)
- [GetAggregationStatusRequest](#api-proto-v1-GetAggregationStatusRequest)
- [GetAggregationStatusResponse](#api-proto-v1-GetAggregationStatusResponse)
- [GetCurrentEpochRequest](#api-proto-v1-GetCurrentEpochRequest)
- [GetCurrentEpochResponse](#api-proto-v1-GetCurrentEpochResponse)
- [GetLastAllCommittedRequest](#api-proto-v1-GetLastAllCommittedRequest)
- [GetLastAllCommittedResponse](#api-proto-v1-GetLastAllCommittedResponse)
- [GetLastAllCommittedResponse.EpochInfosEntry](#api-proto-v1-GetLastAllCommittedResponse-EpochInfosEntry)
- [GetLastCommittedRequest](#api-proto-v1-GetLastCommittedRequest)
- [GetLastCommittedResponse](#api-proto-v1-GetLastCommittedResponse)
- [GetLocalValidatorRequest](#api-proto-v1-GetLocalValidatorRequest)
- [GetLocalValidatorResponse](#api-proto-v1-GetLocalValidatorResponse)
- [GetSignatureRequestIDsByEpochRequest](#api-proto-v1-GetSignatureRequestIDsByEpochRequest)
- [GetSignatureRequestIDsByEpochResponse](#api-proto-v1-GetSignatureRequestIDsByEpochResponse)
- [GetSignatureRequestRequest](#api-proto-v1-GetSignatureRequestRequest)
- [GetSignatureRequestResponse](#api-proto-v1-GetSignatureRequestResponse)
- [GetSignatureRequestsByEpochRequest](#api-proto-v1-GetSignatureRequestsByEpochRequest)
- [GetSignatureRequestsByEpochResponse](#api-proto-v1-GetSignatureRequestsByEpochResponse)
- [GetSignaturesByEpochRequest](#api-proto-v1-GetSignaturesByEpochRequest)
- [GetSignaturesByEpochResponse](#api-proto-v1-GetSignaturesByEpochResponse)
- [GetSignaturesRequest](#api-proto-v1-GetSignaturesRequest)
- [GetSignaturesResponse](#api-proto-v1-GetSignaturesResponse)
- [GetValidatorByAddressRequest](#api-proto-v1-GetValidatorByAddressRequest)
- [GetValidatorByAddressResponse](#api-proto-v1-GetValidatorByAddressResponse)
- [GetValidatorByKeyRequest](#api-proto-v1-GetValidatorByKeyRequest)
- [GetValidatorByKeyResponse](#api-proto-v1-GetValidatorByKeyResponse)
- [GetValidatorSetHeaderRequest](#api-proto-v1-GetValidatorSetHeaderRequest)
- [GetValidatorSetHeaderResponse](#api-proto-v1-GetValidatorSetHeaderResponse)
- [GetValidatorSetMetadataRequest](#api-proto-v1-GetValidatorSetMetadataRequest)
- [GetValidatorSetMetadataResponse](#api-proto-v1-GetValidatorSetMetadataResponse)
- [GetValidatorSetRequest](#api-proto-v1-GetValidatorSetRequest)
- [GetValidatorSetResponse](#api-proto-v1-GetValidatorSetResponse)
- [Key](#api-proto-v1-Key)
- [ListenProofsRequest](#api-proto-v1-ListenProofsRequest)
- [ListenProofsResponse](#api-proto-v1-ListenProofsResponse)
- [ListenSignaturesRequest](#api-proto-v1-ListenSignaturesRequest)
- [ListenSignaturesResponse](#api-proto-v1-ListenSignaturesResponse)
- [ListenValidatorSetRequest](#api-proto-v1-ListenValidatorSetRequest)
- [ListenValidatorSetResponse](#api-proto-v1-ListenValidatorSetResponse)
- [SignMessageRequest](#api-proto-v1-SignMessageRequest)
- [SignMessageResponse](#api-proto-v1-SignMessageResponse)
- [Signature](#api-proto-v1-Signature)
- [SignatureRequest](#api-proto-v1-SignatureRequest)
- [Validator](#api-proto-v1-Validator)
- [ValidatorSet](#api-proto-v1-ValidatorSet)
- [ValidatorVault](#api-proto-v1-ValidatorVault)
- [ErrorCode](#api-proto-v1-ErrorCode)
- [SigningStatus](#api-proto-v1-SigningStatus)
- [ValidatorSetStatus](#api-proto-v1-ValidatorSetStatus)
- [SymbioticAPIService](#api-proto-v1-SymbioticAPIService)
- [Scalar Value Types](#scalar-value-types)
Optional: start epoch. If provided, stream will first send all historical proofs starting from this epoch, then continue with real-time updates
If not provided, only proofs generated after stream creation will be sent
Optional: start epoch. If provided, stream will first send all historical signatures starting from this epoch, then continue with real-time updates
If not provided, only signatures generated after stream creation will be sent
Optional: start epoch. If provided, stream will first send all historical validator sets starting from this epoch, then continue with real-time updates
If not provided, only validator sets generated after stream creation will be sent