-
Notifications
You must be signed in to change notification settings - Fork 0
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
Some functionalities would often revert, due to protocol's assumption that the amount specified in a transfer is directly what's been received #24
Comments
I explained here why this is not an issue and no reverts will occur. |
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 |
I acknowledged your explanation in this submission, which is why I indicated that the issue on 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.
I assume this same logic could be applicable in this protocol's case and considering the reason for reverts would be the 1-2 wei differences wouldn't it be better if protocol just uses the exact amount transferred in to ensure operations always move smoothly
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:
I assume depending on if we're looking at the root cause of this issue as the 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 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 code-423n4/2024-04-renzo-findings#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. |
I do not think this is OOS, because the original finding specifically mentioned |
alcueca marked the issue as unsatisfactory: |
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: lidofinance/core#442 (comment)Now 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
The text was updated successfully, but these errors were encountered: