Skip to content
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

dimah7 - Consequent transfers of stETH, will result in DoS #130

Closed
sherlock-admin4 opened this issue Jun 27, 2024 · 0 comments
Closed

dimah7 - Consequent transfers of stETH, will result in DoS #130

sherlock-admin4 opened this issue Jun 27, 2024 · 0 comments
Labels
Non-Reward This issue will not receive a payout Sponsor Disputed The sponsor disputed this issue's validity

Comments

@sherlock-admin4
Copy link
Contributor

sherlock-admin4 commented Jun 27, 2024

dimah7

High

Consequent transfers of stETH, will result in DoS

Summary

In many cases Lido's stETH token balance is getting with 1 or 2 wei down on transfers due to rounding down math calculation. More specifically, this happens because the balance calculation of the token depends on two integer divisions, where each one has a loss of 1 wei at most. More info about this corner case from Lido's docs here. However in protocol's case deposit function calls will revert, because it's not accounting properly value transfers.

Vulnerability Detail

As can be seen below the DepositWrapper::deposit function is used to deposit tokens into the protocol's vault, with additional functionality to wrap up the tokens to the required standard:

function deposit(
        address to,
        address token,
        uint256 amount,
        uint256 minLpAmount,
        uint256 deadline
    ) external payable returns (uint256 lpAmount) {
        address wrapper = address(this);
        address sender = msg.sender;
        address[] memory tokens = vault.underlyingTokens();
        if (tokens.length != 1 || tokens[0] != wsteth)
            revert InvalidTokenList();
        if (amount == 0) revert InvalidAmount();
        if (token == steth) {
            IERC20(steth).safeTransferFrom(sender, wrapper, amount);
            amount = _stethToWsteth(amount);
            ...

function _stethToWsteth(uint256 amount) private returns (uint256) {
        IERC20(steth).safeIncreaseAllowance(wsteth, amount);
        IWSteth(wsteth).wrap(amount);
        return IERC20(wsteth).balanceOf(address(this));
    }            

Although the _stethToWsteth function returns wstETH balance of the contract, this implementation doesn't account properly for real amount as the call will revert on the wrap function, as we'll have transfered amount - 1 and the contract doesn't hold stETH tokens.

Link to Lido's discussions on this case here

Impact

Will result in DoS, the impact would be even greater if any external protocols implement this contract

Code Snippet

https://github.com/sherlock-audit/2024-06-mellow/blob/6defa2f3481ee3232ea256d0c1e4f9df9860ffa5/mellow-lrt/src/utils/DepositWrapper.sol#L56-L57

Tool used

Manual Review

Recommendation

Implement fee-on-transfer balance check methods, which checks the balances before and after transfer, then the real amount will be as amount input

function deposit(
        address to,
        address token,
        uint256 amount,
        uint256 minLpAmount,
        uint256 deadline
    ) external payable returns (uint256 lpAmount) {
        address wrapper = address(this);
        address sender = msg.sender;
        address[] memory tokens = vault.underlyingTokens();
        if (tokens.length != 1 || tokens[0] != wsteth)
            revert InvalidTokenList();
        if (amount == 0) revert InvalidAmount();
        if (token == steth) {
+           uint256 balanceBefore = IERC20(steth).balanceOf(wrapper);
            IERC20(steth).safeTransferFrom(sender, wrapper, amount);
+           uint256 realAmount =  (IERC20(stETH).balanceOf(wrapper) - balanceBefore); 
-           amount = _stethToWsteth(amount);
+           amount = _stethToWsteth(realAmount);
            ...

Or as Lido recommends implement transferShares function to handle transfer amounts

Duplicate of #299

@sherlock-admin4 sherlock-admin4 changed the title Deep Teal Gorilla - missing receive() function to receive unwrapped ETH in stakingModule.sol Consequent transfers of stETH, will result in DoS Jun 28, 2024
@sherlock-admin3 sherlock-admin3 added the Sponsor Disputed The sponsor disputed this issue's validity label Jun 30, 2024
@github-actions github-actions bot changed the title Consequent transfers of stETH, will result in DoS Bitter Jetblack Finch - Consequent transfers of stETH, will result in DoS Jul 6, 2024
@github-actions github-actions bot closed this as completed Jul 6, 2024
@github-actions github-actions bot added the Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label label Jul 6, 2024
@sherlock-admin3 sherlock-admin3 changed the title Bitter Jetblack Finch - Consequent transfers of stETH, will result in DoS dimah7 - Consequent transfers of stETH, will result in DoS Jul 15, 2024
@sherlock-admin3 sherlock-admin3 added Non-Reward This issue will not receive a payout and removed Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Jul 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Non-Reward This issue will not receive a payout Sponsor Disputed The sponsor disputed this issue's validity
Projects
None yet
Development

No branches or pull requests

2 participants