-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Withdrawals of rebasing tokens can lead to insolvency and unfair distribution of protocol reserves #282
Comments
CloudEllie marked the issue as duplicate of #283 |
alcueca marked the issue as duplicate of #326 |
alcueca marked the issue as satisfactory |
Hi @alcueca I don't understand why this finding was duped under #326: this report highlights an incompatibility with rebasing tokens (like If we related to the criteria you shared for the #326 umbrella:
and would bring to your attention that this issue is not about price swings, but rather evolutions of contract balances that are not accounted for (with a coded PoC of insolvency impact), so I would ask you to consider treating this as a separate finding. |
Actually, my bad. I understood initially that the issue was in that the value of the stETH would change between withdrawal and claim, leading to arbitrage. This issue points out that it is the actual balance of stEth that will change. Usually up, but sometimes down in the case of a slashing. It is debatable whether the protocol will actually profit or lose due to regular upwards rebasing of stETH in the queue being above downwards rebasing of stETH due to slashings (which should be uncommon for Lido). They probably would be better off using wstETH for simplicity. |
alcueca marked the issue as not a duplicate |
alcueca marked the issue as primary issue |
alcueca marked the issue as selected for report |
I'm going to sustain the high severity on the grounds that:
The users that win in a slashing event are not the same users that lose during normal operation. |
@jatinj615 pls leave label here |
Lines of code
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L229-L232
https://github.com/code-423n4/2024-04-renzo/blob/main/contracts/Withdraw/WithdrawQueue.sol#L305-L308
Vulnerability details
The
WithdrawQueue
contract allows users to withdraw their funds in various tokens, including liquid staking derivatives (LSDs) such as stETH. Thewithdraw()
function calculates the amount of the specified_assetOut
token equivalent to the ezETH being withdrawn using therenzoOracle.lookupTokenAmountFromValue()
function. This amount is then stored in theamountToRedeem
field of a newWithdrawRequest
struct, which is added to the user'swithdrawRequests
array and the token'sclaimReserve
.When the user later calls
claim()
, the contract transfers theamountToRedeem
to the user via theIERC20.transfer()
function.However, this implementation does not properly handle rebasing tokens like stETH. The stETH balance of the
WithdrawQueue
can change between the time a withdrawal is recorded and when it is claimed, even though the contract's stETH shares remain constant.If the stETH balance decreases during this period due to a rebasing event (e.g., a slashing of the staked ETH), the
amountToRedeem
stored in theWithdrawRequest
may exceed the contract's actual stETH balance at the time of claiming. As a result, the withdrawal can fail or result in the user receiving a larger share of the total protocol reserves than intended.The issue can be illustrated by comparing the behavior of withdrawals for non-rebasing and rebasing LSDs:
Non-rebasing LSD (e.g., wBETH):
Rebasing LSD (e.g., stETH):
Impact
The current withdrawal mechanism for rebasing tokens like stETH can lead to:
amountToRedeem
of all pending withdrawals due to rebasing, users will face transaction failures when attempting to claim their withdrawals.Proof of Concept
We can validate the vulnerability through a Foundry test case POC. This test case will simulate the exploit scenario and confirm the issue by performing the following actions:
2. Alice and Bob initiate withdrawals of their ezETH shares for stETH.
3. Simulate a negative rebasing event by transferring 10% of stETH balance from the withdrawQueue contract.
4. Alice claims her withdrawal successfully, receiving her original stETH amount.
5. Bob's attempt to claim his withdrawal fails due to insufficient stETH balance.
6. Verify that ezETH supply remains unchanged while TVL is significantly reduced, demonstrating ezETH becoming uncollateralized.
The PoC can be run in Foundry by using the setup and mock infra provided here -> https://gist.github.com/3docSec/a4bc6254f709a6218907a3de370ae84e
Tools Used
Manual review
Recommended Mitigation Steps
To address the issue of unfair distribution of funds when withdrawing rebasing tokens like stETH, the
WithdrawQueue
contract should store and transfer the user's withdrawal as stETH shares instead of a fixed stETH amount.When a user initiates a withdrawal with stETH as the
_assetOut
, the contract should convert the calculatedamountToRedeem
to stETH shares using thestETH.getSharesByPooledEth()
function:The resulting
sharesAmount
should be stored in theWithdrawRequest
struct instead of theamountToRedeem
.When the user calls
claim()
, the contract should transfer the stETH shares directly to the user using thestETH.transferShares()
function:By storing and transferring stETH shares instead of a fixed stETH amount, the contract ensures that each user receives their fair share of the stETH balance, regardless of any rebasing events that occur between the time of the withdrawal request and the claim.
To implement this mitigation, the contract should:
_assetOut
is stETH when processing a withdrawal request.amountToRedeem
to stETH shares usingstETH.getSharesByPooledEth()
and store the shares amount in theWithdrawRequest
struct.claim()
function to check if the withdrawal is in stETH and, if so, transfer the shares directly usingstETH.transferShares()
instead of using the standardIERC20.transfer()
function.Note that this mitigation is specific to stETH and may need to be adapted for other rebasing tokens that use a similar shares-based system.
Furthermore, the
claimReserve
andwithdrawalBufferTarget
for stETH would also need to be stored in shares and converted to underlying in TVL and withdraw buffer calculations, respectively.Assessed type
Other
The text was updated successfully, but these errors were encountered: