Closed c4-bot-10 closed 5 months ago
It’s about stETH 1-2 wei scenario which was downgraded to QA or disputed if I remeber correctly. So I think this argument on stETH is invalid as protocol acknowledged this issue.
Also protocol have updated the safeApprove
to safeIncreaseAllowance
in the PR - https://github.com/Renzo-Protocol/Contracts/pull/100 . Which would forward the remaining shares/tokens in the next deposit with it's increase allowance.
I explained here why this is not an issue and no reverts will occur.
I acknowledged your explanation in this submission, which is why I indicated that the issue on safeApprove()
reverting is indeed invalid, but your explanation only considers when the call is being routed in the same instance from contract to contract with the same amount
, which means that the rounded down amount of shares would be the same in that tx.
However, in Renzo as far as I can remember these amounts are sometimes broken into different parts.
Attaching an example POC below were I still see how a revert could occur, @0xEVom, I'd appreciate if you could clarified if I've missed anything.
It’s about stETH 1-2 wei scenario which was downgraded to QA or disputed if I remeber correctly. So I think this argument on stETH is invalid as protocol acknowledged this issue.
Also protocol have updated the
safeApprove
tosafeIncreaseAllowance
in the PR - https://github.com/Renzo-Protocol/Contracts/pull/100 . Which would forward the remaining shares/tokens in the next deposit with it's increase allowance.
Hi @jatinj615 I can't access the PR, though would be key to note that in this case, the report is not saying the approval reverts, but rather that the transfers would revert since the balance would be less than is needed to be transferred.
Also to save everyone time, I'd like to indicate that the judge hinted this part of the Guidelines on mitigation review from his comment on another issue which I wasn't previously aware of:
Vulnerabilities submitted during the preceding audit should not be submitted as new HM issues during the mitigation review. They will be considered out of scope and ineligible for awards. If a warden feels an issue from the preceding audit was overlooked or undervalued, it is recommended to look into submitting it to the sponsor via other channels (e.g., a bug bounty program).
I assume depending on if we're looking at the root cause of this issue as the 1-2 wei scenario
attached to stETH
or if we are breaking that and having the previous submission being based on the reverts during approvals and this being on reverts during transfers this submission could be in-scope or OOS.
So leaving it to the judge to decide if it's OOS, cause if we perceive the root cause as the former which is the 1-2 wei scenario
attached to stETH
, then imo per Code4rena mitigation reviews guidelines this report should be OOS.
If otherwise, then pending @0xEVom addition in the case if I've missed anything then this submission could be valid/invalid and in-scope.
Agree with @0xEVom and the sponsor's assessment. This is the same as https://github.com/code-423n4/2024-04-renzo-findings/issues/10 therefore should be invalid.
Such issue never appeared in the live instance despite their being 20k stETH deposited in the live protocol at this point.
let's consider the new implementation of the RestakeManager#deposit() Which for effects of this finding is the same as the old implementation.
Such issue never appeared in the live instance despite their being 20k stETH deposited in the live protocol at this point. The issue should have materialized by now.
I do not think this is OOS, because the original finding specifically mentioned safeApprove
, but I do think that there isn't enough proof that the vulnerability exists in the face of the protocol executing deposits without problems.
alcueca marked the issue as unsatisfactory: Insufficient proof
Lines of code
https://github.com/Renzo-Protocol/Contracts/blob/74a6c9963d4e9359c542901fdd2dd3f5a6864f16/contracts/Delegation/OperatorDelegator.sol#L139
Vulnerability details
Proof of Concept
In multiple instances, protocol directly transfers out tokens that were received or in some instances the "exact difference", however this would be problematic for tokens that have features similar to
fee on transfer
, protocol does not support any fee on transfer tokens, however protocol does support thestETH
token. And thestETH
token has a special feature when being transferred, quotig lido's offiicial docs from here: https://docs.lido.fi/guides/lido-tokens-integration-guide/#1-2-wei-corner-case, quoting them:Now before diving deep to this issue, I'd like to indicate that this is not the same as the controversial issue from the previous contest around the DOS of the depositing/withdrawing channel due to the usage of
safeApprove()
on thestETH
asset. After some research and with the help of other wardens that bug case is indeed invalid, cause whenever a transfer is being made on thestETH
asset, the allowance specified in the function call first gets engulfed even if the transferred amount end up being 1-2 wei less, this is because in atransferFrom()
call the entire allowance gets used up via_spendAllowance
before attempting the transfer, see https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code:However the
stETH
token's transfer mechanism is still special as documented by Lido and also we can confirm this from the contract code on Etherscan: https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code: Whenever a transfer is to be executed the function below is called:This function, rounds down the amount to be returned by 1.
And when the final transfer is done this
- 1
would be reflected in the amount that's received, i.e:Asides using the code snippets from Etherscan, the official Lido team have also indicated that after their protocol-wide regression test coverage was introduced. There is now a possibility to even face a 2 wei corner case, which happens due to the fact that
stETH
balance calculation depends on two integer divisions (each one has 1 wei "loss" at most), this claim can be confirmed here: https://github.com/lidofinance/lido-dao/issues/442#issue-1298099918Now since sufficient prove has been given on how the amount specified in a transfer for
stETH
could actually be more than is specified in the transaction we can now go deeper on how this affects Renzo, fortunately this does not mean that the depositing or the withdrawal channel would be permanently DOS'd when this integration is being done withsafeApprove()
, however not taking this into account would lead to often reverts in the case where the tokens being transferred in isstETH
.There are multiple instances of this in scope, with some even having more than one attempt of transferring out the tokens, now for example let's consider the new implementation of the
RestakeManager#deposit()
after this pull request was finalized to mitigate H-08 & M-09 from the previous contestNow, to use only this instance to showcase how not taking the
1-2
wei corner case would cause a revert, let's only look at instances when transfers occur within the execution ofRestakeManager#deposit()
._collateralToken.safeTransferFrom(msg.sender, address(this), _amount);
_amount - 1
.operatorDelegator.deposit()
also queries asafeTransferFrom()
on the amount of token specified as shown below._amount
has been truncated by one, the attempt to transfer inoperatorDelegator.deposit()
reverts, since fromRestakeManager#deposit()
we pass on the non-truncated amount value when querying theoperatorDelegator.deposit(_collateralToken, _amount);
Impact
Frequent reverts in core functionality when integrating with
stETH
, would be key to also note that the instance hinted in the report is just one of many, other call route in scope even include more transfers in their executions which causes this bug case to occur.Submitting this as medium as I assume it satisfies the criteria of the function of the protocol or its availability could be impacted.
Recommended Mitigation Steps
A very popular approach when directly integrating
stETH
and having to calltransfer/transferFrom()
on it, is to also include a balance difference check, i.e before the transfer check to see how much ofstETH
is in the contract and after then after transfer, the accounting should be done on the real amount of tokens received, so a quick pseudo fix for the instance explained in this report would be to integrate the snippet below intoRestakeManager#deposit()
:And extensively all other instances where
steth
could be transferred in/out.Assessed type
Token-Transfer