xanoutas/solidity-security-findings huggingface dataset:
Unchecked return value on call in the _convertRawEthToStETH function on the ZapRouterBase contract
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/ZapRouterBase.sol#L54-L57
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/ZapRouterBase.sol#L56


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

The external function named openCdpWithEth calls the function named _convertRawEthToStETH, which calls the function _depositRawEthIntoLido does not check the return value of the external call to the stEth contract. This can lead to a situation where the call to the stEth contract fails silently, and the function continues execution without any indication of failure. This could result in a discrepancy in the accounting of stEth balances, potentially leading to financial loss.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

```sol
    function _convertRawEthToStETH(uint256 _initialETH) internal returns (uint256) {
        require(msg.value == _initialETH, "EbtcZapRouter: Incorrect ETH amount");
        return _depositRawEthIntoLido(_initialETH);
    }
```

In the above function, the external call is made using ```_depositRawEthIntoLido``` in ```call{value: _initialETH}("")``` without checking the success of the operation. 

```https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/EbtcLeverageZapRouter.sol#L44```
```sol
        uint256 _collVal = _convertRawEthToStETH(_ethMarginBalance);
```
```https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/EbtcLeverageZapRouter.sol#L34-L66```
```sol
    function openCdpWithEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthLoanAmount,
        uint256 _ethMarginBalance,
        uint256 _stEthDepositAmount,
        bytes calldata _positionManagerPermit,
        TradeData calldata _tradeData
    ) external payable returns (bytes32 cdpId) {
        uint256 _collVal = _convertRawEthToStETH(_ethMarginBalance);


        cdpId = _openCdp(
            _debt,
            _upperHint,
            _lowerHint,
            _stEthLoanAmount,
            _collVal,
            _stEthDepositAmount,
            _positionManagerPermit,
            _tradeData
        );


        emit ZapOperationEthVariant(
            cdpId,
            EthVariantZapOperationType.OpenCdp,
            true,
            NATIVE_ETH_ADDRESS,
            _ethMarginBalance,
            _collVal,
            msg.sender
        );
    }
```
## Tools Used
Manual review.
## Recommended Mitigation Steps

To mitigate this issue, 
1. The openCdpWithEth function needs to validate the _convertRawEthToStETH value like so:
```sol
uint256 _collVal = _convertRawEthToStETH(_ethMarginBalance);
require(_collVal > 0, "Inva
_doSwapChecks might fail to validate the expectedMinOut constraint.
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L485-L497


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

```LeverageMacroBase._doSwap()``` is used to swap one token for another and it has a post check to ensure that the output token is no less than ```expectedMinOut```. However, it simply checks the balance of the output token, which is error-prone since there might be some non-zero balance right before the swap. 


## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

First, ```LeverageMacroBase._doSwap()``` is used to swap one token for another and it has a post check to ensure that the output token is no less than ```expectedMinOut```. 

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L448-L481](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L448-L481)

Second, ```LeverageMacroBase._doSwapChecks()``` does the check, but only against the balance of the output token, not the actual output amount from the swap operation. 

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L485-L497](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L485-L497)

Third, below, we show the following: 
1. Before the swap, the router has stETh: 91019547657512117.
2. The swap will return stEth in the amount of : 17994749596122777329
3. after the swap, the router has a balance of: 18085769143780289446
4. expectedMinOut = 18000000000000000000
5. Although the swap output amount is smaller than ```expectedMinOut```, the check will fail to detect this since it will only check the final balance of stEth, which is indeed greater than ```expectedMinOut```.

I revised file LeverageZaps.t.sol. Please run ```forge test --match-test testOpenCdp1 -vv```. 

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

import {Test, console2} from "forge-std/Test.sol";
import {EbtcZapRouter} from "../src/EbtcZapRouter.sol";
import {IERC20} from "@ebtc/contracts/Dependencies/IERC20.sol";
import {ZapRouterBaseInvariants} from "./ZapRouterBaseInvariants.sol";
import {IERC3156FlashLender} from "@ebtc/contracts/Interfaces/IERC3156FlashLender.sol";
import {IBorrowerOperations, IPositionManagers} from "@ebtc/contracts/LeverageMacroBase.sol";
import {ICdpManagerData} from "@ebtc/contracts/Interfaces/ICdpManager.sol";
import {IEbtcZapRouter} from "../src/interface/IEbtcZapRouter.sol";
im
Wrong slippage control for the collateral shares for a cdp due to logical error in LeverageZapRouterBase._getPostCheckParams.
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L185-L192
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L257-L274
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L207-L216
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L277-L290


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
LeverageZapRouterBase._openCdpOperation() allows a user to flashloan and then open a CDP using the loaned stETH. There is postcheck to ensure that the cdp.coll is no less than a certain amount. However, due the the wrong comparison operator, it ensure the other way around: it will ensure that  cdp.coll is not more than a certain amount instead. 


## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

First, LeverageZapRouterBase._openCdpOperation() allows a user to flashloan and then open a CDP using the loaned stETH. There is postcheck to ensure that the cdp.coll is no less than a certain amount.

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L185-L192](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L185-L192)

However, LeverageZapRouterBase._getPostCheckParams() uses the comparison operator ```Operator.gte``` instead of ```Operator.lte```. This is wrong since it will make a comparison like ```check.value >= cdp.coll``` where ```check.value``` is the minimum expected collateral amount and cdp.coll is the collateral shares of the cdp.

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L257-L274](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L257-L274)

Second, the post check will ba made like this: 

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L207-L216](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L207-L216)

where _doCheckValueType() is implemented like this: 

[https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L277-L290])https://github.com/code-42
`Operator.gte` is used for both increase or decrease CDP adjustments
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/main/ebtc-zap-router/src/LeverageZapRouterBase.sol#L151
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L267-L270
https://github.com/code-423n4/2024-06-badger/blob/main/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L219-L228


# Vulnerability details

## Impact

When collateral is increased or decreased via `_adjustCdp()`, within `_doOperation()`, there is a check for the expected collateral after the adjustment is made. This expected collateral is equal to OldCollateral +- CollateralChange multiplied by the buffer you have set. As each user passes `collValidationBufferBPS` when making an increment, it will be set to (e.g. 105% from the tests), which will limit the change to 5% above the expected value and ensure that their position is incremented to the maximum so far. But the same operator `Operator.gte` is used when decreasing. Which will completely remove the purpose of the check as it will always check if the user's **`expected value ≥ the actual amount`**. Which in the case of decrease should be the other way around as user should be allowed to set the **maximum amount** to be decreased and anything lower than that to be returned, but it isn't.

## Proof of Concept

Increase Example numbers:

- `oldCollateral = 100`
- `CollateralChange = 20`
- `NewCollateral should be 120`
- `collValidationBufferBPS = 105%`
- `expectedCollateral = 126`

And then 126 should be ≥ the changed collateral from `cdpInfo.coll` which will be around 120 but can also vary and be up to 126

```solidity
if (postCheckType == PostOperationCheck.cdpStats) {
    ICdpManagerData.Cdp memory cdpInfo = cdpManager.Cdps(checkParams.cdpId);

    _doCheckValueType(checkParams.expectedDebt, cdpInfo.debt);
    _doCheckValueType(checkParams.expectedCollateral, cdpInfo.coll);
    require(
        cdpInfo.status == checkParams.expectedStatus,
        "!LeverageMacroReference: adjustCDP status check"
    );
}
```

**≥** because this was the operator set for all collateral changes, no matter increment or decrement.

```jsx
expectedCollateral: CheckValueAndType({
        value:  _totalCollateral * _collValidationBuffer / BPS,
        operator: Operator.gte
    }),
```

And here will be the problem, when there is a decrease, the check will always pass because there will be no limit on the actual collateral change.

Decrease Example numbers:

- `oldCollateral = 100`
- `CollateralChange = 20`
- `NewCollateral should be 80`
- `collValidationBufferBPS = 105%`
- `expectedCollateral = 84`

here the comparison will be 84 ≥ changed collateral from `cdpInfo.coll`, which must be lower than that, which removes the idea of checking how much collateral is reduced, since the reduced collateral will never be small enough to break this case. But here is the other side of the coin that no matter how much collateral is actually reduced
Low-level call return value is not checked 
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/ZapRouterBase.sol#L38


# Vulnerability details

## vulenrbaility details 
is the use of the low-level call to transfer ETH without verifying if the call succeeded is make a bug that The call function, when used without checks, it's can lead to silent failures, where the intended operation depositing ETH to receive stETH does not occur, but no error is thrown to indicate the issue.
```solidity
payable(address(stEth)).call{value: _initialETH}("");
```
An attacker or user could exploit this bug by calling the function with conditions that cause the call to fail as exceeding gas limits. 
The transaction would proceed without performing the intended ETH transfer, potentially leading to inconsistencies in the system.
## Impact
the silent failure of the ETH transfer can lead to Incorrect accounting of assets, where the expected amount of stETH is not received.
## Proof of Concept
this is explaining here in  documentation: https://docs.soliditylang.org/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions

## Tools Used
manual review 
## Recommended Mitigation Steps
need a check that the call's success, and reverting on failure.


## Assessed type

Other
Potential Collateral Requirement Oversight in CDP Adjustment Functions
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/EbtcLeverageZapRouter.sol#L390-L401


# Vulnerability details


## Proof of Concept
When a CDP is opened, the contract checks that the initial collateral deposited meets the minimum requirement of 2 stETH. This is done through the [_requireAtLeastMinNetStEthBalance](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/EbtcLeverageZapRouter.sol#L217) function, which compares the total `stETH` deposit amount minus a predefined reward (`LIQUIDATOR_REWARD`) against a minimum threshold. However, when adjusting a CDP, the contract does not perform a similar check to ensure that the remaining collateral after the adjustment still meets this minimum requirement.

The [adjustCdp](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/EbtcLeverageZapRouter.sol#L390) functions allow for various operations that might change both the collateral and debt of a CDP. These operations include increasing or decreasing the collateral, changing the debt, and possibly withdrawing some of the collateral as margin. Since there is no check to ensure that the remaining collateral after such adjustments is at least 2 stETH, a user could theoretically reduce their collateral below this threshold through these adjustments. This vulnerability could lead to scenarios where the collateral is insufficient to cover the debt, potentially leading to liquidation events.
### Example Scenario
Consider a scenario where a user opens a CDP with $`4 stETH`$ as collateral, meeting the minimum requirement. Later, the user decides to adjust their CDP by reducing their collateral to $`1.5 stETH`$. Without the enforcement of the minimum collateral requirement during adjustments, the contract would not prevent this action, even though it results in a violation of the minimum collateral rule.
## Impact
Users can reduce their collateral below the required threshold. This could lead to a situation where the collateral is insufficient to cover the debt, posing a significant risk to the stability and security of the CDP mechanism.
## Tools Used
Manual
## Recommended Mitigation Steps
The contract should implement checks in the `adjustCdp` functions to ensure that the remaining collateral after an adjustment is at least equal to the minimum required collateral. This can be achieved by recalculating the total collateral after the adjustment and comparing it against the minimum requirement. If the new total is below the threshold, the transaction should revert with an appropriate error message.


## Assessed type

Other
LeverageMacroBase::_doSwapChecks Misleading Balance Calculation Compromises Slippage Protection
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/main/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L491


# Vulnerability details

## Impact

```solidity
// File: ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol
485:    function _doSwapChecks(SwapCheck[] memory swapChecks) internal {
        ...
490:                require(
491:                    IERC20(swapChecks[i].tokenToCheck).balanceOf(address(this)) > // <= FOUND: reading via `balanceOf` will include pre-existing balance before the swap
492:                        swapChecks[i].expectedMinOut,
493:                    "LeverageMacroReference: swap check failure!"
494:                );
495:            }
        ...
497:    }
```

The `_doSwapChecks` function is designed to check if the `tokenToCheck` balance after a swap is larger than the `expectedMinOut` amount to prevent slippage. However, the function reads the entire `balanceOf(address(this))` which may account all pre-existing tokens instead of calculating the balance change. That means, with the existing balance, the return value of `balanceOf` could easily exceed the `expectedMinOut` and the actual swap returns will be overlooked.

In cases where operations are conducted via a multi-purpose Smart Contract Wallet where the `sweepToCaller` has to be manually `delegatecall` to clear out tokens to the caller, it is easy to leave a significant amount of tokens in the wallet. Consequently, a `balanceOf` read would mistakenly account for these pre-existing tokens in the slippage check, failing to protect the user's funds in case of swap loss. This issue makes the CDP operations susceptiple to sandwich attacks.

## Proof of Concept

https://gist.github.com/hungdoo/3b690b5b1ed116c5fb04e40cb3be1cd9

The POC introduces a test where a CDP close operation with leverage of `eBTC` was executed via a `delegatecall` to a Smart Contract wallet in which the pre-existing `eBTC` tokens were not swept out yet. Apply this patch and run following command:

> cd ebtc-protocol/packages/contracts/ && forge test -vv --match-test test_closeWithLeverage_FailedSlippageProtection

Result:

> Ran 1 test for foundry_test/SimplifiedDiamondLikeLeverage.t.sol:SimplifiedDiamondLikeLeverageTests
> [PASS] test_closeWithLeverage_FailedSlippageProtection() (gas: 876134)
> Logs:
>   block.timestamp 1
>   eBTC remains in wallet after openCdp 99999999300839500000000
>   eBTC Loss 105488345762625000
> Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.93ms (1.77ms CPU time)

Following the test results, it is confirmed that extra eBTC tokens inside the smart contract (SC) wallet were unintentionally transferred out to the Flashloan provider due to a bug in LeverageMacroBase::_doSwapChecks. The sandwich attack is not demonstrated in the proof of concept (POC); however, it is clear that such an attack would force the user to sell the collateral at a much undervalued price. The eBTC loan provider unknowingly takes ex
ZapRouterBase::_depositRawEthIntoLido Lacks Proper Validation Checks for Low-Level call
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-06-badger/blob/main/ebtc-zap-router/src/ZapRouterBase.sol#L38


# Vulnerability details

## Impact

```solidity
// File: src/ZapRouterBase.sol
34:    function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
        ...
36:        uint256 _balBefore = stEth.balanceOf(address(this));
37:        // TODO call submit() with a referral?
38:        payable(address(stEth)).call{value: _initialETH}(""); // <= FOUND: return value of the low-level call to Lido not checked
39:        uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
40:        return _deposit;
41:    }
```

The Lido `_submit`'s [implementation](https://github.com/lidofinance/lido-dao/blob/5fcedc6e9a9f3ec154e69cff47c2b9e25503a78a/contracts/0.4.24/Lido.sol#L922-L947) contains various validations that can potentially revert transactions, such as `STAKING_PAUSED` and `STAKE_LIMIT` exceeded. However, the `ZapRouterBase::_depositRawEthIntoLido` function above does not verify if the `success` return value is actually `true` to proceed further. If a reversion did occur in the Lido's stEth contract, the Zap router will not revert and keep executing as normal. As a result, the `_deposit` will return 0 at Line 40.

```solidity
// File: src/EbtcZapRouter.sol
267:    function adjustCdpWithWrappedEth(
        ...
278:        uint256 _collBalanceIncrease = _wethBalanceIncrease;
279:        if (_wethBalanceIncrease > 0) {
280:            _collBalanceIncrease = _convertWrappedEthToStETH(_wethBalanceIncrease); // <= FOUND: _collBalanceIncrease might be overriden to 0 if deposit failed
                ...
303:    }
```

The return zero `_deposit` would propagate through `_convertWrappedEthToStETH` and then override `_collBalanceIncrease` at line 280 to 0. Since the adjust operation allows 0 changes for either collateral or debt positions, an overridden deposit in the case of an adjust containing both collateral and debt changes might go silent. Therefore, the equivalent `_initialETH` amount of ETH will be kept inside the contract without refunding the caller, causing a loss of funds. 

This vulnerability is reported as HIGH severity as it directly results in the loss of user funds, Zap router cannot sweep native ETH to refund the user and the likelihood of reversion in Lido deposit operation could be MED (STAKING_PAUSED and STAKE_LIMIT conditions could be configured occasionally).

## Proof of Concept

Apply this [patch](https://gist.github.com/hungdoo/1f33a9c498ae769b1c43e5ccd14d22f3):

For test patch: 

```sh
cd 2024-06-badger/ebtc-zap-router/ && git apply test_ZapAdjustCDPWithWrappedEthDepositAndRepay_EthGotStuck_NoCollateralIncrease.patch
``` 

For lib patch: 

```sh
cd 2024-06-badger/ebtc-zap-router/lib/ebtc && git apply ebtcLib.patch
```

### Result

> forge test -vv --mt test_ZapAdjustCDPWithWrappedEthDepositAndRepay_EthGotStuck_NoCollateralIncrease

> [⠊] Compiling...
> No files changed, compilation skipped
> Ran