From f99b374677af75355cb8f25b355a567ac3dd7adb Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 31 Jul 2024 00:15:36 +0400 Subject: [PATCH 1/2] specs --- specs/Collateral.md | 12 +++-- specs/Network.md | 45 ++++++++++++++++- specs/Operator.md | 10 +++- specs/Resolver.md | 2 +- specs/Vault.md | 116 +++++++++++++++++++++++++++++++++----------- 5 files changed, 150 insertions(+), 35 deletions(-) diff --git a/specs/Collateral.md b/specs/Collateral.md index f3e0f490..3cd61e3b 100644 --- a/specs/Collateral.md +++ b/specs/Collateral.md @@ -1,10 +1,16 @@ ## Collateral -### General Overview +Collateral is a concept introduced by Symbiotic that brings capital efficiency and scale by enabling assets used to secure Symbiotic networks to be held outside of the Symbiotic protocol itself - e.g. in DeFi positions on networks other than Ethereum itself. -Any operator wishing to operate in a Proof of Stake (POS) system must have a stake. This stake must be locked in some manner, somewhere. There are solutions that make such a stake liquid, yet the original funds remain locked, and in exchange, depositors/delegators receive LST tokens. They can then operate with these LST tokens. The reasons for locking the original funds include the need for immediate slashing if an operator misbehaves. This requirement for instant action necessitates having the stake locked, a limitation imposed by the current design of POS systems. +Symbiotic achieves this by separating the ability to slash assets from the underlying asset itself, similar to how liquid staking tokens create tokenized representations of underlying staked positions. Technically, collateral positions in Symbiotic are ERC-20 tokens with extended functionality to handle slashing incidents if applicable. In other words, if the collateral token aims to support slashing, it should be possible to create a `Burner` responsible for proper burning of the asset. -Collateral introduces a new type of asset that allows stakeholders to hold onto their funds and earn yield from them without needing to lock these funds in direct manner or convert them to another type of asset. Collateral represents an asset but does not require physically holding or locking this asset. The securities backing the Collateral can be in various forms, such as a liquidity pool position, some real-world asset, or generally any type of asset. Depending on the implementation of Collateral, this securing asset can be held within the Collateral itself or elsewhere. +For example, if asset is ETH LST it can be used as a collateral if it's possible to create `Burner` contract that withdraw ETH from beaconchain and burn it, if asset is native e.g. governance token it also can be used as collateral since burner might be implemented as "black-hole" contract or address. + +Symbiotic allows collateral tokens to be deposited into vaults, which delegate collateral to operators across Symbiotic networks. Vaults define acceptable collateral and it's `Burner` _(if vault supports slashing)_ and networks need to accept these and other vault terms such as slashing limits to receive rewards _(these processes are described in detail in Vault section)_. + +--- + +We do not specify the exact implementation of the Collateral, however, it must satisfy all the following requirement: - Collateral token must support ERC-20 interface - [**OPTIONAL**] Collateral token should be slashable i.e. native token or derivative that supports redeeming the underlying native token. _(Only if collateral is used in slashable vaults)_. diff --git a/specs/Network.md b/specs/Network.md index ef9ef6d7..7d922298 100644 --- a/specs/Network.md +++ b/specs/Network.md @@ -1,13 +1,54 @@ ## 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. +In Symbiotic, networks are represented through a network address (either an EOA or a contract) and a middleware contract, which can incorporate custom logic and is required to include slashing logic. The core protocol's fundamental functionalities encompass slashing operators and rewarding both stakers and operators. --- -Networks are represented through a network address (either an EOA or a contract) and a middleware contract, which can incorporate custom logic and is required to include slashing logic. +A network epoch (let's name it $\text{NETWORK\_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). --- +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 slasher module is $S$. + +Given the current $\text{active}$ balance of the vault and the limits, we can **capture the stake for the subsequent network epoch**: + +$networkOperatorStake = D.stake(network, operator)$ + +--- + +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. + +--- + +The network has the flexibility to configure the operator set within the middleware or network contract. + +The following functions could be useful: + +- `D.stakeAt(network, 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. +- `OperatorOptInService.isOptedInAt(operator, network, timestamp, hint)`: Checks the opt-in status. + +--- + +For each operator, the network can obtain its stake which will be valid during $d = vaultEpoch$. It can slash the whole stake of the operator. Note, that the stake itself is given according to the limits and other conditions. + +Note that **the actual slashed amount may be less than the requested one**. This is influenced by the cross-slashing or veto process of the Slasher module. + +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(network, operator, amount, captureTimestamp, hints)` for the Slasher module. +2. `requestSlash(network, 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 \leq G$. The module will allow slashing no more than $G - C$ to justify the given guarantees. + ### Deploy ```shell diff --git a/specs/Operator.md b/specs/Operator.md index f9af4d86..7945f224 100644 --- a/specs/Operator.md +++ b/specs/Operator.md @@ -12,11 +12,17 @@ In Symbiotic, the operator can be either an EOA or a contract registered in the --- -The operator opts into the network to join it. Each network independently decides whether to include the operator in its active operator set based on various factors, such as reputation, stake amount, and other relevant criteria. +Let the vault be $V$, the delegator module of the vault is $D$ and slasher module is $S$. + +To raise the stake, the operator must opt into networks and vaults by calling the `optIn()` method in the `OperatorNetworkOptInService` and `OperatorVaultOptInService` accordingly. The `OPERATOR_NETWORK_LIMIT_SET_ROLE` then allocates the stake to the operator by calling `D.setOperatorNetworkLimit()`. + +--- + +The operator opts into the network to validate it. Based on various factors, such as reputation, stake amount, and other relevant criteria each network independently decides whether to include the operator in the active operator set or not. --- -The entire amount of stake is subject to slashing. The operator's stake becomes active and subject to slashing after the conclusion of the vault's epoch that follows the opt-in processes to both the network and the vault. +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 $S$ module. ### Deploy diff --git a/specs/Resolver.md b/specs/Resolver.md index f5856dbd..8f0ffb42 100644 --- a/specs/Resolver.md +++ b/specs/Resolver.md @@ -4,4 +4,4 @@ Symbiotic supports various modes of handling slashing incidents through the intr --- -A resolver is an address that can veto a particular slashing request in the vault. It listens to the slashing requests and when it finds the request it has some time to veto the request or agree with the slashing. Note, that a resolver does not veto the request, such a request will be considered approved for slashing by the resolver. Each slashing request has its own veto deadline defined by the vault. +A resolver is an address that can veto a particular slashing request in the slasher module of the vault. It listens to the slashing requests and when it finds the request it has some time to veto the request or agree with the slashing. Note, that if a resolver does not veto the request, such a request will be considered approved for slashing by the resolver. Each slashing request has its own veto deadline defined by the vault. diff --git a/specs/Vault.md b/specs/Vault.md index 7c4f1cd8..5f6ece11 100644 --- a/specs/Vault.md +++ b/specs/Vault.md @@ -14,7 +14,36 @@ Vaults are configurable and can be deployed in an immutable, pre-configured 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 `ICollateral` interface](../src/interfaces/base/ICollateral.sol). 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. +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: + +1. Accounting +2. Slashing logic +3. 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. + +1. The operator must be opted into the vault. +2. 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: + +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 until the end of the next epoch, so it can use this state at least for one epoch. +3. 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. --- @@ -28,12 +57,12 @@ The size of the epoch is not specified. However, all the epochs are consecutive #### Constraints -- $`\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 +- $\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: 1. $\text{active} \rightarrow \text{active} - \text{amount}$ - 2. $`\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} + \text{amount}`$ + 2. $\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} + \text{amount}$ - During deposit: @@ -43,8 +72,8 @@ The size of the epoch is not specified. However, all the epochs are consecutive 1. $\text{q} = \text{1} - \frac{\text{amount}}{\text{totalSupply}}$ 2. $\text{active} \rightarrow \text{active} \cdot \text{q}$ - 3. $`\text{W}_\text{epoch} \rightarrow \text{W}_\text{epoch} \cdot \text{q}`$ - 4. $`\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} \cdot \text{q}`$ + 3. $\text{W}_\text{epoch} \rightarrow \text{W}_\text{epoch} \cdot \text{q}$ + 4. $\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 @@ -62,45 +91,78 @@ Consider the user **requests** the withdrawal at $\text{epoch}$. The user can ** --- -Each slashing incident consists of 3 separate actions: +In the Symbiotic protocol, a slasher module is optional. However, the text below describes the core principles when the vault has a slasher module. -1. Request slash - `requestSlash()` -2. Veto slash - `vetoSlash()` (optional) -3. Execute slash - `executeSlash()` +Consider the network captures the stake of the operator at moment $t$. To do so, it calls the $stakeAt $ function with a given network, operator, and $timestamp$ (moment of capturing guarantees). Let $S$ be the resulting stake. This value is valid for $d$ = EPOCH_SIZE time. From this point, the pair $(S, t)$ is a guarantee given by the vault to the network. The guarantee is valid from the $timestamp $ moment to $timestamp + d$. -The network's middleware calls the `requestSlash()` method with a given `operator`, `resolver`, and `amount`. In return, it receives the `requestIndex` of the slashing. The slashing is **not applied instantly**. +Essentially, slashing is the enforcement of the guarantees described above. Currently, there are two types of slashing: instant and veto-slashing. -- The slashing **can be vetoed during the veto phase** by the `resolver`, and such a slashing will not be executed. -- If the veto phase is passed and the slashing is not vetoed, it can be executed via the `executeSlash()` method. Anyone can call this method after the veto phase has passed. -- Important to note that each slashing has an `executeDeadline`. If the slashing was not executed before `executeDeadline` it can't be executed anymore. +#### Instant slashing -Each slashing **reduces the limits** of the slashed operator and the network requested to slash. After the slashing all the user's funds are decreased **proportionally**. +Instant slashing is executed immediately when a request comes in. ---- +#### Veto slashing -An operator-network limit is the maximum amount of funds the network can slash if it requests a slashing of the given operator. In other words, it means the maximum operator's stake in the network. +Veto slashing consists of two stages: the Veto Phase and the Execute Phase. -If such a **slashing request is executed** the operator-network **limit will be decreased** by the slashed amount. Deposits and withdrawals do not affect the limit. However, the `OPERATOR_NETWORK_LIMIT_SET_ROLE` holder can change it (decrease or increase) manually according to the $\text{totalSupply}$ of the vault and the current limits. +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. --- -A network-resolver limit is the maximum amount of funds the network can slash if it requests a slashing with the given resolver. In other words, it means the maximum stake delegated to the network using a certain resolver. +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: -In general, its logic is the same as for the operator-network limit. However, the `NETWORK_RESOLVER_LIMIT_SET_ROLE` holder can change it, and it can be accessed via the `networkResolverLimit()` method. +1. FullRestakeDelegator +2. NetworkRestakeDelegator -Also, each network-resolver pair has its **_max network-resolver limit_** (which is set by the network) that defines the maximum value of the network-resolver limit that can be set. It serves as a **cap of funds the network wishes to secure itself with**. It can be accessed via the `maxNetworkResolverLimit()` function. +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: -A decrease in the limits produced by the appropriate role holder is not applied instantly but when the $\text{epoch + 1}$ ends (considering that it is an $\text{epoch}$ at the moment). However, an increase in the limits is an instant action. +1. Maintaining a safe re-staking ratio. +2. Choosing the right stake-capturing ratio to minimize reaction time. -When the network $\text{N}$ attempts to slash the given operator $\text{Op}$ with the given resolver $\text{R}$, the maximum amount of funds it can slash is the following: +Here we describe common technical information for both modules. -$$ -\text{slashableAmount} = \min (\text{totalSupply}, \min (\text{networkResolverLimit}(\text{N}, \text{R}), \text{operatorNetworkLimit}(\text{Op}, \text{N}))) -$$ +Let $NL_{j}$ be the limit of the $j^{th}$ network. This limit can be considered as the network's stake, meaning the amount of funds delegated to the network. $NL_{j}$ is set by a special role in the delegator module. However, the module normalizes it. Let the vault’s active supply be $AS$. ---- +Then $NS_{j} = \min(NL_{j}, AS)$ - network stake. + +Additionally, the modules have a max network limit $mNL_{j}$, which is set by the networks themselves. This serves as the maximum possible amount of funds that can be delegated to the network. It is guaranteed that $NL_{j} \leq mNL_{j}$. This limit is mainly used by networks to manage a safe restaking ratio. + +If the $i^{th}$ operator is slashed by $x$ in the $j^{th}$ network his stake can be decreased: + +$NL_{j}(new) = NL_{j} - x$ + +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. + +#### NetworkRestakeDelegator + +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 $i^{th}$ operator’s share in the $j^{th}$ network be $\lambda_{i, j}$. + +Then + +1. $\lambda_{i, j} \cdot NS_{j}$ - the $i^{th}$ operator’s stake in the $j^{th}$ network +2. $\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 $TS$ of the vault will decrease after slashing, which can cause other $NS_{j'}$ for $j' \neq j$ to decrease. + +#### FullRestakeDelegator + +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 $i^{th}$ operator’s limit in the $j^{th}$ network be $OpL_{i, j}$. Such a limit is considered as a stake of the operators. + +$OpS_{i, j} = min(OpL_{i, j}, NS_j)$ - the $i^{th}$ operator’s stake in the $j^{th}$ network + +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. ### Deploy From 213300cd4425de68999385141346353872f60655 Mon Sep 17 00:00:00 2001 From: Kresh Date: Wed, 31 Jul 2024 00:23:17 +0400 Subject: [PATCH 2/2] fix formulas --- specs/Network.md | 2 +- specs/Vault.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/Network.md b/specs/Network.md index 7d922298..db55da1d 100644 --- a/specs/Network.md +++ b/specs/Network.md @@ -4,7 +4,7 @@ In Symbiotic, networks are represented through a network address (either an EOA --- -A network epoch (let's name it $\text{NETWORK\_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). +A network epoch (let's name it $`\text{NETWORK\_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). --- diff --git a/specs/Vault.md b/specs/Vault.md index 5f6ece11..ed86bab1 100644 --- a/specs/Vault.md +++ b/specs/Vault.md @@ -57,12 +57,12 @@ The size of the epoch is not specified. However, all the epochs are consecutive #### Constraints -- $\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 +- $`\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: 1. $\text{active} \rightarrow \text{active} - \text{amount}$ - 2. $\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} + \text{amount}$ + 2. $`\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} + \text{amount}`$ - During deposit: @@ -72,8 +72,8 @@ The size of the epoch is not specified. However, all the epochs are consecutive 1. $\text{q} = \text{1} - \frac{\text{amount}}{\text{totalSupply}}$ 2. $\text{active} \rightarrow \text{active} \cdot \text{q}$ - 3. $\text{W}_\text{epoch} \rightarrow \text{W}_\text{epoch} \cdot \text{q}$ - 4. $\text{W}_\text{epoch + 1} \rightarrow \text{W}_\text{epoch + 1} \cdot \text{q}$ + 3. $`\text{W}_\text{epoch} \rightarrow \text{W}_\text{epoch} \cdot \text{q}`$ + 4. $`\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