xanoutas/solidity-security-findings huggingface dataset:
Wrong judgment causes the user's check to not work
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#L267-L269


# Vulnerability details

## Impact
Due to wrong judgment, the user's slippage settings may not work, resulting in slippage losses.

## Proof of Concept
After adding cdp, there is a check to check the relationship between the actual cdp and the expected cdp. The user can set the maximum acceptable slippage through collValidationBuffer. For simplicity, assume collValidationBuffer]]BPS. That is, the user does not accept slippage, then The check should be that the actual Collateral is greater than or equal to the expectedCollateral expected by the user.
However in the code, [the operation is get](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L267-L269). This means [checking that the user's expected expectedCollateral is greater than or equal to the actual Collateral](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L281-L282). This does not make any sense for the slippage check, which will not protect the user even if the user suffers slippage, even if the actualCollateral==0 also satisfies the condition.
```solidity
                expectedCollateral: CheckValueAndType({
                    value:  _totalCollateral * _collValidationBuffer / BPS,
                    operator: Operator.gte
```
```solidity
        } else if (check.operator == Operator.gte) {
            require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");
```


## Tools Used
manual

## Recommended Mitigation Steps
```diff
                expectedCollateral: CheckValueAndType({
                    value:  _totalCollateral * _collValidationBuffer / BPS,
_                    operator: Operator.gte
+                    operator: Operator.lte
```


## Assessed type

Other
If Lido eth deposit reverts all users deposited Eth  will be locked in smart 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#L34-L41


# Vulnerability details

## Description
The protocol relies on low level `call()` to deposit native eth into lido and get stEth in return, the problem however arises from the fact that `call()` wouldn't revert if lido reverts and the contract doesn't handle the returned value (`success`). this will cause the _deposit() variable to equal 0, and the contract deposited eth being locked there with no way to get them back, causing a critical lock of funds (also knowing that the codeonly has sweep ebtc and sweep stEth functions and no sweep native Eth). This is the function that handels depositing user funds into Lido, 
As we can see .call() is used, and the return value of the low level call is not handeld
https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/ZapRouterBase.sol#L34-L41
```solidity
    function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
        // check before-after balances for 1-wei corner case
        uint256 _balBefore = stEth.balanceOf(address(this));
        // TODO call submit() with a referral?
        payable(address(stEth)).call{value: _initialETH}("");
        uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
        return _deposit;
    }
```

Now let's take a look at the function in Lido that handels user deposits: `_submit()`
https://github.com/lidofinance/lido-dao/blob/5fcedc6e9a9f3ec154e69cff47c2b9e25503a78a/contracts/0.4.24/Lido.sol#L922C1-L936C10
```solidity
    function _submit(address _referral) internal returns (uint256) {
        require(msg.value != 0, "ZERO_DEPOSIT");

        StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct();
        // There is an invariant that protocol pause also implies staking pause.
        // Thus, no need to check protocol pause explicitly.
@>        require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED");

        if (stakeLimitData.isStakingLimitSet()) {
            uint256 currentStakeLimit = stakeLimitData.calculateCurrentStakeLimit();

@>            require(msg.value <= currentStakeLimit, "STAKE_LIMIT");

            STAKING_STATE_POSITION.setStorageStakeLimitStruct(stakeLimitData.updatePrevStakeLimit(currentStakeLimit - msg.value));
        }
```
As we can see there are 2 conditions in which the transaction will revert (other than 0 amt transfer):
- Lido paused (`require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED");`)
- msg.value is more than staking limit (`require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED");)

**If either of those conditions are met, the user deposited eth in the ebtcRouter or leverage router could be locked, with no way to get them**
## Recomendation
To mitigate this issue, we recommend to either use a high level call (submit()) or to handle
Unsafe Ether Deposit Using Low-Level call in _depositRawEthIntoLido function
Audit: 2024-06-badger-findings
Severity: MEDIUM

# Lines of code

https://github.com/ebtc-protocol/ebtc-zap-router/blob/40cd479b1ef2606d44cdc36f8fa2c9d84262a794/src/ZapRouterBase.sol#L37


# Vulnerability details

## Impact
In ZapRouterBase.sol, the _depositRawEthIntoLido function's use of a low-level call introduces significant risks. If the call fails, the function does not revert, which can result in incorrect stETH amounts being returned and leave the contract in an inconsistent state. Additionally, failed transactions are not handled, risking the loss of deposited Ether.

## Proof of Concept
Current code
```solidity
function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
    // check before-after balances for 1-wei corner case
    uint256 _balBefore = stEth.balanceOf(address(this));
    // TODO call submit() with a referral?
    payable(address(stEth)).call{value: _initialETH}(""); // ISSUE HERE
    uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
    return _deposit;
}
```
Example Failure Scenario
If the call fails, Ether is not deposited into the Lido contract. The function does not revert, potentially returning an incorrect _deposit value. This can lead to subsequent contract logic being based on incorrect assumptions.


## Tools Used
vscode

## Recommended Mitigation Steps
Recommended code to use:
```solidity
function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
    uint256 _balBefore = stEth.balanceOf(address(this));
    (bool success,) = payable(address(stEth)).call{value: _initialETH}("");
    require(success, "Lido deposit failed");  // Add this required statement
    uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
    return _deposit;
}
```


## Assessed type

call/delegatecall
Incorrect comparison logic in `_doCheckValueType` leading to incorrect post-operation checks
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#L277-L290


# Vulnerability details


## Impact
The incorrect comparison logic within the `_doCheckValueType` function can lead to improper validation of post-operation conditions. This can cause the protocol to either allow operations that should be blocked or reject operations that should be allowed, leading to potential security and functional issues.

## Proof of Concept
The [`_doCheckValueType` function](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L277-L290) is designed to verify if a value satisfies certain conditions based on the provided operator. However, there is an error in the comparison logic for the `gte` (greater than or equal to) and `lte` (less than or equal to) operators.

Here is the problematic code snippet:

```solidity
function _doCheckValueType(CheckValueAndType memory check, uint256 valueToCheck) internal {
    if (check.operator == Operator.skip) {
        // Early return
        return;
    } else if (check.operator == Operator.gte) {
        require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");
    } else if (check.operator == Operator.lte) {
        require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");
    } else if (check.operator == Operator.equal) {
        require(check.value == valueToCheck, "!LeverageMacroReference: equal post check");
    } else {
        revert("Operator not found");
    }
}
```

The issue lies in the `gte` and `lte` checks. The `gte` check should confirm that `valueToCheck` is greater than or equal to `check.value`, and the `lte` check should confirm that `valueToCheck` is less than or equal to `check.value`. The current implementation does the reverse.



## Tools Used
Manual code inspection.

## Recommended Mitigation Steps
To correct the issue, the comparison logic should be updated to ensure the `gte` and `lte` checks are performed correctly:

- For `gte`, ensure that `valueToCheck` is greater than or equal to `check.value`.
- For `lte`, ensure that `valueToCheck` is less than or equal to `check.value`.

The corrected function should be:

```diff
function _doCheckValueType(CheckValueAndType memory check, uint256 valueToCheck) internal {
    if (check.operator == Operator.skip) {
        // Early return
        return;
    } else if (check.operator == Operator.gte) {
-        require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");
+        require(valueToCheck >= check.value, "!LeverageMacroReference: gte post check");
    } else if (check.operator == Operator.lte) {
-        require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");
+        require(valueToCheck <= check.value, "!LeverageMacroReference: lte pos
Missing the return value check when sending native ETH to Lido can result in mis-functioning of _adjustCDP and user's fund lost
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-L40


# Vulnerability details

## Impact
The function `ZapRouterBase::_depositRawEthIntoLido()` is using a low level `call` method to send raw `ETH`. This method, when failing to send out the `ETH`, will NOT revert the trxn, instead it will return a bool as `false`. However, the `_depositRawEthIntoLido()` function does not check that returned boolean before proceeding to the next steps. This will lead to the `_deposit` return value being `0` when that trxn fails, and this `0` will eventually be passed to the upstream functions to adjust the CDPs. 

The direct impact is that the adjust CDP operations will **NOT** work as the user expected and how it is supposed to be; moreover, the user's fund will get stuck in the router contract of `EbtcLeverageZapRouter` in the form of native `ETH`. The sweep functions the protocol has in design cannot help in this case, because those functions can only sweep tokens(eBTC and stETH) but not native `ETH`. These impacts combined absolutely make the issue **HIGH** severity.

The user touchpoint functions directly impacted by this issue are, for example, `adjustCdpWithEth` and `adjustCdpWithWrappedEth`. The other downstream validations in these functions are not adequate enough to catch the issue, hence cannot help revert it.

## Proof of Concept

The problematic piece of code is this:
```
    function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
        // check before-after balances for 1-wei corner case
        uint256 _balBefore = stEth.balanceOf(address(this));
        // TODO call submit() with a referral?
        payable(address(stEth)).call{value: _initialETH}(""); // @auditor ----- Didn't check the returned boolean
        uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
        return _deposit; // @auditor ----- 0 value will be returned if the call method above failed
    }
```

Then, the `0` value will be returned to the upstream `_params.stEthMarginBalance` for adjustCDP operations. These operations will be performed on this wrong and unexpected value shown as below:

```
_adjustCdp(
    _cdpId, 
    _params, // @auditor ----- unexpected 0 value here in _params.stEthMarginBalance
    _positionManagerPermit, 
    _tradeData, 
    _zapStEthBalanceBefore
);
```

I wrote a test function as the POC shown below:

1. Setup: first, need to revise the `receiver()` in `ebtc-zap-router\lib\ebtc\packages\contracts\contracts\TestContracts\CollateralTokenTester.sol` to make it always revert. This is to simulate the situation where the router contract sending native `ETH` to Lido and the call method shall not be successful.
```
    receive() external payable {
        revert();
    }
```

2. Then, add this test function below in the contract `ebtc-zap-router/test/LeverageZaps.t.sol` and run it.
```
    function test_adjustCdp_deb
[H-1] `PostCheckParams` do not validate collateral correctly.
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#L269


# Vulnerability details

## Impact
When user open Cdp with leverage, he potentially wants his collateral to be as large as possible not fall below some lower bound. To allow the user to set such a boundary, the protocol has a parameter [collValidationBufferBPS in the struct TradeData](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/interface/IEbtcLeverageZapRouter.sol#L50).
By setting the comparison operator [gte](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L269) in the function [_getPostCheckParams](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/src/LeverageZapRouterBase.sol#L257), we set an upper bound for the collateral instead of a lower bound.
Thus, if a slippage occurs during cdp creation and the collateral value decreases, the function which open cdp will not revert and the user will lose part of the collateral.

## Proof of Concept
Look at test [`test_ZapOpenCdp_WithStEth_LowLeverage()`](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/test/LeverageZaps.t.sol#L198), which tests the opening of a cdp.

To find out the `CdpId` that is created when running this test, add the following code to [line 113](https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-zap-router/test/LeverageZaps.t.sol#L113) and run the test with the -vv flag.

```diff

+    console2.log("----------------------------");
+    uint256 b = uint256(expectedCdpId);
+    console2.log("expectedCdpId: ", b);
+    console2.log("----------------------------");

```


```javascript

[PASS] test_ZapOpenCdp_WithStEth_LowLeverage() (gas: 1578880)
Logs:
  block.timestamp 1
  ----------------------------
  expectedCdpId:  26189721900423420331969230490131130767792397847514657037538250302899882033153
  ----------------------------

```

To simulate a slippage situation, let's add the following code to the `BorrowerOperations` contract on [line 522](https://github.com/ebtc-protocol/ebtc/blob/2da05f2d1354190eacf64ec256d2c5c5358e5fa2/packages/contracts/contracts/BorrowerOperations.sol#L522) (add this only for testing, not for real contract)

```diff
+        /// @note add for test
+       uint256 IDfromTest = 26189721900423420331969230490131130767792397847514657037538250302899882033153;
+       if (_cdpId == bytes32(IDfromTest)) {
+          _netCollAsShares = _netCollAsShares - 1e18;
+       }
```

This piece of code will model collateral slippage for our CdpId at 1e18 stETH shares. 

Running our test again we will see that our test has not reverted.

```javascript
$ forge test --mt test_ZapOpenCdp_WithStEth_LowLeverage
[⠆
Unchecked Return Value in Low-Level `call` Function
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#L34


# Vulnerability details

## Vulnerability Details
In Solidity, the low-level `call` function is used to interact with other contracts or send Ether. It returns two values: a boolean indicating success or failure, and a bytes array containing any returned data. When using `call`, it's crucial to check the boolean return value to ensure the operation succeeded. Failing to do so can lead to silent failures, where a transaction appears to complete successfully even if the underlying operation failed.

In Ethereum, failed calls do not automatically revert the transaction. Instead, they return `false`, allowing the calling contract to handle the failure. If this return value is not checked, the contract may continue execution as if the call succeeded, potentially leading to inconsistent state or unexpected behavior.

## Description:
In the `_depositRawEthIntoLido` function of the ZapRouterBase contract, there is an unchecked low-level `call` used to deposit ETH into the Lido contract:

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

```solidity
function _depositRawEthIntoLido(uint256 _initialETH) internal returns (uint256) {
    uint256 _balBefore = stEth.balanceOf(address(this));
    payable(address(stEth)).call{value: _initialETH}("");
    uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
    return _deposit;
}
```

The `call` function's return value is not checked, which means:

1. If the Lido contract's receive function reverts or if the call fails for any other reason, this function will not revert.
2. The function will continue execution and calculate `_deposit` based on the balance difference, which may be zero or incorrect in case of a failed call.
3. The calling function will receive a potentially incorrect deposit amount and continue execution, assuming the deposit was successful.

## Impact
This issue can lead to:
- Inconsistent contract state
- Loss of user funds if the deposit fails silently
- Incorrect accounting of deposited amounts
- Potential vulnerabilities if other parts of the contract rely on this deposit being successful

## Mitigation

To fix this issue, the return value of the `call` function should be checked, and the transaction should revert if the call fails. Additionally, using a proper interface for the Lido contract would provide better type safety and reduce the risk of errors.


## Assessed type

call/delegatecall
Incorrect comparison logic in `_doCheckValueType` leading to incorrect post-operation checks
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#L277-L290


# Vulnerability details

## Impact
The incorrect comparison logic in the `_doCheckValueType` function can lead to incorrect validation of post-operation checks. This will result in the ptotocol not properly verifying the expected conditions, thereby, allowing operations to proceed when they should not, or failing valid operations. 

## Proof of Concept
The `_doCheckValueType` function is intended to check if a value meets certain conditions based on the operator provided. However, there is a mistake in the comparison logic for the `gte` and `lte` operators.

Look at thus part of the code: https://github.com/code-423n4/2024-06-badger/blob/9173558ee1ac8a78a7ae0a39b97b50ff0dd9e0f8/ebtc-protocol/packages/contracts/contracts/LeverageMacroBase.sol#L277-L290

```solidity
function _doCheckValueType(CheckValueAndType memory check, uint256 valueToCheck) internal {
    if (check.operator == Operator.skip) {
        // Early return
        return;
    } else if (check.operator == Operator.gte) {
        require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");
    } else if (check.operator == Operator.lte) {
        require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");
    } else if (check.operator == Operator.equal) {
        require(check.value == valueToCheck, "!LeverageMacroReference: equal post check");
    } else {
        revert("Operator not found");
    }
}
```

The problem here is with the `gte` and `lte` checks. The `gte` (greater than or equal to) check should ensure that `valueToCheck` is greater than or equal to `check.value`, and the `lte` (less than or equal to) check should ensure that `valueToCheck` is less than or equal to `check.value`. However, the current implementation does the opposite.

## Recommended Mitigation Steps
The comparison logic should be corrected to ensure that the `gte` and `lte` checks are performed correctly:

```diff
function _doCheckValueType(CheckValueAndType memory check, uint256 valueToCheck) internal {
    if (check.operator == Operator.skip) {
        // Early return
        return;
    } else if (check.operator == Operator.gte) {
-        require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");
+        require(valueToCheck >= check.value, "!LeverageMacroReference: gte post check");
    } else if (check.operator == Operator.lte) {
-        require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");
+        require(valueToCheck <= check.value, "!LeverageMacroReference: lte post check");
    } else if (check.operator == Operator.equal) {
        require(valueToCheck == check.value, "!LeverageMacroReference: equal post check");
    } else {
        revert("Operator not found");
    }
}
```



## Assessed type

Error