Vaults are the delegation and restaking management layer of Symbiotic. They handle three crucial parts of the Symbiotic economy:
- Accounting: vaults handle deposits, withdrawals, and slashings of collaterals and in turn their underlying assets.
- Delegation Strategies: vault deployers/owners define delegation and restaking strategies to operators across Symbiotic networks, which networks have to opt into.
- Reward Distribution: vaults distribute staking rewards from networks to collateral depositors.
Vaults are configurable and can be deployed in an immutable, pre-configured way, or specifying an owner that is able to update vault parameters. Vaults are expected to be used by operators and curators such as crypto institutions or liquid (re)staking protocols to create differentiated products, e.g.:
- Operator-Specific Vaults: operators may create vaults with collateral restaked to their infrastructure across any configuration of networks. An operator can create multiple vaults with differing configurations to service their clients without requiring additional node infrastructure.
- Curated Multi-Operator Vaults: curated configurations of restaked networks and delegation strategies to a diversified set of operators. Curated vaults can additionally set custom slashing limits to cap the collateral amount that can be slashed for specific operators or networks. The terms of these commitments need to be accepted by networks that vaults seek to provide their curation for.
- Immutable Pre-Configured Vaults: vaults can be deployed with pre-configured rules that cannot be updated to provide extra protection for users that are not comfortable with risks associated with their vault curator being able to add additional restaked networks or change configurations in any other way.
Each vault has a predefined collateral token. The address of this token can be obtained via the collateral()
method of the vault. The collateral token must satisfy the IERC20
interface. All the operations and accounting within the vault are performed only with the collateral token. However, the rewards within the vault can be in different tokens. All the funds are represented in shares internally but the external interaction is done in absolute amounts of funds.
The Vault contract consists of three modules:
- Accounting
- Slashing logic
- Limits and delegation logic
Accounting is performed within the vault itself. Slashing logic is handled by the Slasher module. One important aspect not yet mentioned is the validation of slashing requirements.
When a slashing request is sent, the system verifies its validity. Specifically, it checks that the operator is opted into the vault, and is interacting with the network.
We use separate OptIn service contracts to connect vaults, operators, and networks.
- The operator must be opted into the vault.
- The operator must be opted into the network.
These connections are made using OptIn service contracts.
If all opt-ins are confirmed, the operator is considered to be working with the network through the vault as a stake provider. Only then can the operator be slashed.
To get guarantees, the network calls the Delegator module. In case of slashing, it calls the Slasher module, which will then call the Vault and the Delegator module. This module also checks the provided guarantees as well as the slashed amount of funds to ensure it does not exceed the guaranteed amount.
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:
- 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).
- After this, the network will have slashing guarantees until the end of the next epoch, so it can use this state at least for one epoch.
- When the epoch finishes and a slashing incident has taken place, the network will have time not less than a single epoch to request-veto-execute slash and go back to step 1 in parallel.
The size of the epoch is not specified. However, all the epochs are consecutive and have an equal constant, defined at the moment of deployment size. Next in the text, we refer to it as
-
$\text{active}$ balance - a pure balance of the vault/user that is not in the withdrawal process -
$\text{epoch}$ - a current epoch -
$\text{W}_\text{epoch}$ - withdrawals that will be claimable in the$\text{epoch + 1}$
-
$\text{totalSupply} = \text{active} + \text{W}_\text{epoch} + \text{W}_\text{epoch + 1}$ - a total amount of the collateral that can be slashed at the moment -
During withdrawal:
$\text{active} \rightarrow \text{active} - \text{amount}$ $\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} + \text{amount}$
-
During deposit:
$\text{active} \rightarrow \text{active} + \text{amount}$
-
During slashing:
$\text{q} = \text{1} - \frac{\text{amount}}{\text{totalSupply}}$ $\text{active} \rightarrow \text{active} \cdot \text{q}$ $\text{W}_\text{epoch} \rightarrow \text{W}_\text{epoch} \cdot \text{q}$ $\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} \cdot \text{q}$
-
$\forall \text{k} > \text{0}, \text{W}_\text{epoch - k}$ - claimable -
$\forall \text{k} \ge \text{0}, \text{W}_\text{epoch + k}$ - slashable and not claimable
Any holder of the collateral token can deposit it into the vault using the deposit()
method of the vault. In turn, the user receives shares. Any deposit instantly increases the
Any depositor can withdraw his funds using the withdraw()
method of the vault. The withdrawal process consists of two parts: a request and a claim.
Consider the user requests the withdrawal at
In the Symbiotic protocol, a slasher module is optional. However, the text below describes the core principles when the vault has a slasher module.
Consider the network captures the stake of the operator at moment
Essentially, slashing is the enforcement of the guarantees described above. Currently, there are two types of slashing: instant and veto-slashing.
Instant slashing is executed immediately when a request comes in.
Veto slashing consists of two stages: the Veto Phase and the Execute Phase.
After submitting a slashing request, there is a period of V time to issue a veto on the slashing. The veto can be made by designated participants in the vault, known as resolvers. If the slashing is not resolved after this phase, there is a period of E time to execute the slashing. Any participant can execute it. The network must consider how much time is left until the end of the guarantee before sending the slashing request.
Delegator is a separate module that connects to the Vault. The purpose of this module is to set limits for operators and networks, with the limits representing the operators' stake and the networks' stake. Currently, there are two types of delegators implemented:
- FullRestakeDelegator
- NetworkRestakeDelegator
Symbiotic is a restaking protocol, and these modules differ in how the restaking process is carried out. The modules will be described further:
There are obvious re-staking trade-offs with cross-slashing when stake can be reduced asynchronously. Networks should manage these risks by:
- Maintaining a safe re-staking ratio.
- Choosing the right stake-capturing ratio to minimize reaction time.
Here we describe common technical information for both modules.
Let
Then
Additionally, the modules have a max network limit
If the
Also, it should be mentioned that in the case of slashing, these modules have special hooks that call the method to process the change of limits. In general, we don't need such a method to exist because all the limits can be changed manually and instantly w/o changing already given guarantees.
The main goal of this delegator is to allow restaking between multiple networks but restrict operators from being restaked within the same network. The operators' stakes are represented as shares in the network's stake.
Each network's stakes are divided across operators.
Let the
Then
-
$\lambda_{i, j} \cdot NS_{j}$ - the$i^{th}$ operator’s stake in the$j^{th}$ network $\sum_{i}\lambda_{i, j} \cdot NS_{j} = NS_{j}$
We can conclude that slashing decreases the share of a specific operator and does not affect other operators in the same network. However, the
This module performs restaking for both operators and networks simultaneously. The stake in the vault is shared between operators and networks. The designated role can change these stakes. If a network slashes an operator, it may cause a decrease in the stake of other restaked operators even in the same network. However, it depends on the distribution of the stakes in the module.
In this module, we introduce so-called limits for operators. Each operator has its own limit in every network.
Let the
As already stated, this module enables restaking for operators. This means the sum of operators' stakes in the network can exceed the network’s own stake. This module is useful when operators have an insurance fund for slashing and are curated by a trusted party.
Such a slashing can lead to a situation where all the other operators' stakes will decrease.
source .env
Deployment script: click
forge script script/deploy/VaultFactory.s.sol:VaultFactoryScript 0x0000000000000000000000000000000000000000 --sig "run(address)" --broadcast --rpc-url=$ETH_RPC_URL
Common Vault
Deployment script: click
forge script script/deploy/Vault.s.sol:VaultScript 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 1 false 0 0 0x0000000000000000000000000000000000000000 false 0 0 --sig "run(address,address,address,address,uint48,bool,uint256,uint64,address,bool,uint64,uint48)" --broadcast --rpc-url=$ETH_RPC_URL
Tokenized Vault
Deployment script: click
forge script script/deploy/VaultTokenized.s.sol:VaultTokenizedScript 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 1 false 0 Test TEST 0 0x0000000000000000000000000000000000000000 false 0 0 --sig "run(address,address,address,address,uint48,bool,uint256,string,string,uint64,address,bool,uint64,uint48)" --broadcast --rpc-url=$ETH_RPC_URL