lido
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # VEBO Improvements ![vebo2](https://hackmd.io/_uploads/HkDlClzA6.jpg) ## 🎯 TL;DR It is proposed to modify the algorithm for exiting validators in the Validator Exit Bus Oracle (VEBO). From the staking modules' side, it is suggested to add the ability to signal VEBO about the need to exit validators from an operator regardless of the demand in the Withdrawal Queue (WQ). From the staking router's side, it is proposed to consider the module's share when prioritizing validators for exit. It is assumed that the reader is familiar with the current design of VEBO: - [https://docs.lido.fi/contracts/validators-exit-bus-oracle](https://docs.lido.fi/contracts/validators-exit-bus-oracle) - [https://docs.lido.fi/guides/oracle-spec/validator-exit-bus](https://docs.lido.fi/guides/oracle-spec/validator-exit-bus) ## 🌟 Motivation ### Boosted Exit Requests The current VEBO design assumes that validators can only be requested to exit if there are existing user withdrawal requests. While the protocol has tools to prioritize validator exit requests from specific operators, it does not have tools that allow the protocol to request an operator to exit validators regardless of the demand in WQ. Exit requests without taking into account user withdrawal requests is important for upcoming permisionless modules in order to signal VEBO about the need to exit validator when operator's bond decreases. It's also needed for offboarding of operators or reducing their share in the pool in a situation when there is insufficient user withdrawal requests. This motivates to consider adding a special mode to the protocol to exit validators from the operator without taking into account the demand in WQ. ### Target Share The current design of the staking router uses the `targetShare` parameter of each module when distributing stakes among them. However, this parameter is not considered in the algorithm for choosing which validators request to exit. This could lead to a situation where one of the modules reaches its target share, after which a large number of validators are exited from other modules, leading to an increase in the original module's share above the target share. Since a module's share can be chosen based on security considerations, it is proposed to consider a mechanism to take it into account not only during stake allocation, but also during validator requests to exit. ## 💅 Proposed Design ### Boosted Exit Requests The current VEBO design presupposes a request for validator exits only in the presence of user withdrawal requests in the WQ contract. Modules can signal VEBO about the priority of exiting validators from a particular node operator using the `targetLimit` mechanism. It is proposed to allow modules to signal VEBO about the necessity of sending a request to exit validators at a specific operator without being tied to demand in WQ. For this, it is suggested to modify the current `targetLimit` instrument by adding an additional boosted exit mode, namely, the parameter `bool isTargetLimitActive` is proposed to be replaced with `uint8 targetLimitMode` taking one of the following values: - `0` – Disabled - `1` – Limited stake, smooth exit mode - `2` – Limited stake, boosted exit mode Let's consider the target limit modes in more detail: **Disabled.** This mode implies no limitation. The operator is not restricted in receiving new stakes and does not have additional priorities when choosing validators for exit. **Smooth exit mode.** The operator has a limit on the number of active validators. As long as the number of active validators of the operator does not exceed the `targetLimit`, the operator receives stakes under general conditions. If this value is reached, the operator stops receiving new stakes (should be implemented at the module level). If the number of active keys of the operator exceeds the `targetLimit`, then such an operator's validators are prioritized for exit in the amount of targeted validators to exit. **Boosted exit mode.** Similar to smooth mode, but does not consider demand in WQ. The operator's validators in the amount of targeted validators to exit are prioritized for exit and requested without considering demand in WQ. Adding a new mode does not affect the overall limit on validator exits per report. If it is necessary to accelerated exit a large number of validators, this will be done over several reports. The proposed design suggests the following changes in the `IStakingModule` interface: ```solidity interface IStakingModule { function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( uint8 targetLimitMode, // former isTargetLimitActive uint256 targetValidatorsCount, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp, uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ); function updateTargetValidatorsLimits( uint256 _nodeOperatorId, uint8 _targetLimitMode, // former _isTargetLimitActive uint256 _targetLimit ) external; } ``` The change in the `updateTargetValidatorsLimits` method does not break backward compatibility with the EasyTrack factory `UpdateTargetValidatorLimits` which is used to set limits in the Simple DVT module. Nonetheless, it is proposed to update it, supporting changes in the `IStakingModule` interface. ```solidity interface IUpdateTargetValidatorLimits { struct TargetValidatorsLimit { uint256 nodeOperatorId; uint8 targetLimitMode; // former isTargetLimitActive uint256 targetLimit; } } ``` The change from `bool isTargetLimitActive` to `uint8 targetLimitMode` affects the response from the view method `getNodeOperatorSummary`, which may be used in external integrations and offchain tooling. Tests show that backward compatibility remains: [https://github.com/lidofinance/sr-1.5-compatibility-tests](https://github.com/lidofinance/sr-1.5-compatibility-tests). All modes other than disabled are interpreted by the decoder based on the old interface as the enabled `targetLimit` mode. Changes to the off-chain part are described in the [Exit Order](#Exit-Order) section. ### Target Share When validators are exited from one module, its share decreases, while the shares of other modules increase. This can lead to a situation where a module's share significantly exceeds its target share. <img src="https://hackmd.io/_uploads/Sy-UBFdC6.png" style="width:580px"/> The illustration shows the exit of validators from module `A`, leading to a redistribution of shares between modules: the share of module `A` decreases, while the share of module `B` increases. The most direct and simplest solution could be to consider the target share when prioritizing validators for exit. However, this solution has a problem – the protocol's TVL has some volatility, and operators in different modules have varying costs for rejoining validators. These differences can be expressed in the node operator itself (solo staker or large company), in the automation of processes, technology features (vanilla validator or DVT), etc. TVL volatility, combined with varying rejoining costs, leads to the problem that the protocol may periodically rotate validators in modules with high rejoining costs – requesting exits and then making deposits after some time. Given the described problem and the drawbacks of the direct solution, it is proposed to represent the target share of a module as a range of values: `stakeShareLimit` and `priorityExitShareThreshold`, where `stakeShareLimit <= priorityExitShareThreshold`. The lower value `stakeShareLimit` represents the maximum share that can be allocated to a module when distributing stakes among modules. This parameter is nothing other than the current `targetShare`. Nevertheless, it is suggested to rename it, as its current name does not fully reflect its essence. The higher value `priorityExitShareThreshold` represents the module's share threshold, upon crossing which, exits of validators from the module will be prioritized. <img src="https://hackmd.io/_uploads/Hk3NrFORa.png" style="width:580px"/> These two values allow the module to be in one of three states at any given time: #### <span style="color:#00A3FF">Module has not reached share limit</span> `currentShare < stakeShareLimit`. The proposed design makes no changes for this state. Everything remains as it is: - The staking router **prioritizes stake allocation** to modules in this state - Validators in a module with this state **do not have any extra priority for exit** #### <span style="color:#36E6A6">Module has reached stake share limit</span> `stakeShareLimit <= currentShare <= priorityExitShareThreshold`. The proposed design makes no changes for this state. Everything remains as it is: - The staking router **does not allocate stake** to modules in this state - Validators in a module with this state **do not have any extra priority for exit** #### <span style="color:#FF8E76">Module exceeds priority exit threshold</span> `priorityExitShareThreshold < currentShare`. It is the state that is affected by the proposed changes. - The staking router **does not allocate stake** to modules in this state - Validators in a module with this state have an **increased exit priority** The proposed design suggests the following changes in the Staking Router contract interface: ```solidity interface IStakingRouter { struct StakingModule { uint24 id; address stakingModuleAddress; uint16 stakingModuleFee; uint16 treasuryFee; uint16 stakeShareLimit; // rename targetShare parameter uint8 status; string name; uint64 lastDepositAt; uint256 lastDepositBlock; uint256 exitedValidatorsCount; uint16 priorityExitShareThreshold; // new parameter } event StakingModuleStakeShareLimitSet(uint256 indexed stakingModuleId, uint256 stakeShareLimit, address setBy); event StakingModulePriorityExitShareThresholdSet(uint256 indexed stakingModuleId, uint256 priorityExitShareThreshold, address setBy); function updateStakingModule( uint256 _stakingModuleId, uint256 _stakeShareLimit, // rename _targetShare argument uint256 _priorityExitShareThreshold, // new argument uint256 _stakingModuleFee, uint256 _treasuryFee ) external; function addStakingModule( string calldata _name, address _stakingModuleAddress, uint256 _stakeShareLimit, // rename _targetShare argument uint256 _priorityExitShareThreshold, // new argument uint256 _stakingModuleFee, uint256 _treasuryFee ) external; } ``` :::spoiler Backward compatibility <br> The change to the `StakingModule` struct affects the response from some view methods, which may be used in external integrations and offchain tooling: - getStakingModule - getStakingModules - getStakingModuleDigests - getAllStakingModuleDigests Tests show that backward compatibility remains for both offchain tools and possible onchain integrations: [https://github.com/lidofinance/sr-1.5-compatibility-tests](https://github.com/lidofinance/sr-1.5-compatibility-tests). The modified response is correctly decoded using standard Solidity tools and the ethers library. New bytes in the response are ignored. ::: Changes to the off-chain part are described in the [Exit Order](#Exit-Order) section. ### Exit Order It is proposed to implement two stages of selecting validators for exit: 1. Covering Demand in WQ 2. Boosted Exits #### Stage 1. Covering Demand in WQ This stage is from the current design of VEBO. To determine which validators to request for exit, the Offchain Oracle selects one entry from the sorted list of exitable Lido validators until the demand in WQ is covered by the exiting validators and future rewards, or until the limit per report is reached. Validators are sorted by predicates in the following sequence: 1. Validator whose operator with the lowest number of delayed validators 2. _Validator whose operator with the highest number of targeted validators to boosted exit_ 3. _Validator whose operator with the highest number of targeted validators to smooth exit_ 4. _Validator whose module with the highest deviation from the module share_ 5. Validator whose operator with the highest stake weight 6. Validator whose operator with the highest number of validators 7. Validator with the lowest index The proposed changes affect predicates 2, 3 and 4 (italicized), the others remain unchanged. Let's examine the changing predicates in detail: **Boosted target limit predicate.** If `targetLimitMode` is set to boosted exits, the result will be the number of targeted validators to exit; in other cases, the predicate returns 0. The higher the return value, the higher the priority of the validator to exit. ```python def predicate_boosted_target_limit(): if operator.target_limit_mode == TARGET_LIMIT_MODE.BOOSTED_EXITS: return max(operator.predictable_validators_count - operator.target_limit, 0) return 0 ``` **Smooth target limit predicate.** If `targetLimitMode` is set to smooth limit, the result will be the number of targeted validators to exit; in other cases, the predicate returns 0. The higher the return value, the higher the priority of the validator to exit. ```python def predicate_smooth_target_limit(): if operator.target_limit_mode == TARGET_LIMIT_MODE.SMOOTH_EXITS: return max(operator.predictable_validators_count - operator.target_limit, 0) return 0 ``` **Module share predicate.** The predicate prioritizes the exit of validators from modules where there are more validators than the exit threshold. The higher the number of predicted validators over the exit threshold assigned to a module, the more prioritized the validators in that module are for exit. Predicted validators represent the number of active validators that will be in the module after all effects are applied: all requested validators are exited, deposits that were made recently turned into active validators. ```python def predicate_module_share(): module_max_validators = total_validators * priority_exit_share_threshold if module_predicted_validators > module_max_validators: # the higher is the number of validators in the module over the exit threshold, the higher is the exit priority return module_max_validators - module_predicted_validators return 0 ``` After each iteration of selecting a validator, the state of operators and validators mutates – validators previously sent for exit are marked, after which the array of validators is resorted. After the stage ends, the state is passed to the next stage – Boosted Exits, thus validators requested at an earlier stage are considered in the subsequent one. :::info - The target limit predicate is now split into two: boosted and smooth - Validators of operators with `targetLimitMode` set to boosted exits have a higher priority for exit than operators with the mode set to smooth limit - The new module share predicate prioritizes exits from modules that have more validators than the exit threshold allows ::: #### Stage 2. Boosted Exits The second stage presupposes the exit of validators requiring exit regardless of the demand in WQ. The state of operators and validators after the first step is filtered, leaving only validators of operators having `targetLimitMode` set to boosted exits. Validators are sorted by the number of targeted validators to exit. After each iteration of selecting a validator, the state of operators and validators mutates – validators previously sent for exit are marked, after which the array of validators is resorted. The selection of validators continues as long as there are elements in the array or until the total number of exiting operators per report reach the limit. There is only one sorting predicate on this stage: 1. _Validator whose operator with the highest number of targeted validators to boosted exit_ 2. _Validator with the lowest index_ Let's consider various examples below. <span style="color:#FF8E76">Coral color</span> indicates validators requested due to the enabled boosted target limit of the operator, <span style="color:#B8B8B8">grey color</span> indicates validators requested in general order. <img src="https://hackmd.io/_uploads/BkkztYuRT.png" style="width:580px;margin-top:24px;margin-bottom:12px"/> In the example above, only the first stage of the algorithm works. Demand in WQ is partially covered by <span style="color:#FF8E76">boosted exits</span> and partially by <span style="color:#B8B8B8">other validators in general order</span>. The second stage returns 0 validators to exit because all validators of operators in boosted exit status have already been requested by this time. <img src="https://hackmd.io/_uploads/ry-etKuC6.png" style="width:580px;margin-top:24px;margin-bottom:12px"/> In the example above, both stages of the algorithm work. Demand in WQ is fully covered by <span style="color:#FF8E76">boosted exits</span>, after which the second stage of the algorithm continues to <span style="color:#FF8E76">exit validators</span> until the targeted validators to boosted exit equals 0. <img src="https://hackmd.io/_uploads/HkAsuKOR6.png" style="width:580px;margin-top:24px;margin-bottom:12px"/> In the example above, the operator with the boosted exits mode enabled has delayed validators. As a result, the protocol switched to exiting <span style="color:#B8B8B8">validators from other operators</span> to cover the demand in WQ. After covering the demand, the second stage of the algorithm requested the next <span style="color:#FF8E76">validators to exit</span> from the operator with the boosted exits mode enabled. :::info - The predicate uses the state from the previous stage to ensure that all previously requested validators are accounted for - The selection of validators occurs only from among targeted validators to boosted exit - If an operator with the boosted exits mode enabled delays the exit, the demand in WQ will be covered by other operators ::: ## 🙈 Out of Scope ### Exit Specific Validators The current solution does not cover the scenario of requesting the exit of specific validators of an operator. Validators are requested in the sequence from the smaller index to the larger index, i.e. in the order in which they were deposited. However, there may be a situation in which it is necessary to request validators to be exited out of the order in which they were deposited, for example if the validator's private key has been lost or the DAO suspects that the validator's private key may have been compromised. The exit of specific validators is addressed in another research and is covered by the Priority Exit Bus (PEB) functionality, which allows requesting validators to exit in priority order and without respect to demand in the WQ. ## 💖 Acknowledgements The document is partially based on the works of Raman S and KRogLA: - [Forced Target Limits](https://hackmd.io/@lido/HyOsz8Oap) - [VEBO modify exit order](https://hackmd.io/@F4ever/rkTV5g3Fa)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully