# Symbiotic Symbiotic is a collateral markets platform that brings enforceable economic guarantees onchain. # Connecting capital to onchain applications Symbiotic is a collateral markets platform that brings enforceable economic guarantees onchain. It connects capital to financial applications where collateral is committed to back obligations for defined periods, ensuring it cannot exit before those obligations are fulfilled. By turning collateral into programmable infrastructure, Symbiotic enables protocols to access reliable, stake-backed guarantees without relying on participant discretion.
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. # **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. # **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. # **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). # Overview Symbiotic Liquid Lane enables **redemptions** for otherwise illiquid or time-locked assets by sourcing liquidity from **curator-managed Symbiotic vaults**. Symbiotic’s collateral management infrastructure facilitates market makers to use vault liquidity for the sole purpose of quoting, filling, and natively processing redemptions via an **onchain RFQ workflow**. Vault LPs underwriting this product stand to earn the spread from these redemption flows while continuing to receive base yield on idle funds through DeFi adapters such as Morpho, as well as additional yield from exposure to Symbiotic applications. Liquid Lane is designed for RWAs and crypto derivative assets (e.g. Liquid Staking Tokens, Vault receipt tokens) where primary liquidity is episodic or constrained (e.g. withdrawal queues, redemption windows, vault lockups), and where market makers can price duration in exchange for composable yield for vault depositors supplying short-term liquidity.  ## About Symbiotic V2 Symbiotic is a modular collateral and yield infrastructure that lets institutions and applications deploy, manage, and route productive assets across onchain market structures. Backed by Pantera and Paradigm, Symbiotic is built to make collateral *programmable*: vaults, curators, and adapters can be composed to create market-specific risk and yield profiles. Liquid Lane is one example of this broader “Collateral Markets” strategy, following the successful collaboration with Cap, where Symbiotic powers >\$250m of collateral underwriting borrowers like Susquehanna, M11 Credit, and others. It uses curator-managed, yield-generating vault collateral to underwrite redemption flows for assets whose native liquidity is episodic or time-locked, turning productive collateral into reliable, onchain liquidity while preserving base yield and risk controls. ## Key Facts | | | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Capital Usage** | LP capital sits in curator-managed vaults earning base yield from lending markets (and/or delegating to Symbiotic networks) and is deployed when market makers draw liquidity to fill redemptions. | | **Vault LP Yield** | Yield generated from market maker usage of vault liquidity (fees/spread share), driven by redemption demand (early exits and liquidations) + base yield from DeFi lending and Symbiotic networks. | | **Typical Duration** | Vaults on average have a 14 day lockup period, but a curator may still service liquidity for an RWA redemption that exceeds this window. It is up to curators to manage this based on their different liquidity and risk management practices. | | **Eligible Collateral** | USDC (Cohort 0) + wETH & wBTC/cbBTC & other stablecoins (Cohort 1 onwards) | | **Risks** | • Product-related risks (duration, liquidity, operational)