pshenichnyy
    • Create new note
    • Create a note from template
      • 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
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • 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
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync 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
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
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
# [DRAFT] On withdrawal request finalization rate The document describes the principles and algorithm for calculating the amount of Ether for stETH withdrawal requests finalization. A high-level description of the Lido on Ethereum protocol logic with withdrawals enabled is provided in the [Withdrawals Landscape post](https://hackmd.io/@lido/SyaJQsZoj?type=view#Withdrawal-request-fulfillment-mechanics). ## stETH and shares mechanics Lido on Ethereum protocol is a staking pool which anyone can submit their Ether and gets stETH in return. stETH is a ERC20 token that represents a holders' share in the staking pool, but the share mechanics is hidden underneath, while the balance of the token are dynamic and reflects the amount of Ether of the corresponding share at the moment. If the staking pool earns rewards or suffers losses, each holder's balance changes accordingly. ![](https://i.imgur.com/xXJPjfR.png) As you can see on the picture, shares aren't normalized, so the contract also stores the sum of all shares to be able to calculate each account's balance. When a new holder submits their ETH, the new shares get minted to reflect what share of the protocol controlled ether has been added to the pool. Normally share rate changes after the consensus layer oracle report comes in and total pooled ether has been rewrited by the up to date value. You can see that holders who entered the pool with same Ether at different share prices gets minted different amounts of shares: 1) Assume `totalPooledEther = 100` and `totalShares = 100` 2) Holder `0x1` submits `10 ETH` and gets `10 shares` of stETH minted 3) Suppose, the pool registers rewards and `totalPooledEther = 220 ETH` 4) Now `shareRate = 220 ETH / 110 shares = 2 ETH` 5) Holder `0x2` submits `10 ETH` and gets `5 shares` of stETH minted 6) Holder `0x1` has 20 stETH in the wallet, and `0x2` has 10 stETH. Indeed, the real representation of holder share in the staking pool is `sharesOf(address)` and dynamic `balanceOf(address)` is a UX friendly helper that converts shares to corresponded amount of Ether. ## Withdrawal queue mechanics Due to the async nature of Ethereum withdrawals, withdrawal requests in Lido on Ethereum protocol are oraganized as a queue. When a holder decides to redeem their stETH, they can lock the stETH token in the Withdrawal Queue contract. Once the Lido protocol on Ethereum completes processing the request, the user can claim the withdrawn ETH. Processing of the withdrawal queue is possible only at the moment of the oracle report, since only at these moments the exact share rate is known. During the processing time, the requested Ether is at risk of being slashed. Therefore, it is not fair to give the user Ether according to the amount of the locked stETH. Instead, when a request can be finalized, it is done so according to the current protocol share rate. Also, [an additional rule is enforced at the time of finalization](https://hackmd.io/@lido/SyaJQsZoj?type=view#Main-flow): the redemption rate for fulfilling the request cannot be better than the redemption rate at the time of request creation. Therefore, each withdrawal request store amount of locked stETH in the moment of request sumbission and shares amount. Thus, in each withdrawal request, the actual share rate is preserved at the time of queuing. However, due to [rounding issues related to the stETH shares mechanic](https://docs.lido.fi/guides/steth-integration-guide#1-wei-corner-case), the share rate between requests for the same oracle frame can differ by several weis. This is a minor detail that should be taken into account later. Let's consider an example of a withdrawal queue with requests created at different times when the share rates were different. We will also assume that no requests have been finalized yet, all requests are eligible for finalization in the current oracle report, and there are 1.8 ethers per share. ![](https://i.imgur.com/1HQ1h3B.png) To calculate the amount of Ether required to finalize a batch of withdrawal requests, we need to sum up the amount of Ether necessary for each request's finalization. This can be calculated as the current share rate multiplied by the number of shares locked in each request, but not more than the number of stETH tokens that were locked at the time of request submission. ```python= # withdrawal_queue = [(1, 1), (2, 4), (3, 7), (2, 3), (1, 1.5), (3, 6), (4, 8)] # share_rate = 1.8 eth_amount = sum(min(share_rate * sh, bal) for sh, bal in withdrawal_queue) ``` In this formula, the min function ensures that we don't withdraw more Ether than there were stETH tokens at the time of request submission. ![](https://i.imgur.com/IMvrV4v.png) For the case when the share rate in the staking pool only grows, the amount of Ether required for finalization is equal to the sum of stETH tokens snapshoted in the withdrawal requests. However, for cases where there are requests with a share rate higher and lower than the current one, we cannot rely on the sum of the snapshotted stETH or the sum of shares for all requests multiplied by the current share rate. To fulfill withdrawal requests at the current share rate, there may be an edge case scenario where an oracle report is missed for some reason, and the next report finalizes requests at a lower rate than the missed one. This situation may have implications for users, but the development team suggests sticking with this design and taking the associated risk. An alternative implementation would require additional complexity for on-chain validation of the amount to be redeemed for requests. ## Finalization algorithm Withdrawals requests are finalized during accounting oracle report. Each report, it decides how many requests to finalize and at what rate. Requests are finalized in the order in which they were created by moving the cursor to the last finalized request. Oracle must take two things into account: 1. Available ETH and share rate 2. Safe requests finalisation border To simplify, the logic of calculating the index of the request to which the queue can be finalized is moved to the view function of WQ contract. The accounting oracle calculates the finalization border timestamp, obtains from the smart contract the amount of ether available for the finalization of applications, and also calculates the share rate based on the current CL-balances of the validators and the balance of the withdrawals vault. Further, these three numbers are passed to the view function, which returns the `lastFinalizationRequestIndex` for the current frame. During the report process, the smart contract burns the number of shares corresponding to the segment being processed. This is possible due to the fact that requests store accumulative amounts instead of values. Additionally, the transferred amount of ether is locked in WQ contract. It is important that the transferred amount is consistent with the value that each user can then request. Otherwise the oracle can send less ether than required to WQ and effectively organise DOS for some holders. Additionally, the view function returns an array of withdrawal request indexes that specifies the breakdown of the processed segment of the queue to be broken into batches. This array will then be passed to the oracle report so that the smart contract can verify that the final oracle process the next segment of the queue by transferring enough ether. For the case when the current share rate is higher than all the requests in the queue, it is very easy to build a check, it is enough to calculate the sum of the values of the snapshotted stETHs. In the previous section, it was highlighted that in the case when the share rate is arbitrary, this principle does not work and it is necessary to iterate over all orders to calculate the total amount of ether. ![](https://i.imgur.com/Qx44Ti1.png) It can be seen that any segment of the withdrawal queue can be divided into batches for which the complexity of calculating the ether for finalization is proportional to a constant (due to the storage of partial amounts of share and step in each request). In practice, the number of such batches will be small enough that counting the amount of ether as the sum of batches is practical for a smart contract. Thus, at the report stage, the oracle must transfer the breakdown of the segment into batches, and the smart contract must carry out verification. However, for this, the smart contract must store all local extrema of the share rates of all withdrawal requests. ![](https://i.imgur.com/E9gaKqV.png) The situation is complicated by the already mentioned rounding error, which generates many false positibe local extrema. The second difficulty is that a smart contract can process only a limited number of batches and local extremes of queue segments associated with the data. The first difficulty can be circumvented by storing the frame index alonw with each withdrawal request. The second difficulty will have to be accepted and kept in mind that in extreme situations the oracle will have to finalize fewer applications than is possible.

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