Lido explained, Part 3 : Deposit & Oracles

24 May, 2024
article image
Case Study

Contents

Introduction

So, we’ve arrived at the final, third part of our article series dedicated to the Lido protocol, its history, and how it works from a technical perspective.

In the previous two parts, we’ve already got deeply into the general architecture of the protocol, explored how Ethereum 2.0 operates, and how Lido facilitates withdrawals through its architecture. However, we’ve only briefly touched upon the role the oracle infrastructure plays in these processes. We still don’t fully understand what role it plays in the Deposit & Staking process, or even what it consists of.

In this final installment of the series, we’ll put all the missing pieces in their place, giving us a complete theoretical understanding of how the protocol operates.

But let’s temporarily forget about the Oracle Infrastructure and circle back to finances. We know how Lido processes user funds withdrawals. But how does the protocol make money? What’s its business model? Where does the money for deposit payouts come from? Let’s dive into all this.

Deposit & Staking

Undoubtedly, to answer the posed questions, we first need to examine how the protocol facilitates staking, as it’s precisely through the staking process that the protocol earns money.

Deposit & Staking Flow

So, to make it easier for you to catch the essence, let’s start by revisiting the scheme from the first part of the series, which broadly outlines the deposit process through Lido.

Untitled

Based on the scheme, we can highlight several main functions of the Deposit and Staking module:

  1. Ensuring the economic well-being of the protocol.
  2. Accumulating user funds and their further redistribution.
  3. Ensuring the security of the native staking procedure.
  4. Providing tools for managing the protocol’s validators.

Now, we’ll look at the low-level flow of the Deposit & Staking procedure, both with and without Lido’s involvement.

Here’s what the staking flow looks like without Lido’s participation, at the level of Node Operator interaction with off-chain and on-chain network components:

Untitled

In general, it consists of 4 main stages. Note that the only on-chain component here is Deposit Contract.

The flow is pretty simple:

  1. Node Operator has to run both CL and EL nodes using geth, prysm or some other clients and ensure that they are both connected.
  2. Node Operator has to generate validator keys (Withdrawal Keys and Signing Keys) using staking-deposit-cli which will then return generated validator_keys.
  3. Node Operator has to send a transaction with msg.value = 32 ETH to Deposit Contract. It will then take some time for validator to become activated (we will discuss the process further).
  4. After the validator’s is assigned in Deposit Contract, Node Operator has to run its validator client using his validator_keys.

Here’s what the staking flow looks like with Lido’s participation, at the level of Node Operator interaction with off-chain and on-chain network components:

Untitled

The flow looks a little bit complicated, but in fact it just consists of 5 steps:

  1. Node Operator sends the application for the activation of validator to Lido Guardians Commitee. Guardians then submit applications to Lido DAO, which reviews and approves them. When Guardian receives the response, it adds the address of Node Operator to Node Operators Registry as rewardAddress.
  2. After the approval, Node Operator requests Withdrawal Credentials from Lido and then generates validator_keys using the returned address.
  3. At this step, rewardAddress adds its signing keys into Node Operators Registry in order to become its full-fledged participant.
  4. Node Operator asks Lido for the address of EL Rewards Vault and runs validator client using the returned address (set as EL fees recipient) and its validator_keys.
  5. If everything is fine, Deposit Security Module makes a deposit function call in Lido contract, after which the deposit is processed in the Beacon Chain.

Deposits through the outlook of Beacon Chain

Before diving into the deposit process through the lens of the Beacon Chain, it’s crucial to understand the system of keys used by network validators. Below is a description of the validator key management:

Untitled

As you can see, a single address, for which a mnemonic is generated according to EIP-2334, can manage multiple validators. Each validator has two pairs of keys, with 2 public and 2 private keys in each: Validator Signing Keys and Validator Withdrawing Keys. They are used for different tasks and are not interchangeable.

Untitled

The Signing Keys pair is used for the main activities of validators in the network: signing attestations and block proposals.

The Withdrawing Keys pair is predominantly used for withdrawing deposits and rewards after a validator exits.

Now, let’s dive into the validator activation algorithm on the Network Layer in more detail:

Untitled

Now that we have a basic understanding of how network validators are activated, let’s provide some important technical details about this process:

  1. It all starts with a signed transaction sent to the deposit contract address, which enters the tx mempool. The transaction must include a msg.value = 32 ETH (if it’s less, the validator won’t be activated) and be signed with the public Signing Key and public Withdrawing Key, which set the Withdrawal Credentials where funds and rewards will be sent after the validator exits. We’ll explain Withdrawal Credentials a bit later. Technically, a transaction can stay in the mempool indefinitely, which is why the deposit status at this stage is classified as “UNKNOWN”.
  2. After processing, the transaction reaches the Deposit Contract, where it processes all values and metadata. If msg.value doesn’t reach the Threshold of 1 ETH, or the metadata contains incorrect values, the transaction is rejected. However, there’s a nuance - even if all the transaction data is correct, it must pass a so-called Follow Distance of 2048 blocks (~6.82 hours) to ensure that the block containing the transaction doesn’t become an orphan in a Chain Reorganization situation.
  3. In addition to the Follow Distance, our transaction’s block must withstand 64 Epochs (~6.82 hours), during which already activated validators vote for new deposits. At this stage, the validator’s status is classified as “DEPOSITED”.
  4. After all delays and checks are passed, the validator enters the queue for activation. The processing capacity for validators is 8 per Epoch (=1800 validators per day). When our validator’s turn comes, it receives the epoch in which it will be activated. At this stage, the validator’s status is classified as “PENDING”.
  5. When the designated epoch arrives and the validator is activated, it begins to perform its duties, which we covered in the second cycle part. At this stage, the validator’s status is classified as “ACTIVE”.

Deposits through Lido Architecture

To carry out the entire process described above, Lido uses the familiar Buffer concept. Let’s refer to the scheme below for a better understanding.

This scheme shows how the funds that enter the Withdrawal Vault and EL Rewards Vault after the deactivation of validators are distributed and reserved for activating new validators on behalf of the protocol through the Deposit Contract.

After this process, as described above, Lido sets its own Withdrawal Keys (which we will discuss in the context of the next scheme), and Lido begins to control the activated validator, whose deposit includes funds from previously withdrawn validators.

After validators are activated, Lido starts receiving the snapshot of all validators’ balance via Lido Oracle (~every 24 hours). The scheme shows that Lido validators’ balances can differ from each other: that’s because validators are forced to pay penalties when they work ineffectively.

Untitled

Notice an interesting fact - the whole scheme describes the process of ETH circulation between two users: the depositor and the withdrawer. At the same time, it is shown what iterations are made with their funds, and how these funds generally generate surplus value.

As we can see, there are no difficulties for us in understanding this scheme anymore: the process of validator deactivation, the withdrawal flow, and the process of deposit redistribution after deactivation were covered in the second part of the series.

We’ll just remind you that a single user doesn’t need to contribute all 32 ETH individually - they can deposit any amount in Lido. The Staking Router, which we will discuss further, ensures that deposits of any size are aggregated and divided into 32 ETH portions. However, until now, we haven’t considered that the Ethereum ecosystem has several fundamental problems that compromise the protocol’s security, and it’s crucial to protect against them.

The issue is closed in the process of the protocol’s interaction with the deposit contract. Let’s delve into its essence and see how Lido protects against it!

Deposit Security

To grasp these issues, let’s take a look at the expanded scheme below, which includes modules we haven’t encountered yet. The first question that arises is, “Does Lido directly manage all node operators and validators?”

No, of course not. That would be highly impractical. For these tasks, the protocol employs a Node Operator Registry, which manages the node operators, stores their public keys, and the associated Withdrawal Credentials (provided by Lido DAO), and also distributes the stake among them. It’s their keys and signatures that the Lido protocol submits in transactions to the deposit contract.

Untitled

As we already mentioned, Withdrawal Key is used for withdrawals and transfers, while the Signing Key is used in the process of the validator performing their duties: attesting to blocks, voting for them, etc.

A specific Withdrawal Credentials (WC) are used for each withdrawal:

  • Withdrawal Credentials is a 32-byte field associated with each specific validator, initially set during the deposit to verify the withdrawal destination. There are two types of Withdrawal Credentials: BLS Credentials and Execution Credentials.
  • BLS Credentials: This type is generated by default using the deposit command line interface with a withdrawal key derived from the mnemonic according to EIP2334 format. However, in our days it is much more convenient to use Execution Credentials. Therefore, to become available on the Mainnet, BLS Credentials can be updated to Execution Credentials.
  • Execution Credentials: This is a more familiar type of credentials, representing a standard Ethereum network address. Funds from the Beacon Chain will be transferred to this address.

The fundamental issue is that a validator’s public key becomes associated with Withdrawal Credentials (WC) only after the first valid deposit, and all subsequent deposits for these public keys will work with the same Withdrawal Credentials as the first one (i.e., WC is determined by the first deposit).

How can this be exploited in an attack? Through front-running. A node operator could send a transaction with the same Public Key, their own Withdrawal Credential, and the minimum deposit amount for the Deposit Contract - 1 ETH, ahead of the main deposit contract transaction.

Thus, a malicious node operator could substitute their WC by paying 1 ETH and gain control over a 32 ETH deposit, which will be sent immediately after their transaction and automatically associated with the incorrect WC.

Lido was notified of this issue on October 5, 2021, through the Immunefi bug bounty program. You can read the post-mortem of this bug at this link. The Lido community took numerous steps to address the vulnerability - the final version of the protection was presented in Pull Request #357.

Due to this vulnerability, the Deposit Security Module and DSM Bot are present in our scheme:

  • DSM Bot is an off-chain program for monitoring the tx mempool, which collects information about pre-submitted keys from Guardians (members of the Deposit Security Committee, or Oracle Committee). If a Guardian reports that pre-submitted keys have been found for a planned deposit, it reverts the transaction.
  • Deposit Security Module is the on-chain component parent to DSM Bot, which calls the submitBufferedEther function from the Lido Buffer if the DSM Bot confirms the absence of pre-submitted keys. Only after a call from this contract can a deposit be made.
  • Deposit Security Committee is a group of EOA addresses responsible for monitoring deposit history and setting available keys for node operators. To successfully make a deposit, the committee must reach a quorum of 2/3 of the total number of validators. However, even if a supermajority of committee members are malicious actors, each member has the ability to halt acceptance or extend the voting time for the deposit.

All these modules are responsible for protecting the deposit procedure from front-running by malicious Node Operators. Their interaction is reflected in the scheme below:

Untitled

The process follows the algorithm illustrated below:

  1. Members of the Deposit Security Committee, Guardians, reach a quorum that there are no pre-submitted keys in the mempool for the planned deposit.
  2. Guardians send a message to DSMBot, which then submits this message to the on-chain contract Deposit Security Module.
  3. The Deposit Security Module verifies the received information and then calls the submitBufferedEther function from the Lido Buffer.
  4. The Lido Buffer processes the call from the Deposit Security Module and then calls the Staking Router, transferring the money for the deposit.
  5. The Staking Router receives the funds, distributes them to equal Deposit Modules, and makes the final call to the Deposit Contract.
  6. The deposit process is considered complete, and the validators receive their activation epoch and start earning ETH for the protocol.

However, in the first version of the protocol (before the withdrawal capability was introduced), only BLS Credentials were supported for validators, and the ability to use Execution Credentials was not yet available. Execution Credential is more secure in the context of protocol risks because using BLS Credentials placed additional burdens on the protocol’s off-chain infrastructure. When two types of WC became available, there was a need to securely store and manage both validator keys somewhere.

Moreover, to enhance scalability and attract new node operators, there was a need to create a comprehensive platform that would allow for convenient storage of validator keys, making the registry of all Lido node operators more modular and decentralized. This would enable the combination of different forms of validators in a single Node Operator Registry and distribute rewards between them more effectively.

To understand the importance of the Node Operator Registry, let’s look at the scheme below. It describes the three main updates to this component that were added in Lido V2.

  • As you can see, the Node Operator Registry provides the ability to store validator keys on L2 or off-chain, reducing protocol costs by optimizing gas prices.
  • The new version is permissionless, meaning new node operators can be launched by community members without the need for manual approval from Lido DAO.
  • The new version supports the new Distributed Validator Technology (DVT), which we will discuss further in the context of staking modules.

Untitled

All the updates reviewed for the Node Operator Registry were introduced as part of the Staking Router launch. But what is Staking Router? We have not known anything about it until now. Let’s delve into it.

Staking Router

*Staking Router is a component introduced in the second version of Lido. It acts as a top-level controller contract that oversees the operations of staking modules.*

This solution has made the Node Operator Registry’s architecture more modular and decentralized, significantly expanding the possibilities for launching and maintaining Community Node Operators. These operators can be controlled not only by Lido itself but also by solo stakers, DAOs, and professional staking companies.

Effectively, this solution transforms the Lido protocol into an aggregator of staking validator pools, providing operators with a convenient and understandable way to distribute responsibilities and rewards. Staking Router also facilitates a more reliable distribution of the risks associated with validator activities among active node operators, enhancing the system’s overall resilience. Let’s explore the problems and tasks that Staking Router addresses.

🔦 Problem 1. Allocating buffered ether between modules

The amount of ETH stored in the Lido Buffer doesn’t always match the amount needed for deposits, or it needs to be divided into equal parts. Therefore, the Staking Router evenly distributes the stake amount into equal parts among the least loaded nodes (those with the fewest active validators). This process is illustrated on the scheme below.

Untitled

🔦 Problem 2: Distributing rewards to treasury and node operators

To avoid overloading the Lido Buffer with additional iterations for distributing rewards, the Staking Router handles this immediately, as it is much more convenient.

The old operational model of the protocol assumed a single Node Operators Registry curated by Lido DAO and managed in a semi-manual mode. Rewards were distributed in the same way. Such a scheme had very low scalability potential and required improvements.

With the release of the second version of the protocol, reward distribution occurs automatically in 4 steps. The ****are 4 main stages:

  1. Lido requests the module-to-shares table from StakingRouter;
  2. Lido requests the treasury shares from StakingRouter;
  3. Lido mints the shares to Treasury of Lido DAO.
  4. Lido mints the shares to each module.

🔦 Problem 3. Migrating operators registry

Since the original Node Operator Registry has now become just one of many similar modules (e.g., Curated Module), the protocol needed to create a unified interface for all registries. The protocol does not prohibit custom registries with their unique implementation, leading the protocol to assign the Staking Router the task of ensuring all modules support a unified interface.

Complete Deposit & Staking Flow

The scheme below describes the entire process of Deposit & Staking in full, at the level of all architecture modules we’ve discussed. Above the arrows, you can see the target data passed in each request.

Note that the orange arrows separately show the circulation of staking rewards among the involved nodes. Indeed, the distribution of rewards and the deposit algorithm we’ve already looked at are the only things of importance for us here.

Untitled

However, even looking at this not-so-crucial scheme, you might argue that we still don’t understand the role of the oracle infrastructure. And you would be right. It’s time to address that.

Oracle Infrastructure

This component of the Lido architecture ensures that all other system modules operate in accordance with the current data about the network state, validator statuses, contract balances, and withdrawal/deposit requests. It also participates in the validator exit process and is responsible for the rebase of stETH on user balances and its redemption rate relative to ETH.

Oracle general flow

The oracle infrastructure consists of two functional modules: Ejector Oracle and Accounting Oracle, each with both on-chain and off-chain parts. Let’s examine the working principles in more detail.

Accounting Oracle is responsible for tracking the financial changes in the protocol and monitors the current lifecycle (a 24-hour amortized period).

Ejector Oracle signals requests for validators to exit the Beacon Chain, assesses the necessary number of validators for exit, and interacts with the new ValidatorExitBusOracle contract using a more flexible reporting interval.

Both modules are run using the same Oracle committee (which we discussed in the previous part), but their lifecycle is unlinked due to different asynchronous environments and reporting requirements.

The result of the oracle infrastructure’s work is the Oracle Report, which plays a key role in most system processes. The oracle reports on Validator Exit Keys more frequently (every few hours) than on other data (once a day).

Let’s look at the scheme below that illustrates the general flow of Lido Oracle. At first glance, it might seem complicated, but we will go through each of the functional modules separately later on, and everything will become clearer. This scheme is provided so that after studying the materials below, you can return here and look at the big picture.

Untitled

  • Bunker Service is an implementation of Bunker mode. Its purpose is to maintain socialization of all problems in Lido validators pool and to prevent sophisticated attacks. To achieve this, “bunker mode” limits an operations in Lido protocol (withdrawal requests finalization).
  • Lido Validator State Service is a helper-component that shows aggregated data about the states of all Lido validators (Ongoing, Pending, Slashed validators divided according to their staking pools).
  • Safe Border is a service that calculates the range in which withdrawal requests can’t be finalized. In Turbo mode, there is only one border that does not allow to finalize requests created close to the slot in which the oracle report is performed. In Bunker mode there are more safe borders. The protocol takes into account the impact of negative factors that occurred in a certain period and finalizes requests on which the negative effects have already been socialized. There are 3 types of the border:
  1. Default border
  2. Negative rebase border
  3. Associated slashing border
  • Withdrawal Service is a component that calculates which withdrawal requests should be finalized using next factors:

    1. Safe border epoch for the current reference slot.
    2. The amount of available ETH is determined from the Withdrawal Vault, EL Vault, and buffered ETH.
  • Rewards Prediction Service is one of the components of the Staking Router, which is responsible for predicting the future value of the protocol balance after the finalization of all withdrawal requests from validators who are currently waiting for their turn.

  • Validators To Exit Iterator is a service that prepares lido operator statistic, which used to form validators queue in right order.

  • Lido Validators Provider is a module that helps to merge Lido validators with their Node Operators and validator_keys according to their Staking Module.

The main takeaway from this scheme is that both oracles interact with each other, and the result of one’s work is involved in the process of the other. When the Ejector Oracle completes another cycle of its work, it passes information about the exited validators to the Accounting Oracle. In turn, it uses this information to adjust the total balance of staked funds managed by the protocol, taking into account the reduction caused by the exits conducted. Also, the Accounting Oracle updates data on the state of the protocol’s staking pool, which are then used for the rebase of stETH and changing its redemption rate.

In turn, the Accounting Oracle also informs the Lido Core about the balance of the Withdrawal Vault, EL Rewards Vault, and Buffered Ether. We didn’t reflect this in the scheme merely for aesthetic reasons.

As you’ve come to understand, the oracle infrastructure is not monolithic. So now, let’s delve into each module separately.

This module updates the TVL (Total Value Locked) of the protocol, distributes rewards to node operators, and updates information on the number of exited and pending validators. But for users, this module is critically important because it finalizes user withdrawal requests. The oracles report balance changes daily, and Lido accordingly updates the total volume of stETH reserves.

Some important data for the Lido protocol are collected off-chain and delivered to the chain through AccountingOracle, ValidatorsExitBusOracle contracts.

This module also decides on the activation/deactivation of Bunker Mode based on information about the number of slashings that occurred over the last 36 days. We will discuss this mode of operation of the protocol at the end of the article.

The work of the oracle is divided into frames. Oracles complete a report in each frame.

⌛ The default length of an Accounting Oracle frame in Mainnet is 225 epochs (24 hours).

The frame includes the following stages, which constitute the lifecycle of the oracle:

  • Waiting - oracle starts as daemon and wakes up every 12 seconds (by default) in order to find the last finalized slot (ref slot). If ref slot missed, Oracle tries to find previous non-missed slot.
  • Data collection - oracles monitor the state of both the Execution and Consensus layers and collect the data.
  • Hash consensus - oracles analyze the data, compile the report and submit its hash to the HashConsensus smart contract.
  • Core update report - once the quorum of hashes is reached, meaning required number of Oracles submitted the same hash, one of the oracles chosen in turn submits the actual report to the AccountingOracle contract, which triggers the core protocol state update, including the token rebase, finalization of withdrawal requests, and deciding whether to go in the bunker mode. It processes through function _calculate_report():
  • Extra data report - an additional report carrying additional information. All node operators rewards are distributed in this phase.

Accounting Oracle flow

The scheme below outlines the full operation algorithm of the Accounting Oracle. Let’s examine it and break down the algorithm itself.

Untitled

  1. Take a pre-snapshot of the stETH share price.
  2. Update exited validators number for each Lido-participating node operator.
  3. Estimate transient validators balance.
  4. Finalize withdrawal requests (if possible) by burning stETH shares and locking ether in the same time (i.e., decreasing a total pooled ether amount).
  5. Resubmit remaining funds up to the reported WithdrawalQueue balance at block N to the deposit buffer.
  6. Set the reserve mark value to leave the necessary amount of funds in deposit buffer till the next report to use for withdrawals.
  7. Take a post-snapshot of the stETH share price for rewards.
  8. Calculate both Consensus and Execution layer rewards.
  9. Mint & distribute protocol fee on top of rewards only if Consensus layer rewards part is positive.
  10. Take a post-snapshot of the stETH share price for Annual Percentage Rate calculation.

Accounting Oracle report

In the table below, you can see all the information contained in the oracle report. We’ve categorized all the information according to its source.

Untitled

Ejector Oracle

In the article about withdrawals, we briefly looked at what this module does. Now, let’s delve deeper into its structure.

The oracle is used to inform that some Lido validators need to be exited from the Beacon Chain. The oracle’s goal is to exit the minimum number of validators necessary to fulfill all current pending withdrawal requests (when the balance of these validators will be withdrawn), and then disseminate a report on the exit of these validators by creating an event in the smart contract.

The Ejector Oracle requests validators for exit through events on the EL when the protocol needs additional funds to process user withdrawals.

It also uses these events in the RewardPredictionService submodule to predict how much Ether the protocol will receive as a result of slashing. The algorithm for how this is done will be examined later in the context of the overall Ejector Oracle algorithm.

The selection of a node operator for validator exits is based on the following algorithm:

  1. Take the list of Lido validators in order of increasing validator activation time.
  2. Determine the exit request for the last validator (taking the last ValidatorExitRequest event).
  3. Take the first N validators, skipping already exited/withdrawing validators.

Below, you can explore the flow of the main function of the Ejector.py component. As you can see, the function’s result is the update of the Report.

Untitled

In its report, the Ejector Oracle provides the following data:

  • The last finalized slot.
  • Public Key of the validator for exit.
  • The node operator’s ID and the staking module to which the Public Key belongs.
  • The validator index corresponding to the Public Key.

It is assumed that the operation algorithm of the Ejector Oracle adjusts the future number of validators for each node operator.

Let’s look at this algorithm. As shown below, the oracle collects data on the current state and iteratively finds the most suitable validator for exit, then mutates the state to simulate the exit of this validator, and repeats the cycle until the number of exits is sufficient.

  1. Calculate the amount of ETH needed to cover withdrawal requests.

    expected_balance = (
    future_withdrawals +  # Validators that have withdrawal_epoch
    future_rewards +  # Rewards we get until last validator in validators_to_eject will be withdrawn
    total_available_balance +  # Current EL balance (el vault, wc vault, buffered eth)
    validator_to_eject_balance_sum +  # Validators that we expected to be ejected (requested to exit, not delayed)
    going_to_withdraw_balance  # validators_to_eject balance
    )
    
  2. Calculates the predicted amount of rewards.

  3. Executes the loop we have already explored:

    Untitled

  4. Sends a transaction with the report.

At this point, the lifecycle concludes. Now, let’s look at this process from the perspective of participant interaction.

Ejector Oracle flow

Below is a flowchart representing the eject operation we discussed above, shown as interactions between the Exit Daemon, Oracle, and Node Operator. It slightly differs in that it assumes by default that the epoch of the last validator is already determined, and the predicted rewards have also been calculated.

Untitled

It’s worth noting here that the Ejector Oracle (represented by the Exit Daemon in our scheme) merely creates a report that emits events, and the node operator, in turn, monitors these events and executes validator exits.

However, we also planned to delve deeper into Bunker Mode. Now that we have a complete picture, let’s do that.

Bunker Mode

*Bunker mode is a protection mechanism for users withdrawing their funds under rare but potentially critical conditions of the entire Ethereum network. The most understandable example of such conditions might be mass slashings of validators from the Beacon Chain.*

Recall that Slashing involves burning a portion of a validator’s funds and ejecting them from the active set of validators chosen for the current epoch. We discussed this topic in details in the second part.

If slashings have low or moderate impact, the protocol uses “turbo mode”: withdrawal requests are executed without delay. However, if slashings have a significant impact, the protocol switches to “bunker mode”: withdrawal requests are suspended until the consequences of negative events are mitigated.

Bunker mode aims to create a situation where during the period between the next and previous oracle reports, users who (1) remaining in the staking pool; (2) exited within the current period; (3) exiting in the near periods; would have equally low risks of losing their funds.

Consequently, bunker mode is activated when there’s a negative rebase of the stETH token on the Consensus Layer, or it’s expected to occur in the future. This is dangerous because it can disrupt the balance between users exiting now and those who remain in the staking pool or exit later, as they will receive different amounts of ETH for their shares due to imbalance.

A negative rebase of the stETH token can occur when, over a certain period, the cumulative performance results of all Lido validators on the Consensus Layer lead to penalties exceeding rewards.

The Oracle decides to activate and deactivate bunker mode based on the historical and current state of the network and Lido; this decision can be changed during the slashing resolution period.

Untitled

In the scheme above, you can see the algorithm for determining the mode in which the protocol operates: when the oracle releases an updated report, it notifies other protocol components about the change in key parameter values. If the protocol continues to operate in Turbo Mode, nothing changes.

But what needs to happen for the protocol to switch to Bunker Mode? It’s time to delve into this question.

Most Likely Scenarios for Activating Bunker Mode

  1. Mass slashings of Lido validators leading to a negative stETH rebase.

    • Upcoming penalties for slashing are unpredictable, as they depend on the future state of the network. Therefore, activating bunker mode under this condition is the only way to safeguard user funds.
  2. Lido validators offline for several hours/days due to hardware damage, software malfunctions, or connectivity issues, resulting in a negative stETH rebase for the current period.

    • A negative Consensus Layer (CL) rebase in the current frame is strong evidence of an incident in the network or Protocol. Since a catastrophic scenario is required to trigger a negative CL rebase, it is expected that it will persist into the future for some time, thus there is a high likelihood of a negative future CL rebase.
  3. Negative rebase in the current period, or a rebase lower than expected at the end of the period.

    • A decreased expected CL rebase in the current frame along with a negative CL rebase at the end of the frame signals an incident occurred right before the oracle report. It is expected that the cause of this failure will persist into the future for some time, therefore, there is a high likelihood of a negative future CL rebase.

Many modules within the Lido protocol feature a _is_bunker() function, which checks whether the protocol is in bunker mode:

def _is_bunker(self, blockstamp: ReferenceBlockStamp) -> bool:
    frame_config = self.get_frame_config(blockstamp)
    chain_config = self.get_chain_config(blockstamp)
    cl_rebase_report = self.simulate_cl_rebase(blockstamp)

    bunker_mode = self.bunker_service.is_bunker_mode(
        blockstamp,
        frame_config,
        chain_config,
        cl_rebase_report,
    )
    logger.info({'msg': 'Calculate bunker mode.', 'value': bunker_mode})
    
    return bunker_mode

This is necessary because during bunker mode, the protocol suspends the finalization of withdrawal requests from staking until the slashing situation normalizes, and the DAO decides to exit bunker mode. We discussed this process in more detail in the second part of the article on the withdrawal mechanism.

Bunker Flow

Now it’s the time to understand how Bunker Service works and what is happening behind the scenes. To understand this, let’s look at the flowchart below:

Untitled

As you can see, there are 5 main components involved in the bunker flow:

Off-chain: Accounting.py, Bunker.py, LidoValidatorsProvider.py On-chain: AccountingOracle.sol, WithdrawalQueue.sol

  1. Accounting.py and AccountingOracle.sol are off-chain and on-chain parts of Accounting Oracle that we have already reviewed in the “Accounting Oracle” section.
  2. Bunker.py is the main implementation of Bunker Service that we have already reviewed in context of “Oracle general flow”.
  3. LidoValidatorsProvider is a module of lido_validators.py that we have also reviewed: it helps to merge Lido validators with their Node Operators and validator_keys according to their Staking Module.
  4. WithdrawalQueue.sol is a contract for handling stETH withdrawal request queue within the Lido protocol.

Let’s explore the steps involved into the flow itself:

  1. Off-chain part of Accounting Oracle сhecks if bunker mode is activated by calling is_bunker() function.
  2. While processing this call, Bunker Service checks the assumption if CL rebase rate is negative.
  3. If this assumption is confirmed, then Bunker Service asks LidoValidatorsProvider about the list of all and specifically lido not withdrawn validators that were slashed in the Beacon Chain.
  4. To ensure that the situation is bad enough to activate bunker mode, the Service also checks if maximum midterm penalties of Lido validators are more than current CL rebase rate; and CL rebase in a current frame is lower than usual.
  5. After receiving of bool value, Accounting Oracle submits the result into ReportData and updates the protocol state on contracts side, if necessary.
  6. Finally, activated Bunker Mode affects on the proccess of withdrawal requests finalization, represented in WithdrawalQueue.sol

Conclusion

So, in this article, we have thoroughly explored the deposit and staking process, examined the front-running issue of deposits, and looked into the solutions Lido applies to mitigate it.

We also delved into how Lido utilizes a complex yet highly effective oracle system to ensure the reliability and timeliness of data within the protocol. The oracles integrate off-chain information into the blockchain and monitor the state of the protocol, participating in critical processes such as staking, consensus, fund withdrawal, and the security system.

Accounting Oracle plays a pivotal role in the accounting of protocol assets, updating rewards for node operators, and processing user withdrawal requests. Its lifecycle and workflow serve as an example of how data collection and processing can be optimized for smart contracts.

On the other hand, Ejector Oracle performs the vital task of adjusting the overall balance of the protocol by tracking the “ejection” of validators. This process ensures that Lido users always have up-to-date information on the price of stETH.

Thus, we conclude our series of articles on Lido! We now fully understand all the main technical aspects of the protocol, its economic model, strengths, and weaknesses.

Our team of security engineers went through the process of learning the protocol’s architecture during the audit of Lido V2, and we believe that all ordinary users should first understand the “business” they want to invest their funds in from the inside. We hope this series of articles will aid in that understanding.

During the audit of Lido V2, we gained extensive experience and a thorough understanding of the liquid staking sphere and LSD protocols. We look forward to further developing our collaboration with the Lido team and are already taking steps in this direction. If your protocol falls within the liquid staking sphere and you need an audit, we are ready to assist you!

References

Deposit & Staking

[link] - [research] - “Managing ETH validator keys”

[link] - [research] - “Lido contracts interaction complete flow”

[link] - [research] - “LIP-5 | Mitigations for deposit front-running”

[link] - [specification] - “Staking Router and Lido deposit”

[link] - [specification] - “ADR: Staking Router”

[link] - [specification] - “Leveraging Distributed Validator Technology with Simple DVT”

[link] - [documentation] - “Beacon Chain deposit process”

[link] - [documentation] - “Ethereum 2.0 keys”

[link] - [source file] - @lidofinance/lido-oracle

Accounting Oracle

[link] - [specification] - “Accounting Oracle”

[link] - [documentation] - “Accounting Oracle”

[link] - [source file] - AccountingOracle.sol

[link] - [source file] - accounting.py

Ejector Oracle

[link] - [research] - “Lido Oracle - Associated slashings”

[link] - [specification] - “Ejector Oracle”

[link] - [source file] - ejector.py

Bunker mode

[link] - [specification] - “Lido Withdrawals Design & Bunker Mode”

[link] - [specification] - “Bunker mode”: what it is and how it works”

Telegram
Case Study

Contents

Telegram

Have a question?

Have a question?

Stay Connected with OXORIO

We're here to help and guide you through any inquiries you might have about blockchain security and audits.