Platform: Code4rena
Start Date: 30/04/2024
Pot Size: $112,500 USDC
Total HM: 22
Participants: 122
Period: 8 days
Judge: alcueca
Total Solo HM: 1
Id: 372
League: ETH
Rank: 22/122
Findings: 3
Award: $599.00
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: guhu95
Also found by: 0rpse, 0x007, 0x73696d616f, 0xCiphky, 0xabhay, Audinarey, Bauchibred, Fassi_Security, GalloDaSballo, GoatedAudits, KupiaSec, LessDupes, MSaptarshi, OMEN, Ocean_Sky, RamenPeople, SBSecurity, Tendency, WildSniper, aslanbek, bill, blutorque, crypticdefense, cu5t0mpeo, d3e4, gjaldon, grearlake, gumgumzum, honey-k12, ilchovski, jokr, josephdara, kennedy1030, p0wd3r, peanuts, stonejiajia, t0x1c, tapir, underdog, zzykxx
0.4071 USDC - $0.41
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L315-L321 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L564-L569 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L605-L609 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L355
When users apply for a withdrawal, they deposit ezETH into the WithdrawQueue
. In RestakeManager.sol
, the function renzoOracle.calculateMintAmount
calculates how much new ezETH to mint, taking into account the ezETH in the WithdrawQueue
, and calculateTVLs()
also accounts for the collateral in the WithdrawQueue.
The issue here is that the exchange ratio between ezETH and collateral is fixed at the time of withdrawal application. Any rewards earned by the protocol after this application do not affect this ratio. However, including these deposited ezETH in the TVL calculation can dilute subsequent users' staking rewards and can be manipulated to influence the price of ezETH.
Based on this vulnerability, an further attack scenario can be constructed, assuming the protocol's TVL is initially 0:
Through this attack process, the attacker can realize an instant profit in step three, derived from the staking rewards earned by the victim.
https://gist.github.com/StillFantastic/26338c38774d9e1dfe87d2420737c010
Manual review
In the calculateTVLs
function of RestakeManager.sol
, the calculation should exclude claimReserve
from the WithdrawQueue
, and the total supply of ezETH should also deduct the ezETH in the WithdrawQueue.
Context
#0 - c4-judge
2024-05-16T10:14:36Z
alcueca marked the issue as not a duplicate
#1 - c4-judge
2024-05-16T10:15:58Z
alcueca marked the issue as duplicate of #326
#2 - c4-judge
2024-05-16T10:16:01Z
alcueca marked the issue as satisfactory
#3 - alcueca
2024-05-16T10:16:30Z
While removing claimReserve
from the TVL calculations might be correct, ultimately the root cause is the withdrawal amount being calculated at wthidrawal, not at claim.
๐ Selected for report: LessDupes
Also found by: RamenPeople, SBSecurity, bill, guhu95, ilchovski, peanuts
598.5522 USDC - $598.55
WithdrawQueue
uses the getAvailableToWithdraw
function to calculate the current amount available for withdrawal. Amounts that have been applied for withdrawal but not yet claimed are recorded in claimReserve
and are deducted from the contractโs balance.
However, for rebase tokens like stETH, which uses shares for the underlying accounting, it's possible for the balance of an address's stETH to decrease if there is a loss in the Lido protocol. In scenarios where most of the stETH in the WithdrawQueue
has been applied for withdrawal, the calculation of balance minus claimReserve
could be very close or equal to zero. If the stETH balance then decreases, this could cause the contract to experience an underflow error.
Since the protocol's minting and withdrawal functions both use the getAvailableToWithdraw
function, if such a situation occurs, both minting and withdrawal functionalities will become unusable.
https://gist.github.com/StillFantastic/5ff507216f55427052b3755c3d217ea0
Manual review
It is recommended to add an additional check in getAvailableToWithdraw
to return zero directly when the balance is less than claimReserve
.
DoS
#0 - c4-judge
2024-05-17T12:43:08Z
alcueca marked the issue as not a duplicate
#1 - c4-judge
2024-05-17T12:43:17Z
alcueca marked the issue as primary issue
#2 - c4-judge
2024-05-17T12:44:51Z
alcueca marked the issue as duplicate of #283
#3 - c4-judge
2024-05-17T12:46:14Z
alcueca changed the severity to 3 (High Risk)
#4 - c4-judge
2024-05-17T12:46:30Z
alcueca marked the issue as duplicate of #326
#5 - c4-judge
2024-05-17T12:48:09Z
alcueca marked the issue as satisfactory
#6 - c4-judge
2024-05-27T08:45:51Z
alcueca marked the issue as not a duplicate
#7 - c4-judge
2024-05-27T08:45:58Z
alcueca changed the severity to 2 (Med Risk)
#8 - c4-judge
2024-05-27T08:46:09Z
alcueca marked the issue as duplicate of #282
#9 - c4-judge
2024-05-27T08:51:58Z
alcueca changed the severity to 3 (High Risk)
๐ Selected for report: 0xCiphky
Also found by: 0rpse, 0x007, 0xAadi, 14si2o_Flint, ADM, Aamir, Aymen0909, BiasedMerc, DanielArmstrong, Fassi_Security, FastChecker, KupiaSec, LessDupes, MaslarovK, Neon2835, RamenPeople, SBSecurity, Shaheen, Tendency, ZanyBonzy, adam-idarrha, araj, b0g0, baz1ka, bigtone, bill, blutorque, carrotsmuggler, cu5t0mpeo, fyamf, gesha17, gumgumzum, hunter_w3b, inzinko, jokr, josephdara, kennedy1030, kinda_very_good, lanrebayode77, m_Rassska, mt030d, mussucal, tapir, underdog, xg, zzykxx
0.0402 USDC - $0.04
https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L542-L562 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Delegation/OperatorDelegator.sol#L147-L148
In RestakeManager.sol
, when users deposit LST collateral, the protocol first uses this collateral to fill any deficiencies in the WithdrawQueue
. Only the remaining amount is then deposited into the OperatorDelegator
contract.
When the deficit in the WithdrawQueue
is greater than or equal to the amount deposited by the user, the subsequent amount to be deposited into OperatorDelegator
is reduced to zero. However, the OperatorDelegator
contract performs a check on the deposit amount, and if it is zero, an InvalidZeroInput
error is thrown, causing the transaction to fail.
https://gist.github.com/StillFantastic/cad063751da00348ae192a60319b9865
Manual review
It is recommended to check whether the amount is zero before executing the deposit function in OperatorDelegator
.
DoS
#0 - c4-judge
2024-05-20T05:00:05Z
alcueca marked the issue as satisfactory